loader: remove shouting from ORB's variable name
[hvf.git] / cp / nucleus / init.c
blob0f368a0e4df1af8309f6d7f7a7101dfa93dd77af
1 /*
2 * (C) Copyright 2007-2019 Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
4 * This file is released under the GPLv2. See the COPYING file for more
5 * details.
6 */
8 #include <binfmt_elf.h>
9 #include <symtab.h>
10 #include <mm.h>
11 #include <cpu.h>
12 #include <dat.h>
13 #include <slab.h>
14 #include <page.h>
15 #include <buddy.h>
16 #include <io.h>
17 #include <sched.h>
18 #include <device.h>
19 #include <console.h>
20 #include <interrupt.h>
21 #include <magic.h>
22 #include <guest.h>
23 #include <sclp.h>
25 static struct psw new_io_psw = {
26 .ea = 1,
27 .ba = 1,
29 .ptr = (u64) &IO_INT,
32 static struct psw new_ext_psw = {
33 .ea = 1,
34 .ba = 1,
36 .ptr = (u64) &EXT_INT,
39 static struct psw new_svc_psw = {
40 .ea = 1,
41 .ba = 1,
43 .ptr = (u64) &SVC_INT,
46 static struct psw new_pgm_psw = {
47 .ea = 1,
48 .ba = 1,
50 .ptr = (u64) &PGM_INT,
53 static struct psw new_mch_psw = {
54 .ea = 1,
55 .ba = 1,
57 .ptr = (u64) &MCH_INT,
60 u8 *int_stack_ptr;
62 struct fs *sysfs;
64 const u8 zeropage[PAGE_SIZE];
66 /* the time HVF got IPLd */
67 struct datetime ipltime;
69 static void init_int_stack(void)
71 struct page *page;
73 page = alloc_pages(0, ZONE_NORMAL);
74 assert(page);
76 int_stack_ptr = PAGE_SIZE + (u8*)page_to_addr(page);
79 static void idle_task_body(void)
82 * Warning: hack alert! The following overrides what __init_task
83 * set, this allows us to skip the usual start_task wrapper.
85 current->regs.psw.w = 1;
86 current->regs.psw.ptr = MAGIC_PSW_IDLE_CODE;
89 * Load the new PSW that'll wait with special magic code set
91 lpswe(&current->regs.psw);
93 BUG();
96 static void __add_internal_users()
98 struct list_head vdevs;
99 struct directory_prop prop = {
100 .got_storage = 1,
101 .storage = 1024 * 1024, /* 1MB */
104 INIT_LIST_HEAD(&vdevs);
106 directory_alloc_user("*LOGIN", AUTH_G, &prop, &vdevs);
109 static int __finish_loading(void *data)
111 struct virt_sys *login;
112 u32 iplsch;
113 char *err;
114 int ret;
116 iplsch = (u32) (u64) data;
119 * Load the config file
121 sysfs = load_config(iplsch);
122 if (IS_ERR(sysfs))
123 BUG();
125 /* add internal users */
126 __add_internal_users();
129 * Alright, we have the config, we now need to set up the *LOGIN
130 * guest and attach the operator console rdev to it
132 login = guest_create("*LOGIN", NULL, true);
133 if (!login) {
134 err = "failed to create guest";
135 goto die;
138 ret = guest_ipl_nss(login, "login");
139 if (ret) {
140 err = "failed to IPL NSS";
141 goto die;
144 /* start *LOGIN */
145 ret = guest_begin(login);
146 if (ret) {
147 err = "failed to begin guest";
148 goto die;
152 * attach the operator rdev to *LOGIN, any available vdev
154 * Since we already IPL'd & began the guest, this will generate a
155 * Channel Report Word and a Machine Check Interrupt in the guest.
157 ret = guest_attach(login, sysconf.oper_con, -1);
158 if (ret) {
159 err = "failed to attach operator console";
160 goto die;
164 * At this point we know that *LOGIN is running. From this point
165 * on, we can handle Machine Check Interrupts (of the
166 * Channel-Report-Pending subclass) safely and sanely. Let's enable
167 * the the subclass.
169 set_cr(14, get_cr(14) | BIT64(35));
172 * IPL is more or less done
174 get_parsed_tod(&ipltime);
176 sclp_msg("IPL complete at %02d:%02d:%02d UTC %04d-%02d-%02d\n\n",
177 ipltime.th, ipltime.tm, ipltime.ts, ipltime.dy,
178 ipltime.dm, ipltime.dd);
180 return 0;
182 die:
183 sclp_msg("Failed to initialize '*LOGIN' guest: %s\n", err);
184 BUG();
185 return 0;
189 * This is where everything starts
191 void start(u64 __memsize, u32 __iplsch, Elf64_Ehdr *__elfhdr)
193 u64 first_free_page;
194 u64 struct_page_bytes;
195 struct psw psw;
197 sclp_msg("HVF %s", VERSION);
200 * ticks starts at 0
202 ticks = 0;
205 * save total system memory size & the symbol table pointer
207 memsize = __memsize;
208 symtab = __elfhdr;
211 * Initialize struct page entries
213 init_pages();
216 * Calculate address of the first free page (we may have to round
217 * up)
219 struct_page_bytes = (memsize >> PAGE_SHIFT) * sizeof(struct page);
221 first_free_page = (u64) PAGE_INFO_BASE + struct_page_bytes;
222 if (struct_page_bytes & (PAGE_SIZE-1))
223 first_free_page += PAGE_SIZE - (struct_page_bytes & (PAGE_SIZE-1));
226 * Initialize the buddy allocator
228 init_buddy_alloc(first_free_page);
231 * Initialize slab allocator default caches
233 init_slab();
236 * Set up interrupt PSWs
238 memcpy(IO_INT_NEW_PSW, &new_io_psw, sizeof(struct psw));
239 memcpy(EXT_INT_NEW_PSW, &new_ext_psw, sizeof(struct psw));
240 memcpy(SVC_INT_NEW_PSW, &new_svc_psw, sizeof(struct psw));
241 memcpy(PGM_INT_NEW_PSW, &new_pgm_psw, sizeof(struct psw));
242 memcpy(MCH_INT_NEW_PSW, &new_mch_psw, sizeof(struct psw));
244 /* Turn on Low-address Protection */
245 lap_on();
248 * Set up page table entries for the nucleus
250 setup_dat();
253 * Allocate & initialize the interrupt stack
255 init_int_stack();
258 * Initialize the io subsystem
260 init_io();
263 * Register all the device drivers
265 register_drivers();
268 * Time to enable interrupts => load new psw
270 memset(&psw, 0, sizeof(struct psw));
271 psw.io = 1;
272 psw.ea = 1;
273 psw.ba = 1;
275 asm volatile(
276 " larl %%r1,0f\n"
277 " stg %%r1,%0\n"
278 " lpswe %1\n"
279 "0:\n"
280 : /* output */
281 "=m" (psw.ptr)
282 : /* input */
283 "m" (psw)
284 : /* clobbered */
285 "r1"
289 * Let's discover all the devices attached
291 scan_devices();
294 * Initialize the process scheduler
296 init_sched();
299 * Start tracking locking dependencies
301 ldep_on();
304 * Create a thread that'll finish setting everything up for us
306 create_task("*finish-loading", __finish_loading, (void*) (u64) __iplsch);
309 * THIS IS WHERE THE IDLE TASK BEGINS
312 idle_task_body();