📄 setup.c
字号:
/* * arch/s390/kernel/setup.c * * S390 version * Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation * Author(s): Hartmut Penner (hp@de.ibm.com), * Martin Schwidefsky (schwidefsky@de.ibm.com) * * Derived from "arch/i386/kernel/setup.c" * Copyright (C) 1995, Linus Torvalds *//* * This file handles the architecture-dependent parts of initialization */#include <linux/errno.h>#include <linux/sched.h>#include <linux/kernel.h>#include <linux/mm.h>#include <linux/stddef.h>#include <linux/unistd.h>#include <linux/ptrace.h>#include <linux/slab.h>#include <linux/user.h>#include <linux/a.out.h>#include <linux/tty.h>#include <linux/ioport.h>#include <linux/delay.h>#include <linux/config.h>#include <linux/init.h>#ifdef CONFIG_BLK_DEV_RAM#include <linux/blk.h>#endif#include <linux/bootmem.h>#include <linux/console.h>#include <linux/seq_file.h>#include <asm/uaccess.h>#include <asm/system.h>#include <asm/smp.h>#include <asm/mmu_context.h>#include <asm/cpcmd.h>/* * Machine setup.. */unsigned int console_mode = 0;unsigned int console_device = -1;unsigned long memory_size = 0;unsigned long machine_flags = 0;struct { unsigned long addr, size, type; } memory_chunk[16] = { { 0 } };#define CHUNK_READ_WRITE 0#define CHUNK_READ_ONLY 1__u16 boot_cpu_addr;int cpus_initialized = 0;unsigned long cpu_initialized = 0;volatile int __cpu_logical_map[NR_CPUS]; /* logical cpu to cpu address */unsigned long *pfix_table;unsigned int __global_storage_key;unsigned int get_storage_key(void) { return __global_storage_key; }unsigned long pfix_get_page_addr(void *addr){ if (!MACHINE_HAS_PFIX) return (unsigned long) addr; return pfix_table[(unsigned long)virt_to_phys(addr)>>PAGE_SHIFT];}unsigned long pfix_get_addr(void *addr){ if (!MACHINE_HAS_PFIX) return (unsigned long) addr; return pfix_get_page_addr(addr) + ((unsigned long)addr&(PAGE_SIZE-1));}/* * These functions allow to lock and unlock pages in VM. They need * the absolute address of the page to be locked or unlocked. This will * only work if the diag98 option in the user directory is enabled for * the guest. *//* if result is 0, addr will become the host absolute address */static inline int pfix_lock_page(void *addr){ int ret; __asm__ __volatile__( " sske %1,%2\n" /* set storage key */ " l 0,0(%1)\n" /* addr into gpr 0 */ " lhi 2,0\n" /* function code is 0 */ " diag 2,0,0x98\n" /* result in gpr 1 */ " jnz 0f\n" " lhi %0,0\n" /* if cc=0: return 0 */ " st 1,0(%1)\n" /* gpr1 contains host absol. addr */ " j 1f\n" "0: lr %0,1\n" /* gpr1 contains error code */ " sske %1,2\n" /* reset storage key */ "1:\n" : "=d" (ret), "+d" ((unsigned long)addr) : "d" (__global_storage_key) : "0", "1", "2", "cc" ); return ret;}static inline void pfix_unlock_page(unsigned long addr){ __asm__ __volatile__( " lr 0,%0\n" /* parameter in gpr 0 */ " lhi 2,4\n" /* function code is 4 */ " diag 2,0,0x98\n" /* result in gpr 1 */ " sske %0,%1\n" : : "a" (addr), "d" (0) : "0", "1", "2", "cc" );}static void unpfix_all_pages(void){ unsigned long i; if (!pfix_table) return; for (i=0; i<sizeof(pfix_table); i++) { if (pfix_table[i]) { pfix_unlock_page(i << PAGE_SHIFT); } }}static void pfix_all_pages(unsigned long start_pfn, unsigned long max_pfn){ unsigned long i,r; unsigned long size; size = ((max_pfn - start_pfn) >> PAGE_SHIFT) * sizeof(long); pfix_table = alloc_bootmem(size); if (!pfix_table) return; __global_storage_key = 6 << 4; for (i = 0; i < 16 && memory_chunk[i].size > 0; i++) { unsigned long start; for(start = memory_chunk[i].addr; (start < memory_chunk[i].addr + memory_chunk[i].size && start < max_pfn); start += PAGE_SIZE) { unsigned long index; index = start >> PAGE_SHIFT; pfix_table[index] = start; r = pfix_lock_page(&pfix_table[index]); if (r) { pfix_table[index] = 0; unpfix_all_pages(); free_bootmem((unsigned long)pfix_table, size); machine_flags &= ~128; /* MACHINE_HAS_PFIX=0 */ __global_storage_key = 0; printk(KERN_WARNING "Error enabling PFIX at " "address 0x%08lx.\n", start); return; } } } printk (KERN_INFO "PFIX enabled.\n");}/* * Setup options */extern int _text,_etext, _edata, _end;/* * This is set up by the setup-routine at boot-time * for S390 need to find out, what we have to setup * using address 0x10400 ... */#include <asm/setup.h>static char command_line[COMMAND_LINE_SIZE] = { 0, }; char saved_command_line[COMMAND_LINE_SIZE];static struct resource code_resource = { "Kernel code", 0x100000, 0 };static struct resource data_resource = { "Kernel data", 0, 0 };/* * cpu_init() initializes state that is per-CPU. */void __init cpu_init (void){ int nr = smp_processor_id(); int addr = hard_smp_processor_id(); if (test_and_set_bit(nr,&cpu_initialized)) { printk("CPU#%d ALREADY INITIALIZED!!!!!!!!!\n", nr); for (;;) __sti(); } cpus_initialized++; /* * Store processor id in lowcore (used e.g. in timer_interrupt) */ asm volatile ("stidp %0": "=m" (S390_lowcore.cpu_data.cpu_id)); S390_lowcore.cpu_data.cpu_addr = addr; S390_lowcore.cpu_data.cpu_nr = nr; /* * Force FPU initialization: */ current->flags &= ~PF_USEDFPU; current->used_math = 0; /* Setup active_mm for idle_task */ atomic_inc(&init_mm.mm_count); current->active_mm = &init_mm; if (current->mm) BUG(); enter_lazy_tlb(&init_mm, current, nr);}/* * VM halt and poweroff setup routines */char vmhalt_cmd[128] = "";char vmpoff_cmd[128] = "";static inline void strncpy_skip_quote(char *dst, char *src, int n){ int sx, dx; dx = 0; for (sx = 0; src[sx] != 0; sx++) { if (src[sx] == '"') continue; dst[dx++] = src[sx]; if (dx >= n) break; }}static int __init vmhalt_setup(char *str){ strncpy_skip_quote(vmhalt_cmd, str, 127); vmhalt_cmd[127] = 0; return 1;}__setup("vmhalt=", vmhalt_setup);static int __init vmpoff_setup(char *str){ strncpy_skip_quote(vmpoff_cmd, str, 127); vmpoff_cmd[127] = 0; return 1;}__setup("vmpoff=", vmpoff_setup);/* * condev= and conmode= setup parameter. */static int __init condev_setup(char *str){ int vdev; vdev = simple_strtoul(str, &str, 0); if (vdev >= 0 && vdev < 65536) console_device = vdev; return 1;}__setup("condev=", condev_setup);static int __init conmode_setup(char *str){#if defined(CONFIG_HWC_CONSOLE) if (strncmp(str, "hwc", 4) == 0) SET_CONSOLE_HWC;#endif#if defined(CONFIG_TN3215_CONSOLE) if (strncmp(str, "3215", 5) == 0) SET_CONSOLE_3215;#endif#if defined(CONFIG_TN3270_CONSOLE) if (strncmp(str, "3270", 5) == 0) SET_CONSOLE_3270;#endif return 1;}__setup("conmode=", conmode_setup);static void __init conmode_default(void){ char query_buffer[1024]; char *ptr; if (MACHINE_IS_VM) { cpcmd("QUERY TERM", query_buffer, 1024); ptr = strstr(query_buffer, "CONMODE"); /* * Set the conmode to 3215 so that the device recognition * will set the cu_type of the console to 3215. If the * conmode is 3270 and we don't set it back then both * 3215 and the 3270 driver will try to access the console * device (3215 as console and 3270 as normal tty). */ cpcmd("TERM CONMODE 3215", NULL, 0); if (ptr == NULL) {#if defined(CONFIG_HWC_CONSOLE) SET_CONSOLE_HWC;#endif return; } if (strncmp(ptr + 8, "3270", 4) == 0) {#if defined(CONFIG_TN3270_CONSOLE) SET_CONSOLE_3270;#elif defined(CONFIG_TN3215_CONSOLE) SET_CONSOLE_3215;#elif defined(CONFIG_HWC_CONSOLE) SET_CONSOLE_HWC;#endif } else if (strncmp(ptr + 8, "3215", 4) == 0) {#if defined(CONFIG_TN3215_CONSOLE) SET_CONSOLE_3215;#elif defined(CONFIG_TN3270_CONSOLE) SET_CONSOLE_3270;#elif defined(CONFIG_HWC_CONSOLE) SET_CONSOLE_HWC;#endif } } else if (MACHINE_IS_P390) {#if defined(CONFIG_TN3215_CONSOLE) SET_CONSOLE_3215;#elif defined(CONFIG_TN3270_CONSOLE) SET_CONSOLE_3270;#endif } else {#if defined(CONFIG_HWC_CONSOLE) SET_CONSOLE_HWC;#endif }}#ifdef CONFIG_SMP
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -