linux/arch/s390/kernel/early.c
<<
>>
Prefs
   1/*
   2 *  arch/s390/kernel/early.c
   3 *
   4 *    Copyright IBM Corp. 2007
   5 *    Author(s): Hongjie Yang <hongjie@us.ibm.com>,
   6 *               Heiko Carstens <heiko.carstens@de.ibm.com>
   7 */
   8
   9#include <linux/init.h>
  10#include <linux/errno.h>
  11#include <linux/string.h>
  12#include <linux/ctype.h>
  13#include <linux/lockdep.h>
  14#include <linux/module.h>
  15#include <linux/pfn.h>
  16#include <linux/uaccess.h>
  17#include <asm/ebcdic.h>
  18#include <asm/ipl.h>
  19#include <asm/lowcore.h>
  20#include <asm/processor.h>
  21#include <asm/sections.h>
  22#include <asm/setup.h>
  23#include <asm/cpcmd.h>
  24#include <asm/sclp.h>
  25#include "entry.h"
  26
  27/*
  28 * Create a Kernel NSS if the SAVESYS= parameter is defined
  29 */
  30#define DEFSYS_CMD_SIZE         128
  31#define SAVESYS_CMD_SIZE        32
  32
  33char kernel_nss_name[NSS_NAME_SIZE + 1];
  34
  35static void __init setup_boot_command_line(void);
  36
  37
  38#ifdef CONFIG_SHARED_KERNEL
  39int __init savesys_ipl_nss(char *cmd, const int cmdlen);
  40
  41asm(
  42        "       .section .init.text,\"ax\",@progbits\n"
  43        "       .align  4\n"
  44        "       .type   savesys_ipl_nss, @function\n"
  45        "savesys_ipl_nss:\n"
  46#ifdef CONFIG_64BIT
  47        "       stmg    6,15,48(15)\n"
  48        "       lgr     14,3\n"
  49        "       sam31\n"
  50        "       diag    2,14,0x8\n"
  51        "       sam64\n"
  52        "       lgr     2,14\n"
  53        "       lmg     6,15,48(15)\n"
  54#else
  55        "       stm     6,15,24(15)\n"
  56        "       lr      14,3\n"
  57        "       diag    2,14,0x8\n"
  58        "       lr      2,14\n"
  59        "       lm      6,15,24(15)\n"
  60#endif
  61        "       br      14\n"
  62        "       .size   savesys_ipl_nss, .-savesys_ipl_nss\n");
  63
  64static noinline __init void create_kernel_nss(void)
  65{
  66        unsigned int i, stext_pfn, eshared_pfn, end_pfn, min_size;
  67#ifdef CONFIG_BLK_DEV_INITRD
  68        unsigned int sinitrd_pfn, einitrd_pfn;
  69#endif
  70        int response;
  71        size_t len;
  72        char *savesys_ptr;
  73        char upper_command_line[COMMAND_LINE_SIZE];
  74        char defsys_cmd[DEFSYS_CMD_SIZE];
  75        char savesys_cmd[SAVESYS_CMD_SIZE];
  76
  77        /* Do nothing if we are not running under VM */
  78        if (!MACHINE_IS_VM)
  79                return;
  80
  81        /* Convert COMMAND_LINE to upper case */
  82        for (i = 0; i < strlen(boot_command_line); i++)
  83                upper_command_line[i] = toupper(boot_command_line[i]);
  84
  85        savesys_ptr = strstr(upper_command_line, "SAVESYS=");
  86
  87        if (!savesys_ptr)
  88                return;
  89
  90        savesys_ptr += 8;    /* Point to the beginning of the NSS name */
  91        for (i = 0; i < NSS_NAME_SIZE; i++) {
  92                if (savesys_ptr[i] == ' ' || savesys_ptr[i] == '\0')
  93                        break;
  94                kernel_nss_name[i] = savesys_ptr[i];
  95        }
  96
  97        stext_pfn = PFN_DOWN(__pa(&_stext));
  98        eshared_pfn = PFN_DOWN(__pa(&_eshared));
  99        end_pfn = PFN_UP(__pa(&_end));
 100        min_size = end_pfn << 2;
 101
 102        sprintf(defsys_cmd, "DEFSYS %s 00000-%.5X EW %.5X-%.5X SR %.5X-%.5X",
 103                kernel_nss_name, stext_pfn - 1, stext_pfn, eshared_pfn - 1,
 104                eshared_pfn, end_pfn);
 105
 106#ifdef CONFIG_BLK_DEV_INITRD
 107        if (INITRD_START && INITRD_SIZE) {
 108                sinitrd_pfn = PFN_DOWN(__pa(INITRD_START));
 109                einitrd_pfn = PFN_UP(__pa(INITRD_START + INITRD_SIZE));
 110                min_size = einitrd_pfn << 2;
 111                sprintf(defsys_cmd, "%s EW %.5X-%.5X", defsys_cmd,
 112                sinitrd_pfn, einitrd_pfn);
 113        }
 114#endif
 115
 116        sprintf(defsys_cmd, "%s EW MINSIZE=%.7iK PARMREGS=0-13",
 117                defsys_cmd, min_size);
 118        sprintf(savesys_cmd, "SAVESYS %s \n IPL %s",
 119                kernel_nss_name, kernel_nss_name);
 120
 121        __cpcmd(defsys_cmd, NULL, 0, &response);
 122
 123        if (response != 0) {
 124                kernel_nss_name[0] = '\0';
 125                return;
 126        }
 127
 128        len = strlen(savesys_cmd);
 129        ASCEBC(savesys_cmd, len);
 130        response = savesys_ipl_nss(savesys_cmd, len);
 131
 132        /* On success: response is equal to the command size,
 133         *             max SAVESYS_CMD_SIZE
 134         * On error: response contains the numeric portion of cp error message.
 135         *           for SAVESYS it will be >= 263
 136         */
 137        if (response > SAVESYS_CMD_SIZE) {
 138                kernel_nss_name[0] = '\0';
 139                return;
 140        }
 141
 142        /* re-setup boot command line with new ipl vm parms */
 143        ipl_update_parameters();
 144        setup_boot_command_line();
 145
 146        ipl_flags = IPL_NSS_VALID;
 147}
 148
 149#else /* CONFIG_SHARED_KERNEL */
 150
 151static inline void create_kernel_nss(void) { }
 152
 153#endif /* CONFIG_SHARED_KERNEL */
 154
 155/*
 156 * Clear bss memory
 157 */
 158static noinline __init void clear_bss_section(void)
 159{
 160        memset(__bss_start, 0, __bss_stop - __bss_start);
 161}
 162
 163/*
 164 * Initialize storage key for kernel pages
 165 */
 166static noinline __init void init_kernel_storage_key(void)
 167{
 168        unsigned long end_pfn, init_pfn;
 169
 170        end_pfn = PFN_UP(__pa(&_end));
 171
 172        for (init_pfn = 0 ; init_pfn < end_pfn; init_pfn++)
 173                page_set_storage_key(init_pfn << PAGE_SHIFT, PAGE_DEFAULT_KEY);
 174}
 175
 176static noinline __init void detect_machine_type(void)
 177{
 178        struct cpuinfo_S390 *cpuinfo = &S390_lowcore.cpu_data;
 179
 180        get_cpu_id(&S390_lowcore.cpu_data.cpu_id);
 181
 182        /* Running under z/VM ? */
 183        if (cpuinfo->cpu_id.version == 0xff)
 184                machine_flags |= MACHINE_FLAG_VM;
 185
 186        /* Running under KVM ? */
 187        if (cpuinfo->cpu_id.version == 0xfe)
 188                machine_flags |= MACHINE_FLAG_KVM;
 189}
 190
 191static __init void early_pgm_check_handler(void)
 192{
 193        unsigned long addr;
 194        const struct exception_table_entry *fixup;
 195
 196        addr = S390_lowcore.program_old_psw.addr;
 197        fixup = search_exception_tables(addr & PSW_ADDR_INSN);
 198        if (!fixup)
 199                disabled_wait(0);
 200        S390_lowcore.program_old_psw.addr = fixup->fixup | PSW_ADDR_AMODE;
 201}
 202
 203static noinline __init void setup_lowcore_early(void)
 204{
 205        psw_t psw;
 206
 207        psw.mask = PSW_BASE_BITS | PSW_DEFAULT_KEY;
 208        psw.addr = PSW_ADDR_AMODE | (unsigned long) s390_base_ext_handler;
 209        S390_lowcore.external_new_psw = psw;
 210        psw.addr = PSW_ADDR_AMODE | (unsigned long) s390_base_pgm_handler;
 211        S390_lowcore.program_new_psw = psw;
 212        s390_base_pgm_handler_fn = early_pgm_check_handler;
 213}
 214
 215static noinline __init void setup_hpage(void)
 216{
 217#ifndef CONFIG_DEBUG_PAGEALLOC
 218        unsigned int facilities;
 219
 220        facilities = stfl();
 221        if (!(facilities & (1UL << 23)) || !(facilities & (1UL << 29)))
 222                return;
 223        machine_flags |= MACHINE_FLAG_HPAGE;
 224        __ctl_set_bit(0, 23);
 225#endif
 226}
 227
 228static __init void detect_mvpg(void)
 229{
 230#ifndef CONFIG_64BIT
 231        int rc;
 232
 233        asm volatile(
 234                "       la      0,0\n"
 235                "       mvpg    %2,%2\n"
 236                "0:     la      %0,0\n"
 237                "1:\n"
 238                EX_TABLE(0b,1b)
 239                : "=d" (rc) : "0" (-EOPNOTSUPP), "a" (0) : "memory", "cc", "0");
 240        if (!rc)
 241                machine_flags |= MACHINE_FLAG_MVPG;
 242#endif
 243}
 244
 245static __init void detect_ieee(void)
 246{
 247#ifndef CONFIG_64BIT
 248        int rc, tmp;
 249
 250        asm volatile(
 251                "       efpc    %1,0\n"
 252                "0:     la      %0,0\n"
 253                "1:\n"
 254                EX_TABLE(0b,1b)
 255                : "=d" (rc), "=d" (tmp): "0" (-EOPNOTSUPP) : "cc");
 256        if (!rc)
 257                machine_flags |= MACHINE_FLAG_IEEE;
 258#endif
 259}
 260
 261static __init void detect_csp(void)
 262{
 263#ifndef CONFIG_64BIT
 264        int rc;
 265
 266        asm volatile(
 267                "       la      0,0\n"
 268                "       la      1,0\n"
 269                "       la      2,4\n"
 270                "       csp     0,2\n"
 271                "0:     la      %0,0\n"
 272                "1:\n"
 273                EX_TABLE(0b,1b)
 274                : "=d" (rc) : "0" (-EOPNOTSUPP) : "cc", "0", "1", "2");
 275        if (!rc)
 276                machine_flags |= MACHINE_FLAG_CSP;
 277#endif
 278}
 279
 280static __init void detect_diag9c(void)
 281{
 282        unsigned int cpu_address;
 283        int rc;
 284
 285        cpu_address = stap();
 286        asm volatile(
 287                "       diag    %2,0,0x9c\n"
 288                "0:     la      %0,0\n"
 289                "1:\n"
 290                EX_TABLE(0b,1b)
 291                : "=d" (rc) : "0" (-EOPNOTSUPP), "d" (cpu_address) : "cc");
 292        if (!rc)
 293                machine_flags |= MACHINE_FLAG_DIAG9C;
 294}
 295
 296static __init void detect_diag44(void)
 297{
 298#ifdef CONFIG_64BIT
 299        int rc;
 300
 301        asm volatile(
 302                "       diag    0,0,0x44\n"
 303                "0:     la      %0,0\n"
 304                "1:\n"
 305                EX_TABLE(0b,1b)
 306                : "=d" (rc) : "0" (-EOPNOTSUPP) : "cc");
 307        if (!rc)
 308                machine_flags |= MACHINE_FLAG_DIAG44;
 309#endif
 310}
 311
 312static __init void detect_machine_facilities(void)
 313{
 314#ifdef CONFIG_64BIT
 315        unsigned int facilities;
 316
 317        facilities = stfl();
 318        if (facilities & (1 << 28))
 319                machine_flags |= MACHINE_FLAG_IDTE;
 320        if (facilities & (1 << 23))
 321                machine_flags |= MACHINE_FLAG_PFMF;
 322        if (facilities & (1 << 4))
 323                machine_flags |= MACHINE_FLAG_MVCOS;
 324#endif
 325}
 326
 327static __init void rescue_initrd(void)
 328{
 329#ifdef CONFIG_BLK_DEV_INITRD
 330        /*
 331         * Move the initrd right behind the bss section in case it starts
 332         * within the bss section. So we don't overwrite it when the bss
 333         * section gets cleared.
 334         */
 335        if (!INITRD_START || !INITRD_SIZE)
 336                return;
 337        if (INITRD_START >= (unsigned long) __bss_stop)
 338                return;
 339        memmove(__bss_stop, (void *) INITRD_START, INITRD_SIZE);
 340        INITRD_START = (unsigned long) __bss_stop;
 341#endif
 342}
 343
 344/* Set up boot command line */
 345static void __init setup_boot_command_line(void)
 346{
 347        char *parm = NULL;
 348
 349        /* copy arch command line */
 350        strlcpy(boot_command_line, COMMAND_LINE, ARCH_COMMAND_LINE_SIZE);
 351        boot_command_line[ARCH_COMMAND_LINE_SIZE - 1] = 0;
 352
 353        /* append IPL PARM data to the boot command line */
 354        if (MACHINE_IS_VM) {
 355                parm = boot_command_line + strlen(boot_command_line);
 356                *parm++ = ' ';
 357                get_ipl_vmparm(parm);
 358                if (parm[0] == '=')
 359                        memmove(boot_command_line, parm + 1, strlen(parm));
 360        }
 361}
 362
 363
 364/*
 365 * Save ipl parameters, clear bss memory, initialize storage keys
 366 * and create a kernel NSS at startup if the SAVESYS= parm is defined
 367 */
 368void __init startup_init(void)
 369{
 370        ipl_save_parameters();
 371        rescue_initrd();
 372        clear_bss_section();
 373        init_kernel_storage_key();
 374        lockdep_init();
 375        lockdep_off();
 376        sort_main_extable();
 377        setup_lowcore_early();
 378        detect_machine_type();
 379        ipl_update_parameters();
 380        setup_boot_command_line();
 381        create_kernel_nss();
 382        detect_mvpg();
 383        detect_ieee();
 384        detect_csp();
 385        detect_diag9c();
 386        detect_diag44();
 387        detect_machine_facilities();
 388        setup_hpage();
 389        sclp_facilities_detect();
 390        detect_memory_layout(memory_chunk);
 391        lockdep_on();
 392}
 393