Skip to main content

rustubs/
defs.rs

1//! system level definitions
2
3/// multiboot magic value, it must be 0x2BAD8002. This value is set at runtime
4/// by init asm code. CARE: the release build will not treat these as volatile
5/// and they may hardcode the initial value (0) because they sees "static const
6/// zero". Therefore when reading them must do a volatile read.
7#[no_mangle]
8pub static mb_magic: u64 = 0;
9/// _physical_ address of multiboot info block. This value is set at run time by
10/// init asm code. Both values are safe to read, but [mb_info_pm_addr] must be
11/// converted to the virtual mapping via P2V before dereferencing.
12#[no_mangle]
13pub static mb_info_pm_addr: u64 = 0;
14
15#[inline]
16pub fn roundup_4k(addr: u64) -> u64 { (addr + 0xfff) & !0xfff }
17
18#[inline]
19pub fn rounddown_4k(addr: u64) -> u64 { addr & !0xfff }
20
21#[inline]
22pub fn is_aligned_4k(addr: u64) -> bool { (addr & 0xfff) == 0 }
23
24/// memory definitions
25pub mod Mem {
26	// units
27	pub const K: u64 = 1024;
28	pub const M: u64 = 1024 * K;
29	pub const G: u64 = 1024 * M;
30	// 4 lv 4K paging
31	pub const PAGE_SIZE: u64 = 0x1000;
32	pub const PAGE_SHIFT: u64 = 12;
33	pub const PAGE_MASK: u64 = 0xfff;
34	// 64 GiB available memory
35	pub const MAX_PHY_MEM: u64 = 0x1000000000;
36	// we should have at least 64 MiB free physical memory (excluding the kernel it self)
37	pub const MIN_PHY_MEM: u64 = 64 * M;
38	pub const ID_MAP_START: u64 = 0xffff_8000_0000_0000;
39	pub const ID_MAP_END: u64 = 0xffff_8010_0000_0000;
40	// kernel image:0xffff_8020_0000_0000 ~ 0xffff_802f_0000_0000;
41	pub const KERNEL_OFFSET: u64 = 0xffff_8020_0000_0000;
42	// kernel heap: 0xffff_8030_0000_0000 ~ 0xffff_803f_0000_0000;
43	// (64 GiB)
44	pub const KERNEL_HEAP_START: u64 = 0xffff_8030_0000_0000;
45	pub const KERNEL_HEAP_END: u64 = 0xffff_8040_0000_0000;
46	// unlike the initial "thread" that has 64K stack, new tasks have 4 pages of
47	// kernel stack.
48	pub const KERNEL_STACK_SIZE: u64 = 0x4000;
49	pub const KERNEL_STACK_MASK: u64 = KERNEL_STACK_SIZE - 1;
50	pub const KERNEL_STACK_TASK_MAGIC: u64 = 0x1A2B3C4D5E6F6969;
51	// user (psuedo)
52	pub const USER_STACK_START: u64 = 0x0000_7000_0000_0000;
53	pub const USER_STACK_SIZE: u64 = 8 * M;
54
55	// defs for the PFA
56	//
57	// max order of 11, that is
58	pub const PFA_MAX_PAGE_ORDER: usize = 10; // 2^10 pages = 4MB
59	pub const PFA_NR_PAGE_ORDER: usize = PFA_MAX_PAGE_ORDER + 1;
60	pub const PFA_ORDER_RANGE: core::ops::Range<usize> = 0..PFA_NR_PAGE_ORDER;
61}
62
63// TODO use a consistent naming convention for extern symbols
64pub mod ExternSyms {
65	use crate::EXTERN_SYM_PTR;
66	// symbols from the assembly
67	EXTERN_SYM_PTR!(pub GDT ,            gdt);
68	EXTERN_SYM_PTR!(pub GDT_80 ,         gdt_80);
69	EXTERN_SYM_PTR!(pub TSS_DESC ,       tss_desc);
70	EXTERN_SYM_PTR!(pub TSS0,            tss0);
71
72	EXTERN_SYM_PTR!(pub VECTORS_START,  vectors_start);
73	EXTERN_SYM_PTR!(pub VECTOR_128,     vector_128);
74	EXTERN_SYM_PTR!(pub VECTOR_INV,     vector_invalid);
75	EXTERN_SYM_PTR!(pub IDT,            idt);
76	EXTERN_SYM_PTR!(pub IDT_DESCR,      idt_descr);
77	// symbols produced by linker script
78	EXTERN_SYM_PTR!(pub KERNEL_PM_START, ___KERNEL_PM_START__);
79	EXTERN_SYM_PTR!(pub KERNEL_PM_END,   ___KERNEL_PM_END__);
80	EXTERN_SYM_PTR!(pub BSS_START,       ___BSS_START__);
81	EXTERN_SYM_PTR!(pub BSS_END,         ___BSS_END__);
82	EXTERN_SYM_PTR!(pub RAMFS_START,     ___RAMFS_START__);
83	EXTERN_SYM_PTR!(pub RAMFS_END,       ___RAMFS_END__);
84
85	// TODO grouping symbols into archs
86	// #[cfg(target_arch = "x86_64")]
87	// pub use crate::arch::x86_64::ExternSyms::*;
88}
89
90#[cfg(target_arch = "x86_64")]
91pub mod HWDefs {
92	/// number of entries in IDT
93	pub const IDT_CAPACITY: usize = 256;
94	/// 32 exceptions + 16 irqs from PIC = 48 valid interrupts
95	pub const IDT_VALID: usize = 48;
96	/// size of interrupt handler wrapper routine (vector)
97	pub const VECTOR_SIZE: usize = 16;
98	/// GDT segment selectors (see boot/startup-x86_64.s).docs/
99	/// GDT\[0\]=null, \[1\]=kdata, \[2\]=kcode, \[3\]=ucode, \[4\]=udata,
100	/// \[5\]=tss
101	pub const SEG_KERNEL_DATA: u16 = 0x08;
102	pub const SEG_KERNEL_CODE: u16 = 0x10;
103	/// user code/data with RPL=3
104	pub const SEG_USER_CODE: u16 = 0x18;
105	pub const SEG_USER_DATA: u16 = 0x20;
106}
107
108pub mod Limits {
109	// initialize some queue structs with a reserved capacity to avoid runtime
110	// allocation
111	pub const SEM_WAIT_QUEUE_MIN_CAP: usize = 16;
112	pub const SCHED_RUN_QUEUE_MIN_CAP: usize = 24;
113}
114
115/// convert VA <-> PA wrt. the kernel id mapping
116/// from 0xffff_8000_0000_0000 ~ 0xffff_800f_ffff_ffff virtual
117/// to 0x0 ~ 0xf_ffff_ffff physical (64G)
118///
119/// V2P and P2V works on raw u64 addresses. For a type sanity, use paddr64 and
120/// vaddr64
121#[allow(non_snake_case)]
122#[inline]
123pub const fn V2P(va: u64) -> Option<u64> {
124	if va >= Mem::ID_MAP_END || va < Mem::ID_MAP_START {
125		return None;
126	}
127	return Some(va - Mem::ID_MAP_START);
128}
129
130/// physical address to virtual. reverse of [V2P]
131#[allow(non_snake_case)]
132#[inline]
133pub const fn P2V(pa: u64) -> Option<u64> {
134	if pa >= Mem::MAX_PHY_MEM {
135		return None;
136	}
137	return Some(pa + Mem::ID_MAP_START);
138}
139
140/// interrut numbers. Not complete, add more when needed
141/// (see docs/interrupt.txt)
142pub struct IntNumber {}
143impl IntNumber {
144	pub const PAGEFAULT: u16 = 0xe;
145	pub const TIMER: u16 = 0x20;
146	pub const KEYBOARD: u16 = 0x21;
147	pub const SYSCALL: u16 = 0x80;
148}
149
150#[derive(Debug)]
151pub enum AddrError {
152	InvalidPa,
153	InvalidVa,
154}
155
156/// address types vaddr64 and paddr64 have the same underlying type u64;
157/// We make the explicit distinction to avoid stupid errors.
158#[allow(non_camel_case_types)]
159pub struct vaddr64(u64);
160#[allow(non_camel_case_types)]
161pub struct paddr64(u64);
162
163impl TryFrom<paddr64> for vaddr64 {
164	type Error = AddrError;
165
166	fn try_from(value: paddr64) -> Result<Self, Self::Error> {
167		match P2V(value.0) {
168			Some(va) => Ok(vaddr64(va)),
169			None => Err(AddrError::InvalidPa),
170		}
171	}
172}
173
174impl TryFrom<vaddr64> for paddr64 {
175	type Error = AddrError;
176	fn try_from(value: vaddr64) -> Result<Self, Self::Error> {
177		match V2P(value.0) {
178			Some(pa) => Ok(paddr64(pa)),
179			None => Err(AddrError::InvalidVa),
180		}
181	}
182}