Asterinas 驱动框架
总线初始化
在整个OS初始化的时候:
Rust
pub fn init() {
arch::before_all_init();
logger::init();
#[cfg(feature = "intel_tdx")]
let td_info = init_tdx().unwrap();
#[cfg(feature = "intel_tdx")]
early_println!(
"td gpaw: {}, td attributes: {:?}\nTDX guest is initialized",
td_info.gpaw,
td_info.attributes
);
vm::heap_allocator::init();
boot::init();
vm::init();
trap::init();
arch::after_all_init();
bus::init();
invoke_ffi_init_funcs();
}
先做总线的初始化:
Rust
pub fn init() {
pci::init();
mmio::init();
}
PCI设备
•PCI总线Bus编号从0到255,每条总线可以挂32个设备,每个设备有8个function。
Rust
/// Returns an iterator that enumerates all possible PCI device locations.
pub fn all() -> impl Iterator<Item = PciDeviceLocation> {
iter::from_coroutine(|| {
for bus in Self::MIN_BUS...=Self::MAX_BUS {
for device in Self::MIN_DEVICE...=Self::MAX_DEVICE {
for function in Self::MIN_FUNCTION...=Self::MAX_FUNCTION {
let loc = PciDeviceLocation {
bus,
device,
function,
};
yield loc;
}
}
}
})
}
•枚举到PCI总线上的所有可能的设备后,确认设备是否存在:
Rust
pub(super) fn new(location: PciDeviceLocation) -> Option {
if location.read16(0) == 0xFFFF {
// not exists
return None;
}
let capabilities = Vec::new();
let device_id = PciDeviceId::new(location);
let bar_manager = BarManager::new(location);
let mut device = Self {
device_id,
location,
bar_manager,
capabilities,
};
device.capabilities = Capability::device_capabilities(&mut device);
Some(device)
}
pub(super) fn bar_manager_mut(&mut self) -> &mut BarManager {
&mut self.bar_manager
}
pub(super) fn capabilities_mut(&mut self) -> &mut Vec<Capability> {
&mut self.capabilities
}
}
•如果设备存在,则在PCI BUS上注册这些设备:
Rust
pub(super) fn register_common_device(&mut self, mut common_device: PciCommonDevice) {
debug!("Find pci common devices:{:x?}", common_device);
let device_id = *common_device.device_id();
for driver in self.drivers.iter() {
common_device = match driver.probe(common_device) {
Ok(device) => {
debug_assert!(device_id == device.device_id());
self.devices.push(device);
return;
}
Err((err, common_device)) => {
if err != BusProbeError::DeviceNotMatch {
error!("PCI device construction failed, reason: {:?}", err);
}
debug_assert!(device_id == *common_device.device_id());
common_device
}
};
}
self.common_devices.push_back(common_device);
}
注意,这个时候应该还没有相应的driver。
MMIO设备
在MMIO整个地址空间去枚举设备:
Rust
iter_range(0xFEB0_0000...0xFEB0_4000);
判断地址是否有效:
Rust
fn iter_range(range: Range) {
debug!("[Virtio]: Iter MMIO range:{:x?}", range);
let mut current = range.end;
let mut lock = MMIO_BUS.lock();
let io_apics = IO_APIC.get().unwrap();
let is_ioapic2 = io_apics.len() == 2;
let mut io_apic = if is_ioapic2 {
io_apics.get(1).unwrap().lock()
} else {
io_apics.first().unwrap().lock()
};
let mut device_count = 0;
while current > range.start {
current -= 0x100;
// Safety: It only read the value and judge if the magic value fit 0x74726976
let value = unsafe { *(paddr_to_vaddr(current) as *const u32) };
if value == VIRTIO_MMIO_MAGIC {
// Safety: It only read the device id
let device_id = unsafe { *(paddr_to_vaddr(current + 8) as *const u32) };
device_count += 1;
if device_id == 0 {
continue;
}
let handle = IrqLine::alloc().unwrap();
// If has two IOApic, then start: 24 (0 in IOApic2), end 47 (23 in IOApic2)
// If one IOApic, then start: 16, end 23
io_apic.enable(24 - device_count, handle.clone()).unwrap();
let device = MmioCommonDevice::new(current, handle);
lock.register_mmio_device(device);
}
}
}
•如果有效,首先为设备分配中断号:
Rust
let handle = IrqLine::alloc().unwrap();
•再向申请IOAPIC申请使能:
Rust
io_apic.enable(24 - device_count, handle.clone()).unwrap();
在IOAPIC使能的时候,将设备与中断号做一个绑定关系:
Rust
pub fn enable(&mut self, index: u8, irq: IrqLine) -> Result<()> {
if index >= self.max_redirection_entry() {
return Err(Error::InvalidArgs);
}
let value = self.access.read(Self::TABLE_REG_BASE + 2 * index);
if value.get_bits(0...8) as u8 != 0 {
return Err(Error::AccessDenied);
}
self.access
.write(Self::TABLE_REG_BASE + 2 * index, irq.num() as u32);
self.access.write(Self::TABLE_REG_BASE + 2 * index + 1, 0);
self.irqs.push(irq);
Ok(())
}
设备在IOAPIC中的地址与中断号绑定起来。
•分配MmioCommonDevice:
Rust
let device = MmioCommonDevice::new(current, handle);
•确定设备的IoMem:
Rust
let io_mem = unsafe { IoMem::new(paddr...paddr + 0x200) };
let res: MmioCommonDevice = Self {
io_mem,
irq: handle,
};
•注册这些设备:
Rust
pub(super) fn register_mmio_device(&mut self, mut mmio_device: MmioCommonDevice) {
let device_id = mmio_device.device_id();
for driver in self.drivers.iter() {
mmio_device = match driver.probe(mmio_device) {
Ok(device) => {
debug_assert!(device_id == device.device_id());
self.devices.push(device);
return;
}
Err((err, common_device)) => {
if err != BusProbeError::DeviceNotMatch {
error!("MMIO device construction failed, reason: {:?}", err);
}
debug_assert!(device_id == common_device.device_id());
common_device
}
};
}
self.common_devices.push_back(mmio_device);
}
同理,这个时候应该还没有相应的driver。
驱动初始化
在virtio的component的初始化中:
Rust
fn virtio_component_init() -> Result<(), ComponentInitError> {
// Find all devices and register them to the corresponding crate
transport::init();
首先调用了 transport::init();
Rust
pub fn init() {
virtio_pci_init();
virtio_mmio_init();
}
然后分别注册了PCI driver 与MMIO driver:
Rust
pub fn virtio_pci_init() {
VIRTIO_PCI_DRIVER.call_once(|| Arc::new(VirtioPciDriver::new()));
PCI_BUS
.lock()
.register_driver(VIRTIO_PCI_DRIVER.get().unwrap().clone());
}
Rust
pub fn virtio_mmio_init() {
VIRTIO_MMIO_DRIVER.call_once(|| Arc::new(VirtioMmioDriver::new()));
MMIO_BUS
.lock()
.register_driver(VIRTIO_MMIO_DRIVER.get().unwrap().clone());
}
为device 分配transport:
Rust
pub fn register_driver(&mut self, driver: Arc) {
debug!("Register driver:{:#x?}", driver);
let length = self.common_devices.len();
for i in (0...length).rev() {
let common_device = self.common_devices.pop_front().unwrap();
let device_id = common_device.device_id();
let device: MmioCommonDevice = match driver.probe(common_device) {
Ok(device) => {
debug_assert!(device_id == device.device_id());
self.devices.push(device);
continue;
}
Err((err, device)) => {
if err != BusProbeError::DeviceNotMatch {
error!("MMIO device construction failed, reason: {:?}", err);
}
debug_assert!(device_id == device.device_id());
device
}
};
self.common_devices.push_back(device);
}
self.drivers.push(driver);
}
Rust
impl MmioDriver for VirtioMmioDriver {
fn probe(
&self,
device: MmioCommonDevice,
) -> Result<Arc, (BusProbeError, MmioCommonDevice)> {
let device = VirtioMmioTransport::new(device);
let mmio_device = device.mmio_device().clone();
self.devices.lock().push(device);
Ok(mmio_device)
}
}
中断响应流程
设置中断响应函数,在trapframe中,为255个中断号设置中断响应函数:
Rust
pub fn init() {
extern "C" {
#[link_name = "__vectors"]
static VECTORS: [extern "C" fn(); 256];
}
let idt = Box::leak(Box::new(InterruptDescriptorTable::new()));
// let idt = sidt().base;
let entries: &'static mut [Entry<HandlerFunc>; 256] =
unsafe { core::mem::transmute_copy(&idt) };
for i in 0..256 {
let opt = entries[i].set_handler_fn(unsafe { core::mem::transmute(VECTORS[i]) });
// Enable user space `int3` and `into`
if i == 3 || i == 4 {
opt.set_privilege_level(PrivilegeLevel::Ring3);
}
}
idt.load();
}
其中VECTORS函数数组被定义在:
Rust
.global __vectors
__vectors:
.quad vector0
.quad vector1
.quad vector2
.quad vector3
.quad vector4
.quad vector5
.quad vector6
.quad vector7
.quad vector8
.quad vector9
.quad vector10
.quad vector11
.quad vector12
.quad vector13
.quad vector14
.quad vector15
.quad vector16
.quad vector17
.quad vector18
.quad vector19
数组每个成员函数:
Rust
.section .text
vector0:
push 0
push 0
jmp __alltraps
vector1:
push 0
push 1
jmp __alltraps
vector2:
push 0
push 2
jmp __alltraps
vector3:
push 0
push 3
jmp __alltraps
vector4:
push 0
push 4
jmp __alltraps
vector5:
push 0
push 5
jmp __alltraps
vector6:
push 0
push 6
jmp __alltraps
vector7:
push 0
push 7
jmp __alltraps
vector8:
push 8
jmp __alltraps
将中断响应函数组装载进IDT寄存器:
Rust
pub unsafe fn lidt(idt: &DescriptorTablePointer) {
unsafe {
asm!("lidt [{}]", in(reg) idt, options(readonly, nostack, preserves_flags));
}
}
因此每个中断号上有中断信号时候都会跳进__alltraps函数:
Rust
text
.global __alltraps
__alltraps:
push rax
/*
kernel stack:
- ptr to GeneralRegs
- ss
- rsp
- rflags
- cs
- rip
- error code
- trap num
- rax
*/
mov ax, [rsp + 4*8] # load cs
and ax, 0x3 # test
jz __from_kernel # continue trap
Rust
__from_kernel:
pop rax
push 0
push r15
push r14
push r13
push r12
push r11
push r10
push r9
push r8
lea r8, [rsp + 13*8]
push r8 # push rsp
push rbp
push rdi
push rsi
push rdx
push rcx
push rbx
push rax
mov rdi, rsp
call trap_handler
trap_handler函数在aster-frame中被实现:
Rust
extern "sysv64" fn trap_handler(f: &mut TrapFrame) {
if CpuException::is_cpu_exception(f.trap_num as u16) {
#[cfg(feature = "intel_tdx")]
if f.trap_num as u16 == 20 {
let ve_info = tdcall::get_veinfo().expect("#VE handler: fail to get VE info\n");
handle_virtual_exception(f, &ve_info);
return;
}
panic!("cannot handle kernel cpu fault now, information:{:#x?}", f);
} else {
call_irq_callback_functions(f);
}
}
调用注册进中断的的回调响应函数中处理,根据中断号找到对应的中断,再查到对应的中断回调函数。
Rust
pub(crate) fn call_irq_callback_functions(trap_frame: &TrapFrame) {
let irq_line = IRQ_LIST.get().unwrap().get(trap_frame.trap_num).unwrap();
let callback_functions = irq_line.callback_list();
for callback_function in callback_functions.iter() {
callback_function.call(trap_frame);
}
if !CpuException::is_cpu_exception(trap_frame.trap_num as u16) {
crate::arch::interrupts_ack();
}
}