1#![no_std]
2#![cfg_attr(not(test), no_main)]
3#![allow(clippy::needless_pub_self)] #![allow(clippy::type_complexity)] use self::config::{Config, Dipsw, PAGE_MASK, PAGE_SHIFT, PAGE_SIZE, Param1};
7use self::context::{ContextSetup, arch, config};
8use self::dmem::Dmem;
9use self::imgact::Ps4Abi;
10use self::malloc::KernelHeap;
11use self::proc::{Fork, Proc, ProcAbi, ProcMgr, Thread};
12use self::sched::sleep;
13use self::uma::Uma;
14use self::vm::Vm;
15use ::config::{BootEnv, MapType};
16use alloc::string::String;
17use alloc::sync::Arc;
18use core::cmp::min;
19use core::fmt::Write;
20use humansize::{DECIMAL, SizeFormatter};
21use krt::{boot_env, info, warn};
22
23#[cfg_attr(target_arch = "aarch64", path = "aarch64.rs")]
24#[cfg_attr(target_arch = "x86_64", path = "x86_64.rs")]
25mod arch;
26mod config;
27mod context;
28mod dmem;
29mod event;
30mod imgact;
31mod imgfmt;
32mod lock;
33mod malloc;
34mod mem;
35mod proc;
36mod sched;
37mod signal;
38mod subsystem;
39mod trap;
40mod uma;
41mod vm;
42
43extern crate alloc;
44
45#[cfg_attr(target_os = "none", unsafe(no_mangle))]
49fn main(map: &'static ::config::KernelMap, config: &'static ::config::Config) -> ! {
50 let config = Config::new(config);
52 let params1 = Param1::new(&config);
53 let cpu = self::arch::identify_cpu();
54 let hw = match boot_env() {
55 BootEnv::Vm(vm) => vm.hypervisor(),
56 };
57
58 info!(
59 concat!(
60 "Starting Obliteration Kernel on {}.\n",
61 "cpu_vendor : {} × {}\n",
62 "cpu_id : {:#x}\n",
63 "boot_parameter.idps.product: {}\n",
64 "physfree : {:#x}"
65 ),
66 String::from_utf8_lossy(hw),
67 cpu.cpu_vendor,
68 config.cpu_count(),
69 cpu.cpu_id,
70 config.idps().product,
71 map.kern_vsize
72 );
73
74 let arch = unsafe { self::arch::setup_main_cpu(&config, cpu, map) };
77
78 let proc0 = Proc::new_bare(Arc::new(Proc0Abi));
80
81 let proc0 = Arc::new(proc0);
83 let thread0 = Thread::new_bare(proc0);
84
85 let thread0 = Arc::new(thread0);
87
88 unsafe {
89 self::context::run_with_context(
90 config,
91 arch,
92 0,
93 thread0,
94 move |s| setup(s, map, params1),
95 run,
96 )
97 };
98}
99
100fn setup(
101 setup: &mut ContextSetup,
102 map: &'static ::config::KernelMap,
103 param1: Arc<Param1>,
104) -> SetupResult {
105 let mut mi = load_memory_map();
107 let mut buf = String::with_capacity(0x2000);
108
109 fn format_map(tab: &[usize], last: usize, buf: &mut String) {
110 for i in (0..=last).step_by(2) {
111 let start = tab[i];
112 let end = tab[i + 1];
113 let size = SizeFormatter::new(end - start, DECIMAL);
114
115 write!(buf, "\n{start:#018x}-{end:#018x} ({size})").unwrap();
116 }
117 }
118
119 format_map(&mi.physmap, mi.physmap_last, &mut buf);
120
121 info!(
122 concat!(
123 "Memory map loaded with {} maps.\n",
124 "initial_memory_size: {} ({})\n",
125 "basemem : {:#x}\n",
126 "boot_address : {:#x}\n",
127 "mptramp_pagetables : {:#x}\n",
128 "Maxmem : {:#x}",
129 "{}"
130 ),
131 mi.physmap_last,
132 mi.initial_memory_size,
133 SizeFormatter::new(mi.initial_memory_size, DECIMAL),
134 mi.boot_area,
135 mi.boot_info.addr,
136 mi.boot_info.page_tables,
137 mi.end_page,
138 buf
139 );
140
141 buf.clear();
142
143 let dmem = Dmem::new(&mut mi);
145
146 format_map(&mi.physmap, mi.physmap_last, &mut buf);
147
148 info!(
149 concat!(
150 "DMEM initialized.\n",
151 "Mode : {} ({})\n",
152 "Maxmem: {:#x}",
153 "{}"
154 ),
155 dmem.mode(),
156 dmem.config().name,
157 mi.end_page,
158 buf
159 );
160
161 drop(buf);
162
163 let mut phys_avail = [0usize; 61];
165 let mut pa_indx = 0;
166 let mut dump_avail = [0usize; 61];
167 let mut da_indx = 1;
168 let mut physmem = 0;
169 let unk1 = 0xA494000 + 0x2200000; let paddr_free = match mi.unk {
171 0 => map.kern_vsize.get() + 0x400000, _ => map.kern_vsize.get(),
173 };
174
175 mi.physmap[0] = PAGE_SIZE.get();
176
177 phys_avail[pa_indx] = mi.physmap[0];
178 pa_indx += 1;
179 phys_avail[pa_indx] = mi.physmap[0];
180 dump_avail[da_indx] = mi.physmap[0];
181
182 for i in (0..=mi.physmap_last).step_by(2) {
183 let begin = mi.physmap[i]
184 .checked_next_multiple_of(PAGE_SIZE.get())
185 .unwrap();
186 let end = min(
187 mi.physmap[i + 1] & !PAGE_MASK.get(),
188 mi.end_page << PAGE_SHIFT,
189 );
190
191 for pa in (begin..end).step_by(PAGE_SIZE.get()) {
192 let mut full = false;
193
194 if (pa < (unk1 & 0xffffffffffe00000) || pa >= paddr_free)
195 && (mi.dcons_addr == 0
196 || (pa < (mi.dcons_addr & 0xffffffffffffc000)
197 || (mi.dcons_addr + mi.dcons_size <= pa)))
198 {
199 if mi.memtest == 0 {
200 if pa == phys_avail[pa_indx] {
201 phys_avail[pa_indx] = pa + PAGE_SIZE.get();
202 physmem += 1;
203 } else {
204 let i = pa_indx + 1;
205
206 if i == 60 {
207 warn!("Too many holes in the physical address space, giving up.");
208 full = true;
209 } else {
210 pa_indx += 2;
211 phys_avail[i] = pa;
212 phys_avail[pa_indx] = pa + PAGE_SIZE.get();
213 physmem += 1;
214 }
215 }
216 } else {
217 todo!()
218 }
219 }
220
221 if pa == dump_avail[da_indx] {
222 dump_avail[da_indx] = pa + PAGE_SIZE.get();
223 } else if (da_indx + 1) != 60 {
224 dump_avail[da_indx + 1] = pa;
225 dump_avail[da_indx + 2] = pa + PAGE_SIZE.get();
226 da_indx += 2;
227 }
228
229 if full {
230 break;
231 }
232 }
233 }
234
235 if mi.memtest != 0 {
236 todo!()
237 }
238
239 let msgbuf_size = param1.msgbuf_size().next_multiple_of(PAGE_SIZE.get());
241
242 #[allow(clippy::while_immutable_condition)] while phys_avail[pa_indx] <= (phys_avail[pa_indx - 1] + PAGE_SIZE.get() + msgbuf_size) {
244 todo!()
245 }
246
247 mi.end_page = phys_avail[pa_indx] >> PAGE_SHIFT;
248 phys_avail[pa_indx] -= msgbuf_size;
249
250 let mut pa = String::with_capacity(0x2000);
253 let mut da = String::with_capacity(0x2000);
254
255 format_map(&phys_avail, pa_indx - 1, &mut pa);
256 format_map(&dump_avail, da_indx - 1, &mut da);
257
258 info!(
259 concat!(
260 "Available physical memory populated.\n",
261 "Maxmem : {:#x}\n",
262 "physmem : {}\n",
263 "phys_avail:",
264 "{}\n",
265 "dump_avail:",
266 "{}"
267 ),
268 mi.end_page, physmem, pa, da
269 );
270
271 drop(da);
272 drop(pa);
273
274 let pmgr = ProcMgr::new();
279 let (vm, uma) = init_vm(phys_avail, &dmem);
280
281 setup.set_uma(uma); SetupResult { pmgr, vm }
284}
285
286fn run(sr: SetupResult) -> ! {
287 info!("Activating stage 2 heap.");
289
290 unsafe { KERNEL_HEAP.activate_stage2(sr.vm) };
291
292 create_init(&sr); swapper(&sr); }
296
297fn load_memory_map() -> MemoryInfo {
304 let mut physmap = [0usize; 60];
306 let mut last = 0usize;
307 let memory_map = match boot_env() {
308 BootEnv::Vm(v) => v.memory_map.as_slice(),
309 };
310
311 'top: for m in memory_map {
312 match m.ty {
314 MapType::None => break,
315 MapType::Ram => (),
316 MapType::Reserved => continue,
317 }
318
319 if m.len == 0 {
321 break;
322 }
323
324 let mut insert_idx = last + 2;
326 let mut j = 0usize;
327
328 while j <= last {
329 if m.base < physmap[j + 1] {
330 if m.base + m.len > physmap[j] {
332 warn!("Overlapping memory regions, ignoring second region.");
333 continue 'top;
334 }
335
336 insert_idx = j;
337 break;
338 }
339
340 j += 2;
341 }
342
343 if insert_idx <= last && m.base + m.len == physmap[insert_idx] {
346 physmap[insert_idx] = m.base;
347 continue;
348 }
349
350 if insert_idx > 0 && m.base == physmap[insert_idx - 1] {
353 physmap[insert_idx - 1] = m.base + m.len;
354 continue;
355 }
356
357 last += 2;
358
359 if last == physmap.len() {
360 warn!("Too many segments in the physical address map, giving up.");
361 break;
362 }
363
364 #[allow(clippy::while_immutable_condition)]
367 while insert_idx < last {
368 todo!()
369 }
370
371 physmap[insert_idx] = m.base;
372 physmap[insert_idx + 1] = m.base + m.len;
373 }
374
375 if physmap[1] == 0 {
379 panic!("no memory map provided to the kernel");
380 }
381
382 let mut initial_memory_size = 0;
384 let mut boot_area = None;
385
386 for i in (0..=last).step_by(2) {
387 if physmap[i] == 0 {
389 boot_area = Some(physmap[i + 1] / 1024);
391 }
392
393 let start = physmap[i].next_multiple_of(PAGE_SIZE.get());
395 let end = physmap[i + 1] & !PAGE_MASK.get();
396
397 initial_memory_size += end.saturating_sub(start);
398 }
399
400 let boot_area = match boot_area {
402 Some(v) => v,
403 None => panic!("no boot area provided to the kernel"),
404 };
405
406 let boot_info = adjust_boot_area(physmap[1] / 1024);
409
410 physmap[1] = boot_info.page_tables;
411
412 let mut end_page = physmap[last + 1] >> PAGE_SHIFT;
414 let config = config();
415
416 if let Some(v) = config.env("hw.physmem") {
417 end_page = min(v.parse::<usize>().unwrap() >> PAGE_SHIFT, end_page);
418 }
419
420 let memtest = config
422 .env("hw.memtest.tests")
423 .map(|v| v.parse().unwrap())
424 .unwrap_or(1);
425
426 let mut unk = 0;
428
429 for i in (0..=last).rev().step_by(2) {
430 unk = (unk + physmap[i + 1]) - physmap[i];
431 }
432
433 let mut unk = u32::from((unk >> 33) != 0);
435
436 #[cfg(target_arch = "x86_64")]
439 let cpu_ok = (arch().cpu.cpu_id & 0xffffff80) == 0x740f00;
440 #[cfg(not(target_arch = "x86_64"))]
441 let cpu_ok = true;
442
443 if cpu_ok && !config.dipsw(Dipsw::Unk140) && !config.dipsw(Dipsw::Unk146) {
444 unk |= 2;
445 }
446
447 let (dcons_addr, dcons_size) = match (config.env("dcons.addr"), config.env("dcons.size")) {
449 (Some(addr), Some(size)) => (addr.parse().unwrap(), size.parse().unwrap()),
450 _ => (0, 0),
451 };
452
453 MemoryInfo {
455 physmap,
456 physmap_last: last,
457 boot_area,
458 boot_info,
459 dcons_addr,
460 dcons_size,
461 initial_memory_size,
462 end_page,
463 unk,
464 memtest,
465 }
466}
467
468fn adjust_boot_area(original: usize) -> BootInfo {
475 let need = arch().secondary_start.len();
477 let addr = (original * 1024) & !PAGE_MASK.get();
478
479 let addr = if need <= ((original * 1024) & 0xC00) {
481 addr
482 } else {
483 addr - PAGE_SIZE.get()
484 };
485
486 BootInfo {
487 addr,
488 page_tables: addr - (PAGE_SIZE.get() * 3),
489 }
490}
491
492fn init_vm(phys_avail: [usize; 61], dmem: &Dmem) -> (&'static Vm, Arc<Uma>) {
499 let vm = Vm::new(phys_avail, None, dmem).unwrap();
501
502 (vm, Uma::new(vm))
504}
505
506fn create_init(sr: &SetupResult) {
513 let abi = Arc::new(Ps4Abi);
514 let flags = Fork::CopyFd | Fork::CreateProcess;
515
516 info!("Creating init process.");
517
518 sr.pmgr.fork(abi, flags).unwrap();
519
520 todo!()
521}
522
523fn swapper(sr: &SetupResult) -> ! {
530 loop {
532 let procs = sr.pmgr.list();
534
535 if procs.len() == 0 {
536 sleep();
539 continue;
540 }
541
542 todo!();
543 }
544}
545
546struct Proc0Abi;
550
551impl ProcAbi for Proc0Abi {
552 fn syscall_handler(&self) {
554 unimplemented!()
555 }
556}
557
558struct SetupResult {
560 pmgr: Arc<ProcMgr>,
561 vm: &'static Vm,
562}
563
564struct MemoryInfo {
566 physmap: [usize; 60],
567 physmap_last: usize,
568 boot_area: usize,
569 boot_info: BootInfo,
570 dcons_addr: usize,
571 dcons_size: usize,
572 initial_memory_size: usize,
573 end_page: usize,
574 unk: u32, memtest: u64,
576}
577
578struct BootInfo {
580 addr: usize,
581 page_tables: usize,
582}
583
584#[allow(dead_code)]
587#[cfg_attr(target_os = "none", global_allocator)]
588static KERNEL_HEAP: KernelHeap = unsafe { KernelHeap::new(&raw mut PRIMITIVE_HEAP) };
589static mut PRIMITIVE_HEAP: [u8; 1024 * 1024 * 32] = [0; _];
590
591#[cfg(not(target_pointer_width = "64"))]
594compile_error!("Obliteration can only be used with 64-bit CPU");