diff options
Diffstat (limited to 'arch/um/kernel/um_arch.c')
| -rw-r--r-- | arch/um/kernel/um_arch.c | 409 |
1 files changed, 170 insertions, 239 deletions
diff --git a/arch/um/kernel/um_arch.c b/arch/um/kernel/um_arch.c index e2d3ca445ef..016adf0985d 100644 --- a/arch/um/kernel/um_arch.c +++ b/arch/um/kernel/um_arch.c @@ -1,74 +1,67 @@ /* - * Copyright (C) 2000, 2002 Jeff Dike (jdike@karaya.com) + * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) * Licensed under the GPL */ -#include "linux/config.h" -#include "linux/kernel.h" -#include "linux/sched.h" -#include "linux/notifier.h" -#include "linux/mm.h" -#include "linux/types.h" -#include "linux/tty.h" -#include "linux/init.h" -#include "linux/bootmem.h" -#include "linux/spinlock.h" -#include "linux/utsname.h" -#include "linux/sysrq.h" -#include "linux/seq_file.h" -#include "linux/delay.h" -#include "linux/module.h" -#include "asm/page.h" -#include "asm/pgtable.h" -#include "asm/ptrace.h" -#include "asm/elf.h" -#include "asm/user.h" -#include "asm/setup.h" -#include "ubd_user.h" -#include "asm/current.h" -#include "user_util.h" -#include "kern_util.h" -#include "kern.h" -#include "mem_user.h" -#include "mem.h" -#include "umid.h" -#include "initrd.h" -#include "init.h" -#include "os.h" -#include "choose-mode.h" -#include "mode_kern.h" -#include "mode.h" -#ifdef UML_CONFIG_MODE_SKAS -#include "skas.h" -#endif +#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> +#include <linux/sched.h> +#include <asm/pgtable.h> +#include <asm/processor.h> +#include <asm/sections.h> +#include <asm/setup.h> +#include <as-layout.h> +#include <arch.h> +#include <init.h> +#include <kern.h> +#include <kern_util.h> +#include <mem_user.h> +#include <os.h> #define DEFAULT_COMMAND_LINE "root=98:0" -/* Changed in linux_main and setup_arch, which run before SMP is started */ -static char command_line[COMMAND_LINE_SIZE] = { 0 }; +/* Changed in add_arg and setup_arch, which run before SMP is started */ +static char __initdata command_line[COMMAND_LINE_SIZE] = { 0 }; -static void add_arg(char *arg) +static void __init add_arg(char *arg) { if (strlen(command_line) + strlen(arg) + 1 > COMMAND_LINE_SIZE) { printf("add_arg: Too many command line arguments!\n"); exit(1); } - if(strlen(command_line) > 0) + if (strlen(command_line) > 0) strcat(command_line, " "); strcat(command_line, arg); } -struct cpuinfo_um boot_cpu_data = { +/* + * 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 = { .loops_per_jiffy = 0, .ipi_pipe = { -1, -1 } }; +union thread_union cpu0_irqstack + __attribute__((__section__(".data..init_irqstack"))) = + { INIT_THREAD_INFO(init_task) }; + unsigned long thread_saved_pc(struct task_struct *task) { - return(os_process_pc(CHOOSE_MODE_PROC(thread_pid_tt, thread_pid_skas, - task))); + /* FIXME: Need to look up userspace_pid by cpu */ + return os_process_pc(userspace_pid[0]); } +/* Changed in setup_arch, which is called in early boot */ +static char host_info[(__NEW_UTS_LEN + 1) * 5]; + static int show_cpuinfo(struct seq_file *m, void *v) { int index = 0; @@ -82,13 +75,13 @@ static int show_cpuinfo(struct seq_file *m, void *v) 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"); - seq_printf(m, "mode\t\t: %s\n", CHOOSE_MODE("tt", "skas")); + seq_printf(m, "mode\t\t: skas\n"); 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); - return(0); + return 0; } static void *c_start(struct seq_file *m, loff_t *pos) @@ -106,7 +99,7 @@ static void c_stop(struct seq_file *m, void *v) { } -struct seq_operations cpuinfo_op = { +const struct seq_operations cpuinfo_op = { .start = c_start, .next = c_next, .stop = c_stop, @@ -114,60 +107,29 @@ struct seq_operations cpuinfo_op = { }; /* Set in linux_main */ -unsigned long host_task_size; -unsigned long task_size; - -unsigned long uml_start; - -/* Set in early boot */ unsigned long uml_physmem; -unsigned long uml_reserved; +EXPORT_SYMBOL(uml_physmem); + +unsigned long uml_reserved; /* Also modified in mem_init */ unsigned long start_vm; unsigned long end_vm; -int ncpus = 1; -#ifdef CONFIG_CMDLINE_ON_HOST -/* Pointer set in linux_main, the array itself is private to each thread, - * and changed at address space creation time so this poses no concurrency - * problems. - */ -static char *argv1_begin = NULL; -static char *argv1_end = NULL; -#endif +/* Set in uml_ncpus_setup */ +int ncpus = 1; /* Set in early boot */ static int have_root __initdata = 0; -long long physmem_size = 32 * 1024 * 1024; - -void set_cmdline(char *cmd) -{ -#ifdef CONFIG_CMDLINE_ON_HOST - char *umid, *ptr; - if(CHOOSE_MODE(honeypot, 0)) return; - - umid = get_umid(); - if(*umid != '\0'){ - snprintf(argv1_begin, - (argv1_end - argv1_begin) * sizeof(*ptr), - "(%s) ", umid); - ptr = &argv1_begin[strlen(argv1_begin)]; - } - else ptr = argv1_begin; - - snprintf(ptr, (argv1_end - ptr) * sizeof(*ptr), "[%s]", cmd); - memset(argv1_begin + strlen(argv1_begin), '\0', - argv1_end - argv1_begin - strlen(argv1_begin)); -#endif -} +/* Set in uml_mem_setup and modified in linux_main */ +long long physmem_size = 32 * 1024 * 1024; -static char *usage_string = +static const char *usage_string = "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) { - printf("%s\n", system_utsname.release); + printf("%s\n", init_utsname()->release); exit(0); return 0; @@ -193,81 +155,47 @@ __uml_setup("root=", uml_root_setup, " root=/dev/ubd5\n\n" ); -#ifdef CONFIG_SMP -static int __init uml_ncpus_setup(char *line, int *add) +static int __init no_skas_debug_setup(char *line, int *add) { - if (!sscanf(line, "%d", &ncpus)) { - printf("Couldn't parse [%s]\n", line); - return -1; - } + printf("'debug' is not necessary to gdb UML in skas mode - run \n"); + printf("'gdb linux'\n"); - return 0; + return 0; } -__uml_setup("ncpus=", uml_ncpus_setup, -"ncpus=<# of desired CPUs>\n" -" This tells an SMP kernel how many virtual processors to start.\n\n" +__uml_setup("debug", no_skas_debug_setup, +"debug\n" +" this flag is not needed to run gdb on UML in skas mode\n\n" ); -#endif - -static int force_tt = 0; - -#if defined(CONFIG_MODE_TT) && defined(CONFIG_MODE_SKAS) -#define DEFAULT_TT 0 - -static int __init mode_tt_setup(char *line, int *add) -{ - force_tt = 1; - return(0); -} - -#else -#ifdef CONFIG_MODE_SKAS - -#define DEFAULT_TT 0 -static int __init mode_tt_setup(char *line, int *add) +#ifdef CONFIG_SMP +static int __init uml_ncpus_setup(char *line, int *add) { - printf("CONFIG_MODE_TT disabled - 'mode=tt' ignored\n"); - return(0); -} - -#else -#ifdef CONFIG_MODE_TT - -#define DEFAULT_TT 1 + if (!sscanf(line, "%d", &ncpus)) { + printf("Couldn't parse [%s]\n", line); + return -1; + } -static int __init mode_tt_setup(char *line, int *add) -{ - printf("CONFIG_MODE_SKAS disabled - 'mode=tt' redundant\n"); - return(0); + return 0; } -#endif -#endif -#endif - -__uml_setup("mode=tt", mode_tt_setup, -"mode=tt\n" -" When both CONFIG_MODE_TT and CONFIG_MODE_SKAS are enabled, this option\n" -" forces UML to run in tt (tracing thread) mode. It is not the default\n" -" because it's slower and less secure than skas mode.\n\n" +__uml_setup("ncpus=", uml_ncpus_setup, +"ncpus=<# of desired CPUs>\n" +" This tells an SMP kernel how many virtual processors to start.\n\n" ); - -int mode_tt = DEFAULT_TT; +#endif static int __init Usage(char *line, int *add) { - const char **p; - - printf(usage_string, system_utsname.release); - p = &__uml_help_start; - while (p < &__uml_help_end) { - printf("%s", *p); - p++; - } - exit(0); + const char **p; + printf(usage_string, init_utsname()->release); + p = &__uml_help_start; + while (p < &__uml_help_end) { + printf("%s", *p); + p++; + } + exit(0); return 0; } @@ -276,21 +204,19 @@ __uml_setup("--help", Usage, " Prints this message.\n\n" ); -static int __init uml_checksetup(char *line, int *add) +static void __init uml_checksetup(char *line, int *add) { struct uml_param *p; p = &__uml_setup_start; - while(p < &__uml_setup_end) { - int n; + while (p < &__uml_setup_end) { + size_t n; n = strlen(p->str); - if(!strncmp(line, p->str, n)){ - if (p->setup_func(line + n, add)) return 1; - } + if (!strncmp(line, p->str, n) && p->setup_func(line + n, add)) + return; p++; } - return 0; } static void __init uml_postsetup(void) @@ -298,112 +224,120 @@ static void __init uml_postsetup(void) initcall_t *p; p = &__uml_postsetup_start; - while(p < &__uml_postsetup_end){ + while (p < &__uml_postsetup_end) { (*p)(); p++; } return; } +static int panic_exit(struct notifier_block *self, unsigned long unused1, + void *unused2) +{ + 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 +}; + /* Set during early boot */ +unsigned long task_size; +EXPORT_SYMBOL(task_size); + +unsigned long host_task_size; + unsigned long brk_start; unsigned long end_iomem; EXPORT_SYMBOL(end_iomem); #define MIN_VMALLOC (32 * 1024 * 1024) -int linux_main(int argc, char **argv) +extern char __binary_start; + +int __init linux_main(int argc, char **argv) { unsigned long avail, diff; unsigned long virtmem_size, max_physmem; - unsigned int i, add; + unsigned long stack; + unsigned int i; + int add; char * mode; - for (i = 1; i < argc; i++){ - if((i == 1) && (argv[i][0] == ' ')) continue; + for (i = 1; i < argc; i++) { + if ((i == 1) && (argv[i][0] == ' ')) + continue; add = 1; uml_checksetup(argv[i], &add); if (add) add_arg(argv[i]); } - if(have_root == 0) + if (have_root == 0) add_arg(DEFAULT_COMMAND_LINE); + host_task_size = os_get_top_address(); + /* + * TASK_SIZE needs to be PGDIR_SIZE aligned or else exit_mmap craps + * out + */ + task_size = host_task_size & PGDIR_MASK; + + /* OS sanity checks that need to happen before the kernel runs */ os_early_checks(); - if (force_tt) - clear_can_do_skas(); - mode_tt = force_tt ? 1 : !can_do_skas(); -#ifndef CONFIG_MODE_TT - if (mode_tt) { - /*Since CONFIG_MODE_TT is #undef'ed, force_tt cannot be 1. So, - * can_do_skas() returned 0, and the message is correct. */ - printf("Support for TT mode is disabled, and no SKAS support is present on the host.\n"); - exit(1); - } -#endif -#ifndef CONFIG_MODE_SKAS - mode = "TT"; -#else - /* Show to the user the result of selection */ - if (mode_tt) - mode = "TT"; - else if (proc_mm && ptrace_faultinfo) + can_do_skas(); + + if (proc_mm && ptrace_faultinfo) mode = "SKAS3"; else mode = "SKAS0"; -#endif printf("UML running in %s mode\n", mode); - uml_start = CHOOSE_MODE_PROC(set_task_sizes_tt, set_task_sizes_skas, 0, - &host_task_size, &task_size); + brk_start = (unsigned long) sbrk(0); /* - * Setting up handlers to 'sig_info' struct - */ - os_fill_handlinfo(handlinfo_kern); - - brk_start = (unsigned long) sbrk(0); - CHOOSE_MODE_PROC(before_mem_tt, before_mem_skas, brk_start); - /* 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 */ + * 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 + */ diff = UML_ROUND_UP(brk_start) - UML_ROUND_UP(&_end); - if(diff > 1024 * 1024){ + if (diff > 1024 * 1024) { printf("Adding %ld bytes to physical memory to account for " "exec-shield gap\n", diff); physmem_size += UML_ROUND_UP(brk_start) - UML_ROUND_UP(&_end); } - uml_physmem = uml_start; + uml_physmem = (unsigned long) &__binary_start & PAGE_MASK; /* Reserve up to 4M after the current brk */ uml_reserved = ROUND_4M(brk_start) + (1 << 22); - setup_machinename(system_utsname.machine); + setup_machinename(init_utsname()->machine); -#ifdef CONFIG_CMDLINE_ON_HOST - argv1_begin = argv[1]; - argv1_end = &argv[1][strlen(argv[1])]; -#endif - highmem = 0; iomem_size = (iomem_size + PAGE_SIZE - 1) & PAGE_MASK; - max_physmem = get_kmem_end() - uml_physmem - iomem_size - MIN_VMALLOC; + max_physmem = TASK_SIZE - uml_physmem - iomem_size - MIN_VMALLOC; - /* Zones have to begin on a 1 << MAX_ORDER page boundary, + /* + * Zones have to begin on a 1 << MAX_ORDER page boundary, * so this makes sure that's true for highmem */ max_physmem &= ~((1 << (PAGE_SHIFT + MAX_ORDER)) - 1); - if(physmem_size + iomem_size > max_physmem){ + if (physmem_size + iomem_size > max_physmem) { highmem = physmem_size + iomem_size - max_physmem; physmem_size -= highmem; #ifndef CONFIG_HIGHMEM highmem = 0; printf("CONFIG_HIGHMEM not enabled - physical memory shrunk " - "to %lu bytes\n", physmem_size); + "to %Lu bytes\n", physmem_size); #endif } @@ -414,65 +348,62 @@ int linux_main(int argc, char **argv) start_vm = VMALLOC_START; setup_physmem(uml_physmem, uml_reserved, physmem_size, highmem); - if(init_maps(physmem_size, iomem_size, highmem)){ - printf("Failed to allocate mem_map for %lu bytes of physical " - "memory and %lu bytes of highmem\n", physmem_size, + if (init_maps(physmem_size, iomem_size, highmem)) { + printf("Failed to allocate mem_map for %Lu bytes of physical " + "memory and %Lu bytes of highmem\n", physmem_size, highmem); exit(1); } virtmem_size = physmem_size; - avail = get_kmem_end() - start_vm; - if(physmem_size > avail) virtmem_size = avail; + stack = (unsigned long) argv; + stack &= ~(1024 * 1024 - 1); + avail = stack - start_vm; + if (physmem_size > avail) + virtmem_size = avail; end_vm = start_vm + virtmem_size; - if(virtmem_size < physmem_size) + if (virtmem_size < physmem_size) printf("Kernel virtual memory size shrunk to %lu bytes\n", virtmem_size); - uml_postsetup(); - - task_protections((unsigned long) &init_thread_info); - os_flush_stdout(); + atomic_notifier_chain_register(&panic_notifier_list, + &panic_exit_notifier); - return(CHOOSE_MODE(start_uml_tt(), start_uml_skas())); -} + uml_postsetup(); -extern int uml_exitcode; + stack_protections((unsigned long) &init_thread_info); + os_flush_stdout(); -static int panic_exit(struct notifier_block *self, unsigned long unused1, - void *unused2) -{ - bust_spinlocks(1); - show_regs(&(current->thread.regs)); - bust_spinlocks(0); - uml_exitcode = 1; - machine_halt(); - return(0); + return start_uml(); } -static struct notifier_block panic_exit_notifier = { - .notifier_call = panic_exit, - .next = NULL, - .priority = 0 -}; - void __init setup_arch(char **cmdline_p) { - notifier_chain_register(&panic_notifier_list, &panic_exit_notifier); paging_init(); - strlcpy(saved_command_line, command_line, COMMAND_LINE_SIZE); - *cmdline_p = command_line; - setup_hostinfo(); + strlcpy(boot_command_line, command_line, COMMAND_LINE_SIZE); + *cmdline_p = command_line; + setup_hostinfo(host_info, sizeof host_info); } void __init check_bugs(void) { arch_check_bugs(); - check_sigio(); - check_devanon(); + os_check_bugs(); +} + +void apply_alternatives(struct alt_instr *start, struct alt_instr *end) +{ } -void apply_alternatives(void *start, void *end) +#ifdef CONFIG_SMP +void alternatives_smp_module_add(struct module *mod, char *name, + void *locks, void *locks_end, + void *text, void *text_end) { } + +void alternatives_smp_module_del(struct module *mod) +{ +} +#endif |
