Added tag v0.15-rc4 for changeset 2a97f14b9016
[hvf.git] / cp / nucleus / init.c
blob9801463323dc611d3edd966a2210997e4804291a
1 /*
2 * (C) Copyright 2007-2011 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);
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 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;
198 * ticks starts at 0
200 ticks = 0;
203 * save total system memory size & the symbol table pointer
205 memsize = __memsize;
206 symtab = __elfhdr;
209 * Initialize struct page entries
211 init_pages();
214 * Calculate address of the first free page (we may have to round
215 * up)
217 struct_page_bytes = (memsize >> PAGE_SHIFT) * sizeof(struct page);
219 first_free_page = (u64) PAGE_INFO_BASE + struct_page_bytes;
220 if (struct_page_bytes & (PAGE_SIZE-1))
221 first_free_page += PAGE_SIZE - (struct_page_bytes & (PAGE_SIZE-1));
224 * Initialize the buddy allocator
226 init_buddy_alloc(first_free_page);
229 * Initialize slab allocator default caches
231 init_slab();
234 * Set up interrupt PSWs
236 memcpy(IO_INT_NEW_PSW, &new_io_psw, sizeof(struct psw));
237 memcpy(EXT_INT_NEW_PSW, &new_ext_psw, sizeof(struct psw));
238 memcpy(SVC_INT_NEW_PSW, &new_svc_psw, sizeof(struct psw));
239 memcpy(PGM_INT_NEW_PSW, &new_pgm_psw, sizeof(struct psw));
240 memcpy(MCH_INT_NEW_PSW, &new_mch_psw, sizeof(struct psw));
242 /* Turn on Low-address Protection */
243 lap_on();
246 * Set up page table entries for the nucleus
248 setup_dat();
251 * Allocate & initialize the interrupt stack
253 init_int_stack();
256 * Initialize the io subsystem
258 init_io();
261 * Register all the device drivers
263 register_drivers();
266 * Time to enable interrupts => load new psw
268 memset(&psw, 0, sizeof(struct psw));
269 psw.io = 1;
270 psw.ea = 1;
271 psw.ba = 1;
273 asm volatile(
274 " larl %%r1,0f\n"
275 " stg %%r1,%0\n"
276 " lpswe %1\n"
277 "0:\n"
278 : /* output */
279 "=m" (psw.ptr)
280 : /* input */
281 "m" (psw)
282 : /* clobbered */
283 "r1"
287 * Let's discover all the devices attached
289 scan_devices();
292 * Initialize the process scheduler
294 init_sched();
297 * Start tracking locking dependencies
299 ldep_on();
302 * Create a thread that'll finish setting everything up for us
304 create_task("*finish-loading", __finish_loading, (void*) (u64) __iplsch);
307 * THIS IS WHERE THE IDLE TASK BEGINS
310 idle_task_body();