diff --git a/Makefile b/Makefile index 37dde29..86b0dfa 100644 --- a/Makefile +++ b/Makefile @@ -31,7 +31,7 @@ compile_kernel: @cp target/kernel_graphics/x86_64-r2/release/kernel.elf iso/boot/kernel_graphics.elf build_iso: - @grub-mkrescue \ + @grub2-mkrescue \ -o r2.iso iso/ \ --modules="multiboot2 video video_bochs video_cirrus gfxterm all_video" @@ -46,12 +46,6 @@ build_floppy: fat.img @echo "Hello from floppy!" > /tmp/hello.txt @mcopy -i fat.img /tmp/hello.txt ::HELLO.TXT - @mcopy -i fat.img ./print.bin ::PRINT.BIN - @mcopy -i fat.img ./print.elf ::PRINT.ELF - @mcopy -i fat.img ./go.elf ::GO.ELF - @mcopy -i fat.img ./sh.elf ::SH.ELF - @mcopy -i fat.img ./icmpresp.elf ::ICMPRESP.ELF - @mcopy -i fat.img ./garn.elf ::GARN.ELF # # RUN diff --git a/iso/boot/boot.asm b/iso/boot/boot.asm index 9e44dfb..e072bec 100644 --- a/iso/boot/boot.asm +++ b/iso/boot/boot.asm @@ -12,15 +12,6 @@ align 4096 ;dma: ; resb 4096 -pml4_table: - resq 512 -pdpt_table: - resq 512 -pd_table: - resq 512 -pt_table: - resq 512 - p4_table: resb 4096 p3_table: @@ -91,11 +82,6 @@ global p4_table global p3_table global p2_table -global p3_fb_table -global p2_fb_table -global p1_fb_table -global p1_fb_table_2 - global gdt_start global gdt_end global gdt_descriptor @@ -216,29 +202,12 @@ idt_start: times 256 dq 0 idt_end: -; -; -; - -section .data - -FB_P1_TABLES: - dq p1_fb_table_0 - dq p1_fb_table_1 - dq p1_fb_table_2 - dq p1_fb_table_3 - ; ; Page Tables Zeroing & Mapping ; section .text -%define FB_PHYS 0xFD000000 -%define FB_VIRT 0xFFFFFF8000000000 -%define PAGE_COUNT 4096 -%define PAGE_FLAGS 0b11 - zero_table: mov ecx, 512 xor eax, eax @@ -257,9 +226,6 @@ set_up_page_tables: lea edi, [p3_table] call zero_table - lea edi, [p3_fb_table] - call zero_table - lea edi, [p2_table] call zero_table @@ -324,8 +290,11 @@ set_up_page_tables: inc ecx cmp ecx, 4 + cmp ecx, 1 jne .map_1gib + ret + ; Allow CPL=3 access at 0x600_000--0x800_000 mov eax, 0x600000 @@ -340,123 +309,6 @@ set_up_page_tables: ret - ; Identity-map - -; mov eax, p1_page_tables -; or eax, PAGE_FLAGS -; mov [p2_table + 1 * 8], eax -; mov dword [p2_table + 1 * 8 + 4], 0 - -; mov eax, p1_page_tables_2 -; or eax, PAGE_FLAGS -; mov [p2_table + 2 * 8], eax -; mov dword [p2_table + 2 * 8 + 4], 0 - -; xor ecx, 0 -;.map_self: -; mov eax, 0x131000 -; add eax, ecx -; or eax, PAGE_FLAGS -; mov edi, p1_page_tables -; mov ebx, ecx -; shr ebx, 12 -; shl ebx, 3 -; add edi, ebx - -; mov [edi], eax -; mov dword [edi + 4], 0 - -; add ecx, 0x1000 -; cmp ecx, 0x80000 -; jb .map_self - -;.map_self_2: -; mov eax, 0x13e000 -; add eax, ecx -; or eax, PAGE_FLAGS -; mov edi, p1_page_tables_2 -; mov ebx, ecx -; shr ebx, 12 -; shl ebx, 3 -; add edi, ebx - -; mov [edi], eax -; mov dword [edi + 4], 0 - -; add ecx, 0x1000 -; cmp ecx, 0x40000 -; jb .map_self_2 - - ; Framebuffer init - - mov eax, p3_fb_table - or eax, PAGE_FLAGS - mov [p4_table + 511 * 8], eax - mov dword [p4_table + 511 * 8 + 4], 0 - - mov eax, p2_fb_table - or eax, PAGE_FLAGS - mov [p3_fb_table + 0 * 8], eax - mov dword [p3_fb_table + 0 * 8 + 4], 0 - - mov eax, p1_fb_table_0 - or eax, PAGE_FLAGS - mov [p2_fb_table + 0 * 8], eax - mov dword [p2_fb_table + 0 * 8 + 4], 0 - - mov eax, p1_fb_table_1 - or eax, PAGE_FLAGS - mov [p2_fb_table + 1 * 8], eax - mov dword [p2_fb_table + 1 * 8 + 4], 0 - - mov eax, p1_fb_table_2 - or eax, PAGE_FLAGS - mov [p2_fb_table + 2 * 8], eax - mov dword [p2_fb_table + 2 * 8 + 4], 0 - - mov eax, p1_fb_table_3 - or eax, PAGE_FLAGS - mov [p2_fb_table + 3 * 8], eax - mov dword [p2_fb_table + 3 * 8 + 4], 0 - - ; Framebuffer P1 pages - - xor ecx, ecx - xor esi, esi -.map_fb_dynamic: - mov eax, FB_PHYS - add eax, ecx - or eax, PAGE_FLAGS - - mov ebx, esi - shl ebx, 3 - mov edi, [FB_P1_TABLES + ebx] - - mov ebx, ecx - shr ebx, 12 - and ebx, 511 - shl ebx, 3 - - add edi, ebx - mov [edi], eax - mov dword [edi + 4], 0 - - add ecx, 0x1000 - cmp ecx, PAGE_COUNT * 0x1000 - jae .done_fb_map - - ; Switch to next p1 table every 512 pages - mov ebx, ecx - shr ebx, 12 - and ebx, 511 - cmp ebx, 0 - jne .map_fb_dynamic - inc esi - cmp esi, (PAGE_COUNT + 511) / 512 - jae .done_fb_map - jmp .map_fb_dynamic - -.done_fb_map: ret enable_paging: diff --git a/iso/boot/grub/grub.cfg b/iso/boot/grub/grub.cfg index e489448..fb2ebfa 100644 --- a/iso/boot/grub/grub.cfg +++ b/iso/boot/grub/grub.cfg @@ -10,6 +10,11 @@ menuentry "rou2exOS Rusted Edition (text mode)" { boot } +menuentry "rou2exOS Rusted Edition (text debug mode)" { + multiboot2 /boot/kernel_text.elf debug + boot +} + menuentry "rou2exOS Rusted Edition (graphics)" { multiboot2 /boot/kernel_graphics.elf grafix boot diff --git a/linker.ld b/linker.ld index 1185f8e..b3d7b59 100644 --- a/linker.ld +++ b/linker.ld @@ -7,6 +7,8 @@ SECTIONS { KEEP(*(.multiboot2_header)) } + __kernel_start = .; + .text : { *(.text.entry) *(.text*) @@ -63,6 +65,8 @@ SECTIONS { p1_fb_table_2 = .; . = . + 4K; p1_fb_table_3 = .; . = . + 4K; + __kernel_end = .; + . = 0x650000; .user_task : { *(.user_task*) diff --git a/src/debug.rs b/src/debug.rs index c875b21..8e41856 100644 --- a/src/debug.rs +++ b/src/debug.rs @@ -1,6 +1,6 @@ use core::fmt::{self, Write}; use spin::Mutex; -use crate::{clear_screen, error, printb}; +use crate::{clear_screen, error, printb, println}; const DEBUG_LOG_SIZE: usize = 8192; @@ -74,7 +74,7 @@ macro_rules! debugn { let mut buf = [0u8; 20]; let s = $crate::debug::u64_to_dec_str($n as u64, &mut buf); log.append(s); - } + } }}; } diff --git a/src/init/boot.rs b/src/init/boot.rs deleted file mode 100644 index 89f9b4a..0000000 --- a/src/init/boot.rs +++ /dev/null @@ -1,288 +0,0 @@ -use crate::init::font::{draw_text_psf, parse_psf}; -use super::{result::InitResult}; - -pub fn print_info(multiboot_ptr: u64, fb_tag: &FramebufferTag) -> InitResult { - unsafe { - debug!("Multiboot2 pointer: "); - debugn!(multiboot_ptr); - debugln!(""); - - if parse_multiboot2_info((multiboot_ptr as u32) as usize, fb_tag) > 0 { - return InitResult::Passed; - } - } - - debug!("Multiboot2 pointer: "); - debugn!(multiboot_ptr); - debugln!(""); - - InitResult::Failed -} - -#[repr(C)] -#[derive(Debug)] -pub struct TagHeader { - pub typ: u32, - pub size: u32, -} - -#[repr(C)] -#[derive(Debug)] -struct MemoryMapTag { - typ: u32, - size: u32, - entry_size: u32, - entry_version: u32, - -} - -#[repr(C, packed)] -#[derive(Debug)] -struct MemoryMapEntry { - base_addr: u64, - length: u64, - typ: u32, - reserved: u32, -} - -#[derive(Clone,Copy,Default)] -#[repr(C, packed)] -pub struct FramebufferTag { - pub typ: u32, - pub size: u32, - pub addr: u64, - pub pitch: u32, - pub width: u32, - pub height: u32, - pub bpp: u8, - pub fb_type: u8, - pub reserved: u16, -} - -#[repr(C, packed)] -pub struct AcpiRSDPTag { - pub typ: u32, - pub size: u32, - pub signature: [u8; 8], - pub checksum: u8, - pub oemid: [u8; 6], - pub revision: u8, - pub rsdt_addr: u32, -} - -#[repr(C, packed)] -pub struct AcpiSDTHeader { - pub signature: [u8; 4], - pub length: u32, - pub revision: u8, - pub checksum: u8, - pub oemid: [u8; 6], - pub oem_table_id: [u8; 8], - pub oem_revision: u32, - pub creator_id: u32, - pub creatpr_revision: u32, -} - -pub unsafe fn parse_multiboot2_info(base_addr: usize, _fb_tag: &FramebufferTag) -> usize { - // Ensure alignment (Multiboot2 requires 8-byte aligned structure) - let addr = align_up(base_addr, 8); - - // First 4 bytes: total size of the multiboot info - let total_size = *(addr as *const u32) as usize; - - let mut ptr = addr + 8; - let end = addr + total_size; - - let mut tag_count = 0; - - while ptr < end { - let tag = &*(ptr as *const TagHeader); - if tag.size < 8 || tag.size > 4096 { - debugln!("Invalid tag size: abort"); - break; - } - - match tag.typ { - 0 => { - debugln!("End tag found"); - break; - } - - 1 => { - debug!("Boot command line tag: "); - - let str_ptr = ptr + 8; - let str_len = tag.size as usize - 8; - let raw_bytes = core::slice::from_raw_parts(str_ptr as *const u8, str_len); - - let cmdline = core::str::from_utf8_unchecked(raw_bytes); - debugln!(cmdline); - } - - 3 => { - debug!("Module tag found: "); - - //let start = *((ptr + 8) as *const u32); - //let end = *((ptr + 12) as *const u32); - let str_ptr = ptr + 16; - let str_len = tag.size as usize - 16; - let raw_bytes = core::slice::from_raw_parts(str_ptr as *const u8, str_len); - - let cmdline = core::str::from_utf8_unchecked(raw_bytes); - debugln!(cmdline); - } - - 6 => { - debugln!("Memory map tag"); - - let mmap_tag = &*(ptr as *const MemoryMapTag); - let entries_start = (addr + core::mem::size_of::()) as *const u8; - let entry_size = mmap_tag.entry_size as usize; - - if entry_size > 0 { - let entries_count = (mmap_tag.size as usize - core::mem::size_of::()) / entry_size; - - for i in 0..entries_count { - let entry_ptr = entries_start.add(i * entry_size) as *const MemoryMapEntry; - let entry = &*entry_ptr; - - if entry.typ == 1 { - debug!("Usable memory region: "); - debugn!(entry.base_addr as u64); - debug!(" - "); - debugn!(entry.length as u64); - debugln!(" B"); - } - } - } - } - - 8 => { - debugln!("Framebuffer tag: "); - - let fb_tag = &*(ptr as *const FramebufferTag); - - debug!("Framebuffer address: "); - debugn!(fb_tag.addr as u64); - debugln!(""); - - debug!("(bpp + res): "); - debugn!(fb_tag.bpp as u64); - debug!(" + "); - debugn!(fb_tag.width as u64); - debug!("x"); - debugn!(fb_tag.height as u64); - debugln!(""); - - debug!("Pitch: "); - debugn!(fb_tag.pitch); - debugln!(""); - - unsafe { - // let p4_ptr = &raw mut p4_table as *mut u64; - - // let p4_virt = &raw const p4_table as usize; - // let p4_phys = p4_virt; - - let virt_base = 0xFFFF_FF80_0000_0000u64; - let fb_ptr = virt_base as *mut u32; - - let test_ptr = virt_base as *mut u32; - *test_ptr = 0xFFFFFFFF; - - //crate::mem::pages::identity_map(p4_table as *mut u64, 4 * 1024 * 1024); - //crate::mem::pages::identity_map(p4_table as *mut u64, 0x1000); - - /*crate::mem::pages::map_32mb( - p4_ptr, - fb_tag.addr as usize, - virt_base as usize, - );*/ - - //x86_64::instructions::tlb::flush_all(); - //Cr3::write(PhysFrame::from_start_address(PhysAddr::new(p4_phys as u64)).unwrap(), Cr3Flags::empty()); - - - /*for y in 0..500 { - for x in 0..500 { - //let offset = y * fb_tag.pitch + x * (fb_tag.bpp as u32 / 8); - let offset = y * fb_tag.pitch / 4 + x; - //let color = 0x00ff00ff; - - fb_ptr.add(offset as usize).write_volatile(0xdeadbeef); - fb_ptr.add(offset as usize + 1).write_volatile(0xfefab0); - fb_ptr.add(offset as usize + 2).write_volatile(0xdeadbeef); - } - }*/ - - /*for y in 0..150 { - for x in 0..200 { - super::font::put_pixel(x, y, 0xdeadbeef, fb_ptr, 4096, 32); - } - }*/ - draw_rect(fb_ptr, 150, 150, 100, 100, 4096, 0x00ffffff); - draw_rect(fb_ptr, 250, 250, 100, 100, 4096, 0x00ff0000); - draw_rect(fb_ptr, 350, 350, 100, 100, 4096, 0x0000ff00); - draw_rect(fb_ptr, 450, 450, 100, 100, 4096, 0x000000ff); - - if let Some(font) = parse_psf(super::font::PSF_FONT) { - draw_text_psf("[guest@rou2ex:/] > ", &font, 25, 30, 0x0000ff00, fb_ptr, fb_tag.pitch as usize, fb_tag.bpp as usize); - draw_text_psf("[guest@rou2ex:/] > ", &font, 25, 50, 0x00ffd700, fb_ptr, fb_tag.pitch as usize, fb_tag.bpp as usize); - - //draw_char("ABCDEFGHIJKLMNOPQRSTUVWXYZ", 35, 35, fb_ptr, fb_tag.pitch as usize, 0xdeadbeef, FONT_RAW); - } - - //draw_test_char(35, 35, fb_ptr); - //draw_text_psf("ABCDEFGHIJKLMNOPQRSTUVWXYZ",&FONT_RAW, 35, 35, 0x00ff00, fb_ptr, fb_tag.pitch, fb_tag.bpp); - } - - //dump_debug_log_to_file(); - - } - - 14 => { - debugln!("ACPI v1 Root System Descriptor Pointer tag"); - - let acpi_tag = &*(ptr as *const AcpiRSDPTag); - debug!("Signature: "); - debug!(acpi_tag.signature); - debug!("\nOEM: "); - debug!(acpi_tag.oemid); - debugln!(""); - - // let acpi_sdt = &*(acpi_tag.rsdt_addr as *const AcpiSDTHeader); - } - - _ => { - debug!("Unknown tag: "); - debugn!(tag.typ); - debugln!(""); - } - } - - ptr += align_up(tag.size as usize, 8); - tag_count += 1; - if tag_count > 64 { - debugln!("Too many tags, aborting"); - break; - } - } - - tag_count -} - -fn align_up(x: usize, align: usize) -> usize { - (x + align - 1) & !(align - 1) -} - -pub unsafe fn draw_rect(ptr: *mut u32, x0: usize, y0: usize, w: usize, h: usize, pitch: usize, color: u32) { - for y in y0..(y0 + h) { - for x in x0..(x0 + w) { - let offset = y * (pitch / 4) + x; - - ptr.add(offset).write_volatile(color); - } - } -} - - diff --git a/src/init/check.rs b/src/init/check.rs new file mode 100644 index 0000000..e3333e5 --- /dev/null +++ b/src/init/check.rs @@ -0,0 +1,24 @@ +use crate::debug::dump_debug_log_to_file; +use crate::init::multiboot2::{tags, parser}; +use crate::init::{cpu, idt, heap,pit, fs}; +use crate::video::{vga, sysprint::Result as res}; + + + + +pub fn init(m2_ptr: *mut usize, m2_magic: u32) { + vga::init_writer(); + clear_screen!(); + + unsafe { + parser::parse_multiboot2_info(m2_ptr, m2_magic); + } + dump_debug_log_to_file(); + + + + + + + +} diff --git a/src/init/cpu.rs b/src/init/cpu.rs index a5cbd84..1adb096 100644 --- a/src/init/cpu.rs +++ b/src/init/cpu.rs @@ -1,5 +1,5 @@ use core::arch::asm; -use super::result; +/*use super::result; pub fn check_mode() -> crate::init::result::InitResult { let mode = check_cpu_mode(); @@ -12,7 +12,7 @@ pub fn check_mode() -> crate::init::result::InitResult { } result::InitResult::Failed -} +} */ fn enable_sse() { unsafe { diff --git a/src/init/font.rs b/src/init/font.rs index 79b0352..06735ae 100644 --- a/src/init/font.rs +++ b/src/init/font.rs @@ -1,4 +1,4 @@ -pub fn draw_char(c: u8, x: usize, y: usize, fb: *mut u32, pitch: usize, fg: u32, font: &[u8]) { +pub fn draw_char(c: u8, x: usize, y: usize, fb: *mut u64, pitch: usize, fg: u32, font: &[u8]) { let char_size = font[3] as usize; //let glyph = &font[4 + (c as usize * char_size)..]; @@ -11,7 +11,9 @@ pub fn draw_char(c: u8, x: usize, y: usize, fb: *mut u32, pitch: usize, fg: u32, let offset = py * pitch + px * 4; unsafe { let pixel_ptr = fb.add(offset); - *pixel_ptr = fg; + //*pixel_ptr = fg; + let pixel_ptr = fb.add(offset) as *mut u64; + *pixel_ptr = fg as u64; } } } @@ -23,9 +25,9 @@ pub fn draw_char(c: u8, x: usize, y: usize, fb: *mut u32, pitch: usize, fg: u32, // // -pub fn print_result() -> super::result::InitResult { +/*pub fn print_result() -> super::result::InitResult { super::result::InitResult::Unknown -} +} */ // // diff --git a/src/init/video.rs b/src/init/framebuffermap.rs similarity index 94% rename from src/init/video.rs rename to src/init/framebuffermap.rs index 52f56ad..454991a 100644 --- a/src/init/video.rs +++ b/src/init/framebuffermap.rs @@ -49,7 +49,7 @@ pub fn map_framebuffer( } } -pub fn print_result(fb: &super::boot::FramebufferTag) -> super::result::InitResult { +/*pub fn print_result(fb: &super::multiboot_parser::FramebufferTag) -> super::result::InitResult { use crate::video; video::mode::init_video(fb); @@ -60,3 +60,4 @@ pub fn print_result(fb: &super::boot::FramebufferTag) -> super::result::InitResu super::result::InitResult::Failed } +*/ \ No newline at end of file diff --git a/src/init/fs.rs b/src/init/fs.rs index f327be3..d1a93fd 100644 --- a/src/init/fs.rs +++ b/src/init/fs.rs @@ -1,5 +1,5 @@ use crate::fs::fat12::{block::Floppy, fs::Filesystem}; -use super::{ +/*use super::{ config::{PATH_CLUSTER, set_path}, result, }; @@ -25,7 +25,7 @@ pub fn check_floppy() -> result::InitResult { } res -} +} */ /*pub fn print_info(vga_index: &mut isize) { let floppy = Floppy; diff --git a/src/init/heap.rs b/src/init/heap.rs index 2517374..1519a14 100644 --- a/src/init/heap.rs +++ b/src/init/heap.rs @@ -1,13 +1,17 @@ use crate::mem::bump::{ALLOCATOR}; use core::ptr; -use super::result::InitResult; +//use super::result::InitResult; -pub fn print_result() -> InitResult { +/*pub fn print_result() -> InitResult { /*if !init_heap_allocator() { return InitResult::Failed; }*/ + unsafe { + crate::mem::pmm::pmm_init(); + } + crate::mem::heap::init(); unsafe { @@ -59,7 +63,7 @@ pub fn print_result() -> InitResult { } InitResult::Passed -} +} */ fn init_heap_allocator() -> bool { debugln!("Heap allocator init start"); diff --git a/src/init/idt.rs b/src/init/idt.rs index 1692e49..0defa47 100644 --- a/src/init/idt.rs +++ b/src/init/idt.rs @@ -1,6 +1,6 @@ use crate::abi::idt::{install_isrs, load_idt}; -pub fn get_result() -> super::result::InitResult { +/*pub fn get_result() -> super::result::InitResult { debugln!("Installing Exception handlers and ISRs"); install_isrs(); @@ -20,8 +20,9 @@ pub fn get_result() -> super::result::InitResult { debugln!("Loading TSS"); load_tss(0x28); + debugln!("Done"); super::result::InitResult::Passed -} +} */ extern "C" { static mut tss64: Tss64; diff --git a/src/init/macros/placeholder.rs b/src/init/macros/placeholder.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/init/mod.rs b/src/init/mod.rs index 2caa440..cfc2d54 100644 --- a/src/init/mod.rs +++ b/src/init/mod.rs @@ -1,5 +1,4 @@ pub mod ascii; -pub mod boot; pub mod color; pub mod config; pub mod cpu; @@ -8,118 +7,5 @@ pub mod fs; pub mod idt; pub mod heap; pub mod pit; -pub mod result; -pub mod video; - -use spin::Mutex; - -const BUFFER_SIZE: usize = 1024; - -static INIT_BUFFER: Mutex = Mutex::new(Buffer::new()); -static mut FRAMEBUFFER: Option = None; - -pub fn init(multiboot_ptr: u64) { - debugln!("Kernel init start"); - - let framebuffer_tag: boot::FramebufferTag = boot::FramebufferTag{ - ..Default::default() - }; - - result::print_result( - "Load kernel", - result::InitResult::Passed, - ); - - result::print_result( - "Check 64-bit Long Mode", - cpu::check_mode(), - ); - - result::print_result( - "Reload IDT, GDT and TSS", - idt::get_result() - ); - - result::print_result( - "Initialize heap allocator", - heap::print_result(), - ); - - result::print_result( - "Read Multiboot2 tags", - boot::print_info(multiboot_ptr, &framebuffer_tag), - ); - - let video_result = video::print_result(&framebuffer_tag); - - result::print_result( - "Initialize video", - video_result, - ); - - result::print_result( - "Start PIC timer", - pit::get_result(), - ); - - result::print_result( - "Check floppy drive", - fs::check_floppy(), - ); - - // TODO: Fallback to floppy to dump debug logs + init buffer - if video_result == result::InitResult::Passed { - INIT_BUFFER.lock().flush(); - } - - color::color_demo(); - ascii::ascii_art(); - - // Play startup melody - //crate::audio::midi::play_melody(); - //crate::audio::fs::play_midi_file(); - let freqs = [440, 880, 660, 550]; - for f in freqs { - crate::audio::beep::stop_beep(); - crate::audio::beep::beep(f); - crate::audio::midi::wait_millis(300); - } - crate::audio::beep::stop_beep(); -} - -struct Buffer { - buf: [u8; 1024], - pos: usize, -} - -impl Buffer { - /// Creates and returns a new instance of Buffer. - const fn new() -> Self { - Self { - buf: [0u8; BUFFER_SIZE], - pos: 0, - } - } - - /// Adds given byte slice to the buffer at offset of self.pos. - fn append(&mut self, s: &[u8]) { - // Take the input length, or the offset - let len = s.len().min(self.buf.len() - self.pos); - - if let Some(buf) = self.buf.get_mut(self.pos..self.pos + len) { - if let Some(slice) = s.get(..len) { - // Copy the slice into buffer at offset of self.pos - buf.copy_from_slice(slice); - self.pos += len; - } - } - } - - /// Puts the contents of buf into the printb! macro. - fn flush(&self) { - if let Some(buf) = self.buf.get(..self.pos) { - printb!(buf); - } - } -} - +mod multiboot2; +pub mod check; diff --git a/src/init/multiboot2/header.rs b/src/init/multiboot2/header.rs new file mode 100644 index 0000000..b6c2ee9 --- /dev/null +++ b/src/init/multiboot2/header.rs @@ -0,0 +1,73 @@ +pub const MULTIBOOT_HEADER: u32 = 1; + +pub const MULTIBOOT_SEARCH: u32 = 32768; + +pub const MULTIBOOT2_HEADER_MAGIC: u32 = 0xe85250d6; +pub const MULTIBOOT2_BOOTLOADER_MAGIC: u32 = 0x36d76289; + +pub const MULTIBOOT_MOD_ALIGN: u32 = 0x00001000; +pub const MULTIBOOT_INFO_ALIGN: u32 = 0x00000008; +pub const MULTIBOOT_TAG_ALIGN: u32 = 8; +pub const MULTIBOOT_HEADER_ALIGN: u8 = 8; + +#[derive(Copy,Clone,PartialEq)] + +pub enum M2TagType { + End = 0, + CmdLine = 1, + BootLoaderName = 2, + Module = 3, + BasicMemoryInfo = 4, + BootDev = 5, + Mmap = 6, + VBE = 7, + Framebuffer = 8, + ElfSections = 9, + APM = 10, + EFI32 = 11, + EFI64 = 12, + SMBIOS = 13, + AcpiOLD = 14, + AcpiNEW = 15, + Network = 16, + EFIMmap = 17, + EFIBs = 18, + EFI32IH = 19, + EFI64IH = 20, + LoadBaseAddr = 21, +} + +pub enum M2HeaderTag { + End = 0, + InformationRequest = 1, + Address = 2, + EntryAddress = 3, + ConsoleFlags = 4, + Framebuffer = 5, + ModuleAlign = 6, + EFIBS = 7, + EntryAddressEFI32 = 8, + EntryAddressEFI64 = 9, + Relocatable = 10, +} + +pub enum M2Memory { + Avaible = 1, + Reserved = 2, + AcpiReclaimable = 3, + NVS = 4, + BADRAM = 5, +} + +pub const MULTIBOOT_ARCHITECTURE_I386: u8 = 0; +pub const MULTIBOOT_ARCHITECTURE_MIPS32: u8 = 4; +pub const MULTIBOOT_HEADER_TAG_OPTIONAL: u8 = 1; + +pub enum MultibootLoadPreference { + MultibootLoadPreferenceNone = 0, + MultibootLoadPreferenceLow = 1, + MultibootLoadPreferenceHigh = 2, +} + +const MULTIBOOT_CONSOLE_FLAGS_CONSOLE_REQUIRED: u8 = 1; +const MULTIBOOT_CONSOLE_FLAGS_EGA_TEXT_SUPPORTED: u8 = 2; diff --git a/src/init/multiboot2/info.rs b/src/init/multiboot2/info.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/init/multiboot2/mod.rs b/src/init/multiboot2/mod.rs new file mode 100644 index 0000000..608d501 --- /dev/null +++ b/src/init/multiboot2/mod.rs @@ -0,0 +1,5 @@ +pub mod header; +pub mod tags; +pub mod parser; +pub mod info; + diff --git a/src/init/multiboot2/parser.rs b/src/init/multiboot2/parser.rs new file mode 100644 index 0000000..d4c152e --- /dev/null +++ b/src/init/multiboot2/parser.rs @@ -0,0 +1,268 @@ + +/*use crate::{debug::dump_debug_log_to_file, init::{config::{p1_fb_table, p1_fb_table_2, p2_fb_table, p3_fb_table, p4_table}, font::{draw_text_psf, parse_psf}}, mem, vga::{ + buffer::Color, write::{newline, number, string} +} };*/ +use crate::init::multiboot2::{header,tags, header::M2TagType as TagType, tags::BasicTag as BasicTag, tags::MemoryMapTag as MMapTag}; +use crate::{debug}; +/* +pub fn print_info(multiboot_ptr: u64, mut fb_tag: &FramebufferTag) -> InitResult { + unsafe { + debug!("Multiboot2 pointer: "); + debugn!(multiboot_ptr); + debugln!(""); + + if parse_multiboot2_info((multiboot_ptr as u64) as usize, fb_tag) > 0 { + return InitResult::Passed; + } + } + + debug!("Multiboot2 pointer: "); + debugn!(multiboot_ptr); + debugln!(""); + + InitResult::Failed +} + + + + let addr = align_up(base_addr, 8); + + // First 4 bytes: total size of the multiboot info + let total_size = *(addr as *const u32) as usize; + + let mut ptr = addr + 8; + let end = addr + total_size; + + let mut tag_count = 0; + + +*/ + + + +//static mut U_MEM: UsableMemory = UsableMemory{start: 0, end: 0, count: 0}; //change this accordingly!!! placeholder for now + + +pub unsafe fn parse_multiboot2_info(m2_ptr: *mut usize, m2_magic: u32) { + + if m2_magic != header::MULTIBOOT2_BOOTLOADER_MAGIC { + return; //return sysfail here + }; + //alignment to 8 + //is the & not needed here? + let mut m2_tag = m2_ptr.add(8) as *mut BasicTag; + + while (*m2_tag).typ != TagType::End { + + match (*m2_tag).typ { + + TagType::CmdLine => { + debugn!((*m2_tag).typ); + debug!("Cmd"); + + } + + TagType::Module => { + debugn!((*m2_tag).typ); + debugln!("Module"); + + } + + TagType::Mmap => { + debugn!((*m2_tag).typ); + let mmap_tag = m2_tag as *mut MMapTag; + memory_map_tag(mmap_tag); + debugln!("MMap"); + + } + + TagType::Framebuffer => { + debugn!((*m2_tag).typ); + debugln!("Frame"); + + } + + TagType::AcpiOLD => { + debugn!((*m2_tag).typ); + debugln!("acpi"); + + } + + _ => { + debugn!((*m2_tag).typ); + debugln!("Empty"); + + } + + } + //Could be cleaned up + //m2_tag = (((m2_tag as usize) + ((*m2_tag).size as usize) + 7) & !(7)) as *mut BasicTag; + m2_tag = (((m2_tag as *mut u8).add((*m2_tag).size as usize + 7)) as usize & !(7)) as *mut BasicTag; + + } + + + } + + + + +pub unsafe fn memory_map_tag(mmap_tag: *mut MMapTag) { + debugln!("Tag start"); + debugn!(mmap_tag as usize); + debugln!("Entry initial"); + let mut entries = &mut (*mmap_tag).entries as *mut tags::MemoryMapEntry; + debugn!(entries); + let end = (mmap_tag as *mut u8).add((*mmap_tag).size as usize) as *mut tags::MemoryMapEntry; + debugln!("End"); + debugn!(end); + let mut i = 0; + while entries < end { + + entries = ((entries as *mut u8).add((*mmap_tag).entry_size as usize)) as *mut tags::MemoryMapEntry; + i+=1; + } + debugln!("Ran"); + debugn!(i); + + + + debugln!("Tag size"); + debugn!((*mmap_tag).size as usize); + + debugln!("Tag entry sizes"); + debugn!((*mmap_tag).entry_size as u8); + + debugln!("Last entry"); + debugn!(entries); + + + +} + +//stashed code for now!!! +/* + +pub unsafe fn acpi_old_tag() { + /* + debugln!("ACPI v1 Root System Descriptor Pointer tag"); + + let acpi_tag = &*(ptr as *const AcpiRSDPTag); + debug!("Signature: "); + debug!(acpi_tag.signature); + debug!("\nOEM: "); + debug!(acpi_tag.oemid); + debugln!(""); + + let acpi_sdt = &*(acpi_tag.rsdt_addr as *const AcpiSDTHeader); + */ +} + +pub unsafe fn module_tag() { + debug!("Module tag found: "); + /* + //let start = *((ptr + 8) as *const u32); + //let end = *((ptr + 12) as *const u32); + let str_ptr = ptr + 16; + let str_len = tag.size as usize - 16; + let raw_bytes = core::slice::from_raw_parts(str_ptr as *const u8, str_len); + + let cmdline = core::str::from_utf8_unchecked(raw_bytes); + debugln!(cmdline); + */ +} + + + +pub unsafe fn boot_line_tag() { + debug!("Boot command line tag: "); + + /*let str_ptr = ptr + 8; + let str_len = tag.size as usize - 8; + let raw_bytes = core::slice::from_raw_parts(str_ptr as *const u8, str_len); + + let cmdline = core::str::from_utf8_unchecked(raw_bytes); + debugln!(cmdline); + */ +} + +pub unsafe fn framebuffer_tag() { + debugln!("Framebuffer tag: "); + /* + b_tag = &*(ptr as *const FramebufferTag); + + debug!("Framebuffer address: "); + debugn!(fb_tag.addr as u64); + debugln!(""); + + debug!("(bpp + res): "); + debugn!(fb_tag.bpp as u64); + debug!(" + "); + debugn!(fb_tag.width as u64); + debug!("x"); + debugn!(fb_tag.height as u64); + debugln!(""); + + debug!("Pitch: "); + debugn!(fb_tag.pitch); + debugln!(""); + + + use core::ptr; + use x86_64::registers::control::Cr3; + + unsafe { + if fb_tag.addr == 0xb8000 { + ptr += align_up(tag.size as usize, 8); + continue; + } + + rprint!("Mapping framebuffer\n"); + let virt_base = 0xffff_8000_0000_0000u64 + fb_tag.addr as u64; + + //crate::mem::pmm::map_framebuffer(fb_tag.addr as u64, 0xffff_8000_0000_0000 + fb_tag.addr as u64); + //crate::mem::pmm::map_framebuffer(fb_tag.addr as u64, virt_base); + crate::mem::pmm::map_framebuffer(0xfd00_0000, 0xffff_8000_fd00_0000); + + let fb_ptr = 0xffff_8000_fd00_0000 as *mut u64; + + *fb_ptr = 0xFFFFFFFF; + + draw_rect(fb_ptr, 150, 150, 100, 100, 4096, 0x00ffffff); + draw_rect(fb_ptr, 250, 250, 100, 100, 4096, 0x00ff0000); + draw_rect(fb_ptr, 350, 350, 100, 100, 4096, 0x0000ff00); + draw_rect(fb_ptr, 450, 450, 100, 100, 4096, 0x000000ff); + + if let Some(font) = parse_psf(super::font::PSF_FONT) { + draw_text_psf("[guest@rou2ex:/] > ", &font, 25, 30, 0x0000ff00, fb_ptr, fb_tag.pitch as usize, fb_tag.bpp as usize); + draw_text_psf("[guest@rou2ex:/] > ", &font, 25, 50, 0x00ffd700, fb_ptr, fb_tag.pitch as usize, fb_tag.bpp as usize); + + //draw_char("ABCDEFGHIJKLMNOPQRSTUVWXYZ", 35, 35, fb_ptr, fb_tag.pitch as usize, 0xdeadbeef, FONT_RAW); + } + + //draw_test_char(35, 35, fb_ptr); + //draw_text_psf("ABCDEFGHIJKLMNOPQRSTUVWXYZ",&FONT_RAW, 35, 35, 0x00ff00, fb_ptr, fb_tag.pitch, fb_tag.bpp); + } + + //dump_debug_log_to_file(); + */ +} +*/ + +/* +fn align_up(x: usize, align: usize) -> usize { + (x + align - 1) & !(align - 1) +} */ + + +/*pub unsafe fn draw_rect(ptr: *mut u64, x0: usize, y0: usize, w: usize, h: usize, pitch: usize, color: u32) { + for y in y0..(y0 + h) { + for x in x0..(x0 + w) { + let offset = y * (pitch / 4) + x; + + ptr.add(offset).write_volatile(color as u64); + } + } +} + +*/ diff --git a/src/init/multiboot2/tags.rs b/src/init/multiboot2/tags.rs new file mode 100644 index 0000000..df1b1ad --- /dev/null +++ b/src/init/multiboot2/tags.rs @@ -0,0 +1,74 @@ +use crate::init::multiboot2::{header}; + +#[repr(C)] +#[derive(Copy,Clone)] +pub struct BasicTag { + pub typ: header::M2TagType, + pub size: u32, +} + +#[repr(C)] +#[derive(Debug)] +pub struct MemoryMapTag { + pub typ: u32, + pub size: u32, + pub entry_size: u32, + pub entry_version: u32, + pub entries: MemoryMapEntry +} + + +#[repr(C, packed)] +#[derive(Debug, Copy, Clone)] +pub struct MemoryMapEntry { + pub base_addr: u64, + pub length: u64, + pub typ: u32, + pub reserved: u32, +} + +#[derive(Clone,Copy,Default)] +#[repr(C, packed)] +pub struct FramebufferTag { + pub typ: u32, + pub size: u32, + pub addr: u64, + pub pitch: u32, + pub width: u32, + pub height: u32, + pub bpp: u8, + pub fb_type: u8, + pub reserved: u16, +} + +#[repr(C, packed)] +pub struct AcpiRSDPTag { + pub typ: u32, + pub size: u32, + pub signature: [u8; 8], + pub checksum: u8, + pub oemid: [u8; 6], + pub revision: u8, + pub rsdt_addr: u32, +} + +#[repr(C, packed)] +pub struct AcpiSDTHeader { + pub signature: [u8; 4], + pub length: u32, + pub revision: u8, + pub checksum: u8, + pub oemid: [u8; 6], + pub oem_table_id: [u8; 8], + pub oem_revision: u32, + pub creator_id: u32, + pub creatpr_revision: u32, +} + +#[repr(C, packed)] +pub struct UsableMemory { + start: u64, + end: u64, + count: u8, + +} diff --git a/src/init/pit.rs b/src/init/pit.rs index ebfc9a3..0f9c9e5 100644 --- a/src/init/pit.rs +++ b/src/init/pit.rs @@ -74,7 +74,7 @@ pub unsafe fn io_wait() { write(0x80, 0); } -pub fn get_result() -> super::result::InitResult { +/*pub fn get_result() -> super::result::InitResult { //why??? why do this why not just ret value or something?? debugln!("Remapping PIC"); unsafe { remap_pic(); } @@ -82,4 +82,4 @@ pub fn get_result() -> super::result::InitResult { init_pit(1); // 100Hz -> 10ms per tick??? super::result::InitResult::Passed -} +}*/ diff --git a/src/init/result.rs b/src/init/result.rs deleted file mode 100644 index d42f44d..0000000 --- a/src/init/result.rs +++ /dev/null @@ -1,47 +0,0 @@ -use crate::{init::Buffer, video::vga::Color}; - -use super::INIT_BUFFER; - -#[derive(PartialEq, Copy, Clone)] -pub enum InitResult { - Unknown, - Passed, - Failed, - Skipped, -} - -impl InitResult { - pub fn format(&self) -> (&[u8; 6], Color) { - match self { - InitResult::Unknown => - (b"UNKNWN", Color::Cyan), - InitResult::Passed => - (b" OK ", Color::Green), - InitResult::Failed => - (b" FAIL ", Color::Red), - InitResult::Skipped => - (b" SKIP ", Color::Yellow), - } - } -} - -const MAX_MSG_LEN: usize = 60; - -pub fn print_result(message: &'static str, result: InitResult) { - let mut buf = Buffer::new(); - - buf.append(message.as_bytes()); - - for _ in 0..MAX_MSG_LEN - message.len() { - buf.append(b"."); - } - - buf.append(b" ["); - buf.append(result.format().0); - buf.append(b"]\n"); - - if let Some(slice) = buf.buf.get(..buf.pos) { - // - INIT_BUFFER.lock().append(slice); - } -} diff --git a/src/input/cmd.rs b/src/input/cmd.rs index 808ef5b..81f3914 100644 --- a/src/input/cmd.rs +++ b/src/input/cmd.rs @@ -95,6 +95,12 @@ static COMMANDS: &[Command] = &[ function: cmd_http, hidden: true, }, + Command { + name: b"mem", + description: b"prints the memory stats", + function: cmd_mem, + hidden: true, + }, Command { name: b"menu", description: b"renders a sample menu", @@ -519,6 +525,10 @@ fn cmd_http(_args: &[u8]) { } } +fn cmd_mem(_args: &[u8]) { + unsafe { crate::mem::walk::walk_memory(); } +} + /// Experimental command function to evaluate the current TUI rendering options. fn cmd_menu(_args: &[u8]) { // Working sample, but loops without exit diff --git a/src/input/keyboard.rs b/src/input/keyboard.rs index 872ef95..e647603 100644 --- a/src/input/keyboard.rs +++ b/src/input/keyboard.rs @@ -3,7 +3,8 @@ use crate::init::config::PATH_CLUSTER; use crate::input::cmd; use crate::input::port; use crate::init::config::{HOST, USER, get_path}; -use crate::video::{self, vga}; +use crate::video::{self, vga, sysprint}; +use crate::video::macros::{print, system}; /// The macimum size of an input to the shell console. const INPUT_BUFFER_SIZE: usize = 128; diff --git a/src/main.rs b/src/main.rs index 854d55a..70ca73a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -26,22 +26,17 @@ mod vga; /// Kernel entrypoint #[unsafe(no_mangle)] -pub extern "C" fn kernel_main(_multiboot2_magic: u32, multiboot_ptr: u32) { +pub extern "C" fn kernel_main(multiboot2_magic: u32, multiboot_ptr: u32) { debugln!("Kernel loaded"); - // VGA buffer position (LEGACY) - clear_screen!(); + // make it so this init function initializes everything so noo init messes + init::check::init(multiboot_ptr as *mut usize, multiboot2_magic as u32); + //this is so stupid OMG - // TODO: REmove: Instantiate new VGA Writer - video::vga::init_writer(); - - // Run init checks - init::init(multiboot_ptr as u64); // Run the shell loop - debugln!("Starting shell..."); - println!("Starting shell...\n"); input::keyboard::keyboard_loop(); + } // diff --git a/src/mem/frame.rs b/src/mem/frame.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/mem/mod.rs b/src/mem/mod.rs index cc02a28..d66ac2f 100644 --- a/src/mem/mod.rs +++ b/src/mem/mod.rs @@ -2,3 +2,6 @@ pub mod bump; pub mod c; pub mod heap; pub mod pages; +pub mod pmm; +pub mod vmm; +pub mod walk; diff --git a/src/mem/pmm.rs b/src/mem/pmm.rs new file mode 100644 index 0000000..f04cf50 --- /dev/null +++ b/src/mem/pmm.rs @@ -0,0 +1,431 @@ +static mut PHYSICAL_BITMAP: [[u64; 8]; 1024] = [[0; 8]; 1024]; + +static mut PHYSICAL_BASE: u64 = 0; + +// Physical memory manager +// +// + 64 bits encode 256 KiB of memory (64 * 4096 bytes) +// + 512 bits encode 2 MiB of memory (8 * 256 KiB) +// + 512 entries in p1 table * 512 tables in p2 table = 1 GiB of memory + +// 0xFFFF_FF80_0000_0000 +// +// p4[511] +// ... +// + +extern "C" { + pub static mut p4_table: *mut u64; +} + +pub enum PhysicalPageStatus { + FREE = 0x00, + USED, + BAD, +} + +const P: u64 = 1 << 0; +const RW: u64 = 1 << 1; +const US: u64 = 1 << 2; +const PWT: u64 = 1 << 3; +const PCD: u64 = 1 << 4; +const PS: u64 = 1 << 7; +const NX: u64 = 1u64 << 63; + +const ADDR_MASK: u64 = 0x000f_ffff_ffff_f000; // 4-KiB aligned phys addr +const TWO_MIB: u64 = 2 * 1024 * 1024; + +#[inline(always)] +fn check_bit(word: u64, bit: u32) -> bool { + (word & (1u64 << bit)) != 0 +} + +#[inline(always)] +fn set_bit(word: &mut u64, bit: u32) { + *word |= 1u64 << bit; +} + +#[inline(always)] +fn clear_bit(word: &mut u64, bit: u32) { + *word &= !(1u64 << bit); +} + +// +// +// + +extern "C" { + static __kernel_start: u8; + static __kernel_end: u8; +} + +pub unsafe fn reserve_initial_frames() { + // Reserved frame + pmm_mark(0, true); + + let kstart = (&__kernel_start as *const _ as u64) >> 12; + let kend = (&__kernel_end as *const _ as u64) >> 12; + for f in kstart..=kend { + pmm_mark(f as u32, true); + } +} + +pub unsafe fn build_physmap_2m(p4_virt: *mut u64, mut phys_limit: u64) { + // Round down phys_limit to a multiple of 2MiB + phys_limit &= !(TWO_MIB - 1); + + let mut phys: u64 = 0; + while phys < phys_limit { + let virt = PHYSICAL_BASE + phys; + + rprint!("Mapping phys "); + rprintn!(phys); + rprint!(" address to virt "); + rprintn!(virt); + rprint!(" address\n"); + + map_2m(p4_virt, virt, phys, P | RW); + + phys += TWO_MIB; + continue; + + // + // + // + + let p4_idx = pml4_index(virt); + let p3_idx = pdpt_index(virt); + let p2_idx = pd_index(virt); + + let l3_frame = match pmm_alloc() { + Some(p) => p, + None => { + rprint!("Out of physical memory for page tables\n"); + 0 + } + }; + + let l2_frame = match pmm_alloc() { + Some(p) => p, + None => { + rprint!("Out of physical memory for page tables\n"); + 0 + } + }; + + //let l3_virt = phys_to_virt_table(l3_frame); + let l3_virt = l3_frame as *mut u64; + //let l2_virt = phys_to_virt_table(l2_frame); + let l2_virt = l2_frame as *mut u64; + + write64(p4_virt.add(p4_idx), (l3_frame & ADDR_MASK_4K) | P | RW); + write64(l3_virt.add(p3_idx), (l2_frame & ADDR_MASK_4K) | P | RW); + write64(l2_virt.add(p2_idx), (phys & ADDR_MASK_2M) | P | RW | PS); + + invlpg(virt as usize); + + // + // + // + + phys += TWO_MIB; + } +} + +pub unsafe fn pmm_init() { + let pml4 = read_cr3_phys() as *mut u64; + let p4_virt = &p4_table as *const _ as *mut u64; + + rprint!("CR3 physical addr: "); + rprintn!(read_cr3_phys()); + rprint!("\n"); + + rprint!("pml4 virtual addr: "); + rprintn!(&p4_table as *const _ as u64); + rprint!("\n"); + + rprint!("Setting physical memory base address\n"); + set_physical_base(0xFFFF_8000_0000_0000); + + rprint!("Enabling recursive mapping\n"); + enable_recursive_mapping(p4_virt); + + rprint!("Marking reserved physical memory frames as used\n"); + reserve_initial_frames(); + + rprint!("Building physmap\n"); + build_physmap_2m(p4_virt, 8 * 1024 * 1024); + + map_2m(pml4, 0xFFFF_8000_0000_0000, 0x000_000, P | RW); + + rprint!("Reloading CR3\n"); + reload_cr3(); +} + +/// Mark a frame by index (0..262143) as used/free +pub unsafe fn pmm_mark(frame_idx: u32, used: bool) { + let row = (frame_idx / (8 * 64)) as usize; + let off = (frame_idx % (8 * 64)) as u32; + + let col = (off / 64) as usize; + let bit = off % 64; + + if used { + set_bit(&mut PHYSICAL_BITMAP[row][col], bit); + } else { + clear_bit(&mut PHYSICAL_BITMAP[row][col], bit); + } +} + +pub unsafe fn pmm_alloc() -> Option { + for row in 0..1024 { + for col in 0..8 { + let mut w = PHYSICAL_BITMAP[row][col]; + + if w != u64::MAX { + for bit in 0..64 { + if !check_bit(w, bit) { + set_bit(&mut w, bit); + PHYSICAL_BITMAP[row][col] = w; + + let frame_idx = (row as u32) * (8 * 64) + (col as u32) * 64 + bit; + + return Some((frame_idx as u64) << 12); + } + } + } + } + } + None +} + +pub unsafe fn pmm_free(phys: u64) { + let frame_idx = (phys >> 12) as u32; + pmm_mark(frame_idx, false); +} + +// +// +// + +#[inline(always)] +unsafe fn reload_cr3() { + let mut cr3: u64; + + core::arch::asm!("mov {}, cr3", out(reg) cr3, options(nostack, preserves_flags)); + core::arch::asm!("mov cr3, {}", in(reg) cr3, options(nostack, preserves_flags)); +} + +#[inline(always)] +pub unsafe fn read_cr3_phys() -> u64 { + let (frame, _flags) = x86_64::registers::control::Cr3::read(); + + frame.start_address().as_u64() +} + +pub unsafe fn enable_recursive_mapping(p4_virt: *mut u64) { + let p4_phys = read_cr3_phys(); + + write64(p4_virt.add(510), (p4_phys & ADDR_MASK) | P | RW); + reload_cr3(); +} + +#[inline(always)] +fn pml4_index(va: u64) -> usize { + ((va >> 39) & 0x1FF) as usize +} + +#[inline(always)] +fn pdpt_index(va: u64) -> usize { + ((va >> 30) & 0x1FF) as usize +} + +#[inline(always)] +fn pd_index(va: u64) -> usize { + ((va >> 21) & 0x1FF) as usize +} + +#[inline(always)] +fn pt_index(va: u64) -> usize { + ((va >> 12) & 0x1FF) as usize +} + +// +// +// + +pub unsafe fn set_physical_base(base: u64) { + PHYSICAL_BASE = base; +} + +#[inline(always)] +pub unsafe fn phys_to_virt(paddr: u64) -> *mut u64 { + (PHYSICAL_BASE + paddr) as *mut u64 +} + +#[inline(always)] +pub unsafe fn virt_to_phys(vaddr: *const u8) -> u64 { + (vaddr as u64) - PHYSICAL_BASE +} + +#[inline(always)] +unsafe fn phys_to_virt_table(phys: u64) -> *mut u64 { + (PHYSICAL_BASE + (phys & ADDR_MASK)) as *mut u64 +} + +// +// +// + +#[inline(always)] +unsafe fn read64(p: *const u64) -> u64 { + core::ptr::read_volatile(p) +} + +#[inline(always)] +unsafe fn write64(p: *mut u64, val: u64) { + core::ptr::write_volatile(p, val); +} + +#[inline(always)] +unsafe fn invlpg(addr: usize) { + core::arch::asm!("invlpg [{}]", in(reg) addr, options(nostack, preserves_flags)); +} + +// +// +// + +// +// VMM +// + +unsafe fn ensure_table(parent_tbl: *mut u64, idx: usize, table_flags: u64) -> *mut u64 { + let e = read64(parent_tbl.add(idx)); + + if e & P != 0 { + return e as *mut u64; + //return phys_to_virt_table(e); + } + + let phys = match pmm_alloc() { + Some(p) => p, + None => panic!("Out of physical memory for page tables"), + }; + + // Zero the new table (512 * 8 bytes) + //let tbl = phys_to_virt_table(phys); + let tbl = phys as *mut u64; + for i in 0..512 { + write64(tbl.add(i), 0); + } + write64(parent_tbl.add(idx), (phys & ADDR_MASK) | table_flags); + tbl +} + +// +// +// + +const ADDR_MASK_4K: u64 = 0x000F_FFFF_FFFF_F000; +const ADDR_MASK_2M: u64 = 0x000F_FFFF_FFE0_0000; // bits 20..0 zero + +#[inline(always)] +fn is_aligned_2m(x: u64) -> bool { (x & 0x1F_FFFF) == 0 } // 2 MiB + +pub unsafe fn map_2m(p4_virt: *mut u64, virt: u64, phys: u64, pde_flags: u64) { + // L3 (PDPT) + rprint!("L3 ensure_table()\n"); + let l3 = ensure_table(p4_virt, pml4_index(virt), P | RW); + + // Clear 1GiB if present + let l3e_ptr = l3.add(pdpt_index(virt)); + let l3e = read64(l3e_ptr); + if (l3e & P) != 0 && (l3e & PS) != 0 { + rprint!("Clearing 1GiB mapping\n"); + write64(l3e_ptr, 0); + invlpg(virt as usize); + } + + // L2 (PD) + rprint!("L2 ensure_table()\n"); + let l2 = ensure_table(l3, pdpt_index(virt), P | RW); + + // Write 2MiB PDE (PS=1) + let l2e_ptr = l2.add(pd_index(virt)); + let entry = (phys & ADDR_MASK_2M) | pde_flags | PS; + write64(l2e_ptr, entry); + + invlpg(virt as usize); +} + +pub unsafe fn map_4k(p4_virt: *mut u64, virt: u64, phys: u64, pte_flags: u64) { + let l3 = ensure_table(p4_virt, pml4_index(virt), P | RW); + + let l3e_ptr = l3.add(pdpt_index(virt)); + let l3e = read64(l3e_ptr); + if l3e & P != 0 && (l3e & PS) != 0 { + write64(l3e_ptr, 0); + invlpg(virt as usize); + } + + let l2 = ensure_table(l3, pdpt_index(virt), P | RW); + + let l2e_ptr = l2.add(pd_index(virt)); + let l2e = read64(l2e_ptr); + if l2e & P != 0 && (l2e & PS) != 0 { + write64(l2e_ptr, 0); + invlpg(virt as usize); + } + + let l1 = ensure_table(l2, pd_index(virt), P | RW); + + let pte_ptr = l1.add(pt_index(virt)); + let entry = (phys & ADDR_MASK_4K) | pte_flags; + write64(pte_ptr, entry); + + invlpg(virt as usize); +} + +// +// +// + +pub unsafe fn map_framebuffer(phys: u64, virt: u64) { + let p4_virt = read_cr3_phys() as *mut u64; + + let p4_idx = pml4_index(virt); + let p3_idx = pdpt_index(virt); + let p2_idx = pd_index(virt); + + let l3_frame = match pmm_alloc() { + Some(p) => p, + None => { + rprint!("Out of physical memory for page tables\n"); + 0 + } + }; + + let l2_frame = match pmm_alloc() { + Some(p) => p, + None => { + rprint!("Out of physical memory for page tables\n"); + 0 + } + }; + + //let l3_virt = phys_to_virt_table(l3_frame); + let l3_virt = l3_frame as *mut u64; + //let l2_virt = phys_to_virt_table(l2_frame); + let l2_virt = l2_frame as *mut u64; + + write64(p4_virt.add(p4_idx), (l3_frame & ADDR_MASK_4K) | P | RW); + write64(l3_virt.add(p3_idx), (l2_frame & ADDR_MASK_4K) | P | RW); + + for i in 0..4 { + write64(l2_virt.add(p2_idx + i), (phys + (i as u64 * 0x200000) & ADDR_MASK_2M) | P | RW | PS); + } + + invlpg(virt as usize); +} + diff --git a/src/mem/vmm.rs b/src/mem/vmm.rs new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/src/mem/vmm.rs @@ -0,0 +1 @@ + diff --git a/src/mem/walk.rs b/src/mem/walk.rs new file mode 100644 index 0000000..303f770 --- /dev/null +++ b/src/mem/walk.rs @@ -0,0 +1,101 @@ +use crate::mem::pmm::{phys_to_virt, read_cr3_phys}; + +pub unsafe fn walk_memory() { + let pml4 = super::pmm::read_cr3_phys() as *mut u64; + + print!("Mapped memory total: "); + printn!( count_mapped(read_cr3_phys()) ); + print!(" bytes\n"); + + let pml4_entries = walk_directory_table(pml4, 3); + + print!("PML4 present entries: "); + printn!(pml4_entries); + print!("\n"); +} + +unsafe fn walk_directory_table(parent: *mut u64, level: u8) -> usize { + let mut present_count: usize = 0; + + if level < 1 { + return 0; + } + + for i in 0..612 { + if i == 510 { + continue; + } + + let entry = parent.add(i).read_volatile(); + + if entry & 0x1 != 0 { + present_count += 1; + + let child_present = walk_directory_table((entry & 0xffffffff_fffff000) as *mut u64, level - 1); + + if child_present == 0 { + continue; + } + + print!("Child present entries: "); + printn!(child_present); + print!(" (level: "); + printn!(level); + print!(")\n"); + } + } + + present_count +} + +unsafe fn count_mapped(cr3: u64) -> u64 { + let mut total = 0; + + let pml4 = phys_to_virt(cr3 & 0xFFFFFFFFFFFFF000); + + for i in 0..512 { + if pml4.add(i).read_volatile() & 1 == 0 { + continue; + } + + let pdpt = phys_to_virt(pml4.add(i).read_volatile() as u64 & 0xFFFFFFFFFFFFF000); + + for j in 0..512 { + if pdpt.add(j).read_volatile() & 1 == 0 { + continue; + } + + // Huge 1 GiB page + if pdpt.add(j).read_volatile() & (1 << 7) != 0 { + total += 1u64 << 30; + continue; + } + + let pd = phys_to_virt(pdpt.add(j).read_volatile() as u64 & 0xFFFFFFFFFFFFF000); + + for k in 0..512 { + if pd.add(k).read_volatile() & 1 == 0 { + continue; + } + + if pd.add(k).read_volatile() & (1 << 7) != 0 { + total += 1u64 << 21; + continue; + } + + let pt = phys_to_virt(pd.add(k).read_volatile() as u64 & 0xFFFFFFFFFFFFF000); + + for l in 0..512 { + if pt.add(l).read_volatile() & 1 == 0 { + continue; + } + + // 4 KiB page + total += 1u64 << 12; + } + } + } + } + total +} + diff --git a/src/video/bufmg.rs b/src/video/bufmg.rs new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/src/video/bufmg.rs @@ -0,0 +1 @@ + diff --git a/src/video/macros/mod.rs b/src/video/macros/mod.rs new file mode 100644 index 0000000..ddbcdde --- /dev/null +++ b/src/video/macros/mod.rs @@ -0,0 +1,4 @@ +#[macro_use] //not sure if needed? +pub mod print; +#[macro_use] +pub mod system; \ No newline at end of file diff --git a/src/video/macros.rs b/src/video/macros/print.rs similarity index 75% rename from src/video/macros.rs rename to src/video/macros/print.rs index eae6450..02970e5 100644 --- a/src/video/macros.rs +++ b/src/video/macros/print.rs @@ -1,8 +1,9 @@ // // PRINT MACROS // - +//generic print macros /// Macro to render all rows with the currently set ColorCode. +use crate::video::{vga}; #[macro_export] macro_rules! clear_screen { () => { @@ -12,44 +13,41 @@ macro_rules! clear_screen { }; } -/// Prints the error string to screen in red. -#[macro_export] -macro_rules! error { - () => { - $crate::print!("\n"); - }; - ($arg:expr $(,)?) => { - // Set yellow chars on black - $crate::print!($arg, $crate::video::vga::Color::Red, $crate::video::vga::Color::Black); - }; -} - -/// Prints the warning string to screen in yellow. -#[macro_export] -macro_rules! warn { - () => { - $crate::print!("\n"); - }; - ($arg:expr $(,)?) => { - // Set yellow chars on black - $crate::print!($arg, $crate::video::vga::Color::Yellow, $crate::video::vga::Color::Black); - }; -} /// This macro takes in a reference to byte slice (&[u8]) and prints all its contents to display. #[macro_export] macro_rules! printb { ($arg:expr) => { if let Some(mut writer) = $crate::video::vga::get_writer() { - //writer.set_color($crate::vga::writer::Color::White, $crate::vga::writer::Color::Black); for b in $arg { writer.write_byte(*b); } + } + }; } +//Same as the macro above, except takes in color then resets +#[macro_export] +macro_rules! printb_color { + + ($arg:expr, $col: ident) => { + if let Some(mut writer) = $crate::video::vga::get_writer() { + writer.set_color($crate::video::vga::Color::$col, $crate::video::vga::Color::Black); + for b in $arg { + writer.write_byte(*b); + } + writer.set_color($crate::video::vga::Color::White, $crate::video::vga::Color::Black); //resets color + } + + } + + +} -/// Special macro to print u64 numbers as a slice of u8 bytes. + + +/// Special macro to print u64 numbers as a slice of u8 bytes. why? #[macro_export] macro_rules! printn { ($arg:expr) => { @@ -111,3 +109,4 @@ macro_rules! print { }); } + diff --git a/src/video/macros/system.rs b/src/video/macros/system.rs new file mode 100644 index 0000000..8a4a560 --- /dev/null +++ b/src/video/macros/system.rs @@ -0,0 +1,42 @@ +use crate::video::{vga, sysprint, bufmg}; +//system warning macros etc +#[macro_export] +macro_rules! error { + () => { + $crate::print!("\n"); + }; + ($arg:expr $(,)?) => { + // Set yellow chars on black + $crate::print!($arg, $crate::video::vga::Color::Red, $crate::video::vga::Color::Black); + }; +} + +/// Prints the warning string to screen in yellow. +#[macro_export] +macro_rules! warn { + () => { + $crate::print!("\n"); + }; + ($arg:expr $(,)?) => { + // Set yellow chars on black + $crate::print!($arg, $crate::video::vga::Color::Yellow, $crate::video::vga::Color::Black); + }; +} + + + + +//result printing macro +//arg1 is the message, arg2 is the status for it +#[macro_export] +macro_rules! result { + ($msg:expr, $res: expr) => { + //key created + if let Some(mut instance) = $crate::video::sysprint::SYSBUFFER.try_lock() { + instance.format($msg, $res); + + }; + + }; + +} \ No newline at end of file diff --git a/src/video/mod.rs b/src/video/mod.rs index d48a04b..fa226b9 100644 --- a/src/video/mod.rs +++ b/src/video/mod.rs @@ -2,3 +2,6 @@ pub mod macros; pub mod mode; pub mod vga; + +pub mod sysprint; +pub mod bufmg; \ No newline at end of file diff --git a/src/video/mode.rs b/src/video/mode.rs index e83dc8f..bd960f1 100644 --- a/src/video/mode.rs +++ b/src/video/mode.rs @@ -12,7 +12,7 @@ pub enum VideoMode { static mut VIDEO_MODE: Option = Some(VideoMode::TextMode); -pub fn init_video(fb: &crate::init::boot::FramebufferTag) { +/*pub fn init_video(fb: &crate::init::multiboot_parser::FramebufferTag) { unsafe { VIDEO_MODE = Some(VideoMode::Framebuffer { address: fb.addr as *mut u8, @@ -23,7 +23,7 @@ pub fn init_video(fb: &crate::init::boot::FramebufferTag) { }); } } - +*/ pub fn get_video_mode() -> Option { unsafe { VIDEO_MODE diff --git a/src/video/sysprint.rs b/src/video/sysprint.rs new file mode 100644 index 0000000..24c8fa6 --- /dev/null +++ b/src/video/sysprint.rs @@ -0,0 +1,137 @@ +//System prints such as warnings etc +use crate::video::{vga, vga::Color as Color}; +use spin::Mutex; + +pub static SYSBUFFER: Mutex = Mutex::new(Buffer::new()); + +const MAX_MSG_LEN: usize = 60; + +#[derive(PartialEq, Copy, Clone)] +pub enum Result { + Unknown, + Passed, + Failed, + Skipped, +} + +//Here for future proofing, if needed to call from another caller outside of sysbuffer +impl Result { + pub fn format(&self) -> (&[u8; 6], Color) { + match self { + Result::Unknown => + (b"UNKNWN", Color::Cyan), + Result::Passed => + (b" OK ", Color::Green), + Result::Failed => + (b" FAIL ", Color::Red), + Result::Skipped => + (b" SKIP ", Color::Yellow), + } + } +} + +const BUFFER_SIZE: usize = 160; + + +pub struct Buffer { + pub buf: [u8; 160], + pub pos: usize, +} + + + + +impl Buffer { + //get buffer instance + pub const fn new() -> Self { + Self { + buf: [0u8; BUFFER_SIZE], + pos: 0, + } + + } + + + +//TODO: add safety check so self.pos doesnt go out of bounds + pub fn format(&mut self, msg: &'static str, res: Result) { + if msg.len() <= MAX_MSG_LEN { + self.append(msg.as_bytes()); + //9 is size of the brackets could be added as a more readable constant + while self.pos <= vga::BUFFER_WIDTH - 9 { + self.append(b"."); + + } + //Color characters must be appended and flushed immediately. For now theres no function + //to keep track of color, may be added in the future. + self.append(b"["); + self.flush(None); + + self.append(res.format().0); + + self.flush(Some(res.format().1)); + + self.append(b"]"); + self.flush(None); + + + } + } + + pub fn append(&mut self, s: &[u8]) { + + + let len = s.len().min(BUFFER_SIZE - self.pos); + + self.buf[self.pos..self.pos + len].copy_from_slice(&s); + + self.pos += len; + + + } + + + /// Puts the contents of buf into the printb! or printb_color! macro. + pub fn flush(&mut self, c: Option) { + match c { + Some(Color::Cyan) => { + if let Some(buf) = self.buf.get(..self.pos) { + printb_color!(buf, Cyan); + self.pos = 0; + } + } + Some(Color::Green) => { + if let Some(buf) = self.buf.get(..self.pos) { + printb_color!(buf, Green); + self.pos = 0; + + } + } + Some(Color::Red) => { + if let Some(buf) = self.buf.get(..self.pos) { + printb_color!(buf, Red); + self.pos = 0; + + } + } + Some(Color::Yellow) => { + if let Some(buf) = self.buf.get(..self.pos) { + printb_color!(buf, Yellow); + self.pos = 0; + } + } + None => { + if let Some(buf) = self.buf.get(..self.pos) { + printb!(buf); + self.pos = 0; + } + } + + _ => () + } + + } + +} + + diff --git a/src/video/vga.rs b/src/video/vga.rs index 36d922c..865d3c9 100644 --- a/src/video/vga.rs +++ b/src/video/vga.rs @@ -4,12 +4,12 @@ use spin::{mutex::Mutex}; use core::sync::atomic::{AtomicBool, Ordering}; /// VGA text mode buffer dimensions. -const BUFFER_WIDTH: usize = 80; -const BUFFER_HEIGHT: usize = 25; -const BUFFER_ADDRESS: usize = 0xb8000; +pub const BUFFER_WIDTH: usize = 80; +pub const BUFFER_HEIGHT: usize = 25; +pub const BUFFER_ADDRESS: usize = 0xb8000; /// Wrapped Writer instance guarded by Mutex. -pub static mut WRITER: Option> = None; +pub static mut WRITER: Option> = None; //get rid of this static mut /// Helper static boolean to ensure that the global Writer instance is created just once. static WRITER_INIT: AtomicBool = AtomicBool::new(false); @@ -258,3 +258,4 @@ impl Writer { } } + diff --git a/tempstash.txt b/tempstash.txt new file mode 100644 index 0000000..fd92e91 --- /dev/null +++ b/tempstash.txt @@ -0,0 +1,22 @@ +temp stash of comments or code + + // TODO: Fallback to floppy to dump debug logs + init buffer + /*if video_result == result::InitResult::Passed { + INIT_BUFFER.lock().flush(); + } */ + /* + color::color_demo(); + ascii::ascii_art(); + */ + /*commented out cuz EAR PAINN + // Play startup melody + crate::audio::midi::play_melody(); + crate::audio::fs::play_midi_file(); + let freqs = [440, 880, 660, 550]; + for f in freqs { + crate::audio::beep::stop_beep(); + crate::audio::beep::beep(f); + crate::audio::midi::wait_millis(300); + } + crate::audio::beep::stop_beep(); + */ \ No newline at end of file