diff --git a/rust/lib/mammoth/build.rs b/rust/lib/mammoth/build.rs index 6797dfb..a5c5067 100644 --- a/rust/lib/mammoth/build.rs +++ b/rust/lib/mammoth/build.rs @@ -15,4 +15,11 @@ fn main() { curr_directory.to_str().unwrap() ); println!("cargo:rustc-link-lib=zion_stub"); + + // Trying to recreate bindings? + // Run the following commands + // gcc -E zion/include/zcall.h > /tmp/expanded.h + // bindgen --verbose --use-core --no-layout-tests /tmp/expanded.h -o rust/lib/mammoth/src/bindings.rs -- -x c++ + // + // Then go fix the ThreadExit struct. } diff --git a/rust/lib/mammoth/src/bindings.rs b/rust/lib/mammoth/src/bindings.rs index c26dba3..1db1f3a 100644 --- a/rust/lib/mammoth/src/bindings.rs +++ b/rust/lib/mammoth/src/bindings.rs @@ -1,153 +1,5 @@ /* automatically generated by rust-bindgen 0.69.4 */ -pub const _STDINT_H: u32 = 1; -pub const _FEATURES_H: u32 = 1; -pub const _ISOC95_SOURCE: u32 = 1; -pub const _ISOC99_SOURCE: u32 = 1; -pub const _ISOC11_SOURCE: u32 = 1; -pub const _ISOC2X_SOURCE: u32 = 1; -pub const _POSIX_SOURCE: u32 = 1; -pub const _POSIX_C_SOURCE: u32 = 200809; -pub const _XOPEN_SOURCE: u32 = 700; -pub const _XOPEN_SOURCE_EXTENDED: u32 = 1; -pub const _LARGEFILE64_SOURCE: u32 = 1; -pub const _DEFAULT_SOURCE: u32 = 1; -pub const _ATFILE_SOURCE: u32 = 1; -pub const _DYNAMIC_STACK_SIZE_SOURCE: u32 = 1; -pub const __GLIBC_USE_ISOC2X: u32 = 1; -pub const __USE_ISOC11: u32 = 1; -pub const __USE_ISOC99: u32 = 1; -pub const __USE_ISOC95: u32 = 1; -pub const __USE_ISOCXX11: u32 = 1; -pub const __USE_POSIX: u32 = 1; -pub const __USE_POSIX2: u32 = 1; -pub const __USE_POSIX199309: u32 = 1; -pub const __USE_POSIX199506: u32 = 1; -pub const __USE_XOPEN2K: u32 = 1; -pub const __USE_XOPEN2K8: u32 = 1; -pub const __USE_XOPEN: u32 = 1; -pub const __USE_XOPEN_EXTENDED: u32 = 1; -pub const __USE_UNIX98: u32 = 1; -pub const _LARGEFILE_SOURCE: u32 = 1; -pub const __USE_XOPEN2K8XSI: u32 = 1; -pub const __USE_XOPEN2KXSI: u32 = 1; -pub const __USE_LARGEFILE: u32 = 1; -pub const __USE_LARGEFILE64: u32 = 1; -pub const __WORDSIZE: u32 = 64; -pub const __WORDSIZE_TIME64_COMPAT32: u32 = 1; -pub const __SYSCALL_WORDSIZE: u32 = 64; -pub const __TIMESIZE: u32 = 64; -pub const __USE_MISC: u32 = 1; -pub const __USE_ATFILE: u32 = 1; -pub const __USE_DYNAMIC_STACK_SIZE: u32 = 1; -pub const __USE_GNU: u32 = 1; -pub const __USE_FORTIFY_LEVEL: u32 = 0; -pub const __GLIBC_USE_DEPRECATED_GETS: u32 = 0; -pub const __GLIBC_USE_DEPRECATED_SCANF: u32 = 0; -pub const __GLIBC_USE_C2X_STRTOL: u32 = 1; -pub const _STDC_PREDEF_H: u32 = 1; -pub const __STDC_IEC_559__: u32 = 1; -pub const __STDC_IEC_60559_BFP__: u32 = 201404; -pub const __STDC_IEC_559_COMPLEX__: u32 = 1; -pub const __STDC_IEC_60559_COMPLEX__: u32 = 201404; -pub const __STDC_ISO_10646__: u32 = 201706; -pub const __GNU_LIBRARY__: u32 = 6; -pub const __GLIBC__: u32 = 2; -pub const __GLIBC_MINOR__: u32 = 39; -pub const _SYS_CDEFS_H: u32 = 1; -pub const __glibc_c99_flexarr_available: u32 = 1; -pub const __LDOUBLE_REDIRECTS_TO_FLOAT128_ABI: u32 = 0; -pub const __HAVE_GENERIC_SELECTION: u32 = 0; -pub const __GLIBC_USE_LIB_EXT2: u32 = 1; -pub const __GLIBC_USE_IEC_60559_BFP_EXT: u32 = 1; -pub const __GLIBC_USE_IEC_60559_BFP_EXT_C2X: u32 = 1; -pub const __GLIBC_USE_IEC_60559_EXT: u32 = 1; -pub const __GLIBC_USE_IEC_60559_FUNCS_EXT: u32 = 1; -pub const __GLIBC_USE_IEC_60559_FUNCS_EXT_C2X: u32 = 1; -pub const __GLIBC_USE_IEC_60559_TYPES_EXT: u32 = 1; -pub const _BITS_TYPES_H: u32 = 1; -pub const _BITS_TYPESIZES_H: u32 = 1; -pub const __OFF_T_MATCHES_OFF64_T: u32 = 1; -pub const __INO_T_MATCHES_INO64_T: u32 = 1; -pub const __RLIM_T_MATCHES_RLIM64_T: u32 = 1; -pub const __STATFS_MATCHES_STATFS64: u32 = 1; -pub const __KERNEL_OLD_TIMEVAL_MATCHES_TIMEVAL64: u32 = 1; -pub const __FD_SETSIZE: u32 = 1024; -pub const _BITS_TIME64_H: u32 = 1; -pub const _BITS_WCHAR_H: u32 = 1; -pub const _BITS_STDINT_INTN_H: u32 = 1; -pub const _BITS_STDINT_UINTN_H: u32 = 1; -pub const _BITS_STDINT_LEAST_H: u32 = 1; -pub const INT8_MIN: i32 = -128; -pub const INT16_MIN: i32 = -32768; -pub const INT32_MIN: i32 = -2147483648; -pub const INT8_MAX: u32 = 127; -pub const INT16_MAX: u32 = 32767; -pub const INT32_MAX: u32 = 2147483647; -pub const UINT8_MAX: u32 = 255; -pub const UINT16_MAX: u32 = 65535; -pub const UINT32_MAX: u32 = 4294967295; -pub const INT_LEAST8_MIN: i32 = -128; -pub const INT_LEAST16_MIN: i32 = -32768; -pub const INT_LEAST32_MIN: i32 = -2147483648; -pub const INT_LEAST8_MAX: u32 = 127; -pub const INT_LEAST16_MAX: u32 = 32767; -pub const INT_LEAST32_MAX: u32 = 2147483647; -pub const UINT_LEAST8_MAX: u32 = 255; -pub const UINT_LEAST16_MAX: u32 = 65535; -pub const UINT_LEAST32_MAX: u32 = 4294967295; -pub const INT_FAST8_MIN: i32 = -128; -pub const INT_FAST16_MIN: i64 = -9223372036854775808; -pub const INT_FAST32_MIN: i64 = -9223372036854775808; -pub const INT_FAST8_MAX: u32 = 127; -pub const INT_FAST16_MAX: u64 = 9223372036854775807; -pub const INT_FAST32_MAX: u64 = 9223372036854775807; -pub const UINT_FAST8_MAX: u32 = 255; -pub const UINT_FAST16_MAX: i32 = -1; -pub const UINT_FAST32_MAX: i32 = -1; -pub const INTPTR_MIN: i64 = -9223372036854775808; -pub const INTPTR_MAX: u64 = 9223372036854775807; -pub const UINTPTR_MAX: i32 = -1; -pub const PTRDIFF_MIN: i64 = -9223372036854775808; -pub const PTRDIFF_MAX: u64 = 9223372036854775807; -pub const SIG_ATOMIC_MIN: i32 = -2147483648; -pub const SIG_ATOMIC_MAX: u32 = 2147483647; -pub const SIZE_MAX: i32 = -1; -pub const WINT_MIN: u32 = 0; -pub const WINT_MAX: u32 = 4294967295; -pub const INT8_WIDTH: u32 = 8; -pub const UINT8_WIDTH: u32 = 8; -pub const INT16_WIDTH: u32 = 16; -pub const UINT16_WIDTH: u32 = 16; -pub const INT32_WIDTH: u32 = 32; -pub const UINT32_WIDTH: u32 = 32; -pub const INT64_WIDTH: u32 = 64; -pub const UINT64_WIDTH: u32 = 64; -pub const INT_LEAST8_WIDTH: u32 = 8; -pub const UINT_LEAST8_WIDTH: u32 = 8; -pub const INT_LEAST16_WIDTH: u32 = 16; -pub const UINT_LEAST16_WIDTH: u32 = 16; -pub const INT_LEAST32_WIDTH: u32 = 32; -pub const UINT_LEAST32_WIDTH: u32 = 32; -pub const INT_LEAST64_WIDTH: u32 = 64; -pub const UINT_LEAST64_WIDTH: u32 = 64; -pub const INT_FAST8_WIDTH: u32 = 8; -pub const UINT_FAST8_WIDTH: u32 = 8; -pub const INT_FAST16_WIDTH: u32 = 64; -pub const UINT_FAST16_WIDTH: u32 = 64; -pub const INT_FAST32_WIDTH: u32 = 64; -pub const UINT_FAST32_WIDTH: u32 = 64; -pub const INT_FAST64_WIDTH: u32 = 64; -pub const UINT_FAST64_WIDTH: u32 = 64; -pub const INTPTR_WIDTH: u32 = 64; -pub const UINTPTR_WIDTH: u32 = 64; -pub const INTMAX_WIDTH: u32 = 64; -pub const UINTMAX_WIDTH: u32 = 64; -pub const PTRDIFF_WIDTH: u32 = 64; -pub const SIG_ATOMIC_WIDTH: u32 = 32; -pub const SIZE_WIDTH: u32 = 64; -pub const WCHAR_WIDTH: u32 = 32; -pub const WINT_WIDTH: u32 = 32; pub type __u_char = ::core::ffi::c_uchar; pub type __u_short = ::core::ffi::c_ushort; pub type __u_int = ::core::ffi::c_uint; @@ -257,7 +109,6 @@ pub const kZionPortCreate: u64 = 80; pub const kZionPortSend: u64 = 81; pub const kZionPortRecv: u64 = 82; pub const kZionPortPoll: u64 = 83; -pub const kZionIrqRegister: u64 = 88; pub const kZionMsiIrqRegister: u64 = 89; pub const kZionEndpointCreate: u64 = 96; pub const kZionEndpointSend: u64 = 97; @@ -274,6 +125,10 @@ pub const kZionSemaphoreCreate: u64 = 131; pub const kZionSemaphoreWait: u64 = 132; pub const kZionSemaphoreSignal: u64 = 133; pub const kZionDebug: u64 = 65536; +pub const kZionPciRead: u64 = 69632; +pub const kZionPciCreateBound: u64 = 69633; +pub const kZionPciReadBound: u64 = 69634; +pub const kZionPciWriteBound: u64 = 69635; pub const kZIrqKbd: u64 = 34; pub const kZIrqPci1: u64 = 48; pub const kZIrqPci2: u64 = 49; @@ -351,10 +206,6 @@ pub struct ZThreadStartReq { #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct ZThreadExitReq {} -extern "C" { - #[link_name = "\u{1}_Z11ZThreadExitv"] - pub fn ZThreadExit() -> z_err_t; -} #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct ZThreadWaitReq { @@ -473,12 +324,6 @@ pub struct ZPortPollReq { } #[repr(C)] #[derive(Debug, Copy, Clone)] -pub struct ZIrqRegisterReq { - pub irq_num: u64, - pub port_cap: *mut z_cap_t, -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] pub struct ZMsiIrqRegisterReq { pub irq_num: *mut u64, pub port_cap: *mut z_cap_t, @@ -574,3 +419,36 @@ pub struct ZDebugReq { pub message: *const ::core::ffi::c_char, pub size: u64, } +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct ZPciReadReq { + pub pci_cap: z_cap_t, + pub bus: u8, + pub slot: u8, + pub func: u8, + pub offset: u8, + pub output: *mut u32, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct ZPciCreateBoundReq { + pub pci_cap: z_cap_t, + pub bus: u8, + pub slot: u8, + pub func: u8, + pub new_cap: *mut z_cap_t, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct ZPciReadBoundReq { + pub pci_cap: z_cap_t, + pub offset: u8, + pub data: *mut u32, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct ZPciWriteBoundReq { + pub pci_cap: z_cap_t, + pub offset: u8, + pub data: u32, +} diff --git a/rust/lib/mammoth/src/syscall.rs b/rust/lib/mammoth/src/syscall.rs index 2691458..21833f2 100644 --- a/rust/lib/mammoth/src/syscall.rs +++ b/rust/lib/mammoth/src/syscall.rs @@ -472,3 +472,25 @@ pub fn semaphone_wait(sem_cap: &Capability) -> Result<(), ZError> { }, ) } + +pub fn pci_read( + pci_cap: &Capability, + bus: u8, + slot: u8, + func: u8, + offset: u8, +) -> Result { + let mut data: u32 = 0; + syscall( + zion::kZionPciRead, + &zion::ZPciReadReq { + pci_cap: pci_cap.raw(), + bus, + slot, + func, + offset, + output: &mut data as *mut u32, + }, + )?; + Ok(data) +} diff --git a/rust/sys/yellowstone/src/main.rs b/rust/sys/yellowstone/src/main.rs index dbe8c2e..fa3dda1 100644 --- a/rust/sys/yellowstone/src/main.rs +++ b/rust/sys/yellowstone/src/main.rs @@ -36,13 +36,14 @@ 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 fb_region = MemoryRegion::from_cap(Capability::take(unsafe { BOOT_FRAMEBUFFER_INFO_VMMO })) .expect("Failed to create Framebuffer region"); let context = Arc::new( - server::YellowstoneServerContext::new(pci_region, fb_region) - .expect("Failed to create yellowstone context"), + server::YellowstoneServerContext::new( + Capability::take(unsafe { BOOT_PCI_VMMO }), + fb_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 index e421f74..1520b2e 100644 --- a/rust/sys/yellowstone/src/pci.rs +++ b/rust/sys/yellowstone/src/pci.rs @@ -1,14 +1,29 @@ -use mammoth::{cap::Capability, mem::MemoryRegion, zion::ZError}; +use mammoth::{ + cap::Capability, + mem::MemoryRegion, + syscall, + zion::{kZionPerm_All, ZError}, +}; + +enum PciType { + Port(Capability), + Memory(MemoryRegion), +} pub struct PciReader { - memory_region: MemoryRegion, + internal_type: PciType, } type DevPredicate = fn(u8, u8, u8) -> bool; impl PciReader { - pub fn new(memory_region: MemoryRegion) -> Self { - Self { memory_region } + pub fn new(capability: Capability) -> Self { + let internal_type = + match MemoryRegion::from_cap(capability.duplicate(kZionPerm_All).unwrap()) { + Ok(mem) => PciType::Memory(mem), + Err(_) => PciType::Port(capability), + }; + Self { internal_type } } pub fn get_ahci_region(&self) -> Result { @@ -28,15 +43,13 @@ impl PciReader { } fn probe_pci(&self, pred: DevPredicate) -> Option { - let base_header = self.pci_header(0, 0, 0); - if (base_header.header_type & 0x80) == 0 { + if (self.header_type(0, 0, 0) & 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 self.vendor_id(0, 0, fun) != 0xFFFF { if let Some(dev) = self.probe_bus(pred, fun) { return Some(dev); } @@ -56,8 +69,7 @@ impl PciReader { } 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 { + if self.vendor_id(bus, dev, 0) == 0xFFFF { return None; } @@ -65,7 +77,7 @@ impl PciReader { return Some(dev); } - if (device_base_header.header_type & 0x80) != 0 { + if (self.header_type(bus, dev, 0) & 0x80) != 0 { for fun in 1..8 { if let Some(dev) = self.probe_function(pred, bus, dev, fun) { return Some(dev); @@ -76,37 +88,66 @@ impl PciReader { } fn probe_function(&self, pred: DevPredicate, bus: u8, dev: u8, fun: u8) -> Option { - let function_header = self.pci_header(bus, dev, fun); + let (class, subclass, prog_interface) = self.class_codes(bus, dev, fun); mammoth::debug!( "PCI Function: {:#x} {:#x} {:#x}", - function_header.class_code, - function_header.subclass, - function_header.prog_interface + class, + subclass, + prog_interface ); - if pred( - function_header.class_code, - function_header.subclass, - function_header.prog_interface, - ) { + if pred(class, subclass, 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"), - ) + Some(self.create_cap(bus, dev, fun)) } 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() } + fn header_type(&self, bus: u8, dev: u8, fun: u8) -> u8 { + let data = self.read_at(bus, dev, fun, 0xC); + + ((data >> 16) & 0xFF) as u8 + } + + fn vendor_id(&self, bus: u8, dev: u8, fun: u8) -> u16 { + let data = self.read_at(bus, dev, fun, 0); + + (data & 0xFFFF) as u16 + } + + fn class_codes(&self, bus: u8, dev: u8, fun: u8) -> (u8, u8, u8) { + let data = self.read_at(bus, dev, fun, 0x8); + + let class = (data >> 24) as u8; + let subclass = ((data >> 16) & 0xFF) as u8; + let prog_if = ((data >> 8) & 0xFF) as u8; + + (class, subclass, prog_if) + } + + fn read_at(&self, bus: u8, dev: u8, fun: u8, off: u8) -> u32 { + match &self.internal_type { + PciType::Memory(region) => { + let offset = pci_header_offset(bus, dev, fun); + let header_slice: &[u32] = ®ion.slice()[offset..offset + size_of::()]; + header_slice[(off >> 2) as usize] + } + PciType::Port(pci_cap) => syscall::pci_read(pci_cap, bus, dev, fun, off).unwrap(), + } + } + + fn create_cap(&self, bus: u8, dev: u8, fun: u8) -> Capability { + match &self.internal_type { + PciType::Memory(region) => { + let offset = pci_header_offset(bus, dev, fun); + region + .duplicate(offset as u64, 0x1000) + .expect("Failed to duplicate PCI cap") + } + PciType::Port(_pci_cap) => todo!(), + } } } diff --git a/rust/sys/yellowstone/src/server.rs b/rust/sys/yellowstone/src/server.rs index 8cc4a4b..d2f1327 100644 --- a/rust/sys/yellowstone/src/server.rs +++ b/rust/sys/yellowstone/src/server.rs @@ -43,13 +43,11 @@ impl YellowstoneServerContext { green_mask_shift: fb_info.green_mask_shift as u64, } } -} -impl YellowstoneServerContext { - pub fn new(pci_region: MemoryRegion, fb_region: MemoryRegion) -> Result { + pub fn new(pci_cap: Capability, fb_region: MemoryRegion) -> Result { Ok(Self { registration_semaphore: mammoth::sync::Semaphore::new()?, - pci_reader: PciReader::new(pci_region), + pci_reader: PciReader::new(pci_cap), framebuffer_info_region: fb_region, service_map: Mutex::new(BTreeMap::new()), }) diff --git a/zion/CMakeLists.txt b/zion/CMakeLists.txt index 598a3de..a485758 100644 --- a/zion/CMakeLists.txt +++ b/zion/CMakeLists.txt @@ -30,6 +30,7 @@ add_executable(zion object/ipc_object.cpp object/memory_object.cpp object/mutex.cpp + object/pci_port.cpp object/port.cpp object/process.cpp object/reply_port.cpp @@ -45,6 +46,7 @@ add_executable(zion syscall/debug.cpp syscall/ipc.cpp syscall/memory_object.cpp + syscall/pci.cpp syscall/process.cpp syscall/synchronization.cpp syscall/syscall.cpp diff --git a/zion/common/port.h b/zion/common/port.h index 4919ff4..c3cfaea 100644 --- a/zion/common/port.h +++ b/zion/common/port.h @@ -11,3 +11,13 @@ static inline uint8_t inb(uint16_t port) { static inline void outb(uint16_t port, uint8_t value) { asm volatile("outb %0, %1" ::"a"(value), "Nd"(port)); } + +static inline uint32_t inl(uint16_t port) { + uint32_t result; + asm volatile("inl %1, %0" : "=a"(result) : "Nd"(port)); + return result; +} + +static inline void outl(uint16_t port, uint32_t value) { + asm volatile("outl %0, %1" ::"a"(value), "Nd"(port)); +} diff --git a/zion/include/zcall.h b/zion/include/zcall.h index 6092037..26b69dd 100644 --- a/zion/include/zcall.h +++ b/zion/include/zcall.h @@ -71,3 +71,14 @@ SYS1(SemaphoreWait, z_cap_t, semaphore_cap); SYS1(SemaphoreSignal, z_cap_t, semaphore_cap); SYS2(Debug, const char*, message, uint64_t, size); + +// TODO: These should be handled with a more generic user-space interface. +// To be honest we could just have an inl and outl interface that is provided to +// yellowstone and the extra ipc load would be a good stress test of our +// performance +SYS6(PciRead, z_cap_t, pci_cap, uint8_t, bus, uint8_t, slot, uint8_t, func, + uint8_t, offset, uint32_t*, output); +SYS5(PciCreateBound, z_cap_t, pci_cap, uint8_t, bus, uint8_t, slot, uint8_t, + func, z_cap_t*, new_cap); +SYS3(PciReadBound, z_cap_t, pci_cap, uint8_t, offset, uint32_t*, data); +SYS3(PciWriteBound, z_cap_t, pci_cap, uint8_t, offset, uint32_t, data); diff --git a/zion/include/ztypes.h b/zion/include/ztypes.h index b60db9c..046966e 100644 --- a/zion/include/ztypes.h +++ b/zion/include/ztypes.h @@ -67,6 +67,11 @@ const uint64_t kZionSemaphoreSignal = 0x85; // Debugging Calls. const uint64_t kZionDebug = 0x1'0000; +const uint64_t kZionPciRead = 0x1'1000; +const uint64_t kZionPciCreateBound = 0x1'1001; +const uint64_t kZionPciReadBound = 0x1'1002; +const uint64_t kZionPciWriteBound = 0x1'1003; + // Irq Types const uint64_t kZIrqKbd = 0x22; const uint64_t kZIrqPci1 = 0x30; diff --git a/zion/loader/init_loader.cpp b/zion/loader/init_loader.cpp index b05c70a..8926880 100644 --- a/zion/loader/init_loader.cpp +++ b/zion/loader/init_loader.cpp @@ -8,6 +8,7 @@ #include "debug/debug.h" #include "include/zcall.h" #include "memory/paging_util.h" +#include "object/pci_port.h" #include "object/process.h" #include "object/thread.h" #include "scheduler/process_manager.h" @@ -187,7 +188,9 @@ void LoadInitProgram() { WriteFramebufferVmmo(port); if (WritePciVmmo(port, Z_BOOT_PCI_VMMO) != glcr::OK) { - panic("Failed to provide PCI info to init."); + dbgln("Failed to find PCIe space, creating PCI IO Port Cap"); + auto pci_port = PciPort::Create(); + port->WriteKernel(Z_BOOT_PCI_VMMO, MakeRefCounted(pci_port)); } // Start process. diff --git a/zion/object/kernel_object.h b/zion/object/kernel_object.h index 2bdd477..ced8ba9 100644 --- a/zion/object/kernel_object.h +++ b/zion/object/kernel_object.h @@ -16,6 +16,10 @@ class KernelObject : public glcr::RefCounted { REPLY_PORT = 0x8, MUTEX = 0x9, SEMAPHORE = 0x10, + + // Temporary. + PCI_CAP = 0x100, + PCI_BOUND_CAP = 0x101, }; virtual uint64_t TypeTag() = 0; diff --git a/zion/object/pci_port.cpp b/zion/object/pci_port.cpp new file mode 100644 index 0000000..1daef76 --- /dev/null +++ b/zion/object/pci_port.cpp @@ -0,0 +1,46 @@ +#include "object/pci_port.h" + +#include "common/port.h" + +namespace { + +const uint16_t PCI_ADDR_PORT = 0xCF8; +const uint16_t PCI_DATA_PORT = 0xCFC; + +uint32_t AddressOf(uint8_t bus, uint8_t slot, uint8_t func, uint8_t offset) { + uint32_t lbus = (uint32_t)bus; + uint32_t lslot = (uint32_t)slot; + uint32_t lfunc = (uint32_t)func; + + return (uint32_t)((lbus << 16) | (lslot << 11) | (lfunc << 8) | + (offset & 0xFC) | ((uint32_t)0x80000000)); +} + +uint32_t PciReadAtOffset(uint8_t bus, uint8_t slot, uint8_t func, + uint8_t offset) { + uint32_t address = AddressOf(bus, slot, func, offset); + outl(PCI_ADDR_PORT, address); + return inl(PCI_DATA_PORT); +} + +void PciWriteAtOffset(uint8_t bus, uint8_t slot, uint8_t func, uint8_t offset, + uint32_t word) { + uint32_t address = AddressOf(bus, slot, func, offset); + outl(PCI_ADDR_PORT, address); + outl(PCI_DATA_PORT, word); +} + +} // namespace + +uint32_t PciPort::ReadAtOffset(uint8_t bus, uint8_t slot, uint8_t func, + uint8_t offset) { + return PciReadAtOffset(bus, slot, func, offset); +} + +uint32_t PciPortBound::Read(uint8_t offset) { + return PciReadAtOffset(bus_, slot_, func_, offset); +} + +void PciPortBound::Write(uint8_t offset, uint32_t data) { + PciWriteAtOffset(bus_, slot_, func_, offset, data); +} diff --git a/zion/object/pci_port.h b/zion/object/pci_port.h new file mode 100644 index 0000000..6287f31 --- /dev/null +++ b/zion/object/pci_port.h @@ -0,0 +1,60 @@ +#include + +#include "include/ztypes.h" +#include "object/kernel_object.h" + +class PciPort; +class PciPortBound; + +template <> +struct KernelObjectTag { + static const uint64_t type = KernelObject::PCI_CAP; +}; + +class PciPort : public KernelObject { + public: + static uint64_t DefaultPermissions() { + return kZionPerm_Write | kZionPerm_Read | kZionPerm_Duplicate | + kZionPerm_Transmit; + } + + uint64_t TypeTag() override { return KernelObject::PCI_CAP; } + + static glcr::RefPtr Create() { return glcr::AdoptPtr(new PciPort); } + + uint32_t ReadAtOffset(uint8_t bus, uint8_t slot, uint8_t func, + uint8_t offset); + + private: + PciPort() {} +}; + +template <> +struct KernelObjectTag { + static const uint64_t type = KernelObject::PCI_BOUND_CAP; +}; + +class PciPortBound : public KernelObject { + public: + static uint64_t DefaultPermissions() { + return kZionPerm_Write | kZionPerm_Read | kZionPerm_Duplicate; + } + + uint64_t TypeTag() override { return KernelObject::PCI_BOUND_CAP; } + + static glcr::RefPtr Create(uint8_t bus, uint8_t slot, + uint8_t func) { + return glcr::AdoptPtr(new PciPortBound(bus, slot, func)); + } + + uint32_t Read(uint8_t offset); + void Write(uint8_t offset, uint32_t data); + + private: + PciPortBound(uint8_t bus, uint8_t slot, uint8_t func) + : bus_(bus), slot_(slot), func_(func) {} + + uint8_t bus_; + uint8_t slot_; + uint8_t func_; +}; diff --git a/zion/syscall/pci.cpp b/zion/syscall/pci.cpp new file mode 100644 index 0000000..1a1c7bc --- /dev/null +++ b/zion/syscall/pci.cpp @@ -0,0 +1,44 @@ +#include "syscall/pci.h" + +#include "object/pci_port.h" +#include "scheduler/scheduler.h" + +z_err_t PciRead(ZPciReadReq* req) { + auto& curr_proc = gScheduler->CurrentProcess(); + auto pci_cap = curr_proc.GetCapability(req->pci_cap); + RET_ERR(ValidateCapability(pci_cap, kZionPerm_Read)); + + *req->output = pci_cap->obj()->ReadAtOffset(req->bus, req->slot, + req->func, req->offset); + + return glcr::OK; +} + +z_err_t PciCreateBound(ZPciCreateBoundReq* req) { + auto& curr_proc = gScheduler->CurrentProcess(); + auto pci_cap = curr_proc.GetCapability(req->pci_cap); + RET_ERR(ValidateCapability(pci_cap, kZionPerm_Duplicate)); + + *req->new_cap = curr_proc.AddNewCapability( + PciPortBound::Create(req->bus, req->slot, req->func)); + return glcr::OK; +} + +z_err_t PciReadBound(ZPciReadBoundReq* req) { + auto& curr_proc = gScheduler->CurrentProcess(); + auto pci_cap = curr_proc.GetCapability(req->pci_cap); + RET_ERR(ValidateCapability(pci_cap, kZionPerm_Read)); + + *req->data = pci_cap->obj()->Read(req->offset); + + return glcr::OK; +} +z_err_t PciWriteBound(ZPciWriteBoundReq* req) { + auto& curr_proc = gScheduler->CurrentProcess(); + auto pci_cap = curr_proc.GetCapability(req->pci_cap); + RET_ERR(ValidateCapability(pci_cap, kZionPerm_Write)); + + pci_cap->obj()->Write(req->offset, req->data); + + return glcr::OK; +} diff --git a/zion/syscall/pci.h b/zion/syscall/pci.h new file mode 100644 index 0000000..f31680b --- /dev/null +++ b/zion/syscall/pci.h @@ -0,0 +1,6 @@ +#include "include/zcall.h" + +z_err_t PciRead(ZPciReadReq* req); +z_err_t PciCreateBound(ZPciCreateBoundReq* req); +z_err_t PciReadBound(ZPciReadBoundReq* req); +z_err_t PciWriteBound(ZPciWriteBoundReq* req);