Mercurial > hvf > hvf
view cp/nucleus/init.c @ 647:f0ddee472d74
cp: be less shout-y in IPL complete sclp message
Signed-off-by: Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
author | Josef 'Jeff' Sipek <jeffpc@josefsipek.net> |
---|---|
date | Tue, 30 Jul 2019 19:23:03 -0400 |
parents | 423eca50b7b8 |
children | 3ede15f57135 |
line wrap: on
line source
/* * (C) Copyright 2007-2019 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> * * This file is released under the GPLv2. See the COPYING file for more * details. */ #include <binfmt_elf.h> #include <symtab.h> #include <mm.h> #include <cpu.h> #include <dat.h> #include <slab.h> #include <page.h> #include <buddy.h> #include <io.h> #include <sched.h> #include <device.h> #include <console.h> #include <interrupt.h> #include <magic.h> #include <guest.h> #include <sclp.h> static struct psw new_io_psw = { .ea = 1, .ba = 1, .ptr = (u64) &IO_INT, }; static struct psw new_ext_psw = { .ea = 1, .ba = 1, .ptr = (u64) &EXT_INT, }; static struct psw new_svc_psw = { .ea = 1, .ba = 1, .ptr = (u64) &SVC_INT, }; static struct psw new_pgm_psw = { .ea = 1, .ba = 1, .ptr = (u64) &PGM_INT, }; static struct psw new_mch_psw = { .ea = 1, .ba = 1, .ptr = (u64) &MCH_INT, }; u8 *int_stack_ptr; struct fs *sysfs; const u8 zeropage[PAGE_SIZE]; /* the time HVF got IPLd */ struct datetime ipltime; static void init_int_stack(void) { struct page *page; page = alloc_pages(0, ZONE_NORMAL); assert(page); int_stack_ptr = PAGE_SIZE + (u8*)page_to_addr(page); } static void idle_task_body(void) { /* * Warning: hack alert! The following overrides what __init_task * set, this allows us to skip the usual start_task wrapper. */ current->regs.psw.w = 1; current->regs.psw.ptr = MAGIC_PSW_IDLE_CODE; /* * Load the new PSW that'll wait with special magic code set */ lpswe(¤t->regs.psw); BUG(); } static void __add_internal_users() { struct list_head vdevs; struct directory_prop prop = { .got_storage = 1, .storage = 1024 * 1024, /* 1MB */ }; INIT_LIST_HEAD(&vdevs); directory_alloc_user("*LOGIN", AUTH_G, &prop, &vdevs); } static int __finish_loading(void *data) { struct virt_sys *login; u32 iplsch; char *err; int ret; iplsch = (u32) (u64) data; /* * Load the config file */ sysfs = load_config(iplsch); if (IS_ERR(sysfs)) BUG(); /* add internal users */ __add_internal_users(); /* * Alright, we have the config, we now need to set up the *LOGIN * guest and attach the operator console rdev to it */ login = guest_create("*LOGIN", NULL); if (!login) { err = "failed to create guest"; goto die; } ret = guest_ipl_nss(login, "login"); if (ret) { err = "failed to IPL NSS"; goto die; } /* start *LOGIN */ ret = guest_begin(login); if (ret) { err = "failed to begin guest"; goto die; } /* * attach the operator rdev to *LOGIN, any available vdev * * Since we already IPL'd & began the guest, this will generate a * Channel Report Word and a Machine Check Interrupt in the guest. */ ret = guest_attach(login, sysconf.oper_con, -1); if (ret) { err = "failed to attach operator console"; goto die; } /* * At this point we know that *LOGIN is running. From this point * on, we can handle Machine Check Interrupts (of the * Channel-Report-Pending subclass) safely and sanely. Let's enable * the the subclass. */ set_cr(14, get_cr(14) | BIT64(35)); /* * IPL is more or less done */ get_parsed_tod(&ipltime); sclp_msg("IPL complete at %02d:%02d:%02d UTC %04d-%02d-%02d\n\n", ipltime.th, ipltime.tm, ipltime.ts, ipltime.dy, ipltime.dm, ipltime.dd); return 0; die: sclp_msg("Failed to initialize '*LOGIN' guest: %s\n", err); BUG(); return 0; } /* * This is where everything starts */ void start(u64 __memsize, u32 __iplsch, Elf64_Ehdr *__elfhdr) { u64 first_free_page; u64 struct_page_bytes; struct psw psw; sclp_msg("HVF %s", VERSION); /* * ticks starts at 0 */ ticks = 0; /* * save total system memory size & the symbol table pointer */ memsize = __memsize; symtab = __elfhdr; /* * Initialize struct page entries */ init_pages(); /* * Calculate address of the first free page (we may have to round * up) */ struct_page_bytes = (memsize >> PAGE_SHIFT) * sizeof(struct page); first_free_page = (u64) PAGE_INFO_BASE + struct_page_bytes; if (struct_page_bytes & (PAGE_SIZE-1)) first_free_page += PAGE_SIZE - (struct_page_bytes & (PAGE_SIZE-1)); /* * Initialize the buddy allocator */ init_buddy_alloc(first_free_page); /* * Initialize slab allocator default caches */ init_slab(); /* * Set up interrupt PSWs */ memcpy(IO_INT_NEW_PSW, &new_io_psw, sizeof(struct psw)); memcpy(EXT_INT_NEW_PSW, &new_ext_psw, sizeof(struct psw)); memcpy(SVC_INT_NEW_PSW, &new_svc_psw, sizeof(struct psw)); memcpy(PGM_INT_NEW_PSW, &new_pgm_psw, sizeof(struct psw)); memcpy(MCH_INT_NEW_PSW, &new_mch_psw, sizeof(struct psw)); /* Turn on Low-address Protection */ lap_on(); /* * Set up page table entries for the nucleus */ setup_dat(); /* * Allocate & initialize the interrupt stack */ init_int_stack(); /* * Initialize the io subsystem */ init_io(); /* * Register all the device drivers */ register_drivers(); /* * Time to enable interrupts => load new psw */ memset(&psw, 0, sizeof(struct psw)); psw.io = 1; psw.ea = 1; psw.ba = 1; asm volatile( " larl %%r1,0f\n" " stg %%r1,%0\n" " lpswe %1\n" "0:\n" : /* output */ "=m" (psw.ptr) : /* input */ "m" (psw) : /* clobbered */ "r1" ); /* * Let's discover all the devices attached */ scan_devices(); /* * Initialize the process scheduler */ init_sched(); /* * Start tracking locking dependencies */ ldep_on(); /* * Create a thread that'll finish setting everything up for us */ create_task("*finish-loading", __finish_loading, (void*) (u64) __iplsch); /* * THIS IS WHERE THE IDLE TASK BEGINS */ idle_task_body(); }