feature: framebuffer console WIP
This commit is contained in:
parent
ec5b5bc31b
commit
d4323e3c8f
9
Cargo.lock
generated
9
Cargo.lock
generated
@ -97,6 +97,7 @@ dependencies = [
|
|||||||
"kernel-macros",
|
"kernel-macros",
|
||||||
"libsys",
|
"libsys",
|
||||||
"memfs",
|
"memfs",
|
||||||
|
"multiboot2",
|
||||||
"tock-registers",
|
"tock-registers",
|
||||||
"vfs",
|
"vfs",
|
||||||
]
|
]
|
||||||
@ -162,6 +163,14 @@ dependencies = [
|
|||||||
"autocfg",
|
"autocfg",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "multiboot2"
|
||||||
|
version = "0.12.2"
|
||||||
|
source = "git+https://github.com/alnyan/multiboot2?branch=expose-extra-traits-for-iters#7e86b55fa5ab82e54978021f8022068a1591166b"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num-derive"
|
name = "num-derive"
|
||||||
version = "0.3.3"
|
version = "0.3.3"
|
||||||
|
2
Makefile
2
Makefile
@ -31,7 +31,7 @@ QEMU_OPTS=-s
|
|||||||
ifeq ($(ARCH),x86_64)
|
ifeq ($(ARCH),x86_64)
|
||||||
MACH=none
|
MACH=none
|
||||||
QEMU_OPTS+=-cdrom $(O)/image.iso \
|
QEMU_OPTS+=-cdrom $(O)/image.iso \
|
||||||
-M q35,accel=kvm \
|
-M q35 \
|
||||||
-cpu host \
|
-cpu host \
|
||||||
-enable-kvm \
|
-enable-kvm \
|
||||||
-m 512 \
|
-m 512 \
|
||||||
|
BIN
etc/default8x16.psfu
Normal file
BIN
etc/default8x16.psfu
Normal file
Binary file not shown.
@ -22,5 +22,8 @@ SECTIONS {
|
|||||||
.bss : AT(. - KERNEL_OFFSET) {
|
.bss : AT(. - KERNEL_OFFSET) {
|
||||||
*(COMMON)
|
*(COMMON)
|
||||||
*(.bss*)
|
*(.bss*)
|
||||||
|
. = ALIGN(4K);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PROVIDE(__kernel_end = .);
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,9 @@ bitflags = "^1.3.0"
|
|||||||
kernel-macros = { path = "macros" }
|
kernel-macros = { path = "macros" }
|
||||||
fs-macros = { path = "../fs/macros" }
|
fs-macros = { path = "../fs/macros" }
|
||||||
|
|
||||||
|
[target.'cfg(target_arch = "x86_64")'.dependencies]
|
||||||
|
multiboot2 = { git = "https://github.com/alnyan/multiboot2", branch = "expose-extra-traits-for-iters" }
|
||||||
|
|
||||||
[target.'cfg(target_arch = "aarch64")'.dependencies]
|
[target.'cfg(target_arch = "aarch64")'.dependencies]
|
||||||
cortex-a = { version = "6.x.x" }
|
cortex-a = { version = "6.x.x" }
|
||||||
fdt-rs = { version = "0.x.x", default-features = false }
|
fdt-rs = { version = "0.x.x", default-features = false }
|
||||||
|
@ -8,6 +8,14 @@
|
|||||||
.long ARCH
|
.long ARCH
|
||||||
.long HDRLEN
|
.long HDRLEN
|
||||||
.long CHKSUM
|
.long CHKSUM
|
||||||
|
|
||||||
|
.short 5
|
||||||
|
.short 0
|
||||||
|
.long 20
|
||||||
|
.long 800
|
||||||
|
.long 600
|
||||||
|
.long 32
|
||||||
|
|
||||||
.short 0
|
.short 0
|
||||||
.long 8
|
.long 8
|
||||||
|
|
||||||
|
@ -1,15 +1,105 @@
|
|||||||
use crate::arch::x86_64::{gdt, idt};
|
use crate::arch::x86_64::{self, intc, gdt, idt};
|
||||||
|
use crate::mem::{
|
||||||
|
self, heap,
|
||||||
|
phys::{self, MemoryRegion, PageUsage, ReservedRegion},
|
||||||
|
virt,
|
||||||
|
};
|
||||||
|
use crate::debug;
|
||||||
|
use crate::fs::{devfs, sysfs};
|
||||||
|
use crate::dev::{pseudo, Device, display::FramebufferInfo};
|
||||||
|
use core::mem::MaybeUninit;
|
||||||
|
use crate::font;
|
||||||
|
use multiboot2::{BootInformation, MemoryArea};
|
||||||
|
|
||||||
|
static mut RESERVED_REGION_MB2: MaybeUninit<ReservedRegion> = MaybeUninit::uninit();
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
extern "C" fn __x86_64_bsp_main(mb_checksum: u32, mb_info_ptr: u32) -> ! {
|
extern "C" fn __x86_64_bsp_main(mb_checksum: u32, mb_info_ptr: u32) -> ! {
|
||||||
// TODO enable FP support for kernel/user
|
|
||||||
// Setup a proper GDT
|
|
||||||
unsafe {
|
unsafe {
|
||||||
|
// Enable SSE support
|
||||||
|
asm!(
|
||||||
|
r#"
|
||||||
|
mov %cr4, %rax
|
||||||
|
or $(1 << 9), %rax // FXSAVE, FXRSTOR
|
||||||
|
or $(1 << 10), %rax // OSXMMEXCPT
|
||||||
|
mov %rax, %cr4
|
||||||
|
|
||||||
|
mov %cr0, %rax
|
||||||
|
and $~(1 << 2), %rax // Disable EM
|
||||||
|
or $(1 << 1), %rax // Enable MP
|
||||||
|
mov %rax, %cr0
|
||||||
|
"#,
|
||||||
|
options(att_syntax)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Setup a proper GDT
|
||||||
gdt::init();
|
gdt::init();
|
||||||
idt::init(|_| {});
|
idt::init(intc::map_isr_entries);
|
||||||
}
|
}
|
||||||
|
|
||||||
loop {}
|
virt::enable().expect("Failed to initialize virtual memory");
|
||||||
|
|
||||||
|
let mb_info = unsafe {
|
||||||
|
multiboot2::load_with_offset(mb_info_ptr as usize, mem::KERNEL_OFFSET)
|
||||||
|
.expect("Failed to load multiboot info structure")
|
||||||
|
};
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
let mb_info_page = (mb_info_ptr & !0xFFF) as usize;
|
||||||
|
RESERVED_REGION_MB2.write(ReservedRegion::new(
|
||||||
|
mb_info_page,
|
||||||
|
mb_info_page + ((mb_info.total_size() + 0xFFF) & !0xFFF),
|
||||||
|
));
|
||||||
|
phys::reserve("multiboot2", RESERVED_REGION_MB2.as_mut_ptr());
|
||||||
|
|
||||||
|
phys::init_from_iter(
|
||||||
|
mb_info
|
||||||
|
.memory_map_tag()
|
||||||
|
.unwrap()
|
||||||
|
.memory_areas()
|
||||||
|
.map(|entry| MemoryRegion {
|
||||||
|
start: ((entry.start_address() + 0xFFF) & !0xFFF) as usize,
|
||||||
|
end: (entry.end_address() & !0xFFF) as usize,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup a heap
|
||||||
|
unsafe {
|
||||||
|
let heap_base_phys = phys::alloc_contiguous_pages(PageUsage::KernelHeap, 4096)
|
||||||
|
.expect("Failed to allocate memory for heap");
|
||||||
|
let heap_base_virt = mem::virtualize(heap_base_phys);
|
||||||
|
heap::init(heap_base_virt, 16 * 1024 * 1024);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup hardware
|
||||||
|
unsafe {
|
||||||
|
x86_64::INTC.enable();
|
||||||
|
}
|
||||||
|
|
||||||
|
let fb_info = mb_info.framebuffer_tag().unwrap();
|
||||||
|
let virt = mem::virtualize(fb_info.address as usize);
|
||||||
|
debugln!("Framebuffer base: phys={:#x}, virt={:#x}", fb_info.address, virt);
|
||||||
|
x86_64::DISPLAY.set_framebuffer(FramebufferInfo {
|
||||||
|
width: fb_info.width as usize,
|
||||||
|
height: fb_info.height as usize,
|
||||||
|
phys_base: fb_info.address as usize,
|
||||||
|
virt_base: virt
|
||||||
|
});
|
||||||
|
font::init();
|
||||||
|
debug::set_display(&x86_64::DISPLAY);
|
||||||
|
|
||||||
|
devfs::init();
|
||||||
|
sysfs::init();
|
||||||
|
|
||||||
|
devfs::add_named_char_device(&pseudo::ZERO, "zero").unwrap();
|
||||||
|
devfs::add_named_char_device(&pseudo::RANDOM, "random").unwrap();
|
||||||
|
|
||||||
|
loop {
|
||||||
|
unsafe {
|
||||||
|
asm!("sti; hlt");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
global_asm!(include_str!("macros.S"), options(att_syntax));
|
global_asm!(include_str!("macros.S"), options(att_syntax));
|
||||||
|
@ -2,57 +2,48 @@
|
|||||||
|
|
||||||
.section .text._entry
|
.section .text._entry
|
||||||
__x86_64_enter_upper:
|
__x86_64_enter_upper:
|
||||||
// Setup paging table
|
mov $(PTE_PRESENT | PTE_WRITABLE | PTE_USERSPACE), %edx
|
||||||
mov $(PTE_PRESENT | PTE_BLOCK | PTE_WRITABLE | PTE_USERSPACE), %eax
|
// Setup PML4
|
||||||
// Fill PD0: 0..1GiB
|
lea (KERNEL_FIXED - KERNEL_OFFSET), %edi
|
||||||
lea (KERNEL_PD0 - KERNEL_OFFSET), %edi
|
lea (KERNEL_FIXED + 4096 - KERNEL_OFFSET), %esi
|
||||||
mov $512, %ecx
|
mov %edx, %eax
|
||||||
1:
|
or %esi, %eax
|
||||||
dec %ecx
|
// pml4[0] = %eax
|
||||||
|
mov %eax, (%edi)
|
||||||
mov %ecx, %edx
|
// pml4[511] = %eax
|
||||||
shl $21, %edx
|
mov %eax, 4088(%edi)
|
||||||
or %eax, %edx
|
|
||||||
|
|
||||||
mov %edx, (%edi, %ecx, 8)
|
|
||||||
|
|
||||||
test %ecx, %ecx
|
|
||||||
jnz 1b
|
|
||||||
|
|
||||||
// Fill PD1: 1GiB..2GiB
|
|
||||||
lea (KERNEL_PD1 - KERNEL_OFFSET), %edi
|
|
||||||
mov $512, %ecx
|
|
||||||
1:
|
|
||||||
dec %ecx
|
|
||||||
|
|
||||||
mov %ecx, %edx
|
|
||||||
add $512, %edx
|
|
||||||
shl $21, %edx
|
|
||||||
or %eax, %edx
|
|
||||||
|
|
||||||
mov %edx, (%edi, %ecx, 8)
|
|
||||||
|
|
||||||
test %ecx, %ecx
|
|
||||||
jnz 1b
|
|
||||||
|
|
||||||
// Setup PDPT
|
// Setup PDPT
|
||||||
mov $(PTE_PRESENT | PTE_WRITABLE | PTE_USERSPACE), %eax
|
mov %esi, %edi
|
||||||
lea (KERNEL_PDPT - KERNEL_OFFSET), %edi
|
lea (KERNEL_FIXED + 8192 - KERNEL_OFFSET), %esi
|
||||||
|
xor %ecx, %ecx
|
||||||
|
1:
|
||||||
|
// %eax = &table[%ecx] | attrs
|
||||||
|
mov %esi, %eax
|
||||||
|
or %edx, %eax
|
||||||
|
mov %eax, (%edi, %ecx, 8)
|
||||||
|
|
||||||
lea (KERNEL_PD0 - KERNEL_OFFSET), %esi
|
add $4096, %esi
|
||||||
or %eax, %esi
|
inc %ecx
|
||||||
mov %esi, (%edi)
|
cmp $16, %ecx
|
||||||
|
jne 1b
|
||||||
|
|
||||||
lea (KERNEL_PD1 - KERNEL_OFFSET), %esi
|
// Setup PDs
|
||||||
or %eax, %esi
|
lea (KERNEL_FIXED + 8192 - KERNEL_OFFSET), %edi
|
||||||
mov %esi, 8(%edi)
|
mov $(PTE_PRESENT | PTE_BLOCK | PTE_WRITABLE), %edx
|
||||||
|
mov $(512 * 16), %ecx
|
||||||
|
1:
|
||||||
|
dec %ecx
|
||||||
|
|
||||||
// Setup PML4
|
// %eax = attrs | (i << 21)
|
||||||
lea (KERNEL_PML4 - KERNEL_OFFSET), %edi
|
mov %ecx, %eax
|
||||||
lea (KERNEL_PDPT - KERNEL_OFFSET), %esi
|
shl $21, %eax
|
||||||
or %eax, %esi
|
or %edx, %eax
|
||||||
mov %esi, (%edi)
|
|
||||||
mov %esi, 4088(%edi)
|
mov %eax, (%edi, %ecx, 8)
|
||||||
|
|
||||||
|
test %ecx, %ecx
|
||||||
|
jnz 1b
|
||||||
|
|
||||||
// Enable PAE/PSE
|
// Enable PAE/PSE
|
||||||
mov %cr4, %eax
|
mov %cr4, %eax
|
||||||
@ -66,6 +57,7 @@ __x86_64_enter_upper:
|
|||||||
wrmsr
|
wrmsr
|
||||||
|
|
||||||
// Set CR3
|
// Set CR3
|
||||||
|
lea (KERNEL_FIXED - KERNEL_OFFSET), %edi
|
||||||
mov %edi, %cr3
|
mov %edi, %cr3
|
||||||
|
|
||||||
// Enable paging
|
// Enable paging
|
||||||
|
0
kernel/src/arch/x86_64/display/efi_fb.rs
Normal file
0
kernel/src/arch/x86_64/display/efi_fb.rs
Normal file
@ -1,4 +1,6 @@
|
|||||||
|
use crate::arch::x86_64;
|
||||||
use crate::debug::Level;
|
use crate::debug::Level;
|
||||||
|
use crate::dev::irq::{IrqContext, IntController};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct ExceptionFrame {
|
struct ExceptionFrame {
|
||||||
@ -68,3 +70,11 @@ extern "C" fn __x86_64_exception_handler(frame: &mut ExceptionFrame) {
|
|||||||
|
|
||||||
panic!("Unhandled exception");
|
panic!("Unhandled exception");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
extern "C" fn __x86_64_irq_handler(frame: &mut ExceptionFrame) {
|
||||||
|
unsafe {
|
||||||
|
let ic = IrqContext::new(frame.err_no as usize);
|
||||||
|
x86_64::intc().handle_pending_irqs(&ic);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -18,11 +18,11 @@ struct Pointer {
|
|||||||
offset: usize
|
offset: usize
|
||||||
}
|
}
|
||||||
|
|
||||||
const SIZE: usize = 256;
|
pub const SIZE: usize = 256;
|
||||||
|
|
||||||
impl Entry {
|
impl Entry {
|
||||||
const PRESENT: u8 = 1 << 7;
|
pub const PRESENT: u8 = 1 << 7;
|
||||||
const INT32: u8 = 0xE;
|
pub const INT32: u8 = 0xE;
|
||||||
|
|
||||||
pub const fn new(base: usize, selector: u16, flags: u8) -> Self {
|
pub const fn new(base: usize, selector: u16, flags: u8) -> Self {
|
||||||
Self {
|
Self {
|
||||||
@ -60,6 +60,8 @@ pub unsafe fn init<F: FnOnce(&mut [Entry; SIZE]) -> ()>(f: F) {
|
|||||||
IDT[i] = Entry::new(entry, 0x08, Entry::PRESENT | Entry::INT32);
|
IDT[i] = Entry::new(entry, 0x08, Entry::PRESENT | Entry::INT32);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
f(&mut IDT);
|
||||||
|
|
||||||
let idtr = Pointer {
|
let idtr = Pointer {
|
||||||
limit: size_of_val(&IDT) as u16 - 1,
|
limit: size_of_val(&IDT) as u16 - 1,
|
||||||
offset: &IDT as *const _ as usize
|
offset: &IDT as *const _ as usize
|
||||||
|
144
kernel/src/arch/x86_64/intc.rs
Normal file
144
kernel/src/arch/x86_64/intc.rs
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
use crate::arch::x86_64::{
|
||||||
|
idt::{Entry as IdtEntry, SIZE as IDT_SIZE},
|
||||||
|
PortIo,
|
||||||
|
};
|
||||||
|
use crate::dev::{
|
||||||
|
irq::{IntController, IntSource, IrqContext},
|
||||||
|
Device,
|
||||||
|
};
|
||||||
|
use crate::sync::IrqSafeSpinLock;
|
||||||
|
use libsys::error::Errno;
|
||||||
|
|
||||||
|
const ICW1_INIT: u8 = 0x10;
|
||||||
|
const ICW1_ICW4: u8 = 0x01;
|
||||||
|
|
||||||
|
const ICW4_8086: u8 = 0x01;
|
||||||
|
|
||||||
|
pub(super) struct I8259 {
|
||||||
|
cmd_a: PortIo<u8>,
|
||||||
|
cmd_b: PortIo<u8>,
|
||||||
|
data_a: PortIo<u8>,
|
||||||
|
data_b: PortIo<u8>,
|
||||||
|
|
||||||
|
table: IrqSafeSpinLock<[Option<&'static (dyn IntSource + Sync)>; 15]>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
#[repr(transparent)]
|
||||||
|
pub struct IrqNumber(u32);
|
||||||
|
|
||||||
|
impl IrqNumber {
|
||||||
|
pub const MAX: u32 = 16;
|
||||||
|
|
||||||
|
pub const fn new(u: u32) -> Self {
|
||||||
|
if u > Self::MAX {
|
||||||
|
panic!();
|
||||||
|
}
|
||||||
|
Self(u)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Device for I8259 {
|
||||||
|
fn name(&self) -> &'static str {
|
||||||
|
"i8259-compatible IRQ controller"
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn enable(&self) -> Result<(), Errno> {
|
||||||
|
self.cmd_a.write(ICW1_INIT | ICW1_ICW4);
|
||||||
|
self.cmd_b.write(ICW1_INIT | ICW1_ICW4);
|
||||||
|
self.data_a.write(32);
|
||||||
|
self.data_b.write(32 + 8);
|
||||||
|
self.data_a.write(4);
|
||||||
|
self.data_b.write(2);
|
||||||
|
|
||||||
|
self.data_a.write(ICW4_8086);
|
||||||
|
self.data_b.write(ICW4_8086);
|
||||||
|
|
||||||
|
self.data_a.write(0xFE);
|
||||||
|
self.data_b.write(0xFF);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IntController for I8259 {
|
||||||
|
type IrqNumber = IrqNumber;
|
||||||
|
|
||||||
|
fn register_handler(
|
||||||
|
&self,
|
||||||
|
irq: Self::IrqNumber,
|
||||||
|
handler: &'static (dyn IntSource + Sync),
|
||||||
|
) -> Result<(), Errno> {
|
||||||
|
if irq.0 == 0 {
|
||||||
|
return Err(Errno::InvalidArgument);
|
||||||
|
}
|
||||||
|
|
||||||
|
let index = (irq.0 - 1) as usize;
|
||||||
|
let mut lock = self.table.lock();
|
||||||
|
if lock[index].is_some() {
|
||||||
|
return Err(Errno::AlreadyExists);
|
||||||
|
}
|
||||||
|
|
||||||
|
lock[index] = Some(handler);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn enable_irq(&self, irq: Self::IrqNumber) -> Result<(), Errno> {
|
||||||
|
let port = if irq.0 < 8 {
|
||||||
|
&self.data_a
|
||||||
|
} else {
|
||||||
|
&self.data_b
|
||||||
|
};
|
||||||
|
|
||||||
|
let mask = port.read() & !(1 << (irq.0 & 0x7));
|
||||||
|
port.write(mask);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_pending_irqs<'irq_context>(&'irq_context self, ic: &IrqContext<'irq_context>) {
|
||||||
|
let irq_number = ic.token();
|
||||||
|
assert!(irq_number > 0);
|
||||||
|
|
||||||
|
if irq_number > 8 {
|
||||||
|
self.cmd_b.write(0x20);
|
||||||
|
}
|
||||||
|
self.cmd_a.write(0x20);
|
||||||
|
|
||||||
|
{
|
||||||
|
let table = self.table.lock();
|
||||||
|
match table[irq_number - 1] {
|
||||||
|
None => panic!("No handler registered for irq{}", irq_number),
|
||||||
|
Some(handler) => {
|
||||||
|
drop(table);
|
||||||
|
handler.handle_irq().expect("irq handler failed")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl I8259 {
|
||||||
|
pub const fn new() -> Self {
|
||||||
|
unsafe {
|
||||||
|
Self {
|
||||||
|
cmd_a: PortIo::new(0x20),
|
||||||
|
data_a: PortIo::new(0x21),
|
||||||
|
cmd_b: PortIo::new(0xA0),
|
||||||
|
data_b: PortIo::new(0xA1),
|
||||||
|
table: IrqSafeSpinLock::new([None; 15]),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn map_isr_entries(entries: &mut [IdtEntry; IDT_SIZE]) {
|
||||||
|
extern "C" {
|
||||||
|
static __x86_64_irq_vectors: [usize; 16];
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i, &entry) in unsafe { __x86_64_irq_vectors.iter().enumerate() } {
|
||||||
|
entries[i + 32] = IdtEntry::new(entry, 0x08, IdtEntry::PRESENT | IdtEntry::INT32);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
global_asm!(include_str!("irq_vectors.S"), options(att_syntax));
|
83
kernel/src/arch/x86_64/irq_vectors.S
Normal file
83
kernel/src/arch/x86_64/irq_vectors.S
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
.macro irq_entry no
|
||||||
|
__x86_64_irq_\no:
|
||||||
|
cli
|
||||||
|
pushq $0
|
||||||
|
pushq $\no
|
||||||
|
|
||||||
|
push %rax
|
||||||
|
push %rcx
|
||||||
|
push %rdx
|
||||||
|
push %rbx
|
||||||
|
push %rbp
|
||||||
|
push %rsi
|
||||||
|
push %rdi
|
||||||
|
|
||||||
|
push %r8
|
||||||
|
push %r9
|
||||||
|
push %r10
|
||||||
|
push %r11
|
||||||
|
push %r12
|
||||||
|
push %r13
|
||||||
|
push %r14
|
||||||
|
push %r15
|
||||||
|
|
||||||
|
mov %rsp, %rdi
|
||||||
|
call __x86_64_irq_handler
|
||||||
|
|
||||||
|
jmp .
|
||||||
|
.endm
|
||||||
|
|
||||||
|
.section .text
|
||||||
|
|
||||||
|
__x86_64_irq_0:
|
||||||
|
cli
|
||||||
|
push %rax
|
||||||
|
push %rdx
|
||||||
|
|
||||||
|
mov $'T', %al
|
||||||
|
mov $0x3F8, %dx
|
||||||
|
outb %al, %dx
|
||||||
|
|
||||||
|
mov $0x20, %al
|
||||||
|
mov $0x20, %dx
|
||||||
|
outb %al, %dx
|
||||||
|
|
||||||
|
pop %rdx
|
||||||
|
pop %rax
|
||||||
|
iretq
|
||||||
|
|
||||||
|
irq_entry 1
|
||||||
|
irq_entry 2
|
||||||
|
irq_entry 3
|
||||||
|
irq_entry 4
|
||||||
|
irq_entry 5
|
||||||
|
irq_entry 6
|
||||||
|
irq_entry 7
|
||||||
|
irq_entry 8
|
||||||
|
irq_entry 9
|
||||||
|
irq_entry 10
|
||||||
|
irq_entry 11
|
||||||
|
irq_entry 12
|
||||||
|
irq_entry 13
|
||||||
|
irq_entry 14
|
||||||
|
irq_entry 15
|
||||||
|
|
||||||
|
.section .rodata
|
||||||
|
.global __x86_64_irq_vectors
|
||||||
|
__x86_64_irq_vectors:
|
||||||
|
.quad __x86_64_irq_0
|
||||||
|
.quad __x86_64_irq_1
|
||||||
|
.quad __x86_64_irq_2
|
||||||
|
.quad __x86_64_irq_3
|
||||||
|
.quad __x86_64_irq_4
|
||||||
|
.quad __x86_64_irq_5
|
||||||
|
.quad __x86_64_irq_6
|
||||||
|
.quad __x86_64_irq_7
|
||||||
|
.quad __x86_64_irq_8
|
||||||
|
.quad __x86_64_irq_9
|
||||||
|
.quad __x86_64_irq_10
|
||||||
|
.quad __x86_64_irq_11
|
||||||
|
.quad __x86_64_irq_12
|
||||||
|
.quad __x86_64_irq_13
|
||||||
|
.quad __x86_64_irq_14
|
||||||
|
.quad __x86_64_irq_15
|
@ -1,7 +1,10 @@
|
|||||||
use crate::dev::serial::SerialDevice;
|
use crate::dev::{serial::SerialDevice, display::StaticFramebuffer, irq::IntController};
|
||||||
|
|
||||||
mod uart;
|
mod uart;
|
||||||
use uart::Uart;
|
use uart::Uart;
|
||||||
|
mod intc;
|
||||||
|
use intc::I8259;
|
||||||
|
|
||||||
mod io;
|
mod io;
|
||||||
pub(self) use io::PortIo;
|
pub(self) use io::PortIo;
|
||||||
|
|
||||||
@ -18,7 +21,9 @@ pub(self) mod exception;
|
|||||||
/// Unsafe: disables IRQ handling temporarily
|
/// Unsafe: disables IRQ handling temporarily
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub unsafe fn irq_mask_save() -> u64 {
|
pub unsafe fn irq_mask_save() -> u64 {
|
||||||
loop {}
|
let mut res;
|
||||||
|
asm!("pushf; cli; pop {}", out(reg) res, options(att_syntax));
|
||||||
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Restores IRQ mask state
|
/// Restores IRQ mask state
|
||||||
@ -29,7 +34,13 @@ pub unsafe fn irq_mask_save() -> u64 {
|
|||||||
/// conjunction with [irq_mask_save]
|
/// conjunction with [irq_mask_save]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub unsafe fn irq_restore(state: u64) {
|
pub unsafe fn irq_restore(state: u64) {
|
||||||
loop {}
|
if state & (1 << 9) != 0 {
|
||||||
|
asm!("sti");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn intc() -> &'static impl IntController {
|
||||||
|
&INTC
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn console() -> &'static impl SerialDevice {
|
pub fn console() -> &'static impl SerialDevice {
|
||||||
@ -37,3 +48,5 @@ pub fn console() -> &'static impl SerialDevice {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static COM1: Uart = unsafe { Uart::new(0x3F8) };
|
static COM1: Uart = unsafe { Uart::new(0x3F8) };
|
||||||
|
static INTC: I8259 = I8259::new();
|
||||||
|
pub(self) static DISPLAY: StaticFramebuffer = StaticFramebuffer::uninit();
|
||||||
|
@ -1,13 +1,22 @@
|
|||||||
use crate::mem::virt::AddressSpace;
|
use crate::mem::virt::AddressSpace;
|
||||||
|
use core::ops::{Index, IndexMut};
|
||||||
use libsys::error::Errno;
|
use libsys::error::Errno;
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
pub struct Entry(u64);
|
pub struct Entry(u64);
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
#[repr(C, align(0x1000))]
|
#[repr(C, align(0x1000))]
|
||||||
pub struct Table {
|
pub struct Table {
|
||||||
entries: [Entry; 512],
|
entries: [Entry; 512]
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C, align(0x1000))]
|
||||||
|
pub struct FixedTableGroup {
|
||||||
|
pml4: Table,
|
||||||
|
pdpt: Table,
|
||||||
|
pd: [Table; 16]
|
||||||
}
|
}
|
||||||
|
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
@ -15,14 +24,11 @@ pub struct Space(Table);
|
|||||||
|
|
||||||
// Upper mappings
|
// Upper mappings
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
static KERNEL_PDPT: Table = Table::empty();
|
static mut KERNEL_FIXED: FixedTableGroup = FixedTableGroup {
|
||||||
#[no_mangle]
|
pml4: Table::empty(),
|
||||||
static KERNEL_PD0: Table = Table::empty();
|
pdpt: Table::empty(),
|
||||||
#[no_mangle]
|
pd: [Table::empty(); 16]
|
||||||
static KERNEL_PD1: Table = Table::empty();
|
};
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
static KERNEL_PML4: Space = Space::empty();
|
|
||||||
|
|
||||||
impl Entry {
|
impl Entry {
|
||||||
const fn invalid() -> Self {
|
const fn invalid() -> Self {
|
||||||
@ -61,6 +67,27 @@ impl AddressSpace for Space {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn enable() -> Result<(), Errno> {
|
impl Index<usize> for Table {
|
||||||
loop {}
|
type Output = Entry;
|
||||||
|
|
||||||
|
fn index(&self, index: usize) -> &Self::Output {
|
||||||
|
&self.entries[index]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IndexMut<usize> for Table {
|
||||||
|
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
|
||||||
|
&mut self.entries[index]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn enable() -> Result<(), Errno> {
|
||||||
|
unsafe {
|
||||||
|
// Remove the lower mapping
|
||||||
|
KERNEL_FIXED.pml4.entries[0] = Entry::invalid();
|
||||||
|
|
||||||
|
// Flush the TLB by reloading cr3
|
||||||
|
asm!("mov %cr3, %rax; mov %rax, %cr3", options(att_syntax));
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -11,12 +11,84 @@
|
|||||||
//! * [warnln!]
|
//! * [warnln!]
|
||||||
//! * [errorln!]
|
//! * [errorln!]
|
||||||
|
|
||||||
use crate::dev::serial::SerialDevice;
|
use crate::dev::{
|
||||||
use libsys::{debug::TraceLevel, error::Errno};
|
display::{Display, FramebufferInfo},
|
||||||
|
serial::SerialDevice,
|
||||||
|
};
|
||||||
|
use crate::font;
|
||||||
|
use crate::sync::IrqSafeSpinLock;
|
||||||
use core::convert::TryFrom;
|
use core::convert::TryFrom;
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
|
use libsys::{debug::TraceLevel, error::Errno};
|
||||||
|
|
||||||
pub static LEVEL: Level = Level::Debug;
|
pub static LEVEL: Level = Level::Debug;
|
||||||
|
static COLOR_MAP: [u32; 16] = [
|
||||||
|
0x000000,
|
||||||
|
0x0000AA,
|
||||||
|
0x00AA00,
|
||||||
|
0x00AAAA,
|
||||||
|
0xAA0000,
|
||||||
|
0xAA00AA,
|
||||||
|
0xAA5500,
|
||||||
|
0xAAAAAA,
|
||||||
|
0x555555,
|
||||||
|
0x5555FF,
|
||||||
|
0x55FF55,
|
||||||
|
0x55FFFF,
|
||||||
|
0xFF5555,
|
||||||
|
0xFF55FF,
|
||||||
|
0xFFFF55,
|
||||||
|
0xFFFFFF,
|
||||||
|
];
|
||||||
|
static ATTR_MAP: [usize; 10] = [
|
||||||
|
0, 4, 2, 6, 1, 5, 3, 7, 7, 7
|
||||||
|
];
|
||||||
|
static DISPLAY: IrqSafeSpinLock<FramebufferOutput> = IrqSafeSpinLock::new(FramebufferOutput {
|
||||||
|
display: None,
|
||||||
|
col: 0,
|
||||||
|
row: 0,
|
||||||
|
fg: 0xBBBBBB,
|
||||||
|
bg: 0x000000,
|
||||||
|
esc: EscapeState::None,
|
||||||
|
esc_argv: [0; 8],
|
||||||
|
esc_argc: 0
|
||||||
|
});
|
||||||
|
|
||||||
|
enum EscapeState {
|
||||||
|
None,
|
||||||
|
Esc,
|
||||||
|
Data
|
||||||
|
}
|
||||||
|
|
||||||
|
struct FramebufferOutput {
|
||||||
|
display: Option<&'static dyn Display>,
|
||||||
|
row: usize,
|
||||||
|
col: usize,
|
||||||
|
fg: u32,
|
||||||
|
bg: u32,
|
||||||
|
esc: EscapeState,
|
||||||
|
esc_argv: [usize; 8],
|
||||||
|
esc_argc: usize
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Write for FramebufferOutput {
|
||||||
|
fn write_str(&mut self, s: &str) -> fmt::Result {
|
||||||
|
if self.display.is_none() {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
let fb = self.display.unwrap().framebuffer().unwrap();
|
||||||
|
|
||||||
|
for ch in s.chars() {
|
||||||
|
self.putc(&fb, ch);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_display(disp: &'static dyn Display) {
|
||||||
|
DISPLAY.lock().display = Some(disp);
|
||||||
|
}
|
||||||
|
|
||||||
/// Kernel logging levels
|
/// Kernel logging levels
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
|
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
|
||||||
@ -42,7 +114,7 @@ impl TryFrom<u32> for Level {
|
|||||||
2 => Ok(Level::Info),
|
2 => Ok(Level::Info),
|
||||||
3 => Ok(Level::Warn),
|
3 => Ok(Level::Warn),
|
||||||
4 => Ok(Level::Error),
|
4 => Ok(Level::Error),
|
||||||
_ => Err(Errno::InvalidArgument)
|
_ => Err(Errno::InvalidArgument),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -137,6 +209,10 @@ pub fn _debug(level: Level, args: fmt::Arguments) {
|
|||||||
use crate::arch::machine;
|
use crate::arch::machine;
|
||||||
use fmt::Write;
|
use fmt::Write;
|
||||||
|
|
||||||
|
if level > Level::Debug {
|
||||||
|
DISPLAY.lock().write_fmt(args).ok();
|
||||||
|
}
|
||||||
|
|
||||||
if level >= LEVEL {
|
if level >= LEVEL {
|
||||||
SerialOutput {
|
SerialOutput {
|
||||||
inner: machine::console(),
|
inner: machine::console(),
|
||||||
@ -145,3 +221,89 @@ pub fn _debug(level: Level, args: fmt::Arguments) {
|
|||||||
.ok();
|
.ok();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl FramebufferOutput {
|
||||||
|
const CW: usize = 8;
|
||||||
|
const CH: usize = 12;
|
||||||
|
|
||||||
|
pub fn set_char(&mut self, fb: &FramebufferInfo, x: usize, y: usize, ch: char) {
|
||||||
|
if (x + 1) * Self::CW >= fb.width || (y + 1) * Self::CH >= fb.height {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
font::get().draw(fb, x * Self::CW, y * Self::CH, ch, self.fg, self.bg);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn putc(&mut self, fb: &FramebufferInfo, ch: char) {
|
||||||
|
match self.esc {
|
||||||
|
EscapeState::None => {
|
||||||
|
match ch {
|
||||||
|
'\x1B' => {
|
||||||
|
self.esc = EscapeState::Esc;
|
||||||
|
self.esc_argv.fill(0);
|
||||||
|
self.esc_argc = 0;
|
||||||
|
}
|
||||||
|
' '..='\x7E' => {
|
||||||
|
self.set_char(fb, self.col, self.row, ch);
|
||||||
|
|
||||||
|
// Advance the cursor
|
||||||
|
self.col += 1;
|
||||||
|
if (self.col + 1) * Self::CW >= fb.width {
|
||||||
|
self.col = 0;
|
||||||
|
self.row += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
'\n' => {
|
||||||
|
self.col = 0;
|
||||||
|
self.row += 1;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (self.row + 1) * Self::CH >= fb.height {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EscapeState::Esc => {
|
||||||
|
match ch {
|
||||||
|
'[' => {
|
||||||
|
self.esc = EscapeState::Data;
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
self.esc = EscapeState::None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EscapeState::Data => {
|
||||||
|
match ch {
|
||||||
|
'0'..='9' => {
|
||||||
|
self.esc_argv[self.esc_argc] *= 10;
|
||||||
|
self.esc_argv[self.esc_argc] += (ch as u8 - b'0') as usize;
|
||||||
|
}
|
||||||
|
';' => {
|
||||||
|
self.esc_argc += 1;
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
self.esc_argc += 1;
|
||||||
|
self.esc = EscapeState::None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
match ch {
|
||||||
|
'm' => {
|
||||||
|
for i in 0..self.esc_argc {
|
||||||
|
let item = self.esc_argv[i];
|
||||||
|
if item / 10 == 4 {
|
||||||
|
self.bg = COLOR_MAP[ATTR_MAP[(item % 10) as usize]];
|
||||||
|
}
|
||||||
|
if item / 10 == 3 {
|
||||||
|
self.fg = COLOR_MAP[ATTR_MAP[(item % 10) as usize]];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
58
kernel/src/dev/display.rs
Normal file
58
kernel/src/dev/display.rs
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
use crate::dev::Device;
|
||||||
|
use libsys::error::Errno;
|
||||||
|
use crate::util::InitOnce;
|
||||||
|
|
||||||
|
pub struct FramebufferInfo {
|
||||||
|
pub width: usize,
|
||||||
|
pub height: usize,
|
||||||
|
pub phys_base: usize,
|
||||||
|
pub virt_base: usize
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait Display: Device {
|
||||||
|
fn set_mode(&self, mode: DisplayMode) -> Result<(), Errno>;
|
||||||
|
fn framebuffer<'a>(&'a self) -> Result<&'a FramebufferInfo, Errno>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct DisplayMode {
|
||||||
|
width: u16,
|
||||||
|
height: u16,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct StaticFramebuffer {
|
||||||
|
framebuffer: InitOnce<FramebufferInfo>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Device for StaticFramebuffer {
|
||||||
|
fn name(&self) -> &'static str {
|
||||||
|
"Generic framebuffer device"
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn enable(&self) -> Result<(), Errno> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for StaticFramebuffer {
|
||||||
|
fn set_mode(&self, mode: DisplayMode) -> Result<(), Errno> {
|
||||||
|
Err(Errno::InvalidOperation)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn framebuffer(&self) -> Result<&FramebufferInfo, Errno> {
|
||||||
|
if let Some(fb) = self.framebuffer.as_ref_option() {
|
||||||
|
Ok(fb)
|
||||||
|
} else {
|
||||||
|
Err(Errno::InvalidOperation)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl StaticFramebuffer {
|
||||||
|
pub const fn uninit() -> Self {
|
||||||
|
Self { framebuffer: InitOnce::new() }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_framebuffer(&self, framebuffer: FramebufferInfo) {
|
||||||
|
self.framebuffer.init(framebuffer);
|
||||||
|
}
|
||||||
|
}
|
@ -5,6 +5,7 @@ use libsys::error::Errno;
|
|||||||
|
|
||||||
/// Token to indicate the local core is running in IRQ context
|
/// Token to indicate the local core is running in IRQ context
|
||||||
pub struct IrqContext<'irq_context> {
|
pub struct IrqContext<'irq_context> {
|
||||||
|
token: usize,
|
||||||
_0: PhantomData<&'irq_context ()>,
|
_0: PhantomData<&'irq_context ()>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -45,7 +46,11 @@ impl<'q> IrqContext<'q> {
|
|||||||
///
|
///
|
||||||
/// Only allowed to be constructed in top-level IRQ handlers
|
/// Only allowed to be constructed in top-level IRQ handlers
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub unsafe fn new() -> Self {
|
pub unsafe fn new(token: usize) -> Self {
|
||||||
Self { _0: PhantomData }
|
Self { token, _0: PhantomData }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn token(&self) -> usize {
|
||||||
|
self.token
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,13 +5,14 @@ use libsys::error::Errno;
|
|||||||
// Device classes
|
// Device classes
|
||||||
// pub mod fdt;
|
// pub mod fdt;
|
||||||
// pub mod gpio;
|
// pub mod gpio;
|
||||||
// pub mod irq;
|
pub mod irq;
|
||||||
|
pub mod display;
|
||||||
// pub mod pci;
|
// pub mod pci;
|
||||||
// pub mod rtc;
|
// pub mod rtc;
|
||||||
// pub mod sd;
|
// pub mod sd;
|
||||||
pub mod serial;
|
pub mod serial;
|
||||||
// pub mod timer;
|
pub mod timer;
|
||||||
// pub mod pseudo;
|
pub mod pseudo;
|
||||||
// pub mod tty;
|
// pub mod tty;
|
||||||
|
|
||||||
/// Generic device trait
|
/// Generic device trait
|
||||||
|
@ -1,8 +1,5 @@
|
|||||||
use crate::arch::machine::{self, IrqNumber};
|
|
||||||
use crate::dev::{
|
use crate::dev::{
|
||||||
irq::{IntController, IntSource},
|
|
||||||
serial::SerialDevice,
|
serial::SerialDevice,
|
||||||
tty::{CharRing, TtyDevice},
|
|
||||||
Device,
|
Device,
|
||||||
};
|
};
|
||||||
use crate::mem::virt::DeviceMemoryIo;
|
use crate::mem::virt::DeviceMemoryIo;
|
||||||
|
49
kernel/src/font.rs
Normal file
49
kernel/src/font.rs
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
use crate::util::InitOnce;
|
||||||
|
use libsys::mem::read_le32;
|
||||||
|
use crate::dev::display::FramebufferInfo;
|
||||||
|
|
||||||
|
static FONT_DATA: &[u8] = include_bytes!("../../etc/default8x16.psfu");
|
||||||
|
static FONT: InitOnce<Font> = InitOnce::new();
|
||||||
|
|
||||||
|
pub struct Font {
|
||||||
|
char_width: usize,
|
||||||
|
char_height: usize,
|
||||||
|
bytes_per_glyph: usize,
|
||||||
|
data: &'static [u8],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Font {
|
||||||
|
pub fn draw(&self, fb: &FramebufferInfo, bx: usize, by: usize, ch: char, fg: u32, bg: u32) {
|
||||||
|
if ch >= ' ' && ch < '\x7B' {
|
||||||
|
let char_data = &self.data[ch as usize * self.bytes_per_glyph..];
|
||||||
|
|
||||||
|
for iy in 0..self.char_height {
|
||||||
|
for ix in 0..self.char_width {
|
||||||
|
let cx = self.char_width - ix - 1;
|
||||||
|
let ptr = fb.virt_base + (ix + bx + (iy + by) * fb.width) * 4;
|
||||||
|
let value = if char_data[iy + (cx) / 8] & (1 << (cx & 0x7)) != 0 {
|
||||||
|
fg
|
||||||
|
} else {
|
||||||
|
bg
|
||||||
|
};
|
||||||
|
unsafe { core::ptr::write_volatile(ptr as *mut u32, value) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn init() {
|
||||||
|
assert_eq!(read_le32(&FONT_DATA[..]), 0x864ab572);
|
||||||
|
|
||||||
|
FONT.init(Font {
|
||||||
|
char_width: read_le32(&FONT_DATA[28..]) as usize,
|
||||||
|
char_height: read_le32(&FONT_DATA[24..]) as usize,
|
||||||
|
bytes_per_glyph: read_le32(&FONT_DATA[20..]) as usize,
|
||||||
|
data: &FONT_DATA[32..]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get() -> &'static Font {
|
||||||
|
FONT.get()
|
||||||
|
}
|
@ -162,8 +162,8 @@ pub fn init() {
|
|||||||
use crate::dev::timer::TimestampSource;
|
use crate::dev::timer::TimestampSource;
|
||||||
|
|
||||||
let mut writer = BufferWriter::new(buf);
|
let mut writer = BufferWriter::new(buf);
|
||||||
let time = machine::local_timer().timestamp()?;
|
// let time = machine::local_timer().timestamp()?;
|
||||||
write!(&mut writer, "{} {}\n", time.as_secs(), time.subsec_nanos()).map_err(|_| Errno::InvalidArgument)?;
|
// write!(&mut writer, "{} {}\n", time.as_secs(), time.subsec_nanos()).map_err(|_| Errno::InvalidArgument)?;
|
||||||
Ok(writer.count())
|
Ok(writer.count())
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -11,8 +11,8 @@
|
|||||||
const_panic,
|
const_panic,
|
||||||
panic_info_message,
|
panic_info_message,
|
||||||
alloc_error_handler,
|
alloc_error_handler,
|
||||||
// linked_list_cursors,
|
linked_list_cursors,
|
||||||
// const_btree_new,
|
const_btree_new,
|
||||||
core_intrinsics,
|
core_intrinsics,
|
||||||
const_generics_defaults,
|
const_generics_defaults,
|
||||||
)]
|
)]
|
||||||
@ -26,7 +26,7 @@ extern crate kernel_macros;
|
|||||||
extern crate cfg_if;
|
extern crate cfg_if;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate bitflags;
|
extern crate bitflags;
|
||||||
// extern crate alloc;
|
extern crate alloc;
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
pub mod debug;
|
pub mod debug;
|
||||||
@ -34,7 +34,8 @@ pub mod debug;
|
|||||||
pub mod arch;
|
pub mod arch;
|
||||||
pub mod config;
|
pub mod config;
|
||||||
pub mod dev;
|
pub mod dev;
|
||||||
// pub mod fs;
|
pub mod fs;
|
||||||
|
pub mod font;
|
||||||
// pub mod init;
|
// pub mod init;
|
||||||
pub mod mem;
|
pub mod mem;
|
||||||
// pub mod proc;
|
// pub mod proc;
|
||||||
@ -48,7 +49,7 @@ fn panic_handler(pi: &core::panic::PanicInfo) -> ! {
|
|||||||
// asm!("msr daifset, #2");
|
// asm!("msr daifset, #2");
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// errorln!("Panic: {:?}", pi);
|
errorln!("Panic: {:?}", pi);
|
||||||
// TODO
|
// TODO
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,7 @@ mod manager;
|
|||||||
mod reserved;
|
mod reserved;
|
||||||
|
|
||||||
use manager::{Manager, SimpleManager, MANAGER};
|
use manager::{Manager, SimpleManager, MANAGER};
|
||||||
pub use reserved::ReservedRegion;
|
pub use reserved::{ReservedRegion, reserve};
|
||||||
|
|
||||||
type ManagerImpl = SimpleManager;
|
type ManagerImpl = SimpleManager;
|
||||||
|
|
||||||
@ -209,11 +209,14 @@ pub unsafe fn init_from_iter<T: Iterator<Item = MemoryRegion> + Clone>(iter: T)
|
|||||||
mem_base = reg.start;
|
mem_base = reg.start;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// infoln!("Memory base is {:#x}", mem_base);
|
infoln!("Memory base is {:#x}", mem_base);
|
||||||
// Step 1. Count available memory
|
// Step 1. Count available memory
|
||||||
let mut total_pages = 0usize;
|
let mut total_pages = 0usize;
|
||||||
for reg in iter.clone() {
|
for reg in iter.clone() {
|
||||||
total_pages += (reg.end - reg.start) / PAGE_SIZE;
|
let upper = (reg.end - mem_base) / PAGE_SIZE;
|
||||||
|
if upper > total_pages {
|
||||||
|
total_pages = upper;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// TODO maybe instead of size_of::<...> use Layout?
|
// TODO maybe instead of size_of::<...> use Layout?
|
||||||
let need_pages = ((total_pages * size_of::<PageInfo>()) + 0xFFF) / 0x1000;
|
let need_pages = ((total_pages * size_of::<PageInfo>()) + 0xFFF) / 0x1000;
|
||||||
@ -238,7 +241,7 @@ pub unsafe fn init_from_iter<T: Iterator<Item = MemoryRegion> + Clone>(iter: T)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// infoln!("{}K of usable physical memory", usable_pages * 4);
|
infoln!("{}K of usable physical memory", usable_pages * 4);
|
||||||
*MANAGER.lock() = Some(manager);
|
*MANAGER.lock() = Some(manager);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,12 +47,12 @@ static mut RESERVED_REGION_PAGES: MaybeUninit<ReservedRegion> = MaybeUninit::uni
|
|||||||
///
|
///
|
||||||
/// Unsafe: `region` is passed as a raw pointer.
|
/// Unsafe: `region` is passed as a raw pointer.
|
||||||
pub unsafe fn reserve(usage: &str, region: *mut ReservedRegion) {
|
pub unsafe fn reserve(usage: &str, region: *mut ReservedRegion) {
|
||||||
// infoln!(
|
infoln!(
|
||||||
// "Reserving {:?} region: {:#x}..{:#x}",
|
"Reserving {:?} region: {:#x}..{:#x}",
|
||||||
// usage,
|
usage,
|
||||||
// (*region).start,
|
(*region).start,
|
||||||
// (*region).end
|
(*region).end
|
||||||
// );
|
);
|
||||||
(*region).next = RESERVED_REGIONS_HEAD;
|
(*region).next = RESERVED_REGIONS_HEAD;
|
||||||
RESERVED_REGIONS_HEAD = region;
|
RESERVED_REGIONS_HEAD = region;
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,14 @@ impl<T> InitOnce<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn as_ref_option(&self) -> Option<&T> {
|
||||||
|
if self.is_initialized() {
|
||||||
|
Some(self.get())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns `true` if this [InitOnce<T>] can be used
|
/// Returns `true` if this [InitOnce<T>] can be used
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn is_initialized(&self) -> bool {
|
pub fn is_initialized(&self) -> bool {
|
||||||
@ -29,7 +37,7 @@ impl<T> InitOnce<T> {
|
|||||||
/// Returns the initialized value. Will panic if the value has not
|
/// Returns the initialized value. Will panic if the value has not
|
||||||
/// yet been initialized.
|
/// yet been initialized.
|
||||||
#[allow(clippy::mut_from_ref)]
|
#[allow(clippy::mut_from_ref)]
|
||||||
pub fn get(&self) -> &mut T {
|
pub fn get(&self) -> &T {
|
||||||
assert!(self.is_initialized(), "Access to uninitialized InitOnce<T>");
|
assert!(self.is_initialized(), "Access to uninitialized InitOnce<T>");
|
||||||
unsafe { (*self.inner.get()).assume_init_mut() }
|
unsafe { (*self.inner.get()).assume_init_mut() }
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user