Compare commits
2 Commits
dc801786b1
...
f26fd73116
Author | SHA1 | Date |
---|---|---|
|
f26fd73116 | |
|
c645405ca8 |
|
@ -17,7 +17,6 @@ target_include_directories(mammoth
|
|||
|
||||
target_link_libraries(mammoth
|
||||
glacier
|
||||
victoriafalls_yunq
|
||||
yellowstone_yunq
|
||||
voyageurs_yunq
|
||||
zion_stub
|
||||
|
|
|
@ -34,6 +34,7 @@ version = "0.1.0"
|
|||
dependencies = [
|
||||
"bitfield-struct",
|
||||
"mammoth",
|
||||
"pci",
|
||||
"yellowstone-yunq",
|
||||
"yunq",
|
||||
"yunqc",
|
||||
|
@ -83,6 +84,14 @@ dependencies = [
|
|||
"linked_list_allocator",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pci"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bitfield-struct",
|
||||
"mammoth",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "prettyplease"
|
||||
version = "0.2.20"
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
members = [
|
||||
"lib/client/denali_client", "lib/fs/ext2",
|
||||
"lib/mammoth",
|
||||
"lib/mammoth", "lib/pci",
|
||||
"lib/voyageurs",
|
||||
"lib/yellowstone",
|
||||
"lib/yunq",
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use std::fs;
|
||||
|
||||
fn main() {
|
||||
let input_file = "../../../../sys/denali/lib/denali/denali.yunq";
|
||||
let input_file = "../../../sys/denali/denali.yunq";
|
||||
|
||||
println!("cargo::rerun-if-changed={input_file}");
|
||||
|
||||
|
|
|
@ -258,6 +258,7 @@ 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;
|
||||
pub const kZionEndpointRecv: u64 = 98;
|
||||
|
@ -478,6 +479,12 @@ pub struct ZIrqRegisterReq {
|
|||
}
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct ZMsiIrqRegisterReq {
|
||||
pub irq_num: *mut u64,
|
||||
pub port_cap: *mut z_cap_t,
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct ZEndpointCreateReq {
|
||||
pub endpoint_cap: *mut z_cap_t,
|
||||
}
|
||||
|
|
|
@ -120,6 +120,12 @@ impl<T> AsRef<T> for MemoryRegion {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T> AsMut<T> for MemoryRegion {
|
||||
fn as_mut(&mut self) -> &mut T {
|
||||
unsafe { (self.virt_addr as *mut T).as_mut().unwrap() }
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for MemoryRegion {
|
||||
fn drop(&mut self) {
|
||||
// FIXME: We shouldn't have to do this manual adjustment.
|
||||
|
|
|
@ -310,16 +310,17 @@ pub fn port_poll(
|
|||
Ok((num_bytes, num_caps))
|
||||
}
|
||||
|
||||
pub fn register_irq(irq_num: u64) -> Result<Capability, ZError> {
|
||||
pub fn register_msi_irq() -> Result<(Capability, u64), ZError> {
|
||||
let mut irq_num: u64 = 0;
|
||||
let mut port_cap: z_cap_t = 0;
|
||||
syscall(
|
||||
zion::kZionIrqRegister,
|
||||
&zion::ZIrqRegisterReq {
|
||||
irq_num,
|
||||
zion::kZionMsiIrqRegister,
|
||||
&zion::ZMsiIrqRegisterReq {
|
||||
irq_num: &mut irq_num as *mut u64,
|
||||
port_cap: &mut port_cap,
|
||||
},
|
||||
)?;
|
||||
Ok(Capability::take(port_cap))
|
||||
Ok((Capability::take(port_cap), irq_num))
|
||||
}
|
||||
|
||||
pub fn endpoint_create() -> Result<Capability, ZError> {
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
[package]
|
||||
name = "pci"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
bitfield-struct = "0.8.0"
|
||||
mammoth = {path = "../mammoth/"}
|
|
@ -0,0 +1,89 @@
|
|||
use alloc::vec::Vec;
|
||||
use mammoth::{cap::Capability, mem::MemoryRegion, syscall, zion::ZError};
|
||||
|
||||
use crate::header::{
|
||||
PciCapabilityPointer, PciDeviceHeader, PciHeaderType, PciMsiCapability, PciMsiControl,
|
||||
get_header_type,
|
||||
};
|
||||
|
||||
pub struct PciDevice {
|
||||
memory_region: MemoryRegion,
|
||||
}
|
||||
|
||||
impl PciDevice {
|
||||
pub fn from(mut memory_region: MemoryRegion) -> Result<Self, ZError> {
|
||||
match get_header_type(&memory_region)? {
|
||||
PciHeaderType::Device => {}
|
||||
t => {
|
||||
mammoth::debug!("Invalid header type: {:?}", t);
|
||||
return Err(ZError::INVALID_ARGUMENT);
|
||||
}
|
||||
}
|
||||
Ok(Self { memory_region })
|
||||
}
|
||||
|
||||
pub fn from_cap(capability: Capability) -> Result<Self, ZError> {
|
||||
Self::from(MemoryRegion::from_cap(capability)?)
|
||||
}
|
||||
|
||||
pub fn header(&self) -> &PciDeviceHeader {
|
||||
self.memory_region.as_ref()
|
||||
}
|
||||
|
||||
pub fn get_capability_list(&self) -> Result<Vec<&PciCapabilityPointer>, ZError> {
|
||||
let status = self.header().status;
|
||||
if !status.capability_list() {
|
||||
return Err(ZError::NOT_FOUND);
|
||||
}
|
||||
|
||||
let mut cap_offset = self.header().capability_ptr;
|
||||
|
||||
let mut cap_vec = Vec::new();
|
||||
while cap_offset != 0 {
|
||||
let cap_ptr: &PciCapabilityPointer = unsafe {
|
||||
self.memory_region
|
||||
.raw_ptr_at_offset::<PciCapabilityPointer>(cap_offset as u64)
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
};
|
||||
cap_vec.push(cap_ptr);
|
||||
cap_offset = cap_ptr.next_cap_offset;
|
||||
}
|
||||
|
||||
Ok(cap_vec)
|
||||
}
|
||||
|
||||
pub fn register_msi(&mut self) -> Result<Capability, ZError> {
|
||||
let caps = self.get_capability_list()?;
|
||||
const MSI_CAP_ID: u8 = 0x05;
|
||||
let msi_cap: &PciCapabilityPointer = caps
|
||||
.iter()
|
||||
.find(|cp| cp.cap_id == MSI_CAP_ID)
|
||||
.ok_or(ZError::NOT_FOUND)?;
|
||||
|
||||
let msi_cap = unsafe {
|
||||
((msi_cap as *const PciCapabilityPointer) as *mut PciMsiCapability)
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
};
|
||||
|
||||
mammoth::debug!("MSI Cap: {:#x?}", msi_cap);
|
||||
|
||||
let control = msi_cap.msi_control;
|
||||
assert!(control.capable_address_64());
|
||||
assert!(control.multi_message_capable() == 0);
|
||||
|
||||
// FIXME: These probably need to be volatile writes.
|
||||
let header: &mut PciDeviceHeader = self.memory_region.as_mut();
|
||||
header.command = header.command.with_interrupt_disable(true);
|
||||
msi_cap.msi_control = control.with_msi_enable(true);
|
||||
msi_cap.msi_addr_lower = 0xFEE00000;
|
||||
msi_cap.msi_addr_upper_or_data = 0x0;
|
||||
|
||||
let (cap, irq_num) = syscall::register_msi_irq()?;
|
||||
|
||||
msi_cap.msi_data_if_64 = irq_num as u32;
|
||||
|
||||
Ok(cap)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,180 @@
|
|||
use bitfield_struct::bitfield;
|
||||
use mammoth::{mem::MemoryRegion, zion::ZError};
|
||||
|
||||
#[bitfield(u16)]
|
||||
pub struct PciCommand {
|
||||
io_space_enable: bool,
|
||||
memory_space_enable: bool,
|
||||
bus_master_enable: bool,
|
||||
|
||||
#[bits(access=RO)]
|
||||
special_cycles_enable: bool,
|
||||
|
||||
#[bits(access=RO)]
|
||||
memory_write_and_invalidate_enable: bool,
|
||||
|
||||
#[bits(access=RO)]
|
||||
vga_pallette_snoop_enable: bool,
|
||||
|
||||
parity_error_response_enable: bool,
|
||||
|
||||
#[bits(access=RO)]
|
||||
wait_cycle_enable: bool,
|
||||
|
||||
serr_enable: bool,
|
||||
|
||||
fast_back_to_back_enable: bool,
|
||||
|
||||
/// Parity is reversed here, set to true to disable.
|
||||
/// Does not affect MSI.
|
||||
pub interrupt_disable: bool,
|
||||
|
||||
#[bits(5)]
|
||||
__: u8,
|
||||
}
|
||||
|
||||
#[bitfield(u16)]
|
||||
pub struct PciStatus {
|
||||
#[bits(3)]
|
||||
__: u8,
|
||||
|
||||
#[bits(access=RO)]
|
||||
pub interrupt_status: bool,
|
||||
#[bits(access=RO)]
|
||||
pub capability_list: bool,
|
||||
#[bits(access=RO)]
|
||||
pub capable_of_66mhz: bool,
|
||||
|
||||
___: bool,
|
||||
|
||||
#[bits(access=RO)]
|
||||
pub fast_back_to_back_capabale: bool,
|
||||
|
||||
/// Write 1 to clear
|
||||
pub master_data_parity_error: bool,
|
||||
|
||||
#[bits(2, access=RO)]
|
||||
pub devsel_timing: u8,
|
||||
|
||||
/// Write 1 to clear
|
||||
pub signaled_target_abort: bool,
|
||||
/// Write 1 to clear
|
||||
pub received_target_abort: bool,
|
||||
/// Write 1 to clear
|
||||
pub received_master_abort: bool,
|
||||
/// Write 1 to clear
|
||||
pub signaled_system_erro: bool,
|
||||
/// Write 1 to clear
|
||||
pub detected_parity_error: bool,
|
||||
}
|
||||
|
||||
/// Header definitions from https://wiki.osdev.org/PCI
|
||||
#[repr(C, packed)]
|
||||
#[derive(Debug)]
|
||||
pub struct HeaderShared {
|
||||
pub vendor_id: u16,
|
||||
pub device_id: u16,
|
||||
pub command: PciCommand,
|
||||
pub status: PciStatus,
|
||||
pub revision_id: u8,
|
||||
pub prog_if: u8,
|
||||
pub subclass: u8,
|
||||
pub class_code: u8,
|
||||
pub cache_line_size: u8,
|
||||
pub latency_timer: u8,
|
||||
pub header_type: u8,
|
||||
bist: u8,
|
||||
}
|
||||
|
||||
const _: () = assert!(size_of::<HeaderShared>() == 16);
|
||||
|
||||
#[repr(C, packed)]
|
||||
#[derive(Debug)]
|
||||
pub struct PciDeviceHeader {
|
||||
pub vendor_id: u16,
|
||||
pub device_id: u16,
|
||||
pub command: PciCommand,
|
||||
pub status: PciStatus,
|
||||
pub revision_id: u8,
|
||||
pub prog_if: u8,
|
||||
pub subclass: u8,
|
||||
pub class_code: u8,
|
||||
pub cache_line_size: u8,
|
||||
pub latency_timer: u8,
|
||||
pub header_type: u8,
|
||||
bist: u8,
|
||||
pub bars: [u32; 6],
|
||||
pub cardbus_cis_ptr: u32,
|
||||
pub subsystem_vendor_id: u16,
|
||||
pub subsystem_id: u16,
|
||||
pub expansion_rom_address: u32,
|
||||
pub capability_ptr: u8,
|
||||
__: [u8; 7],
|
||||
pub interrupt_line: u8,
|
||||
pub interrupt_pin: u8,
|
||||
pub min_grant: u8,
|
||||
pub max_latency: u8,
|
||||
}
|
||||
|
||||
const _: () = assert!(size_of::<PciDeviceHeader>() == 0x40);
|
||||
|
||||
#[repr(C, packed)]
|
||||
#[derive(Debug)]
|
||||
pub struct PciCapabilityPointer {
|
||||
pub cap_id: u8,
|
||||
pub next_cap_offset: u8,
|
||||
}
|
||||
|
||||
#[bitfield(u16)]
|
||||
pub struct PciMsiControl {
|
||||
pub msi_enable: bool,
|
||||
#[bits(3, access=RO)]
|
||||
pub multi_message_capable: u8,
|
||||
#[bits(3)]
|
||||
pub multi_message_enable: u8,
|
||||
|
||||
#[bits(access=RO)]
|
||||
pub capable_address_64: bool,
|
||||
|
||||
#[bits(access=RO)]
|
||||
pub per_vector_masking: bool,
|
||||
|
||||
#[bits(7)]
|
||||
__: u8,
|
||||
}
|
||||
|
||||
#[repr(C, packed)]
|
||||
#[derive(Debug)]
|
||||
pub struct PciMsiCapability {
|
||||
pub cap_id: u8,
|
||||
pub next_cap_offset: u8,
|
||||
pub msi_control: PciMsiControl,
|
||||
pub msi_addr_lower: u32,
|
||||
pub msi_addr_upper_or_data: u32,
|
||||
pub msi_data_if_64: u32,
|
||||
pub mask: u32,
|
||||
pub pending: u32,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum PciHeaderType {
|
||||
Device,
|
||||
PciBridge,
|
||||
CardBusBridge,
|
||||
}
|
||||
|
||||
pub fn get_header_type(memory_region: &MemoryRegion) -> Result<PciHeaderType, ZError> {
|
||||
let shared: &HeaderShared = memory_region.as_ref();
|
||||
// The only reference I can find to the high bit here is at
|
||||
// https://www.khoury.northeastern.edu/~pjd/cs7680/homework/pci-enumeration.html
|
||||
// > Header Type: bit 7 (0x80) indicates whether it is a multi-function device,
|
||||
match shared.header_type & (!0x80) {
|
||||
0x0 => Ok(PciHeaderType::Device),
|
||||
0x1 => Ok(PciHeaderType::PciBridge),
|
||||
0x2 => Ok(PciHeaderType::CardBusBridge),
|
||||
_ => {
|
||||
mammoth::debug!("Unknown pci header type: {:#x}", shared.header_type);
|
||||
Err(ZError::INVALID_ARGUMENT)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
#![no_std]
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
mod device;
|
||||
mod header;
|
||||
|
||||
pub use device::PciDevice;
|
|
@ -6,6 +6,7 @@ edition = "2021"
|
|||
[dependencies]
|
||||
bitfield-struct = "0.8.0"
|
||||
mammoth = { path = "../../lib/mammoth" }
|
||||
pci = { path = "../../lib/pci" }
|
||||
yunq = { path = "../../lib/yunq" }
|
||||
yellowstone-yunq = { path = "../../lib/yellowstone" }
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use std::fs;
|
||||
|
||||
fn main() {
|
||||
let input_file = "../../../sys/denali/lib/denali/denali.yunq";
|
||||
let input_file = "denali.yunq";
|
||||
|
||||
println!("cargo::rerun-if-changed={input_file}");
|
||||
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
interface Denali {
|
||||
method Read(ReadRequest) -> (ReadResponse);
|
||||
method ReadMany(ReadManyRequest) -> (ReadResponse);
|
||||
}
|
||||
|
||||
message DiskBlock {
|
||||
u64 lba;
|
||||
u64 size;
|
||||
}
|
||||
|
||||
message ReadRequest {
|
||||
u64 device_id;
|
||||
DiskBlock block;
|
||||
}
|
||||
|
||||
|
||||
message ReadManyRequest {
|
||||
u64 device_id;
|
||||
repeated DiskBlock blocks;
|
||||
}
|
||||
|
||||
message ReadResponse {
|
||||
u64 device_id;
|
||||
u64 size;
|
||||
capability memory;
|
||||
}
|
||||
|
||||
|
|
@ -6,6 +6,7 @@ use mammoth::{
|
|||
thread,
|
||||
zion::ZError,
|
||||
};
|
||||
use pci::PciDevice;
|
||||
|
||||
use crate::ahci::{
|
||||
port::{AhciDeviceDetection, AhciInterfacePowerManagement},
|
||||
|
@ -14,36 +15,8 @@ use crate::ahci::{
|
|||
|
||||
use super::{hba::AhciHba, port::AhciPortHba, port_controller::PortController};
|
||||
|
||||
#[derive(Debug)]
|
||||
#[repr(C, packed)]
|
||||
pub struct PciDeviceHeader {
|
||||
pub vendor_id: u16,
|
||||
pub device_id: u16,
|
||||
pub command_reg: u16,
|
||||
pub status_reg: u16,
|
||||
pub revision: u8,
|
||||
pub prog_interface: u8,
|
||||
pub subclass: u8,
|
||||
pub class_code: u8,
|
||||
pub cache_line_size: u8,
|
||||
pub latency_timer: u8,
|
||||
pub header_type: u8,
|
||||
pub bist: u8,
|
||||
pub bars: [u32; 5],
|
||||
pub abar: u32,
|
||||
__: u32,
|
||||
pub subsystem_id: u32,
|
||||
pub expansion_rom: u32,
|
||||
pub cap_ptr: u8,
|
||||
___: [u8; 7],
|
||||
pub interrupt_line: u8,
|
||||
pub interrupt_pin: u8,
|
||||
pub min_grant: u8,
|
||||
pub max_latency: u8,
|
||||
}
|
||||
|
||||
pub struct AhciController {
|
||||
pci_header: &'static mut PciDeviceHeader,
|
||||
pci_device: Mutex<PciDevice>,
|
||||
hba: Mutex<&'static mut AhciHba>,
|
||||
ports: [Option<PortController>; 32],
|
||||
hba_vaddr: u64,
|
||||
|
@ -51,13 +24,13 @@ pub struct AhciController {
|
|||
|
||||
impl AhciController {
|
||||
pub fn new(pci_memory: Capability) -> Self {
|
||||
let pci_vaddr = mem::map_cap_and_leak(pci_memory);
|
||||
let pci_header = unsafe { (pci_vaddr as *mut PciDeviceHeader).as_mut().unwrap() };
|
||||
let pci_device = PciDevice::from_cap(pci_memory).unwrap();
|
||||
|
||||
let hba_vaddr = mem::map_direct_physical_and_leak(pci_header.abar as u64, 0x1100);
|
||||
let hba_vaddr =
|
||||
mem::map_direct_physical_and_leak(pci_device.header().bars[5] as u64, 0x1100);
|
||||
let hba = unsafe { (hba_vaddr as *mut AhciHba).as_mut().unwrap() };
|
||||
let mut controller = Self {
|
||||
pci_header,
|
||||
pci_device: Mutex::new(pci_device),
|
||||
hba: Mutex::new(hba),
|
||||
ports: [const { None }; 32],
|
||||
hba_vaddr,
|
||||
|
@ -100,17 +73,8 @@ impl AhciController {
|
|||
}
|
||||
}
|
||||
|
||||
fn irq_num(&self) -> u64 {
|
||||
match self.pci_header.interrupt_pin {
|
||||
1 => mammoth::zion::kZIrqPci1,
|
||||
2 => mammoth::zion::kZIrqPci2,
|
||||
3 => mammoth::zion::kZIrqPci3,
|
||||
4 => mammoth::zion::kZIrqPci4,
|
||||
_ => panic!(
|
||||
"Unrecognized pci interrupt pin {}",
|
||||
self.pci_header.interrupt_pin
|
||||
),
|
||||
}
|
||||
fn register_irq(&self) -> Result<Capability, ZError> {
|
||||
self.pci_device.lock().register_msi()
|
||||
}
|
||||
|
||||
fn handle_irq(&self) {
|
||||
|
@ -184,9 +148,8 @@ impl AhciController {
|
|||
|
||||
pub fn spawn_irq_thread(controller: Arc<AhciController>) -> thread::JoinHandle {
|
||||
let irq_thread = move || {
|
||||
let irq_num = controller.irq_num();
|
||||
let irq_port =
|
||||
mammoth::port::PortServer::from_cap(mammoth::syscall::register_irq(irq_num).unwrap());
|
||||
let irq_port_cap = controller.register_irq().unwrap();
|
||||
let irq_port = mammoth::port::PortServer::from_cap(irq_port_cap);
|
||||
controller.hba.lock().global_host_control.update(|ghc| {
|
||||
ghc.set_interrupt_enable(true);
|
||||
});
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use std::fs;
|
||||
|
||||
fn main() {
|
||||
let input_file = "../../../sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq";
|
||||
let input_file = "victoriafalls.yunq";
|
||||
|
||||
println!("cargo::rerun-if-changed={input_file}");
|
||||
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
interface VFS {
|
||||
method OpenFile(OpenFileRequest) -> (OpenFileResponse);
|
||||
method GetDirectory(GetDirectoryRequest) -> (Directory);
|
||||
}
|
||||
|
||||
message OpenFileRequest {
|
||||
string path;
|
||||
}
|
||||
|
||||
message OpenFileResponse {
|
||||
string path;
|
||||
u64 size;
|
||||
capability memory;
|
||||
}
|
||||
|
||||
message GetDirectoryRequest {
|
||||
string path;
|
||||
}
|
||||
|
||||
message Directory {
|
||||
// , separated list of filenames until we have repeated strings.
|
||||
string filenames;
|
||||
}
|
||||
|
|
@ -1,7 +1,5 @@
|
|||
set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "")
|
||||
|
||||
add_subdirectory(denali)
|
||||
add_subdirectory(victoriafalls)
|
||||
add_subdirectory(voyageurs)
|
||||
add_subdirectory(yellowstone)
|
||||
|
||||
|
|
|
@ -48,7 +48,7 @@ SYS5(PortRecv, z_cap_t, port_cap, uint64_t*, num_bytes, void*, data, uint64_t*,
|
|||
SYS5(PortPoll, z_cap_t, port_cap, uint64_t*, num_bytes, void*, data, uint64_t*,
|
||||
num_caps, z_cap_t*, caps);
|
||||
|
||||
SYS2(IrqRegister, uint64_t, irq_num, z_cap_t*, port_cap);
|
||||
SYS2(MsiIrqRegister, uint64_t*, irq_num, z_cap_t*, port_cap);
|
||||
|
||||
SYS1(EndpointCreate, z_cap_t*, endpoint_cap);
|
||||
SYS6(EndpointSend, z_cap_t, endpoint_cap, uint64_t, num_bytes, const void*,
|
||||
|
|
|
@ -43,7 +43,7 @@ const uint64_t kZionPortSend = 0x51;
|
|||
const uint64_t kZionPortRecv = 0x52;
|
||||
const uint64_t kZionPortPoll = 0x53;
|
||||
|
||||
const uint64_t kZionIrqRegister = 0x58;
|
||||
const uint64_t kZionMsiIrqRegister = 0x59;
|
||||
|
||||
const uint64_t kZionEndpointCreate = 0x60;
|
||||
const uint64_t kZionEndpointSend = 0x61;
|
||||
|
|
|
@ -136,23 +136,6 @@ Apic::Apic(const ApicConfiguration& config)
|
|||
// FIXME: Get this offset from ACPI.
|
||||
SetIoDoubleReg(0x14, 0x20 | APIC_MASK);
|
||||
|
||||
// Map Keyboard
|
||||
SetIoDoubleReg(0x12, 0x22);
|
||||
|
||||
// For now set these based on the presets in the following spec.
|
||||
// http://web.archive.org/web/20161130153145/http://download.intel.com/design/chipsets/datashts/29056601.pdf
|
||||
// FIXME: However in the future we should likely use the MADT for legacy
|
||||
// interrupts and AML for PCI etc.
|
||||
// PCI Line 1-4
|
||||
// FIXME: These should be level triggered according to spec I believe
|
||||
// but because we handle the interrupt outside of the kernel it is tricky
|
||||
// to wait to send the end of interrupt message.
|
||||
// Because of this leave them as edge triggered and send EOI immediately.
|
||||
SetIoDoubleReg(0x30, 0x30);
|
||||
SetIoDoubleReg(0x32, 0x31);
|
||||
SetIoDoubleReg(0x34, 0x32);
|
||||
SetIoDoubleReg(0x36, 0x33);
|
||||
|
||||
DumpInfo();
|
||||
}
|
||||
|
||||
|
|
|
@ -9,18 +9,24 @@ DriverManager& DriverManager::Get() { return *gDriverManager; }
|
|||
DriverManager::DriverManager() { gDriverManager = this; }
|
||||
|
||||
void DriverManager::WriteMessage(uint64_t irq_num, IpcMessage&& message) {
|
||||
if (!driver_map_.Contains(irq_num)) {
|
||||
if (irq_num < IRQ_OFFSET) {
|
||||
dbgln("WARN IRQ {x} below min offset {x}", irq_num, IRQ_OFFSET);
|
||||
}
|
||||
uint64_t offset = irq_num - IRQ_OFFSET;
|
||||
if (offset >= driver_list_.size()) {
|
||||
dbgln("WARN IRQ for {x} with no registered driver", irq_num);
|
||||
return;
|
||||
}
|
||||
|
||||
driver_map_.at(irq_num)->Send(glcr::Move(message));
|
||||
driver_list_[offset]->Send(glcr::Move(message));
|
||||
}
|
||||
|
||||
glcr::ErrorCode DriverManager::RegisterListener(uint64_t irq_num,
|
||||
glcr::RefPtr<Port> port) {
|
||||
if (driver_map_.Contains(irq_num)) {
|
||||
return glcr::ALREADY_EXISTS;
|
||||
glcr::ErrorOr<uint8_t> DriverManager::RegisterListener(
|
||||
glcr::RefPtr<Port> port) {
|
||||
if (driver_list_.size() + IRQ_OFFSET >= 0xFF) {
|
||||
return glcr::EXHAUSTED;
|
||||
}
|
||||
return driver_map_.Insert(irq_num, port);
|
||||
uint8_t offset = (driver_list_.size() + IRQ_OFFSET);
|
||||
driver_list_.PushBack(port);
|
||||
return offset;
|
||||
}
|
||||
|
|
|
@ -15,9 +15,10 @@ class DriverManager {
|
|||
|
||||
void WriteMessage(uint64_t irq_num, IpcMessage&& message);
|
||||
|
||||
[[nodiscard]] glcr::ErrorCode RegisterListener(uint64_t irq_num,
|
||||
glcr::RefPtr<Port> port);
|
||||
[[nodiscard]] glcr::ErrorOr<uint8_t> RegisterListener(
|
||||
glcr::RefPtr<Port> port);
|
||||
|
||||
private:
|
||||
glcr::HashMap<uint64_t, glcr::RefPtr<Port>> driver_map_;
|
||||
const uint64_t IRQ_OFFSET = 0x60;
|
||||
glcr::Vector<glcr::RefPtr<Port>> driver_list_;
|
||||
};
|
||||
|
|
|
@ -109,7 +109,7 @@ extern "C" void interrupt_protection_fault(InterruptFrame* frame) {
|
|||
} else {
|
||||
dbgln("GDT");
|
||||
}
|
||||
dbgln("Index: {}", err >> 3);
|
||||
dbgln("Index: {} ({x})", err >> 3, err >> 3);
|
||||
dbgln("RIP: {x}", frame->rip);
|
||||
dbgln("RAX: {x}, RBX: {x}, RCX: {x}, RDX: {x}", frame->rax, frame->rbx,
|
||||
frame->rcx, frame->rdx);
|
||||
|
@ -197,40 +197,27 @@ extern "C" void interrupt_apic_timer(InterruptFrame*) {
|
|||
gScheduler->Preempt();
|
||||
}
|
||||
|
||||
extern "C" void isr_keyboard();
|
||||
extern "C" void interrupt_keyboard(InterruptFrame*) {
|
||||
glcr::Array<uint8_t> data(1);
|
||||
data[0] = inb(0x60);
|
||||
IpcMessage msg{.data = glcr::Move(data)};
|
||||
DriverManager::Get().WriteMessage(kZIrqKbd, glcr::Move(msg));
|
||||
|
||||
extern "C" void isr_60();
|
||||
extern "C" void interrupt_60(InterruptFrame*) {
|
||||
DriverManager::Get().WriteMessage(0x60, {});
|
||||
gApic->SignalEOI();
|
||||
}
|
||||
|
||||
extern "C" void isr_pci1();
|
||||
extern "C" void interrupt_pci1(InterruptFrame*) {
|
||||
DriverManager::Get().WriteMessage(kZIrqPci1, {});
|
||||
extern "C" void isr_61();
|
||||
extern "C" void interrupt_61(InterruptFrame*) {
|
||||
DriverManager::Get().WriteMessage(0x61, {});
|
||||
gApic->SignalEOI();
|
||||
}
|
||||
|
||||
extern "C" void isr_pci2();
|
||||
extern "C" void interrupt_pci2(InterruptFrame*) {
|
||||
DriverManager::Get().WriteMessage(kZIrqPci2, {});
|
||||
dbgln("Interrupt PCI line 2");
|
||||
extern "C" void isr_62();
|
||||
extern "C" void interrupt_62(InterruptFrame*) {
|
||||
DriverManager::Get().WriteMessage(0x62, {});
|
||||
gApic->SignalEOI();
|
||||
}
|
||||
|
||||
extern "C" void isr_pci3();
|
||||
extern "C" void interrupt_pci3(InterruptFrame*) {
|
||||
DriverManager::Get().WriteMessage(kZIrqPci3, {});
|
||||
dbgln("Interrupt PCI line 3");
|
||||
gApic->SignalEOI();
|
||||
}
|
||||
|
||||
extern "C" void isr_pci4();
|
||||
extern "C" void interrupt_pci4(InterruptFrame*) {
|
||||
DriverManager::Get().WriteMessage(kZIrqPci4, {});
|
||||
dbgln("Interrupt PCI line 4");
|
||||
extern "C" void isr_63();
|
||||
extern "C" void interrupt_63(InterruptFrame*) {
|
||||
DriverManager::Get().WriteMessage(0x63, {});
|
||||
gApic->SignalEOI();
|
||||
}
|
||||
|
||||
|
@ -243,12 +230,11 @@ void InitIdt() {
|
|||
|
||||
gIdt[0x20] = CreateDescriptor(isr_timer);
|
||||
gIdt[0x21] = CreateDescriptor(isr_apic_timer);
|
||||
gIdt[0x22] = CreateDescriptor(isr_keyboard);
|
||||
|
||||
gIdt[0x30] = CreateDescriptor(isr_pci1);
|
||||
gIdt[0x31] = CreateDescriptor(isr_pci2);
|
||||
gIdt[0x32] = CreateDescriptor(isr_pci3);
|
||||
gIdt[0x33] = CreateDescriptor(isr_pci4);
|
||||
gIdt[0x60] = CreateDescriptor(isr_60);
|
||||
gIdt[0x61] = CreateDescriptor(isr_61);
|
||||
gIdt[0x62] = CreateDescriptor(isr_62);
|
||||
gIdt[0x63] = CreateDescriptor(isr_63);
|
||||
|
||||
InterruptDescriptorTablePointer idtp{
|
||||
.size = sizeof(gIdt),
|
||||
|
|
|
@ -63,10 +63,8 @@ isr_handler fpe_fault
|
|||
|
||||
isr_handler timer
|
||||
isr_handler apic_timer
|
||||
isr_handler keyboard
|
||||
|
||||
isr_handler pci1
|
||||
isr_handler pci2
|
||||
isr_handler pci3
|
||||
isr_handler pci4
|
||||
|
||||
isr_handler 60
|
||||
isr_handler 61
|
||||
isr_handler 62
|
||||
isr_handler 63
|
||||
|
|
|
@ -156,13 +156,14 @@ glcr::ErrorCode PortPoll(ZPortPollReq* req) {
|
|||
return TranslateIpcMessageToResponse(msg, req);
|
||||
}
|
||||
|
||||
glcr::ErrorCode IrqRegister(ZIrqRegisterReq* req) {
|
||||
glcr::ErrorCode MsiIrqRegister(ZMsiIrqRegisterReq* req) {
|
||||
auto& proc = gScheduler->CurrentProcess();
|
||||
|
||||
glcr::RefPtr<Port> port = glcr::MakeRefCounted<Port>();
|
||||
|
||||
*req->port_cap = proc.AddNewCapability(port);
|
||||
return DriverManager::Get().RegisterListener(req->irq_num, port);
|
||||
ASSIGN_OR_RETURN(*req->irq_num, DriverManager::Get().RegisterListener(port));
|
||||
|
||||
return glcr::OK;
|
||||
}
|
||||
|
||||
glcr::ErrorCode EndpointCreate(ZEndpointCreateReq* req) {
|
||||
|
|
|
@ -12,7 +12,7 @@ glcr::ErrorCode PortCreate(ZPortCreateReq* req);
|
|||
glcr::ErrorCode PortSend(ZPortSendReq* req);
|
||||
glcr::ErrorCode PortRecv(ZPortRecvReq* req);
|
||||
glcr::ErrorCode PortPoll(ZPortPollReq* req);
|
||||
glcr::ErrorCode IrqRegister(ZIrqRegisterReq* req);
|
||||
glcr::ErrorCode MsiIrqRegister(ZMsiIrqRegisterReq* req);
|
||||
|
||||
glcr::ErrorCode EndpointCreate(ZEndpointCreateReq* req);
|
||||
glcr::ErrorCode EndpointSend(ZEndpointSendReq* req);
|
||||
|
|
|
@ -77,7 +77,7 @@ extern "C" z_err_t SyscallHandler(uint64_t call_id, void* req) {
|
|||
CASE(PortSend);
|
||||
CASE(PortRecv);
|
||||
CASE(PortPoll);
|
||||
CASE(IrqRegister);
|
||||
CASE(MsiIrqRegister);
|
||||
CASE(EndpointCreate);
|
||||
CASE(EndpointSend);
|
||||
CASE(EndpointRecv);
|
||||
|
|
Loading…
Reference in New Issue