From f13cb2eb121fc5cbb60e5eb8bdd7f0ee3623dfac Mon Sep 17 00:00:00 2001 From: husky Date: Thu, 11 Sep 2025 16:00:04 -0700 Subject: [PATCH] fix a ton of memory related bugs --- qemurun.sh | 2 +- src/arch/virt/asm/linker.ld | 17 +++--- src/dev/framebuffer/console.rs | 2 +- src/dev/framebuffer/mod.rs | 76 ++++++++++++-------------- src/dev/mod.rs | 23 ++++---- src/dev/virtio/block.rs | 33 +++++++++--- src/dev/virtio/gpu.rs | 86 ++++++++++------------------- src/dev/virtio/mod.rs | 30 +++++++---- src/fs/fat32.rs | 6 +-- src/memory.rs | 71 ++++++++++++------------ src/trafficcontrol.rs | 99 ++++++++++++++++------------------ 11 files changed, 215 insertions(+), 230 deletions(-) diff --git a/qemurun.sh b/qemurun.sh index e1edece..c34e967 100755 --- a/qemurun.sh +++ b/qemurun.sh @@ -2,4 +2,4 @@ storage_device="${1}" -qemu-system-riscv32 -machine virt -bios none -drive if=none,format=raw,file="${storage_device}",id=disk1 -device virtio-blk-device,drive=disk1 -display sdl -device virtio-gpu-device -serial stdio -m 5M -device loader,cpu-num=0,file=target/riscv32imac-unknown-none-elf/release/lbos -monitor telnet:127.0.0.1:1235,server,nowait -d guest_errors,unimp \ No newline at end of file +qemu-system-riscv32 -machine virt -bios none -drive if=none,format=raw,file="${storage_device}",id=disk1 -device virtio-blk-device,drive=disk1 -display sdl -device virtio-gpu-device -serial stdio -m 10M -device loader,cpu-num=0,file=target/riscv32imac-unknown-none-elf/release/lbos -monitor telnet:127.0.0.1:1235,server,nowait -d guest_errors,unimp \ No newline at end of file diff --git a/src/arch/virt/asm/linker.ld b/src/arch/virt/asm/linker.ld index 8face3b..5ac0cc5 100644 --- a/src/arch/virt/asm/linker.ld +++ b/src/arch/virt/asm/linker.ld @@ -4,10 +4,11 @@ ENTRY( _start ) MEMORY { - rom (wxa) : ORIGIN = 0x80000000, LENGTH = 64 * 1024 - ram (wxa) : ORIGIN = ORIGIN(rom) + LENGTH(rom), LENGTH = 64 * 1024 - virtqueues (wxa) : ORIGIN = ORIGIN(ram) + LENGTH(ram), LENGTH = 16 * 1024 * 2 - framebuffer (wxa) : ORIGIN = ORIGIN(virtqueues) + LENGTH(virtqueues), LENGTH = 320 * 240 * 3 + rom (wxa) : ORIGIN = 0x80000000, LENGTH = 0x10000 + + ram (wxa) : ORIGIN = 0x80010000, LENGTH = 0x10000 + + virtqueues (wxa) : ORIGIN = 0x80020000, LENGTH = 0x20000 } PHDRS @@ -38,7 +39,7 @@ SECTIONS { PROVIDE(_bss_start = .); *(.sbss .sbss.*) *(.bss .bss.*) - . = ALIGN(4096); + . = ALIGN(512); PROVIDE(_bss_end = .); } >ram AT>ram :bss @@ -55,9 +56,9 @@ SECTIONS { PROVIDE(_tstack_end = _tstack_start + 16384); PROVIDE(_heap_start = _tstack_end); PROVIDE(_heap_size = _MEM_END - _heap_start); + PROVIDE(_virtio_queue_1_start = ORIGIN(virtqueues)); - PROVIDE(_virtio_queue_1_end = _virtio_queue_1_start + 16384); + PROVIDE(_virtio_queue_1_end = _virtio_queue_1_start + 0x10000); PROVIDE(_virtio_queue_2_start = _virtio_queue_1_end); - PROVIDE(_virtio_queue_2_end = _virtio_queue_2_start + 16384); - PROVIDE(_framebuffer_start = ORIGIN(framebuffer)); + PROVIDE(_virtio_queue_2_end = _virtio_queue_2_start + 0x10000); } \ No newline at end of file diff --git a/src/dev/framebuffer/console.rs b/src/dev/framebuffer/console.rs index 6214267..bd98b90 100644 --- a/src/dev/framebuffer/console.rs +++ b/src/dev/framebuffer/console.rs @@ -1,4 +1,3 @@ -use crate::dev::{framebuffer_update, FRAMEBUFFER_HEIGHT, FRAMEBUFFER_WIDTH}; use crate::dev::framebuffer::{fb_clearscreen, fb_write_char_array}; use crate::spinlock::Spinlock; use crate::trafficcontrol::TrafficControl; @@ -38,6 +37,7 @@ impl FramebufferConsole { // DOES send a framebuffer update! pub fn printstr(&mut self, tc: &mut TrafficControl, str: &str) { + return; for c in str.chars() { let mut was_special_char = false; if c == '\n' || c == '\r' { diff --git a/src/dev/framebuffer/mod.rs b/src/dev/framebuffer/mod.rs index f548170..2e99749 100644 --- a/src/dev/framebuffer/mod.rs +++ b/src/dev/framebuffer/mod.rs @@ -1,6 +1,4 @@ -use crate::dev::{ - FRAMEBUFFER_ADDR, FRAMEBUFFER_BPP, FRAMEBUFFER_HEIGHT, FRAMEBUFFER_WIDTH, framebuffer_update, -}; +use crate::dev::{linebuffer_push, FRAMEBUFFER_HEIGHT, FRAMEBUFFER_WIDTH, LINEBUFFER_ADDR, LINEBUFFER_BPP}; use crate::trafficcontrol::TrafficControl; use core::sync::atomic::Ordering; @@ -37,69 +35,61 @@ impl FBColor { pub fn fb_write_char_array(tc: &mut TrafficControl, mut x: usize, mut y: usize, chars: &[char]) { const BYTES: [u8; 3] = FB_FG_COLOR.to_bytes(); - let ogx = x; - let fbaddr = FRAMEBUFFER_ADDR.load(Ordering::Relaxed); + let fbaddr = LINEBUFFER_ADDR.load(Ordering::Relaxed); if fbaddr == 0 { return; } - let fbstride = FRAMEBUFFER_BPP.load(Ordering::Relaxed) * FRAMEBUFFER_WIDTH; const CHAR_SIZE: usize = 16; let mut drew_anything = false; - for c in chars { - let c = *c; - //if c == '\n' { - // y += CHAR_SIZE; - // x = ogx; - // if y * CHAR_SIZE > FRAMEBUFFER_HEIGHT { - // break; - // } - //} else if c == ' ' { - if c == ' ' { - x += CHAR_SIZE; - //if x * CHAR_SIZE > FRAMEBUFFER_WIDTH { - // x = ogx; - // y += CHAR_SIZE; - // if y * CHAR_SIZE > FRAMEBUFFER_HEIGHT { - // break; - // } - //} - } else if c as u8 > 32 { - let c = c as u8 - 32; - let cx = (c % 16) as usize * CHAR_SIZE; - let cy = (c / 16) as usize * CHAR_SIZE; - for row in 0..CHAR_SIZE { - for col in 0..CHAR_SIZE { - let coff = (VAPFONT_W * (cy + row)) + (cx + col); - let draw = VAPFONT[coff / 8] & (0x80 >> (coff % 8)); - if draw != 0 { - unsafe { - let fb = (fbaddr as *mut u8).add(((y+row)*fbstride) + ((x+col)*4)) as *mut u32; - fb.write_volatile(u32::from_ne_bytes([0, BYTES[0], BYTES[1], BYTES[2]])); - drew_anything = true; + for line in 0..FRAMEBUFFER_HEIGHT { + for c in chars { + let c = *c; + if c == ' ' { + x += CHAR_SIZE; + } else if c as u8 > 32 { + let c = c as u8 - 32; + let cx = (c % 16) as usize * CHAR_SIZE; + let cy = (c / 16) as usize * CHAR_SIZE; + for row in 0..CHAR_SIZE { + if (y+row) != line { + continue; + } + for col in 0..CHAR_SIZE { + let coff = (VAPFONT_W * (cy + row)) + (cx + col); + let draw = VAPFONT[coff / 8] & (0x80 >> (coff % 8)); + if draw != 0 { + unsafe { + //let fb = (fbaddr as *mut u8).add(((y + row) * fbstride) + ((x + col) * 4)) as *mut u32; + let fb = (fbaddr as *mut u8).add((x + col) * 4) as *mut u32; + fb.write_volatile(u32::from_ne_bytes([0, BYTES[0], BYTES[1], BYTES[2]])); + drew_anything = true; + } } } } + x += CHAR_SIZE; } - x += CHAR_SIZE; + } + if drew_anything { + linebuffer_push(tc, line as u32); } } - framebuffer_update(tc, 0, 0, FRAMEBUFFER_WIDTH as u32, FRAMEBUFFER_HEIGHT as u32); } pub fn fb_clearscreen(tc: &mut TrafficControl) { const BYTES: [u8; 3] = FB_BG_COLOR.to_bytes(); - let fbaddr = FRAMEBUFFER_ADDR.load(Ordering::Relaxed); + let fbaddr = LINEBUFFER_ADDR.load(Ordering::Relaxed); if fbaddr == 0 { return; } - let fbstride = FRAMEBUFFER_BPP.load(Ordering::Relaxed) * FRAMEBUFFER_WIDTH; for y in 0..FRAMEBUFFER_HEIGHT { for x in 0..FRAMEBUFFER_WIDTH { unsafe { - let fb = (fbaddr as *mut u8).add(((y)*fbstride) + ((x)*4)) as *mut u32; + //let fb = (fbaddr as *mut u8).add(((y)*fbstride) + ((x)*4)) as *mut u32; + let fb = (fbaddr as *mut u8).add(x*4) as *mut u32; fb.write_volatile(u32::from_ne_bytes([0, BYTES[0], BYTES[1], BYTES[2]])); } } + linebuffer_push(tc, y as u32); } - framebuffer_update(tc, 0, 0, FRAMEBUFFER_WIDTH as u32, FRAMEBUFFER_HEIGHT as u32); } diff --git a/src/dev/mod.rs b/src/dev/mod.rs index 2d0c5b7..2e1bd7a 100644 --- a/src/dev/mod.rs +++ b/src/dev/mod.rs @@ -4,11 +4,14 @@ use crate::trafficcontrol::TrafficControl; pub const FRAMEBUFFER_WIDTH: usize = 320; pub const FRAMEBUFFER_HEIGHT: usize = 240; +pub const LINEBUFFER_BLOCKS: usize = 3; +pub const LINEBUFFER_HEIGHT: usize = 1; + // NOTE: -// FRAMEBUFFER_ADDR should always be 0 if no framebuffer exists -// if FRAMEBUFFER_ADDR is NOT 0, then FRAMEBUFFER_STRIDE should also be NOT 0 -pub static FRAMEBUFFER_ADDR: AtomicUsize = AtomicUsize::new(0); -pub static FRAMEBUFFER_BPP: AtomicUsize = AtomicUsize::new(0); +// LINEBUFFER_ADDR should always be 0 if no framebuffer exists +// if LINEBUFFER_ADDR is NOT 0, then LINEBUFFER_BPP should also be NOT 0 +pub static LINEBUFFER_ADDR: AtomicUsize = AtomicUsize::new(0); +pub static LINEBUFFER_BPP: AtomicUsize = AtomicUsize::new(0); #[cfg(feature = "dev_virtio")] pub mod virtio; @@ -26,16 +29,16 @@ pub fn read_sector(tc: &mut TrafficControl, buffer: usize, size: u32, sector: u6 false } -pub fn framebuffer_address() -> usize { - FRAMEBUFFER_ADDR.load(Ordering::Relaxed) +pub fn linebuffer_address() -> usize { + LINEBUFFER_ADDR.load(Ordering::Relaxed) } -pub fn framebuffer_stride() -> usize { - FRAMEBUFFER_BPP.load(Ordering::Relaxed) +pub fn linebuffer_bpp() -> usize { + LINEBUFFER_BPP.load(Ordering::Relaxed) } -pub fn framebuffer_update(tc: &mut TrafficControl, x: u32, y: u32, width: u32, height: u32) { +pub fn linebuffer_push(tc: &mut TrafficControl, line: u32) { #[cfg(feature = "dev_virtio")] - virtio::framebuffer_update(tc, x, y, width, height); + virtio::framebuffer_update(tc, line); } \ No newline at end of file diff --git a/src/dev/virtio/block.rs b/src/dev/virtio/block.rs index b667e3c..cdf195a 100644 --- a/src/dev/virtio/block.rs +++ b/src/dev/virtio/block.rs @@ -1,4 +1,12 @@ -use crate::dev::virtio::{Descriptor, VIRTIO_DESC_F_NEXT, VIRTIO_DESC_F_WRITE, VIRTIO_MMIO_GUEST_FEATURES, VIRTIO_MMIO_GUEST_PAGE_SIZE, VIRTIO_MMIO_HOST_FEATURES, VIRTIO_MMIO_QUEUE_NOTIFY, VIRTIO_MMIO_QUEUE_NUM, VIRTIO_MMIO_QUEUE_NUM_MAX, VIRTIO_MMIO_QUEUE_PFN, VIRTIO_MMIO_QUEUE_SEL, VIRTIO_MMIO_STATUS, VIRTIO_MMIO_STATUS_ACKNOWLEDGE, VIRTIO_MMIO_STATUS_DRIVER, VIRTIO_MMIO_STATUS_DRIVER_OK, VIRTIO_MMIO_STATUS_FAILED, VIRTIO_MMIO_STATUS_FEATURES_OK, VIRTIO_QUEUE_SIZE, VirtQueue, Used}; +use crate::dev::virtio::{ + Descriptor, Used, VIRTIO_DESC_F_NEXT, VIRTIO_DESC_F_WRITE, VIRTIO_MMIO_GUEST_FEATURES, + VIRTIO_MMIO_GUEST_PAGE_SIZE, VIRTIO_MMIO_HOST_FEATURES, VIRTIO_MMIO_QUEUE_NOTIFY, + VIRTIO_MMIO_QUEUE_NUM, VIRTIO_MMIO_QUEUE_NUM_MAX, VIRTIO_MMIO_QUEUE_PFN, VIRTIO_MMIO_QUEUE_SEL, + VIRTIO_MMIO_STATUS, VIRTIO_MMIO_STATUS_ACKNOWLEDGE, VIRTIO_MMIO_STATUS_DRIVER, + VIRTIO_MMIO_STATUS_DRIVER_OK, VIRTIO_MMIO_STATUS_FAILED, VIRTIO_MMIO_STATUS_FEATURES_OK, + VIRTIO_QUEUE_SIZE, VirtQueue, +}; +use crate::strprint::u32_hex; use crate::trafficcontrol::{TaskWait, TrafficControl}; unsafe extern "C" { @@ -58,7 +66,7 @@ impl VirtIoBlockDevice { // read host features let host_features = unsafe { ((addr + VIRTIO_MMIO_HOST_FEATURES) as *const u32).read_volatile() }; - let guest_features = host_features & !(1 << 5); + let guest_features = 0; let read_only = host_features & (1 << 5) != 0; unsafe { @@ -159,10 +167,9 @@ impl VirtIoBlockDevice { return; } - let blk_request = { - let block = unsafe { tc.memory_manager.as_mut().unwrap_unchecked() }.alloc_one_block(); - unsafe { tc.memory_manager.as_mut().unwrap_unchecked().block_to_addr(block) } - } as *mut Request; + let blk_request = + { unsafe { tc.memory_manager.as_mut().unwrap_unchecked() }.alloc_one_block() } + as *mut Request; let desc = Descriptor { addr: unsafe { &(*blk_request) as *const _ as u64 }, len: size_of::() as u32, @@ -223,8 +230,18 @@ impl VirtIoBlockDevice { let tid = unsafe { (*rq).tid }; - let rq_block = unsafe { tc.memory_manager.as_mut().unwrap_unchecked() }.addr_to_block(rq as usize); - unsafe { tc.memory_manager.as_mut().unwrap_unchecked().free_one_block(rq_block); } + unsafe { + tc.memory_manager + .as_mut() + .unwrap_unchecked() + .free_n_blocks(rq as usize, 1); + } + let actually_freed = unsafe { + tc.memory_manager + .as_mut() + .unwrap_unchecked() + .is_addr_free(rq as usize) + }; // awaken if let Some(Some(task)) = tc.tasks.get_mut(tid as usize) { diff --git a/src/dev/virtio/gpu.rs b/src/dev/virtio/gpu.rs index cef1382..ec68811 100644 --- a/src/dev/virtio/gpu.rs +++ b/src/dev/virtio/gpu.rs @@ -1,12 +1,11 @@ use crate::arch::serial_port; -use crate::dev::{FRAMEBUFFER_HEIGHT, FRAMEBUFFER_WIDTH}; +use crate::dev::{FRAMEBUFFER_HEIGHT, FRAMEBUFFER_WIDTH, LINEBUFFER_BLOCKS}; use crate::dev::virtio::{heap_allocate_type, Descriptor, VirtQueue, VIRTIO_DESC_F_NEXT, VIRTIO_DESC_F_WRITE, VIRTIO_MMIO_GUEST_FEATURES, VIRTIO_MMIO_GUEST_PAGE_SIZE, VIRTIO_MMIO_HOST_FEATURES, VIRTIO_MMIO_QUEUE_NOTIFY, VIRTIO_MMIO_QUEUE_NUM, VIRTIO_MMIO_QUEUE_NUM_MAX, VIRTIO_MMIO_QUEUE_PFN, VIRTIO_MMIO_QUEUE_SEL, VIRTIO_MMIO_STATUS, VIRTIO_MMIO_STATUS_ACKNOWLEDGE, VIRTIO_MMIO_STATUS_DRIVER, VIRTIO_MMIO_STATUS_DRIVER_OK, VIRTIO_MMIO_STATUS_FAILED, VIRTIO_MMIO_STATUS_FEATURES_OK, VIRTIO_QUEUE_SIZE}; use crate::strprint::u32_hex; use crate::trafficcontrol::TrafficControl; unsafe extern "C" { fn _virtio_queue_2_start(); - fn _framebuffer_start(); } pub const VIRTIO_GPU_CMD_GET_DISPLAY_INFO: u32 = 0x0100; @@ -181,7 +180,9 @@ impl VirtIoGpuDevice { } - // allocate memory for framebuffer + // allocate memory for linebuffer + let linebuffer_ptr = unsafe { tc.memory_manager.as_mut().unwrap_unchecked().alloc_n_blocks(LINEBUFFER_BLOCKS) }; + let latest_response = heap_allocate_type::(tc) as *const _ as usize; let mut gpu = Self { @@ -190,7 +191,7 @@ impl VirtIoGpuDevice { queue: queue_ptr, idx: 0, ack_used_idx: 0, - framebuffer: _framebuffer_start as usize, + framebuffer: linebuffer_ptr as usize, width: FRAMEBUFFER_WIDTH, height: FRAMEBUFFER_HEIGHT, }; @@ -251,7 +252,7 @@ impl VirtIoGpuDevice { free_me[1] = unsafe { &(*cmd) as *const _ as usize }; let mem_entry = heap_allocate_type::(tc); mem_entry.addr = gpu.framebuffer as u64; - mem_entry.length = (gpu.height * gpu.width * 4) as u32; + mem_entry.length = (gpu.width * 4) as u32; mem_entry.padding = 0; free_me[2] = unsafe { &(*mem_entry) as *const _ as usize }; @@ -321,14 +322,11 @@ impl VirtIoGpuDevice { //gpu.pending(tc); for free in free_me { - let block = unsafe { tc.memory_manager.as_mut().unwrap_unchecked().addr_to_block(free) }; unsafe { - tc.memory_manager.as_mut().unwrap_unchecked().free_n_blocks(block, 1); + tc.memory_manager.as_mut().unwrap_unchecked().free_n_blocks(free, 1); } } - gpu.transfer(tc, 0, 0, gpu.width as u32, gpu.height as u32); - Ok(gpu) } @@ -353,8 +351,12 @@ impl VirtIoGpuDevice { } unsafe { - (*(self.queue as *mut VirtQueue)).avail.ring[(*(self.queue as *mut VirtQueue)).avail.idx as usize % VIRTIO_QUEUE_SIZE] = head; - (*(self.queue as *mut VirtQueue)).avail.idx = (*(self.queue as *mut VirtQueue)).avail.idx.wrapping_add(1); + (*(self.queue as *mut VirtQueue)).avail.ring + [(*(self.queue as *mut VirtQueue)).avail.idx as usize % VIRTIO_QUEUE_SIZE] = head; + } + unsafe { + (*(self.queue as *mut VirtQueue)).avail.idx = + (*(self.queue as *mut VirtQueue)).avail.idx.wrapping_add(1); } // notify @@ -384,8 +386,12 @@ impl VirtIoGpuDevice { } unsafe { - (*(self.queue as *mut VirtQueue)).avail.ring[(*(self.queue as *mut VirtQueue)).avail.idx as usize % VIRTIO_QUEUE_SIZE] = head; - (*(self.queue as *mut VirtQueue)).avail.idx = (*(self.queue as *mut VirtQueue)).avail.idx.wrapping_add(1); + (*(self.queue as *mut VirtQueue)).avail.ring + [(*(self.queue as *mut VirtQueue)).avail.idx as usize % VIRTIO_QUEUE_SIZE] = head; + } + unsafe { + (*(self.queue as *mut VirtQueue)).avail.idx = + (*(self.queue as *mut VirtQueue)).avail.idx.wrapping_add(1); } // notify @@ -397,42 +403,12 @@ impl VirtIoGpuDevice { // WARNING: THIS VERSION OF PENDING DOES NOT FREE ANYTHING pub fn pending(&mut self, tc: &mut TrafficControl) { let queue = unsafe { &(*(self.queue as *mut VirtQueue)) }; - let mut pended = false; while self.ack_used_idx != queue.used.idx { - pended = true; - let uart = serial_port(); - if let Some(uart) = uart { - //uart.putstr("pended\n"); - } - let elem = &queue.used.ring[self.ack_used_idx as usize % VIRTIO_QUEUE_SIZE]; - let desc = &queue.desc[elem.id as usize]; - let addr = desc.addr as usize; - //let num_blocks = (desc.len as usize).div_ceil(512); - //let block = unsafe { tc.memory_manager.as_mut().unwrap_unchecked().addr_to_block(addr) }; - - //// free - //unsafe { - // tc.memory_manager.as_mut().unwrap_unchecked().free_n_blocks(block, num_blocks); - //} self.ack_used_idx = self.ack_used_idx.wrapping_add(1); - if self.ack_used_idx >= VIRTIO_QUEUE_SIZE as u16 { - self.ack_used_idx = 0; - } - - } - if !pended { - let uart = serial_port(); - if let Some(uart) = uart { - uart.putstr("no pended\n"); - } } } - pub fn transfer(&mut self, tc: &mut TrafficControl, x: u32, y: u32, width: u32, height: u32) { - let uart = serial_port(); - if let Some(uart) = uart { - //uart.putstr("transfer\n"); - } + pub fn transfer(&mut self, tc: &mut TrafficControl, y: u32) { let mut free_me = [0; 4]; let cmd = heap_allocate_type::(tc); @@ -442,10 +418,10 @@ impl VirtIoGpuDevice { cmd.header.ctx_id = 0; cmd.header.ring_idx = 0; cmd.header.padding = [0; 3]; - cmd.rect.x = x; + cmd.rect.x = 0; cmd.rect.y = y; - cmd.rect.width = width; - cmd.rect.height = height; + cmd.rect.width = self.width as u32; + cmd.rect.height = 1; cmd.offset = 0; cmd.resource_id = 1; cmd.padding = 0; @@ -475,10 +451,10 @@ impl VirtIoGpuDevice { cmd.header.ctx_id = 0; cmd.header.ring_idx = 0; cmd.header.padding = [0; 3]; - cmd.rect.x = x; + cmd.rect.x = 0; cmd.rect.y = y; - cmd.rect.width = width; - cmd.rect.height = height; + cmd.rect.width = self.width as u32; + cmd.rect.height = 1; cmd.resource_id = 1; cmd.padding = 0; free_me[2] = unsafe { &(*cmd) as *const _ as usize }; @@ -497,17 +473,9 @@ impl VirtIoGpuDevice { }; self.send_rq_rsp(desc_rq, desc_resp); - // awful hack so that we don't overload the queue - while { - self.ack_used_idx == unsafe { (self.queue as *const VirtQueue).read_volatile().used.idx } - } { - - } - //self.pending(tc); for free in free_me.into_iter().skip(1) { - let block = unsafe { tc.memory_manager.as_mut().unwrap_unchecked().addr_to_block(free) }; unsafe { - tc.memory_manager.as_mut().unwrap_unchecked().free_n_blocks(block, 1); + tc.memory_manager.as_mut().unwrap_unchecked().free_n_blocks(free, 1); } } } diff --git a/src/dev/virtio/mod.rs b/src/dev/virtio/mod.rs index e717903..ed95305 100644 --- a/src/dev/virtio/mod.rs +++ b/src/dev/virtio/mod.rs @@ -2,7 +2,7 @@ //! WARNING: virtio is currently completely broken! don't use it! use core::sync::atomic::Ordering; -use crate::dev::{FRAMEBUFFER_ADDR, FRAMEBUFFER_BPP}; +use crate::dev::{LINEBUFFER_ADDR, LINEBUFFER_BPP}; use crate::dev::virtio::block::{VirtIoBlockDevice, VirtIoBlockDeviceError}; use crate::dev::virtio::gpu::{VirtIoGpuDevice, VirtIoGpuDeviceError}; use crate::spinlock::Spinlock; @@ -36,7 +36,7 @@ pub const VIRTIO_MMIO_STATUS_FAILED: u32 = 1 << 7; pub const VIRTIO_DESC_F_NEXT: u16 = 1 << 0; pub const VIRTIO_DESC_F_WRITE: u16 = 1 << 1; -pub const VIRTIO_QUEUE_SIZE: usize = 128; +pub const VIRTIO_QUEUE_SIZE: usize = 16; pub static VIRTIO_DEVICES: Spinlock<[Option; VIRTIO_MMIO_DEVCOUNT]> = Spinlock::new([const { None }; VIRTIO_MMIO_DEVCOUNT]); pub static VIRTIO_HARD_BLOCK_DEVICE: Spinlock> = Spinlock::new(None); @@ -83,8 +83,7 @@ pub struct VirtQueue { pub fn heap_allocate_type(tc: &mut TrafficControl) -> &'static mut T { let num_blocks = size_of::().div_ceil(512); - let block = unsafe { tc.memory_manager.as_mut().unwrap_unchecked().alloc_n_blocks(num_blocks) }; - let addr = unsafe { tc.memory_manager.as_mut().unwrap_unchecked().block_to_addr(block) }; + let addr = unsafe { tc.memory_manager.as_mut().unwrap_unchecked().alloc_n_blocks(num_blocks) }; unsafe { &mut (*(addr as *mut T)) } } @@ -131,11 +130,12 @@ pub fn probe_virtio_devices(tc: &mut TrafficControl) { } } 16 => { + continue; // gpu device let gpu_device = VirtIoGpuDevice::new_and_init(tc, addr); if let Ok(gpu_device) = gpu_device { - FRAMEBUFFER_ADDR.store(gpu_device.framebuffer, Ordering::Relaxed); - FRAMEBUFFER_BPP.store(4, Ordering::Relaxed); // virtio always uses 4 byte stride + LINEBUFFER_ADDR.store(gpu_device.framebuffer, Ordering::Relaxed); + LINEBUFFER_BPP.store(4, Ordering::Relaxed); // virtio always uses 4 byte stride devices[i] = Some(VirtIoDevice::GPUDevice(gpu_device)); *VIRTIO_GPU_DEVICE.lock() = Some(i as u8); if let Some(serial_port) = &serial_port { @@ -183,8 +183,17 @@ pub fn handle_interrupt(interrupt: u32, tc: &mut TrafficControl) { } } } - VirtIoDevice::GPUDevice(_) => { - // todo: handle gpu interrupts + VirtIoDevice::GPUDevice(gpudev) => { + return; + let gpu = { + let lock = VIRTIO_GPU_DEVICE.lock(); + *lock + }; + if let Some(gpu) = gpu { + if gpu as usize == idx { + gpudev.pending(tc); + } + } } } } @@ -222,7 +231,8 @@ pub fn read_sector(tc: &mut TrafficControl, buffer: usize, size: u32, sector: u6 false } -pub fn framebuffer_update(tc: &mut TrafficControl, x: u32, y: u32, width: u32, height: u32) -> bool { +pub fn framebuffer_update(tc: &mut TrafficControl, y: u32) -> bool { + return true; let idx = { let lock = VIRTIO_GPU_DEVICE.lock(); *lock @@ -232,7 +242,7 @@ pub fn framebuffer_update(tc: &mut TrafficControl, x: u32, y: u32, width: u32, h if let Some(device) = devices[idx as usize].as_mut() { return match device { VirtIoDevice::GPUDevice(device) => { - device.transfer(tc, x, y, width, height); + device.transfer(tc, y); true } _ => { diff --git a/src/fs/fat32.rs b/src/fs/fat32.rs index 507e1e0..71df609 100644 --- a/src/fs/fat32.rs +++ b/src/fs/fat32.rs @@ -1,4 +1,5 @@ use crate::fs::{Record, RecordType}; +use crate::strprint::u32_hex; #[repr(packed(1), C)] pub struct BPB { @@ -286,9 +287,9 @@ pub fn seek_forward_one_sector(bpb: &BPBUseful, reader: &mut Fat32FileReader) -> } let table_value = unsafe { ((fat_addr+(ent_offset)) as *const u32).read_volatile() } & 0x0FFFFFFF; + crate::syscalls::free_blocks(fat_addr, 1); if table_value >= 0x0FFFFFF8 { // no more clusters, whole file has been read - crate::syscalls::free_blocks(fat_addr, 1); reader.eof = 1; return false; } else if table_value >= 0x00000002 { @@ -298,12 +299,10 @@ pub fn seek_forward_one_sector(bpb: &BPBUseful, reader: &mut Fat32FileReader) -> ((reader.cluster - 2) * bpb.sectors_per_cluster as usize) + bpb.first_data_sector(); reader.sector_offset = 0; if table_value == 0x00000000 || table_value == 0x00000001 { - crate::syscalls::free_blocks(fat_addr, 1); reader.eof = 1; return false; } else if table_value == 0x0FFFFFF7 { // bad cluster, stop reading - crate::syscalls::free_blocks(fat_addr, 1); crate::syscalls::write_terminal(b"badcluster"); reader.eof = 1; return false; @@ -338,6 +337,7 @@ pub fn read_file(bpb: &BPBUseful, reader: &mut Fat32FileReader, buffer: &mut [u8 let mut left_in_sector = 512 - reader.sector_offset; if left_in_sector == 0 { crate::syscalls::write_terminal(b"SECTORNULL?"); + crate::syscalls::free_blocks(sector_addr, 1); return false; } while buffer_idx < buffer.len() && left_in_sector > 0 { diff --git a/src/memory.rs b/src/memory.rs index ecfdfa8..4c6a1e3 100644 --- a/src/memory.rs +++ b/src/memory.rs @@ -10,16 +10,11 @@ unsafe extern "C" { } pub const BLOCK_SIZE: usize = 512; -#[cfg(feature = "arch_virt")] -pub const TOTAL_MEMORY: usize = 1048510; -#[cfg(feature = "arch_ppc32")] -pub const TOTAL_MEMORY: usize = 1024 * 1024; // 1MiB; -pub const MEM_BLOCKS: usize = TOTAL_MEMORY / BLOCK_SIZE; pub struct MemoryManager { pub heap_start: usize, pub heap_size: usize, - pub blockmap: [u8; (MEM_BLOCKS+7) / 8], + pub blockmap: [u8; 128/8] } impl MemoryManager { @@ -28,15 +23,19 @@ impl MemoryManager { { let uart = serial_port(); if let Some(uart) = uart { + uart.putstr("heap_start: "); + uart.put_bytes(&u32_hex(_heap_start as u32)); uart.putstr("totalmem: "); - uart.put_bytes(&u32_hex(MEM_BLOCKS as u32)); + uart.put_bytes(&u32_hex(_heap_size as u32)); uart.putstr("\n"); } } + Self { heap_start: _heap_start as _, heap_size: _heap_size as _, - blockmap: [0; (MEM_BLOCKS+7) / 8], + + blockmap: [0; 16], } } #[cfg(feature = "arch_ppc32")] @@ -47,22 +46,7 @@ impl MemoryManager { blockmap: [0; (MEM_BLOCKS+7) / 8], } } - - pub fn is_block_free(&self, block: usize) -> bool { - let block = block % 8; - let block = block / 8; - let val = self.blockmap[block]; - (val & (1 << block)) == 0 - } - pub fn block_to_addr(&self, block: usize) -> usize { - block * BLOCK_SIZE + self.heap_start - } - - pub fn addr_to_block(&self, addr: usize) -> usize { - (addr - self.heap_start) / BLOCK_SIZE - } - pub fn alloc_one_block(&mut self) -> usize { /* for (i, v) in self.blockmap.iter_mut().enumerate() { @@ -81,11 +65,19 @@ impl MemoryManager { */ self.alloc_n_blocks(1) } - pub fn free_one_block(&mut self, block: usize) { + pub fn free_one_block(&mut self, addr: usize) { + let block = (addr - self.heap_start) / BLOCK_SIZE; self.blockmap[block / 8] &= !(1 << (block % 8)); } - + + pub fn is_addr_free(&self, addr: usize) -> bool { + let block = (addr - self.heap_start) / BLOCK_SIZE; + let val = (1 << (block % 8)) & self.blockmap[block / 8]; + val == 0 + } + // can easily fail if too many blocks are requested, will return 0 on failure + // RETURNS ADDRESS pub fn alloc_n_blocks(&mut self, n: usize) -> usize { if n == 0 { return 0; @@ -95,23 +87,29 @@ impl MemoryManager { for i in 0..self.blockmap.len() { for j in 0..8 { let block = i * 8 + j; + let valid = block < (self.heap_size / BLOCK_SIZE); let val = (1 << j) & self.blockmap[i]; - if val == 0 { + if val == 0 && valid { // this is free self.blockmap[i] |= 1 << j; if first_block.is_none() { first_block = Some(block); } found += 1; - if found >= n { - return first_block.unwrap(); + if found == n { + let addr = (first_block.unwrap() * BLOCK_SIZE) + self.heap_start; + return addr; + } + if found > n { + rough_panic(['h', 'm', '?']) } } else { // used, restart search let mut i = 0; while found > 0 { found -= 1; - self.free_one_block(first_block.unwrap() + i); + let addr = ((first_block.unwrap() * BLOCK_SIZE) + self.heap_start) + (i * BLOCK_SIZE); + self.free_one_block(addr); i += 1; } first_block = None; @@ -122,19 +120,24 @@ impl MemoryManager { rough_panic(['o', 'o', 'm']) } - pub fn free_n_blocks(&mut self, block: usize, n: usize) { - if n == 0 || block >= MEM_BLOCKS || block + n > MEM_BLOCKS { - return; + pub fn free_n_blocks(&mut self, addr: usize, n: usize) { + if n == 0 || addr >= self.heap_start + self.heap_size || addr + n * BLOCK_SIZE > self.heap_start + self.heap_size { + rough_panic(['b', 'm', 'f']) } for i in 0..n { - self.free_one_block(block + i); + self.free_one_block(addr + (i * BLOCK_SIZE)); } } pub fn used_blocks(&self) -> usize { let mut used_blocks = 0; - for v in self.blockmap.iter() { + for (i, v) in self.blockmap.iter().enumerate() { for j in 0..8 { + let block = i * 8 + j; + let valid = block < (self.heap_size / BLOCK_SIZE); + if !valid { + continue; + } let val = (1 << j) & *v; if val != 0 { // used diff --git a/src/trafficcontrol.rs b/src/trafficcontrol.rs index 2e7ed96..0a3a8a7 100644 --- a/src/trafficcontrol.rs +++ b/src/trafficcontrol.rs @@ -4,7 +4,8 @@ use crate::arch::serial_port; use crate::memory::{BLOCK_SIZE, MemoryManager}; use crate::spinlock::Spinlock; use crate::syscalls::SysCall; -use crate::{arch}; +use crate::{arch, rough_panic}; +use crate::strprint::u32_hex; #[repr(u32)] pub enum TaskWait { @@ -13,7 +14,7 @@ pub enum TaskWait { WaitForTaskExit = 1 << 2, } -pub const STACK_SIZE_IN_BLOCKS: usize = 16; +pub const STACK_SIZE_IN_BLOCKS: usize = 8; pub const MAX_TASKS: usize = 8; @@ -69,19 +70,12 @@ pub fn handle_syscall( let add = a1 as *mut TaskSetup; tc.init_mem_if_not(); - let blockalloc = unsafe { - tc.memory_manager - .as_mut() - .unwrap_unchecked() - .alloc_n_blocks(STACK_SIZE_IN_BLOCKS) - }; let sp = unsafe { tc.memory_manager .as_mut() .unwrap_unchecked() - .block_to_addr(blockalloc) - + (BLOCK_SIZE * STACK_SIZE_IN_BLOCKS) - }; + .alloc_n_blocks(STACK_SIZE_IN_BLOCKS) + } + (BLOCK_SIZE * STACK_SIZE_IN_BLOCKS); #[cfg(feature = "arch_virt")] let t = Some(Task { @@ -93,10 +87,8 @@ pub fn handle_syscall( incoming_notifications: [const { None }; MAX_TASKS], ackwait: [0; MAX_TASKS], task_wait: 0, - ddi_mem_start_block: unsafe { - tc.memory_manager - .as_mut().unwrap_unchecked() - .addr_to_block((*add).ddi_first_addr) + ddi_mem_start: unsafe { + (*add).ddi_first_addr }, ddi_mem_blocks_count: unsafe { (*add).ddi_size / BLOCK_SIZE }, trap_frame: arch::virt::tasks::setup_task(sp), @@ -134,7 +126,7 @@ pub fn handle_syscall( tc.memory_manager .as_mut() .unwrap_unchecked() - .free_one_block(blockalloc); + .free_n_blocks(sp, 1); } MAX_TASKS + 1 @@ -163,34 +155,22 @@ pub fn handle_syscall( } SysCall::AllocBlocks => { let count = a1; - let block = unsafe { - tc.memory_manager - .as_mut() - .unwrap_unchecked() - .alloc_n_blocks(count) - }; let addr = unsafe { tc.memory_manager .as_mut() .unwrap_unchecked() - .block_to_addr(block) + .alloc_n_blocks(count) }; addr } SysCall::FreeBlocks => { let addr = a1; let count = a2; - let block = unsafe { - tc.memory_manager - .as_mut() - .unwrap_unchecked() - .addr_to_block(addr) - }; unsafe { tc.memory_manager .as_mut() .unwrap_unchecked() - .free_n_blocks(block, count) + .free_n_blocks(addr, count) }; 0 @@ -236,8 +216,34 @@ pub fn handle_syscall( } SysCall::InitKernel => { tc.init_mem_if_not(); + { + // sanity check + const FAILURE: &str = "memory manager sanity check failed"; + let mem = unsafe { + tc.memory_manager.as_mut().unwrap_unchecked() + }; + let addr = mem.alloc_one_block(); + let addr2 = mem.alloc_n_blocks(2); + if mem.is_addr_free(addr) || mem.is_addr_free(addr2) || mem.is_addr_free(addr2 + 512) { + let uart = serial_port(); + if let Some(uart) = uart { + uart.putstr(FAILURE); + } + rough_panic([';', '-', ';']) + } + mem.free_one_block(addr); + mem.free_n_blocks(addr2, 2); + + if !(mem.is_addr_free(addr) || mem.is_addr_free(addr2) || mem.is_addr_free(addr2 + 512)) { + let uart = serial_port(); + if let Some(uart) = uart { + uart.putstr(FAILURE); + } + rough_panic([';', '-', ';']) + } + } crate::dev::probe_devices(&mut tc); - if crate::dev::FRAMEBUFFER_ADDR.load(Ordering::Relaxed) != 0 { + if crate::dev::LINEBUFFER_ADDR.load(Ordering::Relaxed) != 0 { tc.use_fb_console = true; { let uart = serial_port(); @@ -251,7 +257,6 @@ pub fn handle_syscall( SysCall::SendNotification => { let taskid = a1; let addr = a2; - let addr_block = unsafe { tc.memory_manager.as_mut().unwrap_unchecked().addr_to_block(addr) }; let ci = tc.current; if let Some(Some(task)) = tc.tasks.get_mut(taskid).as_mut() { let waiting = task.wait & TaskWait::WaitForNotification as u32 != 0; @@ -268,7 +273,7 @@ pub fn handle_syscall( current_task.ackwait[taskid] = 1; } } else { - task.incoming_notifications[ci] = Some(addr_block); // queue it for them + task.incoming_notifications[ci] = Some(addr); // queue it for them } 0 } else { @@ -281,15 +286,9 @@ pub fn handle_syscall( suspend = true; if let Some(task) = tc.tasks[ci].as_mut() { // is there already a pending notification? - for (i, block) in task.incoming_notifications.iter_mut().enumerate() { - if let Some(block) = block.take() { + for (i, addr) in task.incoming_notifications.iter_mut().enumerate() { + if let Some(addr) = addr.take() { // yes, there is - let addr = unsafe { - tc.memory_manager - .as_mut() - .unwrap_unchecked() - .block_to_addr(block as usize) - }; if let Some(sender_task) = tc.tasks[i].as_mut() { if sender_task.ackwait[ci] == 3 { // they are waiting for us to ack sender_task.ackwait[ci] = 0; @@ -352,7 +351,7 @@ pub fn handle_syscall( 0 } SysCall::EnableFramebufferConsole => { - if crate::dev::FRAMEBUFFER_ADDR.load(Ordering::Relaxed) != 0 { + if crate::dev::LINEBUFFER_ADDR.load(Ordering::Relaxed) != 0 { tc.use_fb_console = true; // clear the screen let mut fbcons = crate::dev::framebuffer::console::FBCONSOLE.lock(); @@ -362,14 +361,14 @@ pub fn handle_syscall( 0 } SysCall::FramebufferPointer => { - crate::dev::FRAMEBUFFER_ADDR.load(Ordering::Relaxed) + crate::dev::LINEBUFFER_ADDR.load(Ordering::Relaxed) } SysCall::FlushFramebufferRect => { let x = a1; let y = a2; let w = a3; let h = a4; - crate::dev::framebuffer_update(&mut tc, x as u32, y as u32, w as u32, h as u32); + crate::dev::linebuffer_push(&mut tc, y as u32); 0 } }, @@ -389,20 +388,14 @@ pub fn context_switch<'a>(tc: &'a mut TrafficControl, current: Task) -> Option<& if want_exit { tc.init_mem_if_not(); let sp = tc.tasks[i].as_ref().map(|v| v.sp).unwrap_or(0); - let ddi_start_block = tc.tasks[i].as_ref().map(|v| v.ddi_mem_start_block).unwrap_or(0); + let ddi_start_block = tc.tasks[i].as_ref().map(|v| v.ddi_mem_start).unwrap_or(0); let ddi_blocks_count = tc.tasks[i].as_ref().map(|v| v.ddi_mem_blocks_count).unwrap_or(0); if sp != 0 { - let stackblock = unsafe { - tc.memory_manager - .as_mut() - .unwrap_unchecked() - .addr_to_block(sp - (BLOCK_SIZE * STACK_SIZE_IN_BLOCKS)) - }; unsafe { tc.memory_manager .as_mut() .unwrap_unchecked() - .free_n_blocks(stackblock, STACK_SIZE_IN_BLOCKS) + .free_n_blocks(sp - (BLOCK_SIZE * STACK_SIZE_IN_BLOCKS), STACK_SIZE_IN_BLOCKS) }; unsafe { tc.memory_manager.as_mut().unwrap_unchecked() @@ -475,7 +468,7 @@ pub struct Task { pub incoming_notifications: [Option; MAX_TASKS], pub ackwait: [u8; MAX_TASKS], // 3 = they have not yet received the notification, 1 = they have received the notification, 0 = we know they received the notification, or don't care pub task_wait: u8, - pub ddi_mem_start_block: usize, + pub ddi_mem_start: usize, pub ddi_mem_blocks_count: usize, #[cfg(feature = "arch_virt")] pub trap_frame: arch::virt::trap::TrapFrame,