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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/767190.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【创作纪念日】我的CSDN1024创作纪念

机缘 注册CSDN是很长时间了&#xff0c;但是上学时因为专业是电气工程&#xff0c;与编程打交道比较少&#xff0c;一直都是寻求帮助&#xff0c;而非内容输出。直到考研后专业改变&#xff0c;成为了主要跟软件编程、计算机知识相关的研究后&#xff0c;才逐步开启自己的CSDN…

模拟布局:为什么井、抽头和保护环至关重要

其中的关键示例是井、抽头和保护环。这些结构对于任何 MOSFET 电路的工作都至关重要。 这就是为什么了解衬底在 MOSFET 电路中的作用对于创建有效的模拟设计至关重要。要做到这一点&#xff0c;首先必须了解 MOSFET 晶体管的工作原理。 让我们来看看一种类型的 MOSFET&#x…

归并排序-MergeSort (C语言详解)

目录 前言归并排序的思想归并排序的递归法归并排序的非递归法归并排序的时间复杂度与适用场景总结 前言 好久不见, 前面我们了解到了快速排序, 那么本篇旨在介绍另外一种排序, 它和快速排序的思想雷同, 但又有区别, 这就是归并排序, 如下图, 我们对比快速排序与归并排序. 本…

编译器的控制流图分析

1&#xff0c;建立感性认识 1.1 源码 hello.c int x 10; int y 11; int main(){int z 12;for (int i 0;i < 10;i){z * x * y;}if(z>7.0)z1.0f;elsez 2.0f;return 0; }1.2 编译 2005 sudo apt-get install -y graphviz-doc libgraphviz-dev graphviz2034 ../ex_…

Java学习高级一

修饰符 static 类变量的应用场景 成员方法的分类 成员变量的执行原理 成员方法的执行原理 Java之 main 方法 类方法的常见应用场景 代码块 设计模式 单例设计模式 饿汉式单例设计模式 懒汉式单例设计模式 继承 权限修饰符

LeetCode题练习与总结:二叉树的后序遍历--145

一、题目描述 给你一棵二叉树的根节点 root &#xff0c;返回其节点值的 后序遍历 。 示例 1&#xff1a; 输入&#xff1a;root [1,null,2,3] 输出&#xff1a;[3,2,1]示例 2&#xff1a; 输入&#xff1a;root [] 输出&#xff1a;[]示例 3&#xff1a; 输入&#xff1a…

以太坊DApp交易量激增83%的背后原因解析

引言 最近&#xff0c;以太坊网络上的去中心化应用程序&#xff08;DApp&#xff09;交易量激增83%&#xff0c;引发了广泛关注和讨论。尽管交易费用高达2.4美元&#xff0c;但以太坊仍在DApp交易量方面遥遥领先于其他区块链网络。本文将深入探讨导致这一现象的主要原因&#…

颅内感染性疾病患者就诊指南

颅内感染性疾病&#xff0c;即病原体侵入中枢神经系统&#xff0c;导致脑部或脑膜发生炎症的疾病。这些病原体可能是细菌、病毒、真菌或寄生虫等。颅内感染不仅会对脑组织造成损害&#xff0c;还可能引发一系列严重的并发症&#xff0c;如癫痫发作、意识障碍等 颅内感染性疾病的…

国产软件号称Windows系统的天花板,却被误认为是外国佬研发

说起国产软件&#xff0c;大家总是容易给它们贴上“流氓、捆绑、满满的都是套路”这样的标签。 其实挺冤枉的&#xff0c;有些软件真的挺好用&#xff0c;也挺良心的&#xff0c;但就是因为这些刻板印象&#xff0c;老是被误以为是外国工程师搞出来的。 VeryCapture 之前小编…

JavaScript之深入对象,详细讲讲构造函数与常见内置构造函数

前言&#xff1a;哈喽&#xff0c;大家好&#xff0c;我是前端菜鸟的自我修养&#xff01;今天给大家详细讲讲构造函数与常见内置构造函数&#xff0c;并提供具体代码帮助大家深入理解&#xff0c;彻底掌握&#xff01;原创不易&#xff0c;如果能帮助到带大家&#xff0c;欢迎…

达梦数据库的系统视图v$deadlock_history

达梦数据库的系统视图v$deadlock_history 在达梦数据库&#xff08;DM Database&#xff09;中&#xff0c;V$DEADLOCK_HISTORY 视图记录了数据库中发生的死锁信息。通过查询这个视图&#xff0c;数据库管理员可以监控和诊断数据库中的死锁问题&#xff0c;从而采取相应的措施…

鸿蒙认证值得考吗?

鸿蒙认证值得考吗&#xff1f; 鸿蒙认证&#xff08;HarmonyOS Certification&#xff09;是华为为了培养和认证开发者在鸿蒙操作系统&#xff08;HarmonyOS&#xff09;领域的专业技能而设立的一系列认证项目。这些认证旨在帮助开发者和企业工程师提升在鸿蒙生态中的专业技能…

小故事——半个世纪的爱情

半个世纪的爱情 故事的开端永远是在那个情窦初开的年纪&#xff0c;那富有蓬勃朝气的少年时代&#xff0c;眼神中青涩未尽&#xff0c;正是这个时间&#xff0c;才真正的让人难以忘怀。她不过是那班级里面普普通通的小孩&#xff0c;故事的男主角同样也是简简单单的存在&#…

激光SLAM如何动态管理关键帧和地图

Tip: 如果你在进行深度学习、自动驾驶、模型推理、微调或AI绘画出图等任务&#xff0c;并且需要GPU资源&#xff0c;可以考虑使用UCloud云计算旗下的Compshare的GPU算力云平台。他们提供高性价比的4090 GPU&#xff0c;按时收费每卡2.6元&#xff0c;月卡只需要1.7元每小时&…

Activity、Window、DecorView的关系

目录 一、Activity、Window、DecorView的层级关系如下图所示&#xff1a; 1、Activity 2、Window 3、DecorView 二、DecorView初始化相关源码 三、DecorView显示时机 前言&#xff1a; 不同的Android版本有差异&#xff0c;以下基于Android 11进行讲解。 一、Activi…

音乐发行平台无加密开源源码

适用于唱片公司&#xff0c;用于接收物料&#xff0c;下载物料功能&#xff1a;个人或机构认证&#xff0c;上传专辑和歌曲&#xff0c;版税结算环境要求php7.4Nginx 1、导入数据库 2、/inc/conn.php里填写数据库密码等后台路径/admin&#xff08;可自行修改任意入口名称&…

Meta 3D Gen:文生 3D 模型

是由 Meta 公布的一个利用 Meta AssetGen&#xff08;模型生成&#xff09;和 TextureGen&#xff08;贴图材质生成&#xff09;的组合 AI 系统&#xff0c;可以在分分钟内生成高质量 3D 模型和高分辨率贴图纹理。 视频演示的效果非常好&#xff0c;目前只有论文&#xff0c;期…

计算机网络--网络层

一、网络层的服务和功能 网络层主要为应用层提供端对端的数据传输服务 网络层接受运输层的报文段&#xff0c;添加自己的首部&#xff0c;形成网络层分组。分组是网络层的传输单元。网络层分组在各个站点的网络层之间传输&#xff0c;最终到达接收方的网络层。接收方网络层将运…

PLC_博图系列☞TP:生成脉冲

PLC_博图系列☞TP&#xff1a;生成脉冲 文章目录 PLC_博图系列☞TP&#xff1a;生成脉冲背景介绍TP&#xff1a; 生成脉冲说明参数脉冲时序图示例 关键字&#xff1a; PLC、 西门子、 博图、 Siemens 、 TP 背景介绍 这是一篇关于PLC编程的文章&#xff0c;特别是关于西门…

快速上手文心一言指令:解锁AI对话新纪元

快速上手文心一言指令 一、引言&#xff1a;文心一言的魅力所在二、准备工作&#xff1a;了解文心一言平台2.1 轻松注册&#xff0c;开启智能对话之旅2.2 深度探索&#xff0c;掌握界面布局奥秘2.2.1 输入框&#xff1a;智慧交流的起点2.2.2 回复区&#xff1a;即时反馈的窗口2…