2019-08-25 12:49:18 +03:00
// SPDX-License-Identifier: GPL-2.0
2005-04-17 02:20:36 +04:00
/*
2015-11-02 19:16:37 +03:00
* Copyright ( C ) 2015 Thomas Meyer ( thomas @ m3y3r . de )
2007-10-16 12:27:00 +04:00
* Copyright ( C ) 2000 - 2007 Jeff Dike ( jdike @ { addtoit , linux . intel } . com )
2005-04-17 02:20:36 +04:00
*/
# include <stdio.h>
# include <stdlib.h>
2007-10-16 12:27:00 +04:00
# include <unistd.h>
2005-04-17 02:20:36 +04:00
# include <errno.h>
2007-10-16 12:27:00 +04:00
# include <signal.h>
# include <string.h>
2005-04-17 02:20:36 +04:00
# include <sys/resource.h>
2012-10-08 06:27:32 +04:00
# include <as-layout.h>
# include <init.h>
# include <kern_util.h>
# include <os.h>
# include <um_malloc.h>
2005-04-17 02:20:36 +04:00
# define PGD_BOUND (4 * 1024 * 1024)
# define STACKSIZE (8 * 1024 * 1024)
# define THREAD_NAME_LEN (256)
2011-07-26 04:12:52 +04:00
long elf_aux_hwcap ;
2005-04-17 02:20:36 +04:00
static void set_stklim ( void )
{
struct rlimit lim ;
2007-10-16 12:27:00 +04:00
if ( getrlimit ( RLIMIT_STACK , & lim ) < 0 ) {
2005-04-17 02:20:36 +04:00
perror ( " getrlimit " ) ;
exit ( 1 ) ;
}
2007-10-16 12:27:00 +04:00
if ( ( lim . rlim_cur = = RLIM_INFINITY ) | | ( lim . rlim_cur > STACKSIZE ) ) {
2005-04-17 02:20:36 +04:00
lim . rlim_cur = STACKSIZE ;
2007-10-16 12:27:00 +04:00
if ( setrlimit ( RLIMIT_STACK , & lim ) < 0 ) {
2005-04-17 02:20:36 +04:00
perror ( " setrlimit " ) ;
exit ( 1 ) ;
}
}
}
static void last_ditch_exit ( int sig )
{
uml_cleanup ( ) ;
exit ( 1 ) ;
}
2006-09-26 10:33:04 +04:00
static void install_fatal_handler ( int sig )
{
struct sigaction action ;
/* All signals are enabled in this handler ... */
sigemptyset ( & action . sa_mask ) ;
2007-10-16 12:27:00 +04:00
/*
* . . . including the signal being handled , plus we want the
2006-09-26 10:33:04 +04:00
* handler reset to the default behavior , so that if an exit
* handler is hanging for some reason , the UML will just die
* after this signal is sent a second time .
*/
action . sa_flags = SA_RESETHAND | SA_NODEFER ;
action . sa_restorer = NULL ;
action . sa_handler = last_ditch_exit ;
2007-10-16 12:27:00 +04:00
if ( sigaction ( sig , & action , NULL ) < 0 ) {
2017-05-17 20:19:31 +03:00
os_warn ( " failed to install handler for signal %d "
" - errno = %d \n " , sig , errno ) ;
2006-09-26 10:33:04 +04:00
exit ( 1 ) ;
}
}
2011-05-25 04:13:00 +04:00
# define UML_LIB_PATH ":" OS_LIB_PATH " / uml"
2006-05-01 23:16:01 +04:00
static void setup_env_path ( void )
{
char * new_path = NULL ;
char * old_path = NULL ;
int path_len = 0 ;
old_path = getenv ( " PATH " ) ;
2007-10-16 12:27:00 +04:00
/*
* if no PATH variable is set or it has an empty value
2006-05-01 23:16:01 +04:00
* just use the default + / usr / lib / uml
*/
if ( ! old_path | | ( path_len = strlen ( old_path ) ) = = 0 ) {
2008-02-05 09:30:35 +03:00
if ( putenv ( " PATH=:/bin:/usr/bin/ " UML_LIB_PATH ) )
perror ( " couldn't putenv " ) ;
2006-05-01 23:16:01 +04:00
return ;
}
/* append /usr/lib/uml to the existing path */
path_len + = strlen ( " PATH= " UML_LIB_PATH ) + 1 ;
new_path = malloc ( path_len ) ;
if ( ! new_path ) {
2008-02-05 09:30:35 +03:00
perror ( " couldn't malloc to set a new PATH " ) ;
2006-05-01 23:16:01 +04:00
return ;
}
snprintf ( new_path , path_len , " PATH=%s " UML_LIB_PATH , old_path ) ;
2008-02-05 09:30:35 +03:00
if ( putenv ( new_path ) ) {
perror ( " couldn't putenv to set a new PATH " ) ;
free ( new_path ) ;
}
2006-05-01 23:16:01 +04:00
}
2005-04-17 02:20:36 +04:00
extern void scan_elf_aux ( char * * envp ) ;
2007-05-07 01:51:11 +04:00
int __init main ( int argc , char * * argv , char * * envp )
2005-04-17 02:20:36 +04:00
{
char * * new_argv ;
2005-05-29 02:51:56 +04:00
int ret , i , err ;
2005-04-17 02:20:36 +04:00
set_stklim ( ) ;
2006-05-01 23:16:01 +04:00
setup_env_path ( ) ;
2013-08-18 15:30:09 +04:00
setsid ( ) ;
2005-04-17 02:20:36 +04:00
new_argv = malloc ( ( argc + 1 ) * sizeof ( char * ) ) ;
2007-10-16 12:27:00 +04:00
if ( new_argv = = NULL ) {
2005-04-17 02:20:36 +04:00
perror ( " Mallocing argv " ) ;
exit ( 1 ) ;
}
2007-10-16 12:27:00 +04:00
for ( i = 0 ; i < argc ; i + + ) {
2005-04-17 02:20:36 +04:00
new_argv [ i ] = strdup ( argv [ i ] ) ;
2007-10-16 12:27:00 +04:00
if ( new_argv [ i ] = = NULL ) {
2005-04-17 02:20:36 +04:00
perror ( " Mallocing an arg " ) ;
exit ( 1 ) ;
}
}
new_argv [ argc ] = NULL ;
2007-10-16 12:27:00 +04:00
/*
* Allow these signals to bring down a UML if all other
2006-09-26 10:33:04 +04:00
* methods of control fail .
*/
install_fatal_handler ( SIGINT ) ;
install_fatal_handler ( SIGTERM ) ;
2005-04-17 02:20:36 +04:00
2011-07-26 04:12:52 +04:00
# ifdef CONFIG_ARCH_REUSE_HOST_VSYSCALL_AREA
2007-10-16 12:27:00 +04:00
scan_elf_aux ( envp ) ;
2011-07-26 04:12:52 +04:00
# endif
2005-04-17 02:20:36 +04:00
2014-03-07 22:37:46 +04:00
change_sig ( SIGPIPE , 0 ) ;
2005-04-17 02:20:36 +04:00
ret = linux_main ( argc , argv ) ;
2007-10-16 12:27:00 +04:00
/*
* Disable SIGPROF - I have no idea why libc doesn ' t do this or turn
2005-04-17 02:20:36 +04:00
* off the profiling time , but UML dies with a SIGPROF just before
* exiting when profiling is active .
*/
change_sig ( SIGPROF , 0 ) ;
2007-10-16 12:27:00 +04:00
/*
* This signal stuff used to be in the reboot case . However ,
2015-11-02 19:16:37 +03:00
* sometimes a timer signal can come in when we ' re halting ( reproducably
2005-11-07 11:58:50 +03:00
* when writing out gcov information , presumably because that takes
* some time ) and cause a segfault .
*/
2015-11-02 19:16:37 +03:00
/* stop timers and set timer signal to be ignored */
os_timer_disable ( ) ;
2005-11-07 11:58:50 +03:00
/* disable SIGIO for the fds and set SIGIO to be ignored */
err = deactivate_all_fds ( ) ;
2007-10-16 12:27:00 +04:00
if ( err )
2017-05-17 20:19:31 +03:00
os_warn ( " deactivate_all_fds failed, errno = %d \n " , - err ) ;
2005-11-07 11:58:50 +03:00
2007-10-16 12:27:00 +04:00
/*
* Let any pending signals fire now . This ensures
2005-11-07 11:58:50 +03:00
* that they won ' t be delivered after the exec , when
* they are definitely not expected .
*/
2019-09-17 14:20:14 +03:00
unblock_signals ( ) ;
2005-04-17 02:20:36 +04:00
2017-05-17 20:17:14 +03:00
os_info ( " \n " ) ;
2005-05-29 02:51:56 +04:00
/* Reboot */
2007-10-16 12:27:00 +04:00
if ( ret ) {
2005-04-17 02:20:36 +04:00
execvp ( new_argv [ 0 ] , new_argv ) ;
perror ( " Failed to exec kernel " ) ;
ret = 1 ;
}
2007-05-07 01:50:58 +04:00
return uml_exitcode ;
2005-04-17 02:20:36 +04:00
}
extern void * __real_malloc ( int ) ;
void * __wrap_malloc ( int size )
{
void * ret ;
2007-10-16 12:27:00 +04:00
if ( ! kmalloc_ok )
2007-05-07 01:50:58 +04:00
return __real_malloc ( size ) ;
2007-10-16 12:27:00 +04:00
else if ( size < = UM_KERN_PAGE_SIZE )
2007-06-16 21:16:09 +04:00
/* finding contiguous pages can be hard*/
2008-05-13 01:01:52 +04:00
ret = uml_kmalloc ( size , UM_GFP_KERNEL ) ;
2007-07-16 10:38:56 +04:00
else ret = vmalloc ( size ) ;
2005-04-17 02:20:36 +04:00
2007-10-16 12:27:00 +04:00
/*
* glibc people insist that if malloc fails , errno should be
2005-04-17 02:20:36 +04:00
* set by malloc as well . So we do .
*/
2007-10-16 12:27:00 +04:00
if ( ret = = NULL )
2005-04-17 02:20:36 +04:00
errno = ENOMEM ;
2007-05-07 01:50:58 +04:00
return ret ;
2005-04-17 02:20:36 +04:00
}
void * __wrap_calloc ( int n , int size )
{
void * ptr = __wrap_malloc ( n * size ) ;
2007-10-16 12:27:00 +04:00
if ( ptr = = NULL )
2007-05-07 01:50:58 +04:00
return NULL ;
2005-04-17 02:20:36 +04:00
memset ( ptr , 0 , n * size ) ;
2007-05-07 01:50:58 +04:00
return ptr ;
2005-04-17 02:20:36 +04:00
}
extern void __real_free ( void * ) ;
extern unsigned long high_physmem ;
void __wrap_free ( void * ptr )
{
unsigned long addr = ( unsigned long ) ptr ;
2007-10-16 12:27:00 +04:00
/*
* We need to know how the allocation happened , so it can be correctly
2005-04-17 02:20:36 +04:00
* freed . This is done by seeing what region of memory the pointer is
* in -
* physical memory - kmalloc / kfree
* kernel virtual memory - vmalloc / vfree
* anywhere else - malloc / free
* If kmalloc is not yet possible , then either high_physmem and / or
* end_vm are still 0 ( as at startup ) , in which case we call free , or
* we have set them , but anyway addr has not been allocated from those
* areas . So , in both cases __real_free is called .
*
* CAN_KMALLOC is checked because it would be bad to free a buffer
* with kmalloc / vmalloc after they have been turned off during
* shutdown .
* XXX : However , we sometimes shutdown CAN_KMALLOC temporarily , so
* there is a possibility for memory leaks .
*/
2007-10-16 12:27:00 +04:00
if ( ( addr > = uml_physmem ) & & ( addr < high_physmem ) ) {
if ( kmalloc_ok )
2005-04-17 02:20:36 +04:00
kfree ( ptr ) ;
}
2007-10-16 12:27:00 +04:00
else if ( ( addr > = start_vm ) & & ( addr < end_vm ) ) {
if ( kmalloc_ok )
2005-04-17 02:20:36 +04:00
vfree ( ptr ) ;
}
else __real_free ( ptr ) ;
}