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