feat(riscv): riscv下能够运行hello world用户程序 (#770)

* feat(riscv): riscv下能够运行hello world用户程序
This commit is contained in:
LoGin
2024-04-26 11:59:47 +08:00
committed by GitHub
parent 40348dd8d5
commit 471d65cf15
33 changed files with 402 additions and 97 deletions

View File

@ -1,7 +1,7 @@
CFLAGS += -I .
kernel_driver_subdirs:=acpi disk multiboot2 timers
kernel_driver_subdirs:=acpi multiboot2
ECHO:
@echo "$@"

View File

@ -34,11 +34,11 @@ impl RiscVSbiTimer {
fn handle_irq(trap_frame: &mut TrapFrame) -> Result<(), SystemError> {
// 更新下一次中断时间
kdebug!(
"riscv_sbi_timer: handle_irq: cpu_id: {}, time: {}",
smp_get_processor_id().data(),
CurrentTimeArch::get_cycles() as u64
);
// kdebug!(
// "riscv_sbi_timer: handle_irq: cpu_id: {}, time: {}",
// smp_get_processor_id().data(),
// CurrentTimeArch::get_cycles() as u64
// );
sbi_rt::set_timer(CurrentTimeArch::get_cycles() as u64 + unsafe { INTERVAL_CNT } as u64);
ProcessManager::update_process_times(trap_frame.is_from_user());
Ok(())

View File

@ -1,10 +0,0 @@
SRC = $(wildcard *.c)
OBJ = $(SRC:.c=.o)
CFLAGS += -I .
.PHONY: all
all: $(OBJ)
%.o: %.c
$(CC) $(CFLAGS) -c $< -o $@

View File

@ -0,0 +1,13 @@
//! 参考: https://code.dragonos.org.cn/xref/linux-6.1.9/drivers/firmware/efi/esrt.c#1
use super::efi_manager;
#[inline(never)]
pub(super) fn efi_esrt_init() {
if !efi_manager().esrt_table_exists() {
return;
}
// todo: 参考linux 的 `efi_esrt_init`来实现
todo!("efi_esrt_init")
}

View File

@ -29,6 +29,15 @@ pub static EFI_MEMRESERVE_TABLE_GUID: Guid = Guid::new(
0xf0,
[0x9a, 0xee, 0x5c, 0xb9, 0x77, 0xc2],
);
pub static EFI_SYSTEM_RESOURCE_TABLE_GUID: Guid = Guid::new(
unsafe { mem::transmute_copy(&0xb122a263u32) },
unsafe { mem::transmute_copy(&0x3661u32) },
unsafe { mem::transmute_copy(&0x4f68u32) },
0x99,
0x29,
[0x78, 0xf8, 0xb0, 0xd6, 0x21, 0x80],
);
/// 表示内核被加载到的地址的信息。
///
/// 对应 `DRAGONSTUB_EFI_PAYLOAD_EFI_GUID`

View File

@ -5,7 +5,10 @@ use uefi_raw::table::boot::{MemoryAttribute, MemoryType};
use crate::{
arch::MMArch,
driver::{firmware::efi::EFIInitFlags, open_firmware::fdt::open_firmware_fdt_driver},
driver::{
firmware::efi::{esrt::efi_esrt_init, EFIInitFlags},
open_firmware::fdt::open_firmware_fdt_driver,
},
libs::align::{page_align_down, page_align_up},
mm::{
allocator::page_frame::PhysPageFrame, early_ioremap::EarlyIoRemap,
@ -66,6 +69,11 @@ pub fn efi_init() {
// todo: 模仿Linux的行为做好接下来的几步工作
// 参考: https://code.dragonos.org.cn/xref/linux-6.1.9/drivers/firmware/efi/efi-init.c#217
// todo: early_init_dt_check_for_usable_mem_range
efi_find_mirror();
efi_esrt_init();
// 保留mmap table的内存
let base = page_align_down(data_from_fdt.mmap_base.unwrap() as usize);
let offset = data_from_fdt.mmap_base.unwrap() as usize - base;
@ -78,7 +86,7 @@ pub fn efi_init() {
.expect("Failed to reserve memory for EFI mmap table");
// 保留内核的内存
if let Some(info) = efi_manager().inner.read().dragonstub_load_info {
if let Some(info) = efi_manager().inner_read().dragonstub_load_info {
mem_block_manager()
.reserve_block(
PhysAddr::new(info.paddr as usize),
@ -92,6 +100,31 @@ pub fn efi_init() {
kinfo!("UEFI init done!");
}
fn efi_find_mirror() {
let efi_guard = efi_manager().inner_read();
let mut total_size = 0;
let mut mirror_size = 0;
for md in efi_guard.mmap.iter() {
let start = PhysAddr::new(md.phys_start as usize);
let size = (md.page_count << (MMArch::PAGE_SHIFT as u64)) as usize;
if md.att.contains(MemoryAttribute::MORE_RELIABLE) {
mem_block_manager().mark_mirror(start, size).unwrap();
mirror_size += size;
}
total_size += size;
}
if mirror_size > 0 {
kinfo!(
"Memory: {}M/{}M mirrored memory",
mirror_size >> 20,
total_size >> 20
);
}
}
#[inline(never)]
fn uefi_init(system_table: PhysAddr) -> Result<(), SystemError> {
// 定义错误处理函数
@ -142,7 +175,7 @@ fn uefi_init(system_table: PhysAddr) -> Result<(), SystemError> {
let st_ref = unsafe { st_ptr.as_ref().unwrap() };
let runtime_service_paddr = efi_vaddr_2_paddr(st_ref.runtime_services as usize);
let mut inner_write_guard = efi_manager().inner.write();
let mut inner_write_guard = efi_manager().inner_write();
inner_write_guard.runtime_paddr = Some(runtime_service_paddr);
inner_write_guard.runtime_service_version = Some(st_ref.header.revision);
@ -189,7 +222,7 @@ fn uefi_init(system_table: PhysAddr) -> Result<(), SystemError> {
///
/// 在进入该函数前,请不要持有`efi_manager().inner`的写锁
fn efi_vaddr_2_paddr(efi_vaddr: usize) -> PhysAddr {
let guard = efi_manager().inner.read();
let guard = efi_manager().inner_read();
let mmap = &guard.mmap;
let efi_vaddr: u64 = efi_vaddr as u64;
@ -236,6 +269,11 @@ fn reserve_memory_regions() {
if md.is_memory() {
open_firmware_fdt_driver().early_init_dt_add_memory(phys_start as u64, size as u64);
if !md.is_usable_memory() {
// kdebug!(
// "Marking non-usable memory as nomap: {:#x}-{:#x}",
// phys_start,
// phys_start + size
// );
mem_block_manager()
.mark_nomap(PhysAddr::new(phys_start), size)
.unwrap();

View File

@ -1,9 +1,13 @@
use system_error::SystemError;
use crate::{libs::rwlock::RwLock, mm::PhysAddr};
use crate::{
libs::rwlock::{RwLock, RwLockReadGuard, RwLockWriteGuard},
mm::PhysAddr,
};
use self::{guid::DragonStubPayloadEFI, memmap::EFIMemoryMapInfo};
pub mod esrt;
mod fdt;
pub mod guid;
pub mod init;
@ -39,6 +43,8 @@ struct InnerEFIManager {
pub memory_attribute_table_paddr: Option<PhysAddr>,
/// uefi 内存保留表的物理地址
pub memreserve_table_paddr: Option<PhysAddr>,
/// uefi esrt表的物理地址
pub esrt_table_paddr: Option<PhysAddr>,
}
impl EFIManager {
@ -52,6 +58,7 @@ impl EFIManager {
dragonstub_load_info: None,
memory_attribute_table_paddr: None,
memreserve_table_paddr: None,
esrt_table_paddr: None,
}),
}
}
@ -97,6 +104,19 @@ impl EFIManager {
return Ok(());
}
fn inner_read(&self) -> RwLockReadGuard<InnerEFIManager> {
self.inner.read()
}
fn inner_write(&self) -> RwLockWriteGuard<InnerEFIManager> {
self.inner.write()
}
/// 是否存在ESRT表
fn esrt_table_exists(&self) -> bool {
self.inner_read().esrt_table_paddr.is_some()
}
}
// 在Rust中我们使用枚举和bitflags来表示这些宏

View File

@ -20,7 +20,9 @@ use crate::{
};
use super::{
guid::{EFI_MEMORY_ATTRIBUTES_TABLE_GUID, EFI_MEMRESERVE_TABLE_GUID},
guid::{
EFI_MEMORY_ATTRIBUTES_TABLE_GUID, EFI_MEMRESERVE_TABLE_GUID, EFI_SYSTEM_RESOURCE_TABLE_GUID,
},
EFIManager,
};
@ -29,6 +31,7 @@ static TABLE_PARSERS: &[&TableMatcher] = &[
&TableMatcher::new(&MatchTableDragonStubPayloadEFI),
&TableMatcher::new(&MatchTableMemoryAttributes),
&TableMatcher::new(&MatchTableMemReserve),
&TableMatcher::new(&MatchTableEsrt),
];
impl EFIManager {
@ -99,7 +102,7 @@ impl EFIManager {
}
// 如果存在mem reserve table
if let Some(mem_reserve) = efi_manager().inner.read().memreserve_table_paddr {
if let Some(mem_reserve) = efi_manager().inner_read().memreserve_table_paddr {
let mut prev_paddr = mem_reserve;
while !prev_paddr.is_null() {
let vaddr = EarlyIoRemap::map_not_aligned(prev_paddr, MMArch::PAGE_SIZE, true)
@ -283,7 +286,7 @@ impl MatchTable for MatchTableDragonStubPayloadEFI {
let vendor_table_vaddr = vendor_table_vaddr.unwrap();
let data = unsafe { *(vendor_table_vaddr.data() as *const DragonStubPayloadEFI) };
efi_manager().inner.write().dragonstub_load_info = Some(data);
efi_manager().inner_write().dragonstub_load_info = Some(data);
return Ok(());
}
@ -349,6 +352,33 @@ impl MatchTable for MatchTableMemReserve {
}
}
struct MatchTableEsrt;
impl MatchTable for MatchTableEsrt {
fn name(&self) -> &'static str {
"ESRT"
}
fn guid(&self) -> &'static uefi_raw::Guid {
&EFI_SYSTEM_RESOURCE_TABLE_GUID
}
fn map_size(&self) -> usize {
0
}
fn post_process(
&self,
_vendor_table_vaddr: Option<VirtAddr>,
table_raw: &ConfigurationTable,
) -> Result<(), SystemError> {
efi_manager().inner.write_irqsave().esrt_table_paddr =
Some(PhysAddr::new(table_raw.vendor_table as usize));
kdebug!("esrt_table_paddr: {:#x}", table_raw.vendor_table as usize);
return Ok(());
}
}
/// 用于匹配配置表的匹配器
struct TableMatcher {
table: &'static dyn MatchTable,

View File

@ -162,7 +162,7 @@ pub unsafe fn riscv_intc_init() -> Result<(), SystemError> {
/// 参考 https://code.dragonos.org.cn/xref/linux-6.6.21/drivers/irqchip/irq-riscv-intc.c#23
pub fn riscv_intc_irq(trap_frame: &mut TrapFrame) {
let hwirq = HardwareIrqNumber::new(trap_frame.cause.code() as u32);
kdebug!("riscv64_do_irq: interrupt {hwirq:?}");
// kdebug!("riscv64_do_irq: interrupt {hwirq:?}");
GenericIrqHandler::handle_domain_irq(riscv_intc_domain().clone().unwrap(), hwirq, trap_frame)
.ok();
if hwirq.data() == RiscVSbiTimer::TIMER_IRQ.data() {

View File

@ -1,6 +0,0 @@
all:
CFLAGS += -I .
#HPET.o: HPET/HPET.c
# $(CC) $(CFLAGS) -c HPET/HPET.c -o HPET/HPET.o