Asterinas 驱动框架

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();

}

}

相关推荐
影子LEON1 天前
【Asterinas】Asterinas 进程启动与切换
rust·asterinas