From e90018b42e20bfd070a04d7e9d7bffc0d412092a Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Sat, 17 Aug 2024 21:54:30 -0700 Subject: [PATCH] [Yellowstone] Allow registering denali. --- rust/lib/mammoth/src/mem.rs | 4 + rust/lib/mammoth/src/syscall.rs | 18 +++++ rust/lib/yunq/src/server.rs | 4 +- rust/sys/yellowstone/src/main.rs | 10 ++- rust/sys/yellowstone/src/pci.rs | 122 +++++++++++++++++++++++++++++ rust/sys/yellowstone/src/server.rs | 49 ++++++++---- yunq/rust/src/codegen.rs | 14 ++-- 7 files changed, 195 insertions(+), 26 deletions(-) create mode 100644 rust/sys/yellowstone/src/pci.rs diff --git a/rust/lib/mammoth/src/mem.rs b/rust/lib/mammoth/src/mem.rs index 5f58904..89037c5 100644 --- a/rust/lib/mammoth/src/mem.rs +++ b/rust/lib/mammoth/src/mem.rs @@ -78,6 +78,10 @@ impl MemoryRegion { pub fn cap(&self) -> &Capability { &self.mem_cap } + + pub fn duplicate(&self, offset: u64, length: u64) -> Result { + syscall::memory_obj_duplicate(&self.mem_cap, offset, length) + } } impl Drop for MemoryRegion { diff --git a/rust/lib/mammoth/src/syscall.rs b/rust/lib/mammoth/src/syscall.rs index 3d3635a..2ffaca5 100644 --- a/rust/lib/mammoth/src/syscall.rs +++ b/rust/lib/mammoth/src/syscall.rs @@ -167,6 +167,24 @@ pub fn memory_object_inspect(mem_cap: &Capability) -> Result { Ok(mem_size) } +pub fn memory_obj_duplicate( + mem_cap: &Capability, + base_offset: u64, + length: u64, +) -> Result { + let mut new_cap = 0; + syscall( + zion::kZionMemoryObjectDuplicate, + &zion::ZMemoryObjectDuplicateReq { + vmmo_cap: mem_cap.raw(), + base_offset, + length, + new_vmmo_cap: &mut new_cap, + }, + )?; + Ok(Capability::take(new_cap)) +} + pub fn address_space_map(vmmo_cap: &Capability) -> Result { let mut vaddr: u64 = 0; // FIXME: Allow caller to pass these options. diff --git a/rust/lib/yunq/src/server.rs b/rust/lib/yunq/src/server.rs index 0a7d77e..49d7276 100644 --- a/rust/lib/yunq/src/server.rs +++ b/rust/lib/yunq/src/server.rs @@ -6,7 +6,7 @@ use mammoth::zion::z_cap_t; use mammoth::zion::ZError; pub trait YunqServer { - fn server_loop(&self) { + fn server_loop(&mut self) { loop { let mut byte_buffer = ByteBuffer::<1024>::new(); let mut cap_buffer = vec![0; 10]; @@ -44,7 +44,7 @@ pub trait YunqServer { .duplicate(!mammoth::zion::kZionPerm_Read) } fn handle_request( - &self, + &mut self, method_number: u64, byte_buffer: &mut ByteBuffer<1024>, cap_buffer: &mut Vec, diff --git a/rust/sys/yellowstone/src/main.rs b/rust/sys/yellowstone/src/main.rs index f416168..6bbb339 100644 --- a/rust/sys/yellowstone/src/main.rs +++ b/rust/sys/yellowstone/src/main.rs @@ -6,11 +6,14 @@ extern crate alloc; use mammoth::{ cap::Capability, define_entry, elf, - zion::{kZionPerm_Read, z_cap_t, z_err_t, ZError}, + init::BOOT_PCI_VMMO, + mem::MemoryRegion, + zion::{z_cap_t, z_err_t, ZError}, }; use yellowstone_yunq::YellowstoneServer; use yunq::server::YunqServer; +mod pci; mod server; define_entry!(); @@ -23,8 +26,11 @@ fn spawn_from_vmmo(vmmo_cap: z_cap_t, server_cap: Capability) -> Result<(), ZErr #[no_mangle] extern "C" fn main() -> z_err_t { + let pci_region = MemoryRegion::from_cap(Capability::take(unsafe { BOOT_PCI_VMMO })) + .expect("Failed to create PCI region"); let context = alloc::rc::Rc::new( - server::YellowstoneServerContext::new().expect("Failed to create yellowstone context"), + server::YellowstoneServerContext::new(pci_region) + .expect("Failed to create yellowstone context"), ); let handler = server::YellowstoneServerImpl::new(context.clone()); let server = YellowstoneServer::new(handler).expect("Couldn't create yellowstone server"); diff --git a/rust/sys/yellowstone/src/pci.rs b/rust/sys/yellowstone/src/pci.rs new file mode 100644 index 0000000..b7b4116 --- /dev/null +++ b/rust/sys/yellowstone/src/pci.rs @@ -0,0 +1,122 @@ +use mammoth::{cap::Capability, mem::MemoryRegion, zion::ZError}; + +pub struct PciReader { + memory_region: MemoryRegion, +} + +type DevPredicate = fn(u8, u8, u8) -> bool; + +impl PciReader { + pub fn new(memory_region: MemoryRegion) -> Self { + Self { memory_region } + } + + pub fn get_ahci_region(&self) -> Result { + match self.probe_pci(|class, _, _| class == 0x1) { + Some(m) => Ok(m), + None => Err(ZError::NOT_FOUND), + } + } + + fn probe_pci(&self, pred: DevPredicate) -> Option { + let base_header = self.pci_header(0, 0, 0); + if (base_header.header_type & 0x80) == 0 { + if let Some(dev) = self.probe_bus(pred, 0) { + return Some(dev); + } + } else { + for fun in 0..8 { + let fun_hdr = self.pci_header(0, 0, fun); + if fun_hdr.vendor_id != 0xFFFF { + if let Some(dev) = self.probe_bus(pred, fun) { + return Some(dev); + } + } + } + } + None + } + + fn probe_bus(&self, pred: DevPredicate, bus: u8) -> Option { + for dev in 0..0x20 { + if let Some(dev) = self.probe_device(pred, bus, dev) { + return Some(dev); + } + } + None + } + + fn probe_device(&self, pred: DevPredicate, bus: u8, dev: u8) -> Option { + let device_base_header = self.pci_header(bus, dev, 0); + if device_base_header.vendor_id == 0xFFFF { + return None; + } + + if let Some(dev) = self.probe_function(pred, bus, dev, 0) { + return Some(dev); + } + + if (device_base_header.header_type & 0x80) != 0 { + for fun in 1..8 { + if let Some(dev) = self.probe_function(pred, bus, dev, fun) { + return Some(dev); + } + } + } + None + } + + fn probe_function(&self, pred: DevPredicate, bus: u8, dev: u8, fun: u8) -> Option { + let function_header = self.pci_header(bus, dev, fun); + + mammoth::debug!( + "PCI Function: {:#x} {:#x} {:#x}", + function_header.class_code, + function_header.subclass, + function_header.prog_interface + ); + + if pred( + function_header.class_code, + function_header.subclass, + function_header.prog_interface, + ) { + mammoth::debug!("Found!"); + let offset = pci_header_offset(bus, dev, fun); + Some( + self.memory_region + .duplicate(offset as u64, 0x1000) + .expect("Failed to duplicate PCI cap"), + ) + } else { + None + } + } + + fn pci_header(&self, bus: u8, dev: u8, fun: u8) -> &PciHeader { + let offset = pci_header_offset(bus, dev, fun); + let header_slice: &[u8] = + &self.memory_region.slice()[offset..offset + size_of::()]; + unsafe { header_slice.as_ptr().cast::().as_ref().unwrap() } + } +} + +#[repr(C, packed)] +struct PciHeader { + vendor_id: u16, + device_id: u16, + command_reg: u16, + status_reg: u16, + revision: u8, + prog_interface: u8, + subclass: u8, + class_code: u8, + cache_line_size: u8, + latency_timer: u8, + header_type: u8, + bist: u8, +} + +fn pci_header_offset(bus: u8, dev: u8, fun: u8) -> usize { + ((bus as usize) << 20) | ((dev as usize) << 15) | ((fun as usize) << 12) +} diff --git a/rust/sys/yellowstone/src/server.rs b/rust/sys/yellowstone/src/server.rs index d3da021..037fb57 100644 --- a/rust/sys/yellowstone/src/server.rs +++ b/rust/sys/yellowstone/src/server.rs @@ -1,18 +1,23 @@ use alloc::rc::Rc; -use mammoth::zion::ZError; +use alloc::{collections::BTreeMap, string::String}; +use mammoth::{cap::Capability, mem::MemoryRegion, zion::ZError}; use yellowstone_yunq::{ AhciInfo, DenaliInfo, Endpoint, FramebufferInfo, GetEndpointRequest, RegisterEndpointRequest, XhciInfo, YellowstoneServerHandler, }; +use crate::pci::PciReader; + pub struct YellowstoneServerContext { denali_semaphore: mammoth::sync::Semaphore, + pci_reader: PciReader, } impl YellowstoneServerContext { - pub fn new() -> Result { + pub fn new(pci_region: MemoryRegion) -> Result { Ok(Self { denali_semaphore: mammoth::sync::Semaphore::new()?, + pci_reader: PciReader::new(pci_region), }) } @@ -23,36 +28,50 @@ impl YellowstoneServerContext { pub struct YellowstoneServerImpl { context: Rc, + service_map: BTreeMap, } impl YellowstoneServerImpl { pub fn new(context: Rc) -> Self { - Self { context } + Self { + context, + service_map: BTreeMap::new(), + } } } impl YellowstoneServerHandler for YellowstoneServerImpl { - fn register_endpoint(&self, req: &RegisterEndpointRequest) -> Result<(), ZError> { + fn register_endpoint(&mut self, req: RegisterEndpointRequest) -> Result<(), ZError> { + let signal_denali = req.endpoint_name == "denali"; + self.service_map + .insert(req.endpoint_name, Capability::take(req.endpoint_capability)); + + if signal_denali { + self.context.denali_semaphore.signal()? + } + Ok(()) + } + + fn get_endpoint(&mut self, req: GetEndpointRequest) -> Result { todo!() } - fn get_endpoint(&self, req: &GetEndpointRequest) -> Result { + fn get_ahci_info(&mut self) -> Result { + Ok(AhciInfo { + ahci_region: self.context.pci_reader.get_ahci_region()?.release(), + region_length: 0x1000, + }) + } + + fn get_xhci_info(&mut self) -> Result { todo!() } - fn get_ahci_info(&self) -> Result { + fn get_framebuffer_info(&mut self) -> Result { todo!() } - fn get_xhci_info(&self) -> Result { - todo!() - } - - fn get_framebuffer_info(&self) -> Result { - todo!() - } - - fn get_denali(&self) -> Result { + fn get_denali(&mut self) -> Result { todo!() } } diff --git a/yunq/rust/src/codegen.rs b/yunq/rust/src/codegen.rs index 34477cf..71e493e 100644 --- a/yunq/rust/src/codegen.rs +++ b/yunq/rust/src/codegen.rs @@ -82,7 +82,7 @@ fn generate_server_case(method: &Method) -> TokenStream { (Some(req), Some(_)) => quote! { #id => { let req = #req::parse_from_request(byte_buffer, cap_buffer)?; - let resp = self.handler.#name(&req)?; + let resp = self.handler.#name(req)?; cap_buffer.resize(0, 0); let resp_len = resp.serialize_as_request(0, byte_buffer, cap_buffer)?; Ok(resp_len) @@ -91,7 +91,7 @@ fn generate_server_case(method: &Method) -> TokenStream { (Some(req), None) => quote! { #id => { let req = #req::parse_from_request(byte_buffer, cap_buffer)?; - self.handler.#name(&req)?; + self.handler.#name(req)?; cap_buffer.resize(0, 0); // TODO: Implement serialization for EmptyMessage so this is less hacky. yunq::message::serialize_error(byte_buffer, ZError::from(0)); @@ -116,13 +116,13 @@ fn generate_server_method(method: &Method) -> TokenStream { let maybe_resp = method.response.clone().map(|r| ident(&r)); match (maybe_req, maybe_resp) { (Some(req), Some(resp)) => quote! { - fn #name (&self, req: & #req) -> Result<#resp, ZError>; + fn #name (&mut self, req: #req) -> Result<#resp, ZError>; }, (Some(req), None) => quote! { - fn #name (&self, req: & #req) -> Result<(), ZError>; + fn #name (&mut self, req: #req) -> Result<(), ZError>; }, (None, Some(resp)) => quote! { - fn #name (&self) -> Result<#resp, ZError>; + fn #name (&mut self) -> Result<#resp, ZError>; }, _ => unreachable!(), } @@ -153,7 +153,7 @@ fn generate_server(interface: &Interface) -> TokenStream { pub fn run_server(&self) -> Result, ZError> { let thread_entry = |server_ptr: *const c_void| { - let server = unsafe { (server_ptr as *const #server_name).as_ref().expect("Failed to convert to server") }; + let server = unsafe { (server_ptr as *mut #server_name).as_mut().expect("Failed to convert to server") }; server.server_loop(); }; thread::Thread::spawn( @@ -169,7 +169,7 @@ fn generate_server(interface: &Interface) -> TokenStream { } fn handle_request( - &self, + &mut self, method_number: u64, byte_buffer: &mut ByteBuffer<1024>, cap_buffer: &mut Vec,