|
@@ -38,6 +38,7 @@
|
|
|
#include <linux/device.h>
|
|
|
#include <linux/notifier.h>
|
|
|
#include <linux/pfn.h>
|
|
|
+#include <linux/ctype.h>
|
|
|
#include <linux/reboot.h>
|
|
|
|
|
|
#include <asm/uaccess.h>
|
|
@@ -50,6 +51,7 @@
|
|
|
#include <asm/page.h>
|
|
|
#include <asm/ptrace.h>
|
|
|
#include <asm/sections.h>
|
|
|
+#include <asm/ebcdic.h>
|
|
|
#include <asm/compat.h>
|
|
|
|
|
|
long psw_kernel_bits = (PSW_BASE_BITS | PSW_MASK_DAT | PSW_ASC_PRIMARY |
|
|
@@ -282,6 +284,140 @@ static void __init conmode_default(void)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * Create a Kernel NSS if the SAVESYS= parameter is defined
|
|
|
+*/
|
|
|
+#define DEFSYS_CMD_SIZE 96
|
|
|
+#define SAVESYS_CMD_SIZE 32
|
|
|
+
|
|
|
+extern int _eshared;
|
|
|
+char kernel_nss_name[NSS_NAME_SIZE + 1];
|
|
|
+
|
|
|
+#ifdef CONFIG_SHARED_KERNEL
|
|
|
+static __init void create_kernel_nss(void)
|
|
|
+{
|
|
|
+ unsigned int i, stext_pfn, eshared_pfn, end_pfn, min_size;
|
|
|
+#ifdef CONFIG_BLK_DEV_INITRD
|
|
|
+ unsigned int sinitrd_pfn, einitrd_pfn;
|
|
|
+#endif
|
|
|
+ int response;
|
|
|
+ char *savesys_ptr;
|
|
|
+ char upper_command_line[COMMAND_LINE_SIZE];
|
|
|
+ char defsys_cmd[DEFSYS_CMD_SIZE];
|
|
|
+ char savesys_cmd[SAVESYS_CMD_SIZE];
|
|
|
+
|
|
|
+ /* Do nothing if we are not running under VM */
|
|
|
+ if (!MACHINE_IS_VM)
|
|
|
+ return;
|
|
|
+
|
|
|
+ /* Convert COMMAND_LINE to upper case */
|
|
|
+ for (i = 0; i < strlen(COMMAND_LINE); i++)
|
|
|
+ upper_command_line[i] = toupper(COMMAND_LINE[i]);
|
|
|
+
|
|
|
+ savesys_ptr = strstr(upper_command_line, "SAVESYS=");
|
|
|
+
|
|
|
+ if (!savesys_ptr)
|
|
|
+ return;
|
|
|
+
|
|
|
+ savesys_ptr += 8; /* Point to the beginning of the NSS name */
|
|
|
+ for (i = 0; i < NSS_NAME_SIZE; i++) {
|
|
|
+ if (savesys_ptr[i] == ' ' || savesys_ptr[i] == '\0')
|
|
|
+ break;
|
|
|
+ kernel_nss_name[i] = savesys_ptr[i];
|
|
|
+ }
|
|
|
+
|
|
|
+ stext_pfn = PFN_DOWN(__pa(&_stext));
|
|
|
+ eshared_pfn = PFN_DOWN(__pa(&_eshared));
|
|
|
+ end_pfn = PFN_UP(__pa(&_end));
|
|
|
+ min_size = end_pfn << 2;
|
|
|
+
|
|
|
+ sprintf(defsys_cmd, "DEFSYS %s 00000-%.5X EW %.5X-%.5X SR %.5X-%.5X",
|
|
|
+ kernel_nss_name, stext_pfn - 1, stext_pfn, eshared_pfn - 1,
|
|
|
+ eshared_pfn, end_pfn);
|
|
|
+
|
|
|
+#ifdef CONFIG_BLK_DEV_INITRD
|
|
|
+ if (INITRD_START && INITRD_SIZE) {
|
|
|
+ sinitrd_pfn = PFN_DOWN(__pa(INITRD_START));
|
|
|
+ einitrd_pfn = PFN_UP(__pa(INITRD_START + INITRD_SIZE));
|
|
|
+ min_size = einitrd_pfn << 2;
|
|
|
+ sprintf(defsys_cmd, "%s EW %.5X-%.5X", defsys_cmd,
|
|
|
+ sinitrd_pfn, einitrd_pfn);
|
|
|
+ }
|
|
|
+#endif
|
|
|
+
|
|
|
+ sprintf(defsys_cmd, "%s EW MINSIZE=%.7iK", defsys_cmd, min_size);
|
|
|
+ sprintf(savesys_cmd, "SAVESYS %s \n IPL %s",
|
|
|
+ kernel_nss_name, kernel_nss_name);
|
|
|
+
|
|
|
+ __cpcmd(defsys_cmd, NULL, 0, &response);
|
|
|
+
|
|
|
+ if (response != 0)
|
|
|
+ return;
|
|
|
+
|
|
|
+ __cpcmd(savesys_cmd, NULL, 0, &response);
|
|
|
+
|
|
|
+ if (response != strlen(savesys_cmd))
|
|
|
+ return;
|
|
|
+
|
|
|
+ ipl_flags = IPL_NSS_VALID;
|
|
|
+}
|
|
|
+
|
|
|
+#else /* CONFIG_SHARED_KERNEL */
|
|
|
+
|
|
|
+static inline void create_kernel_nss(void) { }
|
|
|
+
|
|
|
+#endif /* CONFIG_SHARED_KERNEL */
|
|
|
+
|
|
|
+/*
|
|
|
+ * Clear bss memory
|
|
|
+ */
|
|
|
+static __init void clear_bss_section(void)
|
|
|
+{
|
|
|
+ memset(__bss_start, 0, _end - __bss_start);
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * Initialize storage key for kernel pages
|
|
|
+ */
|
|
|
+static __init void init_kernel_storage_key(void)
|
|
|
+{
|
|
|
+ unsigned long end_pfn, init_pfn;
|
|
|
+
|
|
|
+ end_pfn = PFN_UP(__pa(&_end));
|
|
|
+
|
|
|
+ for (init_pfn = 0 ; init_pfn < end_pfn; init_pfn++)
|
|
|
+ page_set_storage_key(init_pfn << PAGE_SHIFT, PAGE_DEFAULT_KEY);
|
|
|
+}
|
|
|
+
|
|
|
+static __init void detect_machine_type(void)
|
|
|
+{
|
|
|
+ struct cpuinfo_S390 *cpuinfo = &S390_lowcore.cpu_data;
|
|
|
+
|
|
|
+ asm volatile("stidp %0" : "=m" (S390_lowcore.cpu_data.cpu_id));
|
|
|
+
|
|
|
+ /* Running under z/VM ? */
|
|
|
+ if (cpuinfo->cpu_id.version == 0xff)
|
|
|
+ machine_flags |= 1;
|
|
|
+
|
|
|
+ /* Running on a P/390 ? */
|
|
|
+ if (cpuinfo->cpu_id.machine == 0x7490)
|
|
|
+ machine_flags |= 4;
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * Save ipl parameters, clear bss memory, initialize storage keys
|
|
|
+ * and create a kernel NSS at startup if the SAVESYS= parm is defined
|
|
|
+ */
|
|
|
+void __init startup_init(void)
|
|
|
+{
|
|
|
+ ipl_save_parameters();
|
|
|
+ clear_bss_section();
|
|
|
+ init_kernel_storage_key();
|
|
|
+ lockdep_init();
|
|
|
+ detect_machine_type();
|
|
|
+ create_kernel_nss();
|
|
|
+}
|
|
|
+
|
|
|
#ifdef CONFIG_SMP
|
|
|
void (*_machine_restart)(char *command) = machine_restart_smp;
|
|
|
void (*_machine_halt)(void) = machine_halt_smp;
|
|
@@ -523,7 +659,7 @@ setup_lowcore(void)
|
|
|
static void __init
|
|
|
setup_resources(void)
|
|
|
{
|
|
|
- struct resource *res;
|
|
|
+ struct resource *res, *sub_res;
|
|
|
int i;
|
|
|
|
|
|
code_resource.start = (unsigned long) &_text;
|
|
@@ -548,8 +684,38 @@ setup_resources(void)
|
|
|
res->start = memory_chunk[i].addr;
|
|
|
res->end = memory_chunk[i].addr + memory_chunk[i].size - 1;
|
|
|
request_resource(&iomem_resource, res);
|
|
|
- request_resource(res, &code_resource);
|
|
|
- request_resource(res, &data_resource);
|
|
|
+
|
|
|
+ if (code_resource.start >= res->start &&
|
|
|
+ code_resource.start <= res->end &&
|
|
|
+ code_resource.end > res->end) {
|
|
|
+ sub_res = alloc_bootmem_low(sizeof(struct resource));
|
|
|
+ memcpy(sub_res, &code_resource,
|
|
|
+ sizeof(struct resource));
|
|
|
+ sub_res->end = res->end;
|
|
|
+ code_resource.start = res->end + 1;
|
|
|
+ request_resource(res, sub_res);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (code_resource.start >= res->start &&
|
|
|
+ code_resource.start <= res->end &&
|
|
|
+ code_resource.end <= res->end)
|
|
|
+ request_resource(res, &code_resource);
|
|
|
+
|
|
|
+ if (data_resource.start >= res->start &&
|
|
|
+ data_resource.start <= res->end &&
|
|
|
+ data_resource.end > res->end) {
|
|
|
+ sub_res = alloc_bootmem_low(sizeof(struct resource));
|
|
|
+ memcpy(sub_res, &data_resource,
|
|
|
+ sizeof(struct resource));
|
|
|
+ sub_res->end = res->end;
|
|
|
+ data_resource.start = res->end + 1;
|
|
|
+ request_resource(res, sub_res);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (data_resource.start >= res->start &&
|
|
|
+ data_resource.start <= res->end &&
|
|
|
+ data_resource.end <= res->end)
|
|
|
+ request_resource(res, &data_resource);
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -585,7 +751,7 @@ static void __init
|
|
|
setup_memory(void)
|
|
|
{
|
|
|
unsigned long bootmap_size;
|
|
|
- unsigned long start_pfn, end_pfn, init_pfn;
|
|
|
+ unsigned long start_pfn, end_pfn;
|
|
|
int i;
|
|
|
|
|
|
/*
|
|
@@ -595,10 +761,6 @@ setup_memory(void)
|
|
|
start_pfn = PFN_UP(__pa(&_end));
|
|
|
end_pfn = max_pfn = PFN_DOWN(memory_end);
|
|
|
|
|
|
- /* Initialize storage key for kernel pages */
|
|
|
- for (init_pfn = 0 ; init_pfn < start_pfn; init_pfn++)
|
|
|
- page_set_storage_key(init_pfn << PAGE_SHIFT, PAGE_DEFAULT_KEY);
|
|
|
-
|
|
|
#ifdef CONFIG_BLK_DEV_INITRD
|
|
|
/*
|
|
|
* Move the initrd in case the bitmap of the bootmem allocater
|