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
8 #include <binfmt_elf.h>
20 #include <interrupt.h>
25 static struct psw new_io_psw
= {
32 static struct psw new_ext_psw
= {
36 .ptr
= (u64
) &EXT_INT
,
39 static struct psw new_svc_psw
= {
43 .ptr
= (u64
) &SVC_INT
,
46 static struct psw new_pgm_psw
= {
50 .ptr
= (u64
) &PGM_INT
,
53 static struct psw new_mch_psw
= {
57 .ptr
= (u64
) &MCH_INT
,
64 const u8 zeropage
[PAGE_SIZE
];
66 /* the time HVF got IPLd */
67 struct datetime ipltime
;
69 static void init_int_stack(void)
73 page
= alloc_pages(0, ZONE_NORMAL
);
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(¤t
->regs
.psw
);
96 static void __add_internal_users()
98 struct list_head vdevs
;
99 struct directory_prop prop
= {
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
;
116 iplsch
= (u32
) (u64
) data
;
119 * Load the config file
121 sysfs
= load_config(iplsch
);
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);
134 err
= "failed to create guest";
138 ret
= guest_ipl_nss(login
, "login");
140 err
= "failed to IPL NSS";
145 ret
= guest_begin(login
);
147 err
= "failed to begin guest";
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);
159 err
= "failed to attach operator console";
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
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
);
183 sclp_msg("Failed to initialize '*LOGIN' guest: %s\n", err
);
189 * This is where everything starts
191 void start(u64 __memsize
, u32 __iplsch
, Elf64_Ehdr
*__elfhdr
)
194 u64 struct_page_bytes
;
197 sclp_msg("HVF %s", VERSION
);
205 * save total system memory size & the symbol table pointer
211 * Initialize struct page entries
216 * Calculate address of the first free page (we may have to round
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
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 */
248 * Set up page table entries for the nucleus
253 * Allocate & initialize the interrupt stack
258 * Initialize the io subsystem
263 * Register all the device drivers
268 * Time to enable interrupts => load new psw
270 memset(&psw
, 0, sizeof(struct psw
));
289 * Let's discover all the devices attached
294 * Initialize the process scheduler
299 * Start tracking locking dependencies
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