2019-08-25 10:49:17 +01:00
// SPDX-License-Identifier: GPL-2.0
2006-01-08 01:01:31 -08:00
/*
2007-10-16 01:27:00 -07:00
* Copyright ( C ) 2000 - 2007 Jeff Dike ( jdike @ { addtoit , linux . intel } . com )
2005-04-16 15:20:36 -07:00
*/
2008-02-04 22:31:14 -08:00
# include <linux/delay.h>
# include <linux/init.h>
# include <linux/mm.h>
# include <linux/module.h>
# include <linux/seq_file.h>
# include <linux/string.h>
# include <linux/utsname.h>
2012-05-03 09:03:00 +00:00
# include <linux/sched.h>
2017-02-04 01:20:53 +01:00
# include <linux/sched/task.h>
2015-03-28 10:07:37 +01:00
# include <linux/kmsg_dump.h>
2017-02-04 01:20:53 +01:00
2008-02-04 22:31:14 -08:00
# include <asm/pgtable.h>
# include <asm/processor.h>
2013-11-12 20:42:27 +01:00
# include <asm/sections.h>
2008-02-04 22:31:14 -08:00
# include <asm/setup.h>
2012-10-08 03:27:32 +01:00
# include <as-layout.h>
# include <arch.h>
# include <init.h>
# include <kern.h>
# include <kern_util.h>
# include <mem_user.h>
# include <os.h>
2005-04-16 15:20:36 -07:00
# define DEFAULT_COMMAND_LINE "root=98:0"
2007-05-06 14:51:26 -07:00
/* Changed in add_arg and setup_arch, which run before SMP is started */
2007-02-12 00:54:26 -08:00
static char __initdata command_line [ COMMAND_LINE_SIZE ] = { 0 } ;
2005-04-16 15:20:36 -07:00
2007-02-12 00:54:26 -08:00
static void __init add_arg ( char * arg )
2005-04-16 15:20:36 -07:00
{
if ( strlen ( command_line ) + strlen ( arg ) + 1 > COMMAND_LINE_SIZE ) {
2017-05-18 02:19:31 +09:00
os_warn ( " add_arg: Too many command line arguments! \n " ) ;
2005-04-16 15:20:36 -07:00
exit ( 1 ) ;
}
2007-10-16 01:27:00 -07:00
if ( strlen ( command_line ) > 0 )
2005-04-16 15:20:36 -07:00
strcat ( command_line , " " ) ;
strcat ( command_line , arg ) ;
}
2007-05-06 14:51:26 -07:00
/*
* These fields are initialized at boot time and not changed .
* XXX This structure is used only in the non - SMP case . Maybe this
* should be moved to smp . c .
*/
struct cpuinfo_um boot_cpu_data = {
2005-04-16 15:20:36 -07:00
. loops_per_jiffy = 0 ,
. ipi_pipe = { - 1 , - 1 }
} ;
2012-05-03 09:03:00 +00:00
union thread_union cpu0_irqstack
__attribute__ ( ( __section__ ( " .data..init_irqstack " ) ) ) =
2018-01-02 15:12:01 +00:00
{ . thread_info = INIT_THREAD_INFO ( init_task ) } ;
2012-05-03 09:03:00 +00:00
2007-05-06 14:50:59 -07:00
/* Changed in setup_arch, which is called in early boot */
static char host_info [ ( __NEW_UTS_LEN + 1 ) * 5 ] ;
2005-04-16 15:20:36 -07:00
static int show_cpuinfo ( struct seq_file * m , void * v )
{
int index = 0 ;
seq_printf ( m , " processor \t : %d \n " , index ) ;
seq_printf ( m , " vendor_id \t : User Mode Linux \n " ) ;
seq_printf ( m , " model name \t : UML \n " ) ;
2007-10-16 01:26:56 -07:00
seq_printf ( m , " mode \t \t : skas \n " ) ;
2005-04-16 15:20:36 -07:00
seq_printf ( m , " host \t \t : %s \n " , host_info ) ;
seq_printf ( m , " bogomips \t : %lu.%02lu \n \n " ,
loops_per_jiffy / ( 500000 / HZ ) ,
( loops_per_jiffy / ( 5000 / HZ ) ) % 100 ) ;
2007-05-06 14:50:58 -07:00
return 0 ;
2005-04-16 15:20:36 -07:00
}
static void * c_start ( struct seq_file * m , loff_t * pos )
{
return * pos < NR_CPUS ? cpu_data + * pos : NULL ;
}
static void * c_next ( struct seq_file * m , void * v , loff_t * pos )
{
+ + * pos ;
return c_start ( m , pos ) ;
}
static void c_stop ( struct seq_file * m , void * v )
{
}
2006-09-27 01:50:33 -07:00
const struct seq_operations cpuinfo_op = {
2005-04-16 15:20:36 -07:00
. start = c_start ,
. next = c_next ,
. stop = c_stop ,
. show = show_cpuinfo ,
} ;
/* Set in linux_main */
unsigned long uml_physmem ;
2011-08-18 20:14:10 +01:00
EXPORT_SYMBOL ( uml_physmem ) ;
2007-05-06 14:51:26 -07:00
unsigned long uml_reserved ; /* Also modified in mem_init */
2005-04-16 15:20:36 -07:00
unsigned long start_vm ;
unsigned long end_vm ;
2007-05-06 14:51:26 -07:00
/* Set in uml_ncpus_setup */
2005-04-16 15:20:36 -07:00
int ncpus = 1 ;
/* Set in early boot */
static int have_root __initdata = 0 ;
2007-05-06 14:51:26 -07:00
/* Set in uml_mem_setup and modified in linux_main */
2005-11-07 00:58:57 -08:00
long long physmem_size = 32 * 1024 * 1024 ;
2019-09-11 14:51:20 +02:00
EXPORT_SYMBOL ( physmem_size ) ;
2005-04-16 15:20:36 -07:00
2008-04-28 02:13:52 -07:00
static const char * usage_string =
2005-04-16 15:20:36 -07:00
" User Mode Linux v%s \n "
" available at http://user-mode-linux.sourceforge.net/ \n \n " ;
static int __init uml_version_setup ( char * line , int * add )
{
2017-05-18 02:19:31 +09:00
/* Explicitly use printf() to show version in stdout */
2006-10-02 02:18:13 -07:00
printf ( " %s \n " , init_utsname ( ) - > release ) ;
2005-04-16 15:20:36 -07:00
exit ( 0 ) ;
return 0 ;
}
__uml_setup ( " --version " , uml_version_setup ,
" --version \n "
" Prints the version number of the kernel. \n \n "
) ;
static int __init uml_root_setup ( char * line , int * add )
{
have_root = 1 ;
return 0 ;
}
__uml_setup ( " root= " , uml_root_setup ,
" root=<file containing the root fs> \n "
" This is actually used by the generic kernel in exactly the same \n "
" way as in any other kernel. If you configure a number of block \n "
" devices and want to boot off something other than ubd0, you \n "
" would use something like: \n "
" root=/dev/ubd5 \n \n "
) ;
2006-02-07 12:58:40 -08:00
static int __init no_skas_debug_setup ( char * line , int * add )
{
2017-05-18 02:19:31 +09:00
os_warn ( " 'debug' is not necessary to gdb UML in skas mode - run \n " ) ;
os_warn ( " 'gdb linux' \n " ) ;
2006-02-07 12:58:40 -08:00
return 0 ;
}
__uml_setup ( " debug " , no_skas_debug_setup ,
" debug \n "
" this flag is not needed to run gdb on UML in skas mode \n \n "
) ;
2005-04-16 15:20:36 -07:00
static int __init Usage ( char * line , int * add )
{
2007-05-06 14:50:58 -07:00
const char * * p ;
2005-04-16 15:20:36 -07:00
2006-10-02 02:18:13 -07:00
printf ( usage_string , init_utsname ( ) - > release ) ;
2007-05-06 14:50:58 -07:00
p = & __uml_help_start ;
2017-05-18 02:19:31 +09:00
/* Explicitly use printf() to show help in stdout */
2007-05-06 14:50:58 -07:00
while ( p < & __uml_help_end ) {
printf ( " %s " , * p ) ;
p + + ;
}
2005-04-16 15:20:36 -07:00
exit ( 0 ) ;
return 0 ;
}
__uml_setup ( " --help " , Usage ,
" --help \n "
" Prints this message. \n \n "
) ;
2008-02-04 22:30:50 -08:00
static void __init uml_checksetup ( char * line , int * add )
2005-04-16 15:20:36 -07:00
{
struct uml_param * p ;
p = & __uml_setup_start ;
2008-02-04 22:31:14 -08:00
while ( p < & __uml_setup_end ) {
2008-04-28 02:13:52 -07:00
size_t n ;
2005-04-16 15:20:36 -07:00
n = strlen ( p - > str ) ;
2007-10-16 01:27:00 -07:00
if ( ! strncmp ( line , p - > str , n ) & & p - > setup_func ( line + n , add ) )
2008-02-04 22:30:50 -08:00
return ;
2005-04-16 15:20:36 -07:00
p + + ;
}
}
static void __init uml_postsetup ( void )
{
initcall_t * p ;
p = & __uml_postsetup_start ;
2008-02-04 22:31:14 -08:00
while ( p < & __uml_postsetup_end ) {
2005-04-16 15:20:36 -07:00
( * p ) ( ) ;
p + + ;
}
return ;
}
2008-02-04 22:31:08 -08:00
static int panic_exit ( struct notifier_block * self , unsigned long unused1 ,
void * unused2 )
{
2015-03-28 10:07:37 +01:00
kmsg_dump ( KMSG_DUMP_PANIC ) ;
2008-02-04 22:31:08 -08:00
bust_spinlocks ( 1 ) ;
bust_spinlocks ( 0 ) ;
uml_exitcode = 1 ;
os_dump_core ( ) ;
return 0 ;
}
static struct notifier_block panic_exit_notifier = {
. notifier_call = panic_exit ,
. next = NULL ,
. priority = 0
} ;
2015-03-28 09:59:46 +01:00
void uml_finishsetup ( void )
{
atomic_notifier_chain_register ( & panic_notifier_list ,
& panic_exit_notifier ) ;
uml_postsetup ( ) ;
new_thread_handler ( ) ;
}
2005-04-16 15:20:36 -07:00
/* Set during early boot */
2008-02-08 04:22:07 -08:00
unsigned long task_size ;
EXPORT_SYMBOL ( task_size ) ;
unsigned long host_task_size ;
2005-04-16 15:20:36 -07:00
unsigned long brk_start ;
unsigned long end_iomem ;
EXPORT_SYMBOL ( end_iomem ) ;
# define MIN_VMALLOC (32 * 1024 * 1024)
2007-02-12 00:54:26 -08:00
int __init linux_main ( int argc , char * * argv )
2005-04-16 15:20:36 -07:00
{
unsigned long avail , diff ;
unsigned long virtmem_size , max_physmem ;
2008-05-12 14:01:57 -07:00
unsigned long stack ;
2008-04-28 02:13:52 -07:00
unsigned int i ;
int add ;
2005-04-16 15:20:36 -07:00
2007-10-16 01:27:00 -07:00
for ( i = 1 ; i < argc ; i + + ) {
if ( ( i = = 1 ) & & ( argv [ i ] [ 0 ] = = ' ' ) )
continue ;
2005-04-16 15:20:36 -07:00
add = 1 ;
uml_checksetup ( argv [ i ] , & add ) ;
if ( add )
add_arg ( argv [ i ] ) ;
}
2007-10-16 01:27:00 -07:00
if ( have_root = = 0 )
2005-04-16 15:20:36 -07:00
add_arg ( DEFAULT_COMMAND_LINE ) ;
2008-06-05 22:46:12 -07:00
host_task_size = os_get_top_address ( ) ;
2008-02-08 04:22:07 -08:00
/*
* TASK_SIZE needs to be PGDIR_SIZE aligned or else exit_mmap craps
* out
*/
task_size = host_task_size & PGDIR_MASK ;
2007-10-16 01:27:00 -07:00
/* OS sanity checks that need to happen before the kernel runs */
2005-09-03 15:57:47 -07:00
os_early_checks ( ) ;
2005-07-27 11:43:31 -07:00
2005-04-16 15:20:36 -07:00
brk_start = ( unsigned long ) sbrk ( 0 ) ;
2007-10-16 01:26:58 -07:00
2007-10-16 01:27:00 -07:00
/*
* Increase physical memory size for exec - shield users
* so they actually get what they asked for . This should
* add zero for non - exec shield users
*/
2005-04-16 15:20:36 -07:00
diff = UML_ROUND_UP ( brk_start ) - UML_ROUND_UP ( & _end ) ;
2007-10-16 01:27:00 -07:00
if ( diff > 1024 * 1024 ) {
2017-05-18 02:17:14 +09:00
os_info ( " Adding %ld bytes to physical memory to account for "
" exec-shield gap \n " , diff ) ;
2005-04-16 15:20:36 -07:00
physmem_size + = UML_ROUND_UP ( brk_start ) - UML_ROUND_UP ( & _end ) ;
}
2014-10-12 13:02:12 +02:00
uml_physmem = ( unsigned long ) __binary_start & PAGE_MASK ;
2005-04-16 15:20:36 -07:00
/* Reserve up to 4M after the current brk */
uml_reserved = ROUND_4M ( brk_start ) + ( 1 < < 22 ) ;
2006-10-02 02:18:13 -07:00
setup_machinename ( init_utsname ( ) - > machine ) ;
2005-04-16 15:20:36 -07:00
highmem = 0 ;
iomem_size = ( iomem_size + PAGE_SIZE - 1 ) & PAGE_MASK ;
2008-02-08 04:22:07 -08:00
max_physmem = TASK_SIZE - uml_physmem - iomem_size - MIN_VMALLOC ;
2005-04-16 15:20:36 -07:00
2007-10-16 01:27:00 -07:00
/*
* Zones have to begin on a 1 < < MAX_ORDER page boundary ,
2005-04-16 15:20:36 -07:00
* so this makes sure that ' s true for highmem
*/
max_physmem & = ~ ( ( 1 < < ( PAGE_SHIFT + MAX_ORDER ) ) - 1 ) ;
2007-10-16 01:27:00 -07:00
if ( physmem_size + iomem_size > max_physmem ) {
2005-04-16 15:20:36 -07:00
highmem = physmem_size + iomem_size - max_physmem ;
physmem_size - = highmem ;
}
high_physmem = uml_physmem + physmem_size ;
end_iomem = high_physmem + iomem_size ;
high_memory = ( void * ) end_iomem ;
start_vm = VMALLOC_START ;
virtmem_size = physmem_size ;
2008-05-12 14:01:57 -07:00
stack = ( unsigned long ) argv ;
stack & = ~ ( 1024 * 1024 - 1 ) ;
avail = stack - start_vm ;
2007-10-16 01:27:00 -07:00
if ( physmem_size > avail )
virtmem_size = avail ;
2005-04-16 15:20:36 -07:00
end_vm = start_vm + virtmem_size ;
2007-10-16 01:27:00 -07:00
if ( virtmem_size < physmem_size )
2017-05-18 02:17:14 +09:00
os_info ( " Kernel virtual memory size shrunk to %lu bytes \n " ,
virtmem_size ) ;
2005-04-16 15:20:36 -07:00
os_flush_stdout ( ) ;
2007-10-16 01:26:58 -07:00
return start_uml ( ) ;
2005-04-16 15:20:36 -07:00
}
2017-04-27 12:15:10 +09:00
int __init __weak read_initrd ( void )
{
return 0 ;
}
2005-04-16 15:20:36 -07:00
void __init setup_arch ( char * * cmdline_p )
{
2016-06-12 21:56:42 +02:00
stack_protections ( ( unsigned long ) & init_thread_info ) ;
setup_physmem ( uml_physmem , uml_reserved , physmem_size , highmem ) ;
mem_total_pages ( physmem_size , iomem_size , highmem ) ;
2017-04-27 12:15:10 +09:00
read_initrd ( ) ;
2016-06-12 21:56:42 +02:00
2005-04-16 15:20:36 -07:00
paging_init ( ) ;
2007-02-12 00:54:23 -08:00
strlcpy ( boot_command_line , command_line , COMMAND_LINE_SIZE ) ;
2007-05-06 14:50:58 -07:00
* cmdline_p = command_line ;
2007-05-06 14:50:59 -07:00
setup_hostinfo ( host_info , sizeof host_info ) ;
2005-04-16 15:20:36 -07:00
}
void __init check_bugs ( void )
{
arch_check_bugs ( ) ;
2007-05-06 14:50:58 -07:00
os_check_bugs ( ) ;
2005-04-16 15:20:36 -07:00
}
2006-03-23 02:59:32 -08:00
void apply_alternatives ( struct alt_instr * start , struct alt_instr * end )
{
}