[Yellowstone] Allow registering denali.
This commit is contained in:
		
							parent
							
								
									c9b484089e
								
							
						
					
					
						commit
						e90018b42e
					
				|  | @ -78,6 +78,10 @@ impl MemoryRegion { | |||
|     pub fn cap(&self) -> &Capability { | ||||
|         &self.mem_cap | ||||
|     } | ||||
| 
 | ||||
|     pub fn duplicate(&self, offset: u64, length: u64) -> Result<Capability, ZError> { | ||||
|         syscall::memory_obj_duplicate(&self.mem_cap, offset, length) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl Drop for MemoryRegion { | ||||
|  |  | |||
|  | @ -167,6 +167,24 @@ pub fn memory_object_inspect(mem_cap: &Capability) -> Result<u64, ZError> { | |||
|     Ok(mem_size) | ||||
| } | ||||
| 
 | ||||
| pub fn memory_obj_duplicate( | ||||
|     mem_cap: &Capability, | ||||
|     base_offset: u64, | ||||
|     length: u64, | ||||
| ) -> Result<Capability, ZError> { | ||||
|     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<u64, ZError> { | ||||
|     let mut vaddr: u64 = 0; | ||||
|     // FIXME: Allow caller to pass these options.
 | ||||
|  |  | |||
|  | @ -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<z_cap_t>, | ||||
|  |  | |||
|  | @ -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"); | ||||
|  |  | |||
|  | @ -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<Capability, ZError> { | ||||
|         match self.probe_pci(|class, _, _| class == 0x1) { | ||||
|             Some(m) => Ok(m), | ||||
|             None => Err(ZError::NOT_FOUND), | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fn probe_pci(&self, pred: DevPredicate) -> Option<Capability> { | ||||
|         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<Capability> { | ||||
|         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<Capability> { | ||||
|         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<Capability> { | ||||
|         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::<PciHeader>()]; | ||||
|         unsafe { header_slice.as_ptr().cast::<PciHeader>().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) | ||||
| } | ||||
|  | @ -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<Self, ZError> { | ||||
|     pub fn new(pci_region: MemoryRegion) -> Result<Self, ZError> { | ||||
|         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<YellowstoneServerContext>, | ||||
|     service_map: BTreeMap<String, Capability>, | ||||
| } | ||||
| 
 | ||||
| impl YellowstoneServerImpl { | ||||
|     pub fn new(context: Rc<YellowstoneServerContext>) -> 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<Endpoint, ZError> { | ||||
|         todo!() | ||||
|     } | ||||
| 
 | ||||
|     fn get_endpoint(&self, req: &GetEndpointRequest) -> Result<Endpoint, ZError> { | ||||
|     fn get_ahci_info(&mut self) -> Result<AhciInfo, ZError> { | ||||
|         Ok(AhciInfo { | ||||
|             ahci_region: self.context.pci_reader.get_ahci_region()?.release(), | ||||
|             region_length: 0x1000, | ||||
|         }) | ||||
|     } | ||||
| 
 | ||||
|     fn get_xhci_info(&mut self) -> Result<XhciInfo, ZError> { | ||||
|         todo!() | ||||
|     } | ||||
| 
 | ||||
|     fn get_ahci_info(&self) -> Result<AhciInfo, ZError> { | ||||
|     fn get_framebuffer_info(&mut self) -> Result<FramebufferInfo, ZError> { | ||||
|         todo!() | ||||
|     } | ||||
| 
 | ||||
|     fn get_xhci_info(&self) -> Result<XhciInfo, ZError> { | ||||
|         todo!() | ||||
|     } | ||||
| 
 | ||||
|     fn get_framebuffer_info(&self) -> Result<FramebufferInfo, ZError> { | ||||
|         todo!() | ||||
|     } | ||||
| 
 | ||||
|     fn get_denali(&self) -> Result<DenaliInfo, ZError> { | ||||
|     fn get_denali(&mut self) -> Result<DenaliInfo, ZError> { | ||||
|         todo!() | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -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<Box<thread::Thread>, ZError> { | ||||
|                 let thread_entry = |server_ptr: *const c_void| { | ||||
|                     let server = unsafe { (server_ptr as *const #server_name<T>).as_ref().expect("Failed to convert to server") }; | ||||
|                     let server = unsafe { (server_ptr as *mut #server_name<T>).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<z_cap_t>, | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue