working again

This commit is contained in:
husky 2025-09-11 16:28:11 -07:00
parent f13cb2eb12
commit b3af2a7967
8 changed files with 105 additions and 78 deletions

View file

@ -9,6 +9,8 @@ MEMORY
ram (wxa) : ORIGIN = 0x80010000, LENGTH = 0x10000 ram (wxa) : ORIGIN = 0x80010000, LENGTH = 0x10000
virtqueues (wxa) : ORIGIN = 0x80020000, LENGTH = 0x20000 virtqueues (wxa) : ORIGIN = 0x80020000, LENGTH = 0x20000
framebuffer (wxa) : ORIGIN = 0x80040000, LENGTH = 320 * 240 * 4
} }
PHDRS PHDRS
@ -61,4 +63,6 @@ SECTIONS {
PROVIDE(_virtio_queue_1_end = _virtio_queue_1_start + 0x10000); PROVIDE(_virtio_queue_1_end = _virtio_queue_1_start + 0x10000);
PROVIDE(_virtio_queue_2_start = _virtio_queue_1_end); PROVIDE(_virtio_queue_2_start = _virtio_queue_1_end);
PROVIDE(_virtio_queue_2_end = _virtio_queue_2_start + 0x10000); PROVIDE(_virtio_queue_2_end = _virtio_queue_2_start + 0x10000);
PROVIDE(_framebuffer_start = ORIGIN(framebuffer));
} }

View file

@ -37,7 +37,6 @@ impl FramebufferConsole {
// DOES send a framebuffer update! // DOES send a framebuffer update!
pub fn printstr(&mut self, tc: &mut TrafficControl, str: &str) { pub fn printstr(&mut self, tc: &mut TrafficControl, str: &str) {
return;
for c in str.chars() { for c in str.chars() {
let mut was_special_char = false; let mut was_special_char = false;
if c == '\n' || c == '\r' { if c == '\n' || c == '\r' {

View file

@ -1,4 +1,5 @@
use crate::dev::{linebuffer_push, FRAMEBUFFER_HEIGHT, FRAMEBUFFER_WIDTH, LINEBUFFER_ADDR, LINEBUFFER_BPP}; use crate::dev::virtio::framebuffer_update;
use crate::dev::{FRAMEBUFFER_ADDR, FRAMEBUFFER_BPP, FRAMEBUFFER_HEIGHT, FRAMEBUFFER_WIDTH};
use crate::trafficcontrol::TrafficControl; use crate::trafficcontrol::TrafficControl;
use core::sync::atomic::Ordering; use core::sync::atomic::Ordering;
@ -33,63 +34,73 @@ impl FBColor {
} }
} }
pub fn fb_write_char_array(tc: &mut TrafficControl, mut x: usize, mut y: usize, chars: &[char]) { pub fn fb_write_char_array(tc: &mut TrafficControl, mut x: usize, y: usize, chars: &[char]) {
let ogx = x;
let ogy = y;
const BYTES: [u8; 3] = FB_FG_COLOR.to_bytes(); const BYTES: [u8; 3] = FB_FG_COLOR.to_bytes();
let fbaddr = LINEBUFFER_ADDR.load(Ordering::Relaxed); let fbaddr = FRAMEBUFFER_ADDR.load(Ordering::Relaxed);
if fbaddr == 0 { if fbaddr == 0 {
return; return;
} }
let fbstride = FRAMEBUFFER_BPP.load(Ordering::Relaxed) * FRAMEBUFFER_WIDTH;
const CHAR_SIZE: usize = 16; const CHAR_SIZE: usize = 16;
let mut drew_anything = false; for c in chars {
for line in 0..FRAMEBUFFER_HEIGHT { let c = *c;
for c in chars { if c == ' ' {
let c = *c; x += CHAR_SIZE;
if c == ' ' { } else if c as u8 > 32 {
x += CHAR_SIZE; let c = c as u8 - 32;
} else if c as u8 > 32 { let cx = (c % 16) as usize * CHAR_SIZE;
let c = c as u8 - 32; let cy = (c / 16) as usize * CHAR_SIZE;
let cx = (c % 16) as usize * CHAR_SIZE; for row in 0..CHAR_SIZE {
let cy = (c / 16) as usize * CHAR_SIZE; for col in 0..CHAR_SIZE {
for row in 0..CHAR_SIZE { let coff = (VAPFONT_W * (cy + row)) + (cx + col);
if (y+row) != line { let draw = VAPFONT[coff / 8] & (0x80 >> (coff % 8));
continue; if draw != 0 {
} unsafe {
for col in 0..CHAR_SIZE { let fb = (fbaddr as *mut u8)
let coff = (VAPFONT_W * (cy + row)) + (cx + col); .add(((y + row) * fbstride) + ((x + col) * 4))
let draw = VAPFONT[coff / 8] & (0x80 >> (coff % 8)); as *mut u32;
if draw != 0 { fb.write_volatile(u32::from_ne_bytes([
unsafe { 0, BYTES[0], BYTES[1], BYTES[2],
//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) { pub fn fb_clearscreen(tc: &mut TrafficControl) {
const BYTES: [u8; 3] = FB_BG_COLOR.to_bytes(); const BYTES: [u8; 3] = FB_BG_COLOR.to_bytes();
let fbaddr = LINEBUFFER_ADDR.load(Ordering::Relaxed); let fbaddr = FRAMEBUFFER_ADDR.load(Ordering::Relaxed);
if fbaddr == 0 { if fbaddr == 0 {
return; return;
} }
let fbstride = FRAMEBUFFER_BPP.load(Ordering::Relaxed) * FRAMEBUFFER_WIDTH;
for y in 0..FRAMEBUFFER_HEIGHT { for y in 0..FRAMEBUFFER_HEIGHT {
for x in 0..FRAMEBUFFER_WIDTH { for x in 0..FRAMEBUFFER_WIDTH {
unsafe { 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]])); 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,
);
} }

View file

@ -8,10 +8,10 @@ pub const LINEBUFFER_BLOCKS: usize = 3;
pub const LINEBUFFER_HEIGHT: usize = 1; pub const LINEBUFFER_HEIGHT: usize = 1;
// NOTE: // NOTE:
// LINEBUFFER_ADDR should always be 0 if no framebuffer exists // FRAMEBUFFER_ADDR should always be 0 if no framebuffer exists
// if LINEBUFFER_ADDR is NOT 0, then LINEBUFFER_BPP should also be NOT 0 // if FRAMEBUFFER_ADDR is NOT 0, then FRAMEBUFFER_BPP should also be NOT 0
pub static LINEBUFFER_ADDR: AtomicUsize = AtomicUsize::new(0); pub static FRAMEBUFFER_ADDR: AtomicUsize = AtomicUsize::new(0);
pub static LINEBUFFER_BPP: AtomicUsize = AtomicUsize::new(0); pub static FRAMEBUFFER_BPP: AtomicUsize = AtomicUsize::new(0);
#[cfg(feature = "dev_virtio")] #[cfg(feature = "dev_virtio")]
pub mod virtio; pub mod virtio;
@ -29,16 +29,16 @@ pub fn read_sector(tc: &mut TrafficControl, buffer: usize, size: u32, sector: u6
false false
} }
pub fn linebuffer_address() -> usize { pub fn framebuffer_address() -> usize {
LINEBUFFER_ADDR.load(Ordering::Relaxed) FRAMEBUFFER_ADDR.load(Ordering::Relaxed)
} }
pub fn linebuffer_bpp() -> usize { pub fn framebuffer_bpp() -> usize {
LINEBUFFER_BPP.load(Ordering::Relaxed) FRAMEBUFFER_BPP.load(Ordering::Relaxed)
} }
pub fn linebuffer_push(tc: &mut TrafficControl, line: u32) { pub fn framebuffer_push(tc: &mut TrafficControl, x: u32, y: u32, w: u32, h: u32) {
#[cfg(feature = "dev_virtio")] #[cfg(feature = "dev_virtio")]
virtio::framebuffer_update(tc, line); virtio::framebuffer_update(tc, x, y, w, h);
} }

View file

@ -6,6 +6,7 @@ use crate::trafficcontrol::TrafficControl;
unsafe extern "C" { unsafe extern "C" {
fn _virtio_queue_2_start(); fn _virtio_queue_2_start();
fn _framebuffer_start();
} }
pub const VIRTIO_GPU_CMD_GET_DISPLAY_INFO: u32 = 0x0100; pub const VIRTIO_GPU_CMD_GET_DISPLAY_INFO: u32 = 0x0100;
@ -180,8 +181,8 @@ impl VirtIoGpuDevice {
} }
// allocate memory for linebuffer // allocate memory for framebuffer
let linebuffer_ptr = unsafe { tc.memory_manager.as_mut().unwrap_unchecked().alloc_n_blocks(LINEBUFFER_BLOCKS) }; let framebuffer_ptr = _framebuffer_start as usize;
let latest_response = heap_allocate_type::<CtrlHeader>(tc) as *const _ as usize; let latest_response = heap_allocate_type::<CtrlHeader>(tc) as *const _ as usize;
@ -191,7 +192,7 @@ impl VirtIoGpuDevice {
queue: queue_ptr, queue: queue_ptr,
idx: 0, idx: 0,
ack_used_idx: 0, ack_used_idx: 0,
framebuffer: linebuffer_ptr as usize, framebuffer: framebuffer_ptr,
width: FRAMEBUFFER_WIDTH, width: FRAMEBUFFER_WIDTH,
height: FRAMEBUFFER_HEIGHT, height: FRAMEBUFFER_HEIGHT,
}; };
@ -252,7 +253,7 @@ impl VirtIoGpuDevice {
free_me[1] = unsafe { &(*cmd) as *const _ as usize }; free_me[1] = unsafe { &(*cmd) as *const _ as usize };
let mem_entry = heap_allocate_type::<GPUMemEntry>(tc); let mem_entry = heap_allocate_type::<GPUMemEntry>(tc);
mem_entry.addr = gpu.framebuffer as u64; mem_entry.addr = gpu.framebuffer as u64;
mem_entry.length = (gpu.width * 4) as u32; mem_entry.length = (gpu.height * gpu.width * 4) as u32;
mem_entry.padding = 0; mem_entry.padding = 0;
free_me[2] = unsafe { &(*mem_entry) as *const _ as usize }; free_me[2] = unsafe { &(*mem_entry) as *const _ as usize };
@ -319,7 +320,7 @@ impl VirtIoGpuDevice {
} { } {
} }
//gpu.pending(tc); gpu.pending(tc);
for free in free_me { for free in free_me {
unsafe { unsafe {
@ -408,8 +409,8 @@ impl VirtIoGpuDevice {
} }
} }
pub fn transfer(&mut self, tc: &mut TrafficControl, y: u32) { pub fn transfer(&mut self, tc: &mut TrafficControl, x: u32, y: u32, w: u32, h: u32) {
let mut free_me = [0; 4]; let mut free_me = [0; 2];
let cmd = heap_allocate_type::<TransferToHost2D>(tc); let cmd = heap_allocate_type::<TransferToHost2D>(tc);
cmd.header.ctrl_type = VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D; cmd.header.ctrl_type = VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D;
@ -418,14 +419,14 @@ impl VirtIoGpuDevice {
cmd.header.ctx_id = 0; cmd.header.ctx_id = 0;
cmd.header.ring_idx = 0; cmd.header.ring_idx = 0;
cmd.header.padding = [0; 3]; cmd.header.padding = [0; 3];
cmd.rect.x = 0; cmd.rect.x = x;
cmd.rect.y = y; cmd.rect.y = y;
cmd.rect.width = self.width as u32; cmd.rect.width = w;
cmd.rect.height = 1; cmd.rect.height = h;
cmd.offset = 0; cmd.offset = 0;
cmd.resource_id = 1; cmd.resource_id = 1;
cmd.padding = 0; cmd.padding = 0;
free_me[1] = unsafe { &(*cmd) as *const _ as usize }; free_me[0] = unsafe { &(*cmd) as *const _ as usize };
let desc_rq = Descriptor { let desc_rq = Descriptor {
addr: unsafe { &(*cmd) as *const _ as u64 }, addr: unsafe { &(*cmd) as *const _ as u64 },
@ -451,13 +452,13 @@ impl VirtIoGpuDevice {
cmd.header.ctx_id = 0; cmd.header.ctx_id = 0;
cmd.header.ring_idx = 0; cmd.header.ring_idx = 0;
cmd.header.padding = [0; 3]; cmd.header.padding = [0; 3];
cmd.rect.x = 0; cmd.rect.x = x;
cmd.rect.y = y; cmd.rect.y = y;
cmd.rect.width = self.width as u32; cmd.rect.width = w;
cmd.rect.height = 1; cmd.rect.height = h;
cmd.resource_id = 1; cmd.resource_id = 1;
cmd.padding = 0; cmd.padding = 0;
free_me[2] = unsafe { &(*cmd) as *const _ as usize }; free_me[1] = unsafe { &(*cmd) as *const _ as usize };
let desc_rq = Descriptor { let desc_rq = Descriptor {
addr: unsafe { &(*cmd) as *const _ as u64 }, addr: unsafe { &(*cmd) as *const _ as u64 },
@ -473,7 +474,17 @@ impl VirtIoGpuDevice {
}; };
self.send_rq_rsp(desc_rq, desc_resp); self.send_rq_rsp(desc_rq, desc_resp);
for free in free_me.into_iter().skip(1) {
// hack to make sure the queue doesn't get overloaded
while {
let queue = unsafe { (self.queue as *mut VirtQueue).read_volatile() };
self.ack_used_idx == queue.used.idx
} {
}
self.pending(tc);
for free in free_me.into_iter() {
unsafe { unsafe {
tc.memory_manager.as_mut().unwrap_unchecked().free_n_blocks(free, 1); tc.memory_manager.as_mut().unwrap_unchecked().free_n_blocks(free, 1);
} }

View file

@ -2,9 +2,10 @@
//! WARNING: virtio is currently completely broken! don't use it! //! WARNING: virtio is currently completely broken! don't use it!
use core::sync::atomic::Ordering; use core::sync::atomic::Ordering;
use crate::dev::{LINEBUFFER_ADDR, LINEBUFFER_BPP}; use crate::dev::{FRAMEBUFFER_ADDR, FRAMEBUFFER_BPP};
use crate::dev::virtio::block::{VirtIoBlockDevice, VirtIoBlockDeviceError}; use crate::dev::virtio::block::{VirtIoBlockDevice, VirtIoBlockDeviceError};
use crate::dev::virtio::gpu::{VirtIoGpuDevice, VirtIoGpuDeviceError}; use crate::dev::virtio::gpu::{VirtIoGpuDevice, VirtIoGpuDeviceError};
use crate::rough_panic;
use crate::spinlock::Spinlock; use crate::spinlock::Spinlock;
use crate::strprint::twodigit; use crate::strprint::twodigit;
use crate::trafficcontrol::{TrafficControl}; use crate::trafficcontrol::{TrafficControl};
@ -83,6 +84,9 @@ pub struct VirtQueue {
pub fn heap_allocate_type<T: Sized>(tc: &mut TrafficControl) -> &'static mut T { pub fn heap_allocate_type<T: Sized>(tc: &mut TrafficControl) -> &'static mut T {
let num_blocks = size_of::<T>().div_ceil(512); let num_blocks = size_of::<T>().div_ceil(512);
if num_blocks != 1 {
rough_panic(['f', 'm', 'l']);
}
let addr = unsafe { tc.memory_manager.as_mut().unwrap_unchecked().alloc_n_blocks(num_blocks) }; let addr = unsafe { tc.memory_manager.as_mut().unwrap_unchecked().alloc_n_blocks(num_blocks) };
unsafe { &mut (*(addr as *mut T)) } unsafe { &mut (*(addr as *mut T)) }
} }
@ -130,12 +134,11 @@ pub fn probe_virtio_devices(tc: &mut TrafficControl) {
} }
} }
16 => { 16 => {
continue;
// gpu device // gpu device
let gpu_device = VirtIoGpuDevice::new_and_init(tc, addr); let gpu_device = VirtIoGpuDevice::new_and_init(tc, addr);
if let Ok(gpu_device) = gpu_device { if let Ok(gpu_device) = gpu_device {
LINEBUFFER_ADDR.store(gpu_device.framebuffer, Ordering::Relaxed); FRAMEBUFFER_ADDR.store(gpu_device.framebuffer, Ordering::Relaxed);
LINEBUFFER_BPP.store(4, Ordering::Relaxed); // virtio always uses 4 byte stride FRAMEBUFFER_BPP.store(4, Ordering::Relaxed); // virtio always uses 4 byte stride
devices[i] = Some(VirtIoDevice::GPUDevice(gpu_device)); devices[i] = Some(VirtIoDevice::GPUDevice(gpu_device));
*VIRTIO_GPU_DEVICE.lock() = Some(i as u8); *VIRTIO_GPU_DEVICE.lock() = Some(i as u8);
if let Some(serial_port) = &serial_port { if let Some(serial_port) = &serial_port {
@ -231,8 +234,7 @@ pub fn read_sector(tc: &mut TrafficControl, buffer: usize, size: u32, sector: u6
false false
} }
pub fn framebuffer_update(tc: &mut TrafficControl, y: u32) -> bool { pub fn framebuffer_update(tc: &mut TrafficControl, x: u32, y: u32, w: u32, h: u32) -> bool {
return true;
let idx = { let idx = {
let lock = VIRTIO_GPU_DEVICE.lock(); let lock = VIRTIO_GPU_DEVICE.lock();
*lock *lock
@ -242,7 +244,7 @@ pub fn framebuffer_update(tc: &mut TrafficControl, y: u32) -> bool {
if let Some(device) = devices[idx as usize].as_mut() { if let Some(device) = devices[idx as usize].as_mut() {
return match device { return match device {
VirtIoDevice::GPUDevice(device) => { VirtIoDevice::GPUDevice(device) => {
device.transfer(tc, y); device.transfer(tc, x, y, w, h);
true true
} }
_ => { _ => {

View file

@ -121,7 +121,7 @@ impl MemoryManager {
} }
pub fn free_n_blocks(&mut self, addr: usize, n: usize) { 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 { if n == 0 || addr < self.heap_start || addr >= self.heap_start + self.heap_size || addr + n * BLOCK_SIZE > self.heap_start + self.heap_size {
rough_panic(['b', 'm', 'f']) rough_panic(['b', 'm', 'f'])
} }
for i in 0..n { for i in 0..n {

View file

@ -243,7 +243,7 @@ pub fn handle_syscall(
} }
} }
crate::dev::probe_devices(&mut tc); crate::dev::probe_devices(&mut tc);
if crate::dev::LINEBUFFER_ADDR.load(Ordering::Relaxed) != 0 { if crate::dev::FRAMEBUFFER_ADDR.load(Ordering::Relaxed) != 0 {
tc.use_fb_console = true; tc.use_fb_console = true;
{ {
let uart = serial_port(); let uart = serial_port();
@ -351,7 +351,7 @@ pub fn handle_syscall(
0 0
} }
SysCall::EnableFramebufferConsole => { SysCall::EnableFramebufferConsole => {
if crate::dev::LINEBUFFER_ADDR.load(Ordering::Relaxed) != 0 { if crate::dev::FRAMEBUFFER_ADDR.load(Ordering::Relaxed) != 0 {
tc.use_fb_console = true; tc.use_fb_console = true;
// clear the screen // clear the screen
let mut fbcons = crate::dev::framebuffer::console::FBCONSOLE.lock(); let mut fbcons = crate::dev::framebuffer::console::FBCONSOLE.lock();
@ -361,14 +361,14 @@ pub fn handle_syscall(
0 0
} }
SysCall::FramebufferPointer => { SysCall::FramebufferPointer => {
crate::dev::LINEBUFFER_ADDR.load(Ordering::Relaxed) crate::dev::FRAMEBUFFER_ADDR.load(Ordering::Relaxed)
} }
SysCall::FlushFramebufferRect => { SysCall::FlushFramebufferRect => {
let x = a1; let x = a1 as u32;
let y = a2; let y = a2 as u32;
let w = a3; let w = a3 as u32;
let h = a4; let h = a4 as u32;
crate::dev::linebuffer_push(&mut tc, y as u32); crate::dev::framebuffer_push(&mut tc, x, y, w, h);
0 0
} }
}, },