Compare commits
2 Commits
dc801786b1
...
f26fd73116
Author | SHA1 | Date |
---|---|---|
|
f26fd73116 | |
|
c645405ca8 |
|
@ -17,7 +17,6 @@ target_include_directories(mammoth
|
||||||
|
|
||||||
target_link_libraries(mammoth
|
target_link_libraries(mammoth
|
||||||
glacier
|
glacier
|
||||||
victoriafalls_yunq
|
|
||||||
yellowstone_yunq
|
yellowstone_yunq
|
||||||
voyageurs_yunq
|
voyageurs_yunq
|
||||||
zion_stub
|
zion_stub
|
||||||
|
|
|
@ -34,6 +34,7 @@ version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitfield-struct",
|
"bitfield-struct",
|
||||||
"mammoth",
|
"mammoth",
|
||||||
|
"pci",
|
||||||
"yellowstone-yunq",
|
"yellowstone-yunq",
|
||||||
"yunq",
|
"yunq",
|
||||||
"yunqc",
|
"yunqc",
|
||||||
|
@ -83,6 +84,14 @@ dependencies = [
|
||||||
"linked_list_allocator",
|
"linked_list_allocator",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pci"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"bitfield-struct",
|
||||||
|
"mammoth",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "prettyplease"
|
name = "prettyplease"
|
||||||
version = "0.2.20"
|
version = "0.2.20"
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
members = [
|
members = [
|
||||||
"lib/client/denali_client", "lib/fs/ext2",
|
"lib/client/denali_client", "lib/fs/ext2",
|
||||||
"lib/mammoth",
|
"lib/mammoth", "lib/pci",
|
||||||
"lib/voyageurs",
|
"lib/voyageurs",
|
||||||
"lib/yellowstone",
|
"lib/yellowstone",
|
||||||
"lib/yunq",
|
"lib/yunq",
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use std::fs;
|
use std::fs;
|
||||||
|
|
||||||
fn main() {
|
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}");
|
println!("cargo::rerun-if-changed={input_file}");
|
||||||
|
|
||||||
|
|
|
@ -258,6 +258,7 @@ pub const kZionPortSend: u64 = 81;
|
||||||
pub const kZionPortRecv: u64 = 82;
|
pub const kZionPortRecv: u64 = 82;
|
||||||
pub const kZionPortPoll: u64 = 83;
|
pub const kZionPortPoll: u64 = 83;
|
||||||
pub const kZionIrqRegister: u64 = 88;
|
pub const kZionIrqRegister: u64 = 88;
|
||||||
|
pub const kZionMsiIrqRegister: u64 = 89;
|
||||||
pub const kZionEndpointCreate: u64 = 96;
|
pub const kZionEndpointCreate: u64 = 96;
|
||||||
pub const kZionEndpointSend: u64 = 97;
|
pub const kZionEndpointSend: u64 = 97;
|
||||||
pub const kZionEndpointRecv: u64 = 98;
|
pub const kZionEndpointRecv: u64 = 98;
|
||||||
|
@ -478,6 +479,12 @@ pub struct ZIrqRegisterReq {
|
||||||
}
|
}
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[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 struct ZEndpointCreateReq {
|
||||||
pub endpoint_cap: *mut z_cap_t,
|
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 {
|
impl Drop for MemoryRegion {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
// FIXME: We shouldn't have to do this manual adjustment.
|
// FIXME: We shouldn't have to do this manual adjustment.
|
||||||
|
|
|
@ -310,16 +310,17 @@ pub fn port_poll(
|
||||||
Ok((num_bytes, num_caps))
|
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;
|
let mut port_cap: z_cap_t = 0;
|
||||||
syscall(
|
syscall(
|
||||||
zion::kZionIrqRegister,
|
zion::kZionMsiIrqRegister,
|
||||||
&zion::ZIrqRegisterReq {
|
&zion::ZMsiIrqRegisterReq {
|
||||||
irq_num,
|
irq_num: &mut irq_num as *mut u64,
|
||||||
port_cap: &mut port_cap,
|
port_cap: &mut port_cap,
|
||||||
},
|
},
|
||||||
)?;
|
)?;
|
||||||
Ok(Capability::take(port_cap))
|
Ok((Capability::take(port_cap), irq_num))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn endpoint_create() -> Result<Capability, ZError> {
|
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]
|
[dependencies]
|
||||||
bitfield-struct = "0.8.0"
|
bitfield-struct = "0.8.0"
|
||||||
mammoth = { path = "../../lib/mammoth" }
|
mammoth = { path = "../../lib/mammoth" }
|
||||||
|
pci = { path = "../../lib/pci" }
|
||||||
yunq = { path = "../../lib/yunq" }
|
yunq = { path = "../../lib/yunq" }
|
||||||
yellowstone-yunq = { path = "../../lib/yellowstone" }
|
yellowstone-yunq = { path = "../../lib/yellowstone" }
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use std::fs;
|
use std::fs;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let input_file = "../../../sys/denali/lib/denali/denali.yunq";
|
let input_file = "denali.yunq";
|
||||||
|
|
||||||
println!("cargo::rerun-if-changed={input_file}");
|
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,
|
thread,
|
||||||
zion::ZError,
|
zion::ZError,
|
||||||
};
|
};
|
||||||
|
use pci::PciDevice;
|
||||||
|
|
||||||
use crate::ahci::{
|
use crate::ahci::{
|
||||||
port::{AhciDeviceDetection, AhciInterfacePowerManagement},
|
port::{AhciDeviceDetection, AhciInterfacePowerManagement},
|
||||||
|
@ -14,36 +15,8 @@ use crate::ahci::{
|
||||||
|
|
||||||
use super::{hba::AhciHba, port::AhciPortHba, port_controller::PortController};
|
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 {
|
pub struct AhciController {
|
||||||
pci_header: &'static mut PciDeviceHeader,
|
pci_device: Mutex<PciDevice>,
|
||||||
hba: Mutex<&'static mut AhciHba>,
|
hba: Mutex<&'static mut AhciHba>,
|
||||||
ports: [Option<PortController>; 32],
|
ports: [Option<PortController>; 32],
|
||||||
hba_vaddr: u64,
|
hba_vaddr: u64,
|
||||||
|
@ -51,13 +24,13 @@ pub struct AhciController {
|
||||||
|
|
||||||
impl AhciController {
|
impl AhciController {
|
||||||
pub fn new(pci_memory: Capability) -> Self {
|
pub fn new(pci_memory: Capability) -> Self {
|
||||||
let pci_vaddr = mem::map_cap_and_leak(pci_memory);
|
let pci_device = PciDevice::from_cap(pci_memory).unwrap();
|
||||||
let pci_header = unsafe { (pci_vaddr as *mut PciDeviceHeader).as_mut().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 hba = unsafe { (hba_vaddr as *mut AhciHba).as_mut().unwrap() };
|
||||||
let mut controller = Self {
|
let mut controller = Self {
|
||||||
pci_header,
|
pci_device: Mutex::new(pci_device),
|
||||||
hba: Mutex::new(hba),
|
hba: Mutex::new(hba),
|
||||||
ports: [const { None }; 32],
|
ports: [const { None }; 32],
|
||||||
hba_vaddr,
|
hba_vaddr,
|
||||||
|
@ -100,17 +73,8 @@ impl AhciController {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn irq_num(&self) -> u64 {
|
fn register_irq(&self) -> Result<Capability, ZError> {
|
||||||
match self.pci_header.interrupt_pin {
|
self.pci_device.lock().register_msi()
|
||||||
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 handle_irq(&self) {
|
fn handle_irq(&self) {
|
||||||
|
@ -184,9 +148,8 @@ impl AhciController {
|
||||||
|
|
||||||
pub fn spawn_irq_thread(controller: Arc<AhciController>) -> thread::JoinHandle {
|
pub fn spawn_irq_thread(controller: Arc<AhciController>) -> thread::JoinHandle {
|
||||||
let irq_thread = move || {
|
let irq_thread = move || {
|
||||||
let irq_num = controller.irq_num();
|
let irq_port_cap = controller.register_irq().unwrap();
|
||||||
let irq_port =
|
let irq_port = mammoth::port::PortServer::from_cap(irq_port_cap);
|
||||||
mammoth::port::PortServer::from_cap(mammoth::syscall::register_irq(irq_num).unwrap());
|
|
||||||
controller.hba.lock().global_host_control.update(|ghc| {
|
controller.hba.lock().global_host_control.update(|ghc| {
|
||||||
ghc.set_interrupt_enable(true);
|
ghc.set_interrupt_enable(true);
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use std::fs;
|
use std::fs;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let input_file = "../../../sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq";
|
let input_file = "victoriafalls.yunq";
|
||||||
|
|
||||||
println!("cargo::rerun-if-changed={input_file}");
|
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 "")
|
set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "")
|
||||||
|
|
||||||
add_subdirectory(denali)
|
|
||||||
add_subdirectory(victoriafalls)
|
|
||||||
add_subdirectory(voyageurs)
|
add_subdirectory(voyageurs)
|
||||||
add_subdirectory(yellowstone)
|
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*,
|
SYS5(PortPoll, z_cap_t, port_cap, uint64_t*, num_bytes, void*, data, uint64_t*,
|
||||||
num_caps, z_cap_t*, caps);
|
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);
|
SYS1(EndpointCreate, z_cap_t*, endpoint_cap);
|
||||||
SYS6(EndpointSend, z_cap_t, endpoint_cap, uint64_t, num_bytes, const void*,
|
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 kZionPortRecv = 0x52;
|
||||||
const uint64_t kZionPortPoll = 0x53;
|
const uint64_t kZionPortPoll = 0x53;
|
||||||
|
|
||||||
const uint64_t kZionIrqRegister = 0x58;
|
const uint64_t kZionMsiIrqRegister = 0x59;
|
||||||
|
|
||||||
const uint64_t kZionEndpointCreate = 0x60;
|
const uint64_t kZionEndpointCreate = 0x60;
|
||||||
const uint64_t kZionEndpointSend = 0x61;
|
const uint64_t kZionEndpointSend = 0x61;
|
||||||
|
|
|
@ -136,23 +136,6 @@ Apic::Apic(const ApicConfiguration& config)
|
||||||
// FIXME: Get this offset from ACPI.
|
// FIXME: Get this offset from ACPI.
|
||||||
SetIoDoubleReg(0x14, 0x20 | APIC_MASK);
|
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();
|
DumpInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,18 +9,24 @@ DriverManager& DriverManager::Get() { return *gDriverManager; }
|
||||||
DriverManager::DriverManager() { gDriverManager = this; }
|
DriverManager::DriverManager() { gDriverManager = this; }
|
||||||
|
|
||||||
void DriverManager::WriteMessage(uint64_t irq_num, IpcMessage&& message) {
|
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);
|
dbgln("WARN IRQ for {x} with no registered driver", irq_num);
|
||||||
return;
|
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::ErrorOr<uint8_t> DriverManager::RegisterListener(
|
||||||
glcr::RefPtr<Port> port) {
|
glcr::RefPtr<Port> port) {
|
||||||
if (driver_map_.Contains(irq_num)) {
|
if (driver_list_.size() + IRQ_OFFSET >= 0xFF) {
|
||||||
return glcr::ALREADY_EXISTS;
|
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);
|
void WriteMessage(uint64_t irq_num, IpcMessage&& message);
|
||||||
|
|
||||||
[[nodiscard]] glcr::ErrorCode RegisterListener(uint64_t irq_num,
|
[[nodiscard]] glcr::ErrorOr<uint8_t> RegisterListener(
|
||||||
glcr::RefPtr<Port> port);
|
glcr::RefPtr<Port> port);
|
||||||
|
|
||||||
private:
|
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 {
|
} else {
|
||||||
dbgln("GDT");
|
dbgln("GDT");
|
||||||
}
|
}
|
||||||
dbgln("Index: {}", err >> 3);
|
dbgln("Index: {} ({x})", err >> 3, err >> 3);
|
||||||
dbgln("RIP: {x}", frame->rip);
|
dbgln("RIP: {x}", frame->rip);
|
||||||
dbgln("RAX: {x}, RBX: {x}, RCX: {x}, RDX: {x}", frame->rax, frame->rbx,
|
dbgln("RAX: {x}, RBX: {x}, RCX: {x}, RDX: {x}", frame->rax, frame->rbx,
|
||||||
frame->rcx, frame->rdx);
|
frame->rcx, frame->rdx);
|
||||||
|
@ -197,40 +197,27 @@ extern "C" void interrupt_apic_timer(InterruptFrame*) {
|
||||||
gScheduler->Preempt();
|
gScheduler->Preempt();
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" void isr_keyboard();
|
extern "C" void isr_60();
|
||||||
extern "C" void interrupt_keyboard(InterruptFrame*) {
|
extern "C" void interrupt_60(InterruptFrame*) {
|
||||||
glcr::Array<uint8_t> data(1);
|
DriverManager::Get().WriteMessage(0x60, {});
|
||||||
data[0] = inb(0x60);
|
|
||||||
IpcMessage msg{.data = glcr::Move(data)};
|
|
||||||
DriverManager::Get().WriteMessage(kZIrqKbd, glcr::Move(msg));
|
|
||||||
|
|
||||||
gApic->SignalEOI();
|
gApic->SignalEOI();
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" void isr_pci1();
|
extern "C" void isr_61();
|
||||||
extern "C" void interrupt_pci1(InterruptFrame*) {
|
extern "C" void interrupt_61(InterruptFrame*) {
|
||||||
DriverManager::Get().WriteMessage(kZIrqPci1, {});
|
DriverManager::Get().WriteMessage(0x61, {});
|
||||||
gApic->SignalEOI();
|
gApic->SignalEOI();
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" void isr_pci2();
|
extern "C" void isr_62();
|
||||||
extern "C" void interrupt_pci2(InterruptFrame*) {
|
extern "C" void interrupt_62(InterruptFrame*) {
|
||||||
DriverManager::Get().WriteMessage(kZIrqPci2, {});
|
DriverManager::Get().WriteMessage(0x62, {});
|
||||||
dbgln("Interrupt PCI line 2");
|
|
||||||
gApic->SignalEOI();
|
gApic->SignalEOI();
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" void isr_pci3();
|
extern "C" void isr_63();
|
||||||
extern "C" void interrupt_pci3(InterruptFrame*) {
|
extern "C" void interrupt_63(InterruptFrame*) {
|
||||||
DriverManager::Get().WriteMessage(kZIrqPci3, {});
|
DriverManager::Get().WriteMessage(0x63, {});
|
||||||
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");
|
|
||||||
gApic->SignalEOI();
|
gApic->SignalEOI();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -243,12 +230,11 @@ void InitIdt() {
|
||||||
|
|
||||||
gIdt[0x20] = CreateDescriptor(isr_timer);
|
gIdt[0x20] = CreateDescriptor(isr_timer);
|
||||||
gIdt[0x21] = CreateDescriptor(isr_apic_timer);
|
gIdt[0x21] = CreateDescriptor(isr_apic_timer);
|
||||||
gIdt[0x22] = CreateDescriptor(isr_keyboard);
|
|
||||||
|
|
||||||
gIdt[0x30] = CreateDescriptor(isr_pci1);
|
gIdt[0x60] = CreateDescriptor(isr_60);
|
||||||
gIdt[0x31] = CreateDescriptor(isr_pci2);
|
gIdt[0x61] = CreateDescriptor(isr_61);
|
||||||
gIdt[0x32] = CreateDescriptor(isr_pci3);
|
gIdt[0x62] = CreateDescriptor(isr_62);
|
||||||
gIdt[0x33] = CreateDescriptor(isr_pci4);
|
gIdt[0x63] = CreateDescriptor(isr_63);
|
||||||
|
|
||||||
InterruptDescriptorTablePointer idtp{
|
InterruptDescriptorTablePointer idtp{
|
||||||
.size = sizeof(gIdt),
|
.size = sizeof(gIdt),
|
||||||
|
|
|
@ -63,10 +63,8 @@ isr_handler fpe_fault
|
||||||
|
|
||||||
isr_handler timer
|
isr_handler timer
|
||||||
isr_handler apic_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);
|
return TranslateIpcMessageToResponse(msg, req);
|
||||||
}
|
}
|
||||||
|
|
||||||
glcr::ErrorCode IrqRegister(ZIrqRegisterReq* req) {
|
glcr::ErrorCode MsiIrqRegister(ZMsiIrqRegisterReq* req) {
|
||||||
auto& proc = gScheduler->CurrentProcess();
|
auto& proc = gScheduler->CurrentProcess();
|
||||||
|
|
||||||
glcr::RefPtr<Port> port = glcr::MakeRefCounted<Port>();
|
glcr::RefPtr<Port> port = glcr::MakeRefCounted<Port>();
|
||||||
|
|
||||||
*req->port_cap = proc.AddNewCapability(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) {
|
glcr::ErrorCode EndpointCreate(ZEndpointCreateReq* req) {
|
||||||
|
|
|
@ -12,7 +12,7 @@ glcr::ErrorCode PortCreate(ZPortCreateReq* req);
|
||||||
glcr::ErrorCode PortSend(ZPortSendReq* req);
|
glcr::ErrorCode PortSend(ZPortSendReq* req);
|
||||||
glcr::ErrorCode PortRecv(ZPortRecvReq* req);
|
glcr::ErrorCode PortRecv(ZPortRecvReq* req);
|
||||||
glcr::ErrorCode PortPoll(ZPortPollReq* req);
|
glcr::ErrorCode PortPoll(ZPortPollReq* req);
|
||||||
glcr::ErrorCode IrqRegister(ZIrqRegisterReq* req);
|
glcr::ErrorCode MsiIrqRegister(ZMsiIrqRegisterReq* req);
|
||||||
|
|
||||||
glcr::ErrorCode EndpointCreate(ZEndpointCreateReq* req);
|
glcr::ErrorCode EndpointCreate(ZEndpointCreateReq* req);
|
||||||
glcr::ErrorCode EndpointSend(ZEndpointSendReq* 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(PortSend);
|
||||||
CASE(PortRecv);
|
CASE(PortRecv);
|
||||||
CASE(PortPoll);
|
CASE(PortPoll);
|
||||||
CASE(IrqRegister);
|
CASE(MsiIrqRegister);
|
||||||
CASE(EndpointCreate);
|
CASE(EndpointCreate);
|
||||||
CASE(EndpointSend);
|
CASE(EndpointSend);
|
||||||
CASE(EndpointRecv);
|
CASE(EndpointRecv);
|
||||||
|
|
Loading…
Reference in New Issue