rv64: boot into upper half
This commit is contained in:
parent
07458f33e4
commit
86eb2d3252
16
Cargo.lock
generated
16
Cargo.lock
generated
@ -967,6 +967,7 @@ dependencies = [
|
|||||||
"kernel-arch-hosted",
|
"kernel-arch-hosted",
|
||||||
"kernel-arch-i686",
|
"kernel-arch-i686",
|
||||||
"kernel-arch-interface",
|
"kernel-arch-interface",
|
||||||
|
"kernel-arch-riscv64",
|
||||||
"kernel-arch-x86_64",
|
"kernel-arch-x86_64",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -1018,6 +1019,20 @@ dependencies = [
|
|||||||
"yggdrasil-abi",
|
"yggdrasil-abi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "kernel-arch-riscv64"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 2.6.0",
|
||||||
|
"device-api",
|
||||||
|
"kernel-arch-interface",
|
||||||
|
"libk-mm-interface",
|
||||||
|
"memtables",
|
||||||
|
"static_assertions",
|
||||||
|
"tock-registers 0.9.0",
|
||||||
|
"yggdrasil-abi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "kernel-arch-x86"
|
name = "kernel-arch-x86"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
@ -2658,6 +2673,7 @@ dependencies = [
|
|||||||
"kernel-arch-aarch64",
|
"kernel-arch-aarch64",
|
||||||
"kernel-arch-i686",
|
"kernel-arch-i686",
|
||||||
"kernel-arch-interface",
|
"kernel-arch-interface",
|
||||||
|
"kernel-arch-riscv64",
|
||||||
"kernel-arch-x86",
|
"kernel-arch-x86",
|
||||||
"kernel-arch-x86_64",
|
"kernel-arch-x86_64",
|
||||||
"libk",
|
"libk",
|
||||||
|
@ -16,8 +16,9 @@ members = [
|
|||||||
"lib/abi",
|
"lib/abi",
|
||||||
"lib/libyalloc",
|
"lib/libyalloc",
|
||||||
"lib/runtime",
|
"lib/runtime",
|
||||||
"lib/qemu"
|
"lib/qemu",
|
||||||
, "lib/abi-serde"]
|
"lib/abi-serde"
|
||||||
|
]
|
||||||
|
|
||||||
[workspace.dependencies]
|
[workspace.dependencies]
|
||||||
chrono = { version = "0.4.38", default-features = false, features = ["alloc"] }
|
chrono = { version = "0.4.38", default-features = false, features = ["alloc"] }
|
||||||
@ -53,6 +54,7 @@ abi-generator.path = "tool/abi-generator"
|
|||||||
# Kernel parts
|
# Kernel parts
|
||||||
kernel-arch-interface.path = "kernel/arch/interface"
|
kernel-arch-interface.path = "kernel/arch/interface"
|
||||||
kernel-arch-aarch64.path = "kernel/arch/aarch64"
|
kernel-arch-aarch64.path = "kernel/arch/aarch64"
|
||||||
|
kernel-arch-riscv64.path = "kernel/arch/riscv64"
|
||||||
kernel-arch-x86_64.path = "kernel/arch/x86_64"
|
kernel-arch-x86_64.path = "kernel/arch/x86_64"
|
||||||
kernel-arch-i686.path = "kernel/arch/i686"
|
kernel-arch-i686.path = "kernel/arch/i686"
|
||||||
kernel-arch-x86.path = "kernel/arch/x86"
|
kernel-arch-x86.path = "kernel/arch/x86"
|
||||||
|
57
etc/ld/riscv/riscv64-unknown-qemu.ld
Normal file
57
etc/ld/riscv/riscv64-unknown-qemu.ld
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
ENTRY(__rv64_entry);
|
||||||
|
|
||||||
|
KERNEL_PHYS_BASE = 0x80000000;
|
||||||
|
KERNEL_VIRT_OFFSET = 0xFFFFFFF000000000;
|
||||||
|
|
||||||
|
SECTIONS {
|
||||||
|
. = KERNEL_PHYS_BASE;
|
||||||
|
PROVIDE(__kernel_start = . + KERNEL_VIRT_OFFSET);
|
||||||
|
|
||||||
|
.text.entry : {
|
||||||
|
*(.text.entry)
|
||||||
|
}
|
||||||
|
|
||||||
|
. = ALIGN(16);
|
||||||
|
. = . + KERNEL_VIRT_OFFSET;
|
||||||
|
|
||||||
|
.text : AT(. - KERNEL_VIRT_OFFSET) {
|
||||||
|
KEEP(*(.text.vectors));
|
||||||
|
*(.text*)
|
||||||
|
}
|
||||||
|
|
||||||
|
. = ALIGN(4K);
|
||||||
|
.rodata : AT(. - KERNEL_VIRT_OFFSET) {
|
||||||
|
*(.rodata*)
|
||||||
|
*(.eh_frame*)
|
||||||
|
|
||||||
|
. = ALIGN(16);
|
||||||
|
PROVIDE(__init_array_start = .);
|
||||||
|
KEEP(*(.init_array*))
|
||||||
|
PROVIDE(__init_array_end = .);
|
||||||
|
}
|
||||||
|
|
||||||
|
. = ALIGN(4K);
|
||||||
|
.data.tables : AT (. - KERNEL_VIRT_OFFSET) {
|
||||||
|
KEEP(*(.data.tables))
|
||||||
|
}
|
||||||
|
|
||||||
|
. = ALIGN(4K);
|
||||||
|
.data : AT(. - KERNEL_VIRT_OFFSET) {
|
||||||
|
*(.data*)
|
||||||
|
. = ALIGN(8);
|
||||||
|
PROVIDE(__global_pointer = . + 0x800 - KERNEL_VIRT_OFFSET);
|
||||||
|
*(.got*)
|
||||||
|
}
|
||||||
|
|
||||||
|
. = ALIGN(4K);
|
||||||
|
PROVIDE(__bss_start_phys = . - KERNEL_VIRT_OFFSET);
|
||||||
|
.bss : AT(. - KERNEL_VIRT_OFFSET) {
|
||||||
|
*(COMMON)
|
||||||
|
*(.bss*)
|
||||||
|
}
|
||||||
|
. = ALIGN(4K);
|
||||||
|
PROVIDE(__bss_end_phys = . - KERNEL_VIRT_OFFSET);
|
||||||
|
PROVIDE(__bss_size = __bss_end_phys - __bss_start_phys);
|
||||||
|
|
||||||
|
PROVIDE(__kernel_end = .);
|
||||||
|
};
|
25
etc/riscv64-unknown-none.json
Normal file
25
etc/riscv64-unknown-none.json
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
{
|
||||||
|
"arch": "riscv64",
|
||||||
|
"os": "none",
|
||||||
|
"abi": "softfloat",
|
||||||
|
"cpu": "generic-rv64",
|
||||||
|
"llvm-target": "riscv64",
|
||||||
|
"data-layout": "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128",
|
||||||
|
"max-atomic-width": 64,
|
||||||
|
"target-pointer-width": "64",
|
||||||
|
"features": "+m,+a,+c",
|
||||||
|
|
||||||
|
"disable-redzone": true,
|
||||||
|
"executables": true,
|
||||||
|
"panic-strategy": "abort",
|
||||||
|
"dynamic-linking": true,
|
||||||
|
"relocation-model": "pic",
|
||||||
|
"eh-frame-header": false,
|
||||||
|
|
||||||
|
"crt-objects-fallback": "false",
|
||||||
|
"emit-debug-gdb-scripts": false,
|
||||||
|
"llvm-abiname": "lp64",
|
||||||
|
|
||||||
|
"linker": "rust-lld",
|
||||||
|
"linker-flavor": "ld.lld"
|
||||||
|
}
|
@ -53,6 +53,9 @@ aarch64-cpu.workspace = true
|
|||||||
device-tree.workspace = true
|
device-tree.workspace = true
|
||||||
kernel-arch-aarch64.workspace = true
|
kernel-arch-aarch64.workspace = true
|
||||||
|
|
||||||
|
[target.'cfg(target_arch = "riscv64")'.dependencies]
|
||||||
|
kernel-arch-riscv64.workspace = true
|
||||||
|
|
||||||
[target.'cfg(target_arch = "x86_64")'.dependencies]
|
[target.'cfg(target_arch = "x86_64")'.dependencies]
|
||||||
yboot-proto.workspace = true
|
yboot-proto.workspace = true
|
||||||
kernel-arch-x86_64.workspace = true
|
kernel-arch-x86_64.workspace = true
|
||||||
@ -81,6 +84,7 @@ kernel-arch-x86_64.workspace = true
|
|||||||
kernel-arch-i686.workspace = true
|
kernel-arch-i686.workspace = true
|
||||||
kernel-arch-x86.workspace = true
|
kernel-arch-x86.workspace = true
|
||||||
kernel-arch-aarch64.workspace = true
|
kernel-arch-aarch64.workspace = true
|
||||||
|
kernel-arch-riscv64.workspace = true
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["fb_console"]
|
default = ["fb_console"]
|
||||||
|
@ -3,21 +3,22 @@ name = "kernel-arch"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
|
||||||
|
|
||||||
[target.'cfg(all(target_os = "none", target_arch = "x86_64"))'.dependencies]
|
[target.'cfg(all(target_os = "none", target_arch = "x86_64"))'.dependencies]
|
||||||
kernel-arch-x86_64 = { path = "x86_64" }
|
kernel-arch-x86_64.path = "x86_64"
|
||||||
|
|
||||||
[target.'cfg(all(target_os = "none", target_arch = "aarch64"))'.dependencies]
|
[target.'cfg(all(target_os = "none", target_arch = "aarch64"))'.dependencies]
|
||||||
kernel-arch-aarch64 = { path = "aarch64" }
|
kernel-arch-aarch64.path = "aarch64"
|
||||||
|
|
||||||
[target.'cfg(all(target_os = "none", target_arch = "x86"))'.dependencies]
|
[target.'cfg(all(target_os = "none", target_arch = "x86"))'.dependencies]
|
||||||
kernel-arch-i686 = { path = "i686" }
|
kernel-arch-i686.path = "i686"
|
||||||
|
|
||||||
|
[target.'cfg(all(target_os = "none", target_arch = "riscv64"))'.dependencies]
|
||||||
|
kernel-arch-riscv64.path = "riscv64"
|
||||||
|
|
||||||
[target.'cfg(not(target_os = "none"))'.dependencies]
|
[target.'cfg(not(target_os = "none"))'.dependencies]
|
||||||
kernel-arch-hosted = { path = "hosted" }
|
kernel-arch-hosted.path = "hosted"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
kernel-arch-interface = { path = "interface" }
|
kernel-arch-interface.path = "interface"
|
||||||
|
|
||||||
cfg-if.workspace = true
|
cfg-if.workspace = true
|
||||||
|
18
kernel/arch/riscv64/Cargo.toml
Normal file
18
kernel/arch/riscv64/Cargo.toml
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
[package]
|
||||||
|
name = "kernel-arch-riscv64"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2024"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
yggdrasil-abi.workspace = true
|
||||||
|
kernel-arch-interface.workspace = true
|
||||||
|
libk-mm-interface.workspace = true
|
||||||
|
memtables.workspace = true
|
||||||
|
device-api = { workspace = true, features = ["derive"] }
|
||||||
|
|
||||||
|
tock-registers.workspace = true
|
||||||
|
bitflags.workspace = true
|
||||||
|
static_assertions.workspace = true
|
||||||
|
|
||||||
|
[lints]
|
||||||
|
workspace = true
|
54
kernel/arch/riscv64/src/context.rs
Normal file
54
kernel/arch/riscv64/src/context.rs
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
use core::marker::PhantomData;
|
||||||
|
|
||||||
|
use kernel_arch_interface::{
|
||||||
|
mem::{KernelTableManager, PhysicalMemoryAllocator},
|
||||||
|
task::{TaskContext, UserContextInfo},
|
||||||
|
};
|
||||||
|
use libk_mm_interface::address::PhysicalAddress;
|
||||||
|
use yggdrasil_abi::error::Error;
|
||||||
|
|
||||||
|
pub struct TaskContextImpl<K, PA> {
|
||||||
|
_pd: PhantomData<(K, PA)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<K: KernelTableManager, PA: PhysicalMemoryAllocator<Address = PhysicalAddress>>
|
||||||
|
TaskContext<K, PA> for TaskContextImpl<K, PA>
|
||||||
|
{
|
||||||
|
const USER_STACK_EXTRA_ALIGN: usize = 0;
|
||||||
|
const SIGNAL_STACK_EXTRA_ALIGN: usize = 0;
|
||||||
|
|
||||||
|
fn user(context: UserContextInfo) -> Result<Self, Error> {
|
||||||
|
let _ = context;
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn kernel(entry: extern "C" fn(usize) -> !, arg: usize) -> Result<Self, Error> {
|
||||||
|
let _ = entry;
|
||||||
|
let _ = arg;
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_thread_pointer(&self, tp: usize) {
|
||||||
|
let _ = tp;
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn align_stack_for_entry(sp: usize) -> usize {
|
||||||
|
let _ = sp;
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn enter(&self) -> ! {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn switch(&self, from: &Self) {
|
||||||
|
let _ = from;
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn switch_and_drop(&self, thread: *const ()) {
|
||||||
|
let _ = thread;
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
109
kernel/arch/riscv64/src/lib.rs
Normal file
109
kernel/arch/riscv64/src/lib.rs
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
#![feature(decl_macro)]
|
||||||
|
#![no_std]
|
||||||
|
|
||||||
|
extern crate alloc;
|
||||||
|
|
||||||
|
use alloc::vec::Vec;
|
||||||
|
use device_api::interrupt::{LocalInterruptController, MessageInterruptController};
|
||||||
|
use kernel_arch_interface::{
|
||||||
|
cpu::{CpuImpl, IpiQueue},
|
||||||
|
task::Scheduler,
|
||||||
|
Architecture,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub mod mem;
|
||||||
|
pub use mem::{KernelTableManagerImpl, ProcessAddressSpaceImpl};
|
||||||
|
pub mod context;
|
||||||
|
pub use context::TaskContextImpl;
|
||||||
|
use registers::MSTATUS;
|
||||||
|
use tock_registers::interfaces::{ReadWriteable, Readable};
|
||||||
|
pub mod registers;
|
||||||
|
|
||||||
|
pub struct ArchitectureImpl;
|
||||||
|
|
||||||
|
impl Architecture for ArchitectureImpl {
|
||||||
|
type PerCpuData = ();
|
||||||
|
type CpuFeatures = ();
|
||||||
|
type BreakpointType = u32;
|
||||||
|
|
||||||
|
const BREAKPOINT_VALUE: Self::BreakpointType = 0;
|
||||||
|
|
||||||
|
fn halt() -> ! {
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn set_local_cpu(cpu: *mut ()) {
|
||||||
|
let _ = cpu;
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn local_cpu() -> *mut () {
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn init_local_cpu<S: Scheduler + 'static>(id: Option<u32>, data: Self::PerCpuData) {
|
||||||
|
let _ = id;
|
||||||
|
let _ = data;
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn init_ipi_queues(queues: Vec<IpiQueue<Self>>) {
|
||||||
|
let _ = queues;
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ipi_queue(cpu_id: u32) -> Option<&'static IpiQueue<Self>> {
|
||||||
|
let _ = cpu_id;
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
unsafe fn set_interrupt_mask(mask: bool) -> bool {
|
||||||
|
let old = Self::interrupt_mask();
|
||||||
|
if mask {
|
||||||
|
MSTATUS.modify(MSTATUS::MIE::CLEAR);
|
||||||
|
} else {
|
||||||
|
MSTATUS.modify(MSTATUS::MIE::SET);
|
||||||
|
}
|
||||||
|
old
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn interrupt_mask() -> bool {
|
||||||
|
MSTATUS.matches_all(MSTATUS::MIE::SET)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn wait_for_interrupt() {
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cpu_count() -> usize {
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cpu_index<S: Scheduler + 'static>() -> u32 {
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cpu_enabled_features<S: Scheduler>(cpu: &CpuImpl<Self, S>) -> Option<&Self::CpuFeatures> {
|
||||||
|
let _ = cpu;
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cpu_available_features<S: Scheduler>(cpu: &CpuImpl<Self, S>) -> Option<&Self::CpuFeatures> {
|
||||||
|
let _ = cpu;
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn local_interrupt_controller() -> Option<&'static dyn LocalInterruptController> {
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn message_interrupt_controller() -> Option<&'static dyn MessageInterruptController> {
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn idle_task() -> extern "C" fn(usize) -> ! {
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
}
|
120
kernel/arch/riscv64/src/mem/mod.rs
Normal file
120
kernel/arch/riscv64/src/mem/mod.rs
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
use core::marker::PhantomData;
|
||||||
|
|
||||||
|
use kernel_arch_interface::{
|
||||||
|
mem::{DeviceMemoryAttributes, KernelTableManager, RawDeviceMemoryMapping},
|
||||||
|
split_spinlock,
|
||||||
|
};
|
||||||
|
use libk_mm_interface::{
|
||||||
|
address::PhysicalAddress,
|
||||||
|
process::ProcessAddressSpaceManager,
|
||||||
|
table::{page_index, MapAttributes, TableAllocator},
|
||||||
|
};
|
||||||
|
use static_assertions::const_assert_eq;
|
||||||
|
use table::{L1, L2};
|
||||||
|
use yggdrasil_abi::error::Error;
|
||||||
|
|
||||||
|
pub use memtables::riscv64::FixedTables;
|
||||||
|
|
||||||
|
pub mod table;
|
||||||
|
|
||||||
|
split_spinlock! {
|
||||||
|
use crate::ArchitectureImpl;
|
||||||
|
use crate::mem::FixedTables;
|
||||||
|
use libk_mm_interface::KernelImageObject;
|
||||||
|
|
||||||
|
#[link_section = ".data.tables"]
|
||||||
|
#[used]
|
||||||
|
static KERNEL_TABLES: KernelImageObject<FixedTables> =
|
||||||
|
unsafe { KernelImageObject::new(FixedTables::zeroed()) };
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const KERNEL_VIRT_OFFSET: usize = 0xFFFFFFF0_00000000;
|
||||||
|
pub const KERNEL_PHYS_BASE: usize = 0x80000000;
|
||||||
|
pub const SIGN_EXTEND_MASK: usize = 0xFFFFFFC0_00000000;
|
||||||
|
|
||||||
|
pub const KERNEL_START_L1I: usize = page_index::<L1>(KERNEL_VIRT_OFFSET + KERNEL_PHYS_BASE);
|
||||||
|
pub const KERNEL_L2I: usize = page_index::<L2>(KERNEL_VIRT_OFFSET + KERNEL_PHYS_BASE);
|
||||||
|
const_assert_eq!(KERNEL_START_L1I, 450);
|
||||||
|
const_assert_eq!(KERNEL_L2I, 0);
|
||||||
|
|
||||||
|
/// Any VAs above this one are sign-extended
|
||||||
|
pub const USER_BOUNDARY: usize = 0x40_00000000;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct KernelTableManagerImpl;
|
||||||
|
|
||||||
|
pub struct ProcessAddressSpaceImpl<TA: TableAllocator> {
|
||||||
|
_pd: PhantomData<TA>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl KernelTableManager for KernelTableManagerImpl {
|
||||||
|
fn virtualize(phys: u64) -> usize {
|
||||||
|
let _ = phys;
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn physicalize(virt: usize) -> u64 {
|
||||||
|
let _ = virt;
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn map_device_pages(
|
||||||
|
base: u64,
|
||||||
|
count: usize,
|
||||||
|
attrs: DeviceMemoryAttributes,
|
||||||
|
) -> Result<RawDeviceMemoryMapping<Self>, Error> {
|
||||||
|
let _ = base;
|
||||||
|
let _ = count;
|
||||||
|
let _ = attrs;
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn unmap_device_pages(mapping: &RawDeviceMemoryMapping<Self>) {
|
||||||
|
let _ = mapping;
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn unmap_physical_address(virt: usize) {
|
||||||
|
let _ = virt;
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<TA: TableAllocator> ProcessAddressSpaceManager<TA> for ProcessAddressSpaceImpl<TA> {
|
||||||
|
const LOWER_LIMIT_PFN: usize = 0;
|
||||||
|
const UPPER_LIMIT_PFN: usize = 0;
|
||||||
|
|
||||||
|
fn new() -> Result<Self, Error> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn map_page(
|
||||||
|
&mut self,
|
||||||
|
address: usize,
|
||||||
|
physical: PhysicalAddress,
|
||||||
|
flags: MapAttributes,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
let _ = address;
|
||||||
|
let _ = physical;
|
||||||
|
let _ = flags;
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn unmap_page(&mut self, address: usize) -> Result<PhysicalAddress, Error> {
|
||||||
|
let _ = address;
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn translate(&self, address: usize) -> Result<(PhysicalAddress, MapAttributes), Error> {
|
||||||
|
let _ = address;
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_address_with_asid(&self) -> u64 {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn clear(&mut self) {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
169
kernel/arch/riscv64/src/mem/table.rs
Normal file
169
kernel/arch/riscv64/src/mem/table.rs
Normal file
@ -0,0 +1,169 @@
|
|||||||
|
use core::{
|
||||||
|
marker::PhantomData,
|
||||||
|
ops::{Index, IndexMut},
|
||||||
|
};
|
||||||
|
|
||||||
|
use bitflags::bitflags;
|
||||||
|
use libk_mm_interface::{
|
||||||
|
address::PhysicalAddress,
|
||||||
|
pointer::{PhysicalRef, PhysicalRefMut},
|
||||||
|
table::{EntryLevel, NextPageTable, NonTerminalEntryLevel, TableAllocator},
|
||||||
|
};
|
||||||
|
use yggdrasil_abi::error::Error;
|
||||||
|
|
||||||
|
use super::KernelTableManagerImpl;
|
||||||
|
|
||||||
|
bitflags! {
|
||||||
|
pub struct PageAttributes: u64 {
|
||||||
|
const N = 1 << 63;
|
||||||
|
/// Dirty bit
|
||||||
|
const D = 1 << 7;
|
||||||
|
/// Access bit
|
||||||
|
const A = 1 << 6;
|
||||||
|
/// Global mapping bit, implies all lower levels are also global
|
||||||
|
const G = 1 << 5;
|
||||||
|
/// U-mode access permission
|
||||||
|
const U = 1 << 4;
|
||||||
|
/// Execute permission
|
||||||
|
const X = 1 << 3;
|
||||||
|
/// Write permission
|
||||||
|
const W = 1 << 2;
|
||||||
|
/// Read-permission
|
||||||
|
const R = 1 << 1;
|
||||||
|
/// Valid bit
|
||||||
|
const V = 1 << 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// X W R Meaning
|
||||||
|
// 0 0 0 Pointer to next level of page table
|
||||||
|
// 0 0 1 Read-only page
|
||||||
|
// 0 1 0 ---
|
||||||
|
// 0 1 1 Read-write page
|
||||||
|
// 1 0 0 Execute only
|
||||||
|
// 1 0 1 Read-execute page
|
||||||
|
// 1 1 0 ---
|
||||||
|
// 1 1 1 Read-write-execute page
|
||||||
|
}
|
||||||
|
|
||||||
|
/// L3 - entry is 4KiB
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub struct L3;
|
||||||
|
/// L2 - entry is 2MiB
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub struct L2;
|
||||||
|
/// L1 - entry is 1GiB
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub struct L1;
|
||||||
|
|
||||||
|
impl EntryLevel for L3 {
|
||||||
|
const SHIFT: usize = 12;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EntryLevel for L2 {
|
||||||
|
const SHIFT: usize = 21;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EntryLevel for L1 {
|
||||||
|
const SHIFT: usize = 30;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C, align(0x1000))]
|
||||||
|
pub struct PageTable<L: EntryLevel> {
|
||||||
|
entries: [PageEntry<L>; 512],
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
|
pub struct PageEntry<L: EntryLevel>(u64, PhantomData<L>);
|
||||||
|
|
||||||
|
impl NonTerminalEntryLevel for L1 {
|
||||||
|
type NextLevel = L2;
|
||||||
|
}
|
||||||
|
impl NonTerminalEntryLevel for L2 {
|
||||||
|
type NextLevel = L3;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<L: EntryLevel> PageTable<L> {
|
||||||
|
pub const fn zeroed() -> Self {
|
||||||
|
Self {
|
||||||
|
entries: [PageEntry::INVALID; 512],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<L: EntryLevel> PageEntry<L> {
|
||||||
|
pub const INVALID: Self = Self(0, PhantomData);
|
||||||
|
|
||||||
|
pub const fn is_present(&self) -> bool {
|
||||||
|
self.0 & PageAttributes::V.bits() != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn attributes(self) -> PageAttributes {
|
||||||
|
PageAttributes::from_bits_retain(self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<L: NonTerminalEntryLevel + 'static> NextPageTable for PageTable<L> {
|
||||||
|
type NextLevel = PageTable<L::NextLevel>;
|
||||||
|
type TableRef = PhysicalRef<'static, PageTable<L::NextLevel>, KernelTableManagerImpl>;
|
||||||
|
type TableRefMut = PhysicalRefMut<'static, PageTable<L::NextLevel>, KernelTableManagerImpl>;
|
||||||
|
|
||||||
|
fn get(&self, _index: usize) -> Option<Self::TableRef> {
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_mut(&mut self, _index: usize) -> Option<Self::TableRefMut> {
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_mut_or_alloc<TA: TableAllocator>(
|
||||||
|
&mut self,
|
||||||
|
_index: usize,
|
||||||
|
) -> Result<Self::TableRefMut, Error> {
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<L: NonTerminalEntryLevel> PageEntry<L> {
|
||||||
|
pub fn block(address: PhysicalAddress, attrs: PageAttributes) -> Self {
|
||||||
|
// TODO validate address alignment
|
||||||
|
Self(
|
||||||
|
(address.into_u64() >> 2) | (PageAttributes::R | PageAttributes::V | attrs).bits(),
|
||||||
|
PhantomData,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn table(address: PhysicalAddress, mut attrs: PageAttributes) -> Self {
|
||||||
|
attrs.remove(PageAttributes::R | PageAttributes::W | PageAttributes::X);
|
||||||
|
Self(
|
||||||
|
(address.into_u64() >> 2) | (PageAttributes::V | attrs).bits(),
|
||||||
|
PhantomData,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PageEntry<L3> {
|
||||||
|
pub fn page(address: PhysicalAddress, attrs: PageAttributes) -> Self {
|
||||||
|
Self(
|
||||||
|
(address.into_u64() >> 2) | (PageAttributes::R | PageAttributes::V | attrs).bits(),
|
||||||
|
PhantomData,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_page(&self) -> Option<PhysicalAddress> {
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<L: EntryLevel> Index<usize> for PageTable<L> {
|
||||||
|
type Output = PageEntry<L>;
|
||||||
|
|
||||||
|
fn index(&self, index: usize) -> &Self::Output {
|
||||||
|
&self.entries[index]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<L: EntryLevel> IndexMut<usize> for PageTable<L> {
|
||||||
|
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
|
||||||
|
&mut self.entries[index]
|
||||||
|
}
|
||||||
|
}
|
183
kernel/arch/riscv64/src/registers.rs
Normal file
183
kernel/arch/riscv64/src/registers.rs
Normal file
@ -0,0 +1,183 @@
|
|||||||
|
macro impl_csr_read($struct:ident, $repr:ty, $reg:ident, $register:ty) {
|
||||||
|
impl tock_registers::interfaces::Readable for $struct {
|
||||||
|
type T = $repr;
|
||||||
|
type R = $register;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn get(&self) -> $repr {
|
||||||
|
let mut value: $repr;
|
||||||
|
unsafe {
|
||||||
|
core::arch::asm!(concat!("csrr {0}, ", stringify!($reg)), out(reg) value);
|
||||||
|
}
|
||||||
|
value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
macro impl_csr_write($struct:ident, $repr:ty, $reg:ident, $register:ty) {
|
||||||
|
impl tock_registers::interfaces::Writeable for $struct {
|
||||||
|
type T = $repr;
|
||||||
|
type R = $register;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn set(&self, value: $repr) {
|
||||||
|
unsafe {
|
||||||
|
core::arch::asm!(concat!("csrw ", stringify!($reg), ", {0}"), in(reg) value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub mod misa {
|
||||||
|
use tock_registers::{interfaces::Readable, register_bitfields};
|
||||||
|
|
||||||
|
use super::{impl_csr_read, impl_csr_write};
|
||||||
|
|
||||||
|
register_bitfields!(
|
||||||
|
u64,
|
||||||
|
pub MISA [
|
||||||
|
A OFFSET(0) NUMBITS(1) [],
|
||||||
|
C OFFSET(2) NUMBITS(1) [],
|
||||||
|
D OFFSET(3) NUMBITS(1) [],
|
||||||
|
E OFFSET(4) NUMBITS(1) [],
|
||||||
|
F OFFSET(5) NUMBITS(1) [],
|
||||||
|
H OFFSET(6) NUMBITS(1) [],
|
||||||
|
I OFFSET(7) NUMBITS(1) [],
|
||||||
|
M OFFSET(12) NUMBITS(1) [],
|
||||||
|
Q OFFSET(16) NUMBITS(1) [],
|
||||||
|
S OFFSET(17) NUMBITS(1) [],
|
||||||
|
U OFFSET(18) NUMBITS(1) [],
|
||||||
|
X OFFSET(23) NUMBITS(1) [],
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
pub struct Reg;
|
||||||
|
|
||||||
|
impl_csr_read!(Reg, u64, misa, MISA::Register);
|
||||||
|
impl_csr_write!(Reg, u64, misa, MISA::Register);
|
||||||
|
|
||||||
|
impl Reg {
|
||||||
|
pub fn is_valid(&self) -> bool {
|
||||||
|
self.get() != 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const MISA: Reg = Reg;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub mod mstatus {
|
||||||
|
use tock_registers::register_bitfields;
|
||||||
|
|
||||||
|
use super::{impl_csr_read, impl_csr_write};
|
||||||
|
|
||||||
|
register_bitfields!(
|
||||||
|
u64,
|
||||||
|
pub MSTATUS [
|
||||||
|
/// Interrupt enable for S-mode
|
||||||
|
SIE OFFSET(1) NUMBITS(1) [],
|
||||||
|
/// Interrupt enable for M-mode
|
||||||
|
MIE OFFSET(3) NUMBITS(1) [],
|
||||||
|
/// Stored SIE state on S-mode trap delegation
|
||||||
|
SPIE OFFSET(5) NUMBITS(1) [],
|
||||||
|
/// U-mode big endian
|
||||||
|
UBE OFFSET(6) NUMBITS(1) [],
|
||||||
|
/// TODO: something written here on trap to M-mode
|
||||||
|
MPIE OFFSET(7) NUMBITS(1) [],
|
||||||
|
/// TODO: something for nested traps
|
||||||
|
SPP OFFSET(8) NUMBITS(1) [],
|
||||||
|
/// Vector register dirty status
|
||||||
|
VS OFFSET(9) NUMBITS(2) [],
|
||||||
|
/// Original mode before being trapped into M-mode
|
||||||
|
MPP OFFSET(11) NUMBITS(2) [
|
||||||
|
U = 0,
|
||||||
|
S = 1,
|
||||||
|
M = 3
|
||||||
|
],
|
||||||
|
/// Float register dirty status
|
||||||
|
FS OFFSET(13) NUMBITS(2) [],
|
||||||
|
/// U-mode extension dirty status
|
||||||
|
XS OFFSET(15) NUMBITS(2) [],
|
||||||
|
/// Effective privilege mode at which loads and stores execute.
|
||||||
|
///
|
||||||
|
/// When MPRV = 0, loads and stores behave as normal
|
||||||
|
/// MPRV = 1, loads/stores are translated and protected
|
||||||
|
MPRV OFFSET(17) NUMBITS(1) [],
|
||||||
|
/// Permit supervisor user memory access
|
||||||
|
///
|
||||||
|
/// When SUM = 0, S-mode access to pages accessible by U-mode will fault
|
||||||
|
SUM OFFSET(18) NUMBITS(1) [],
|
||||||
|
MXR OFFSET(19) NUMBITS(1) [],
|
||||||
|
/// Trap virtual memory
|
||||||
|
///
|
||||||
|
/// When TVM = 1, attempts to read/write satp CSR, execute sfence.vma or sinval.vma
|
||||||
|
/// in S-mode will raise an illegal instruction exception
|
||||||
|
TVM OFFSET(20) NUMBITS(1) [],
|
||||||
|
/// Timeout wait
|
||||||
|
///
|
||||||
|
/// When TW = 1, wfi executed in lower privilege level which does not complete
|
||||||
|
/// within some implementation-specific timeout, raises an illegal
|
||||||
|
/// instruction exception
|
||||||
|
TW OFFSET(21) NUMBITS(1) [],
|
||||||
|
TSR OFFSET(22) NUMBITS(1) [],
|
||||||
|
/// U-mode XLEN value
|
||||||
|
UXL OFFSET(32) NUMBITS(2) [],
|
||||||
|
/// S-mode XLEN value
|
||||||
|
SXL OFFSET(34) NUMBITS(2) [],
|
||||||
|
/// S-mode big endian
|
||||||
|
SBE OFFSET(36) NUMBITS(1) [],
|
||||||
|
/// M-mode big endian
|
||||||
|
MBE OFFSET(37) NUMBITS(1) [],
|
||||||
|
SD OFFSET(63) NUMBITS(1) [],
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
pub struct Reg;
|
||||||
|
|
||||||
|
impl_csr_read!(Reg, u64, mstatus, MSTATUS::Register);
|
||||||
|
impl_csr_write!(Reg, u64, mstatus, MSTATUS::Register);
|
||||||
|
|
||||||
|
pub const MSTATUS: Reg = Reg;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub mod mepc {
|
||||||
|
use super::{impl_csr_read, impl_csr_write};
|
||||||
|
|
||||||
|
pub struct Reg;
|
||||||
|
|
||||||
|
impl_csr_read!(Reg, u64, mepc, ());
|
||||||
|
impl_csr_write!(Reg, u64, mepc, ());
|
||||||
|
|
||||||
|
pub const MEPC: Reg = Reg;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub mod satp {
|
||||||
|
use tock_registers::register_bitfields;
|
||||||
|
|
||||||
|
use super::{impl_csr_read, impl_csr_write};
|
||||||
|
|
||||||
|
register_bitfields!(
|
||||||
|
u64,
|
||||||
|
pub SATP [
|
||||||
|
PPN OFFSET(0) NUMBITS(44) [],
|
||||||
|
ASID OFFSET(44) NUMBITS(16) [],
|
||||||
|
MODE OFFSET(60) NUMBITS(4) [
|
||||||
|
Bare = 0,
|
||||||
|
Sv39 = 8,
|
||||||
|
Sv48 = 9,
|
||||||
|
Sv57 = 10,
|
||||||
|
Sv64 = 11,
|
||||||
|
],
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
pub struct Reg;
|
||||||
|
|
||||||
|
impl_csr_read!(Reg, u64, satp, SATP::Register);
|
||||||
|
impl_csr_write!(Reg, u64, satp, SATP::Register);
|
||||||
|
|
||||||
|
pub const SATP: Reg = Reg;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub use mepc::MEPC;
|
||||||
|
pub use misa::MISA;
|
||||||
|
pub use mstatus::MSTATUS;
|
||||||
|
pub use satp::SATP;
|
@ -28,6 +28,8 @@ cfg_if! {
|
|||||||
extern crate kernel_arch_x86_64 as imp;
|
extern crate kernel_arch_x86_64 as imp;
|
||||||
} else if #[cfg(target_arch = "x86")] {
|
} else if #[cfg(target_arch = "x86")] {
|
||||||
extern crate kernel_arch_i686 as imp;
|
extern crate kernel_arch_i686 as imp;
|
||||||
|
} else if #[cfg(target_arch = "riscv64")] {
|
||||||
|
extern crate kernel_arch_riscv64 as imp;
|
||||||
} else {
|
} else {
|
||||||
compile_error!("Unsupported architecture");
|
compile_error!("Unsupported architecture");
|
||||||
}
|
}
|
||||||
|
@ -92,6 +92,7 @@ fn main() {
|
|||||||
"x86" => (),
|
"x86" => (),
|
||||||
"x86_64" => build_x86_64(),
|
"x86_64" => build_x86_64(),
|
||||||
"aarch64" => (),
|
"aarch64" => (),
|
||||||
|
"riscv64" => (),
|
||||||
_ => panic!("Unknown target arch: {:?}", arch),
|
_ => panic!("Unknown target arch: {:?}", arch),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -122,7 +122,10 @@ struct BusAddressAllocator {
|
|||||||
offset_32: u32,
|
offset_32: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(any(target_arch = "x86_64", target_arch = "x86"), allow(dead_code))]
|
#[cfg_attr(
|
||||||
|
any(target_arch = "x86_64", target_arch = "x86", target_arch = "riscv64"),
|
||||||
|
allow(dead_code)
|
||||||
|
)]
|
||||||
impl BusAddressAllocator {
|
impl BusAddressAllocator {
|
||||||
pub fn from_ranges(ranges: &[PciAddressRange]) -> Self {
|
pub fn from_ranges(ranges: &[PciAddressRange]) -> Self {
|
||||||
let mut range_32 = None;
|
let mut range_32 = None;
|
||||||
|
@ -14,6 +14,12 @@ pub mod x86_64;
|
|||||||
#[cfg(all(not(feature = "all"), target_arch = "x86_64"))]
|
#[cfg(all(not(feature = "all"), target_arch = "x86_64"))]
|
||||||
pub use x86_64::FixedTables;
|
pub use x86_64::FixedTables;
|
||||||
|
|
||||||
|
// RISC-V 64-bit
|
||||||
|
#[cfg(any(feature = "all", target_arch = "riscv64"))]
|
||||||
|
pub mod riscv64;
|
||||||
|
#[cfg(all(not(feature = "all"), target_arch = "riscv64"))]
|
||||||
|
pub use riscv64::FixedTables;
|
||||||
|
|
||||||
#[cfg(feature = "all")]
|
#[cfg(feature = "all")]
|
||||||
pub mod any;
|
pub mod any;
|
||||||
|
|
||||||
|
19
kernel/lib/memtables/src/riscv64.rs
Normal file
19
kernel/lib/memtables/src/riscv64.rs
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
use bytemuck::{Pod, Zeroable};
|
||||||
|
|
||||||
|
use crate::RawTable;
|
||||||
|
|
||||||
|
pub const KERNEL_L3_COUNT: usize = 8;
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Pod, Zeroable)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct FixedTables {
|
||||||
|
_dummy: RawTable,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FixedTables {
|
||||||
|
pub const fn zeroed() -> Self {
|
||||||
|
Self {
|
||||||
|
_dummy: RawTable::zeroed(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -30,6 +30,8 @@ cfg_if! {
|
|||||||
const EXPECTED_ELF_MACHINE: u16 = elf::abi::EM_AARCH64;
|
const EXPECTED_ELF_MACHINE: u16 = elf::abi::EM_AARCH64;
|
||||||
} else if #[cfg(target_arch = "x86")] {
|
} else if #[cfg(target_arch = "x86")] {
|
||||||
const EXPECTED_ELF_MACHINE: u16 = elf::abi::EM_386;
|
const EXPECTED_ELF_MACHINE: u16 = elf::abi::EM_386;
|
||||||
|
} else if #[cfg(target_arch = "riscv64")] {
|
||||||
|
const EXPECTED_ELF_MACHINE: u16 = elf::abi::EM_RISCV;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,10 +7,6 @@ use device_api::{
|
|||||||
interrupt::{IpiDeliveryTarget, IpiMessage},
|
interrupt::{IpiDeliveryTarget, IpiMessage},
|
||||||
ResetDevice,
|
ResetDevice,
|
||||||
};
|
};
|
||||||
// use device_api::{
|
|
||||||
// interrupt::{IpiDeliveryTarget, IpiMessage},
|
|
||||||
// ResetDevice,
|
|
||||||
// };
|
|
||||||
use kernel_arch::{Architecture, ArchitectureImpl};
|
use kernel_arch::{Architecture, ArchitectureImpl};
|
||||||
use libk_mm::table::EntryLevel;
|
use libk_mm::table::EntryLevel;
|
||||||
|
|
||||||
@ -32,7 +28,17 @@ pub mod i686;
|
|||||||
#[cfg(any(target_arch = "x86", rust_analyzer))]
|
#[cfg(any(target_arch = "x86", rust_analyzer))]
|
||||||
pub use i686::{I686 as PlatformImpl, PLATFORM};
|
pub use i686::{I686 as PlatformImpl, PLATFORM};
|
||||||
|
|
||||||
#[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64", target_arch = "x86")))]
|
#[cfg(any(target_arch = "riscv64", rust_analyzer))]
|
||||||
|
pub mod riscv64;
|
||||||
|
#[cfg(any(target_arch = "riscv64", rust_analyzer))]
|
||||||
|
pub use riscv64::{Riscv64 as PlatformImpl, PLATFORM};
|
||||||
|
|
||||||
|
#[cfg(not(any(
|
||||||
|
target_arch = "x86_64",
|
||||||
|
target_arch = "aarch64",
|
||||||
|
target_arch = "riscv64",
|
||||||
|
target_arch = "x86"
|
||||||
|
)))]
|
||||||
compile_error!("Unsupported architecture");
|
compile_error!("Unsupported architecture");
|
||||||
|
|
||||||
/// Architecture-specific lowest level of page mapping
|
/// Architecture-specific lowest level of page mapping
|
||||||
|
59
kernel/src/arch/riscv64/boot/entry.S
Normal file
59
kernel/src/arch/riscv64/boot/entry.S
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
.macro LOAD_PCREL label, register, symbol
|
||||||
|
\label: auipc \register, %pcrel_hi(\symbol)
|
||||||
|
addi \register, \register, %pcrel_lo(\label)
|
||||||
|
.endm
|
||||||
|
|
||||||
|
.section .text.entry
|
||||||
|
.option norvc
|
||||||
|
.type __rv64_entry, @function
|
||||||
|
.global __rv64_entry
|
||||||
|
__rv64_entry:
|
||||||
|
// Jump to parking place if hard id is not zero
|
||||||
|
csrr t0, mhartid
|
||||||
|
bnez t0, .spin_loop
|
||||||
|
|
||||||
|
// Reset translation control
|
||||||
|
csrw satp, zero
|
||||||
|
|
||||||
|
// Zero the .bss
|
||||||
|
LOAD_PCREL .L00, t0, __bss_start_phys
|
||||||
|
LOAD_PCREL .L01, t1, __bss_end_phys
|
||||||
|
|
||||||
|
1: bgeu t0, t1, 2f
|
||||||
|
sd zero, (t0)
|
||||||
|
addi t0, t0, 4
|
||||||
|
j 1b
|
||||||
|
2:
|
||||||
|
|
||||||
|
// Setup boot stack
|
||||||
|
LOAD_PCREL .L02, sp, {boot_stack_bottom} + {boot_stack_size} - {kernel_virt_offset}
|
||||||
|
|
||||||
|
// Jump to entry
|
||||||
|
LOAD_PCREL .L03, t0, {entry_mmode_lower} - {kernel_virt_offset}
|
||||||
|
|
||||||
|
jr t0
|
||||||
|
|
||||||
|
3: wfi
|
||||||
|
j 3b
|
||||||
|
|
||||||
|
.spin_loop:
|
||||||
|
wfi
|
||||||
|
j .spin_loop
|
||||||
|
|
||||||
|
.size __rv64_entry, . - __rv64_entry
|
||||||
|
|
||||||
|
.section .text
|
||||||
|
.global __rv64_smode_entry
|
||||||
|
.type __rv64_smode_entry, @function
|
||||||
|
.p2align 4
|
||||||
|
__rv64_smode_entry:
|
||||||
|
// Set up the stack again
|
||||||
|
LOAD_PCREL .L04, sp, {boot_stack_bottom} + {boot_stack_size}
|
||||||
|
// Enter kernel proper
|
||||||
|
LOAD_PCREL .L05, t0, {entry_smode_lower}
|
||||||
|
|
||||||
|
jr t0
|
||||||
|
|
||||||
|
1: wfi
|
||||||
|
j 1b
|
||||||
|
.size __rv64_smode_entry, . - __rv64_smode_entry
|
125
kernel/src/arch/riscv64/boot/mod.rs
Normal file
125
kernel/src/arch/riscv64/boot/mod.rs
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
use core::arch::global_asm;
|
||||||
|
|
||||||
|
use kernel_arch_riscv64::{
|
||||||
|
mem::{
|
||||||
|
table::{PageAttributes, PageEntry, PageTable, L1},
|
||||||
|
KERNEL_VIRT_OFFSET,
|
||||||
|
},
|
||||||
|
registers::{MEPC, MSTATUS, SATP},
|
||||||
|
};
|
||||||
|
use libk_mm::{address::PhysicalAddress, table::EntryLevel};
|
||||||
|
use tock_registers::interfaces::{ReadWriteable, Writeable};
|
||||||
|
|
||||||
|
const BOOT_STACK_SIZE: usize = 65536;
|
||||||
|
|
||||||
|
#[repr(C, align(0x10))]
|
||||||
|
struct BootStack<const N: usize>([u8; N]);
|
||||||
|
|
||||||
|
impl<const N: usize> BootStack<N> {
|
||||||
|
pub const fn zeroed() -> Self {
|
||||||
|
Self([0; N])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[link_section = ".bss"]
|
||||||
|
static mut BOOT_STACK: BootStack<BOOT_STACK_SIZE> = BootStack::zeroed();
|
||||||
|
static mut TABLE: PageTable<L1> = PageTable::zeroed();
|
||||||
|
|
||||||
|
unsafe fn long_jump(pc: usize, sp: usize) -> ! {
|
||||||
|
core::arch::asm!(r#"
|
||||||
|
mv sp, {sp}
|
||||||
|
jr {pc}
|
||||||
|
"#, pc = in(reg) pc, sp = in(reg) sp, options(noreturn));
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe extern "C" fn __rv64_bsp_smode_entry_lower() -> ! {
|
||||||
|
// TODO move this to kernel-arch-riscv64, like in other archs
|
||||||
|
for i in 0..4 {
|
||||||
|
TABLE[i] = PageEntry::block(
|
||||||
|
PhysicalAddress::from_usize(i << L1::SHIFT),
|
||||||
|
PageAttributes::W | PageAttributes::X,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
// TODO magic numbers
|
||||||
|
// Map kernel
|
||||||
|
TABLE[450] = PageEntry::block(
|
||||||
|
PhysicalAddress::from_usize(0x8000_0000),
|
||||||
|
PageAttributes::W | PageAttributes::X,
|
||||||
|
);
|
||||||
|
|
||||||
|
let address = (&raw const TABLE).addr();
|
||||||
|
let address = if address >= KERNEL_VIRT_OFFSET {
|
||||||
|
address - KERNEL_VIRT_OFFSET
|
||||||
|
} else {
|
||||||
|
address
|
||||||
|
};
|
||||||
|
|
||||||
|
SATP.modify(SATP::PPN.val((address as u64) >> 12) + SATP::MODE::Sv39);
|
||||||
|
|
||||||
|
let stack = (&raw const BOOT_STACK).addr() + KERNEL_VIRT_OFFSET;
|
||||||
|
let pc = __rv64_bsp_entry_upper as usize + KERNEL_VIRT_OFFSET;
|
||||||
|
let sp = stack + BOOT_STACK_SIZE;
|
||||||
|
|
||||||
|
long_jump(pc, sp)
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe extern "C" fn __rv64_bsp_entry_upper() -> ! {
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Drop to S-mode
|
||||||
|
unsafe extern "C" fn __rv64_bsp_mmode_entry_lower() -> ! {
|
||||||
|
extern "C" {
|
||||||
|
fn __rv64_smode_entry() -> !;
|
||||||
|
}
|
||||||
|
|
||||||
|
MSTATUS.modify(
|
||||||
|
// Mask S-mode interrupts
|
||||||
|
MSTATUS::SIE::CLEAR
|
||||||
|
+ MSTATUS::MPIE::CLEAR
|
||||||
|
// UXLEN=SXLEN=64
|
||||||
|
+ MSTATUS::UXL.val(2)
|
||||||
|
+ MSTATUS::SXL.val(2)
|
||||||
|
// Little endian
|
||||||
|
+ MSTATUS::UBE::CLEAR
|
||||||
|
+ MSTATUS::SBE::CLEAR
|
||||||
|
// Don't trap S-mode VM insns, sret + U-mode wfi
|
||||||
|
+ MSTATUS::TVM::CLEAR
|
||||||
|
+ MSTATUS::TW::CLEAR
|
||||||
|
+ MSTATUS::TSR::CLEAR
|
||||||
|
// Disable effective privilege modification
|
||||||
|
+ MSTATUS::MPRV::CLEAR
|
||||||
|
// Enable S-mode access to U-mode pages
|
||||||
|
+ MSTATUS::SUM::SET
|
||||||
|
// Make mret return to S-mode
|
||||||
|
+ MSTATUS::MPP::S,
|
||||||
|
);
|
||||||
|
|
||||||
|
let entry = __rv64_smode_entry as usize - KERNEL_VIRT_OFFSET;
|
||||||
|
MEPC.set(entry as u64);
|
||||||
|
|
||||||
|
// Modify pmpcfg/pmpaddr to allow lower-level execution
|
||||||
|
unsafe {
|
||||||
|
let mut pmpcfg0: u64;
|
||||||
|
core::arch::asm!("csrr {0}, pmpcfg0", out(reg) pmpcfg0);
|
||||||
|
|
||||||
|
let pmpaddr0: u64 = 0xFFFFffffFFFFffff;
|
||||||
|
|
||||||
|
pmpcfg0 &= !0xFF;
|
||||||
|
// A = 1, X, W, R
|
||||||
|
pmpcfg0 |= 0xF;
|
||||||
|
|
||||||
|
core::arch::asm!("csrw pmpaddr0, {0}; csrw pmpcfg0, {1}", in(reg) pmpaddr0, in(reg) pmpcfg0);
|
||||||
|
}
|
||||||
|
|
||||||
|
core::arch::asm!("mret", options(noreturn));
|
||||||
|
}
|
||||||
|
|
||||||
|
global_asm!(
|
||||||
|
include_str!("entry.S"),
|
||||||
|
entry_mmode_lower = sym __rv64_bsp_mmode_entry_lower,
|
||||||
|
entry_smode_lower = sym __rv64_bsp_smode_entry_lower,
|
||||||
|
boot_stack_bottom = sym BOOT_STACK,
|
||||||
|
kernel_virt_offset = const KERNEL_VIRT_OFFSET,
|
||||||
|
boot_stack_size = const BOOT_STACK_SIZE,
|
||||||
|
);
|
48
kernel/src/arch/riscv64/mod.rs
Normal file
48
kernel/src/arch/riscv64/mod.rs
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
#![allow(missing_docs)]
|
||||||
|
use abi::error::Error;
|
||||||
|
use alloc::sync::Arc;
|
||||||
|
use device_api::{
|
||||||
|
interrupt::{IpiDeliveryTarget, IpiMessage},
|
||||||
|
ResetDevice,
|
||||||
|
};
|
||||||
|
use kernel_arch_riscv64::mem::KERNEL_VIRT_OFFSET;
|
||||||
|
use libk_mm::table::EntryLevel;
|
||||||
|
|
||||||
|
use super::Platform;
|
||||||
|
|
||||||
|
pub mod boot;
|
||||||
|
|
||||||
|
pub struct Riscv64;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub struct L3;
|
||||||
|
impl EntryLevel for L3 {
|
||||||
|
const SIZE: usize = 4096;
|
||||||
|
const SHIFT: usize = 12;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Platform for Riscv64 {
|
||||||
|
const KERNEL_VIRT_OFFSET: usize = KERNEL_VIRT_OFFSET;
|
||||||
|
type L3 = L3;
|
||||||
|
|
||||||
|
unsafe fn reset(&self) -> ! {
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn send_ipi(&self, target: IpiDeliveryTarget, msg: IpiMessage) -> Result<bool, Error> {
|
||||||
|
let _ = target;
|
||||||
|
let _ = msg;
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn start_application_processors(&self) {
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn register_reset_device(&self, reset: Arc<dyn ResetDevice>) -> Result<(), Error> {
|
||||||
|
let _ = reset;
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub static PLATFORM: Riscv64 = Riscv64;
|
@ -52,6 +52,10 @@ pub const fn arch_str() -> &'static str {
|
|||||||
{
|
{
|
||||||
"x86_64"
|
"x86_64"
|
||||||
}
|
}
|
||||||
|
#[cfg(target_arch = "riscv64")]
|
||||||
|
{
|
||||||
|
"riscv64"
|
||||||
|
}
|
||||||
#[cfg(target_arch = "x86")]
|
#[cfg(target_arch = "x86")]
|
||||||
{
|
{
|
||||||
"i686"
|
"i686"
|
||||||
|
@ -9,7 +9,7 @@ use std::{
|
|||||||
|
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use elf::{
|
use elf::{
|
||||||
abi::{EM_386, EM_AARCH64, EM_X86_64, PT_LOAD},
|
abi::{EM_386, EM_AARCH64, EM_RISCV, EM_X86_64, PT_LOAD},
|
||||||
endian::AnyEndian,
|
endian::AnyEndian,
|
||||||
ElfStream,
|
ElfStream,
|
||||||
};
|
};
|
||||||
@ -115,6 +115,7 @@ fn find_tables<F: Read + Seek>(elf: &mut ElfStream<AnyEndian, F>) -> Result<(u64
|
|||||||
let section_size = match elf.ehdr.e_machine {
|
let section_size = match elf.ehdr.e_machine {
|
||||||
EM_AARCH64 => size_of::<memtables::aarch64::FixedTables>(),
|
EM_AARCH64 => size_of::<memtables::aarch64::FixedTables>(),
|
||||||
EM_X86_64 => size_of::<memtables::x86_64::FixedTables>(),
|
EM_X86_64 => size_of::<memtables::x86_64::FixedTables>(),
|
||||||
|
EM_RISCV => size_of::<memtables::riscv64::FixedTables>(),
|
||||||
_ => unimplemented!(),
|
_ => unimplemented!(),
|
||||||
};
|
};
|
||||||
let (shdrs, strtab) = elf.section_headers_with_strtab()?;
|
let (shdrs, strtab) = elf.section_headers_with_strtab()?;
|
||||||
@ -237,6 +238,10 @@ fn build_tables<F: Read + Seek>(
|
|||||||
)?
|
)?
|
||||||
.build()
|
.build()
|
||||||
.map(into_any),
|
.map(into_any),
|
||||||
|
EM_RISCV => {
|
||||||
|
// TODO
|
||||||
|
std::process::exit(0);
|
||||||
|
}
|
||||||
_ => todo!(),
|
_ => todo!(),
|
||||||
}?;
|
}?;
|
||||||
|
|
||||||
|
@ -17,6 +17,11 @@ pub(crate) mod i686;
|
|||||||
#[cfg(target_arch = "x86")]
|
#[cfg(target_arch = "x86")]
|
||||||
use i686 as arch_impl;
|
use i686 as arch_impl;
|
||||||
|
|
||||||
|
#[cfg(target_arch = "riscv64")]
|
||||||
|
pub(crate) mod riscv64;
|
||||||
|
#[cfg(target_arch = "riscv64")]
|
||||||
|
use riscv64 as arch_impl;
|
||||||
|
|
||||||
pub use arch_impl::SavedFrame;
|
pub use arch_impl::SavedFrame;
|
||||||
|
|
||||||
pub trait FrameOps {
|
pub trait FrameOps {
|
||||||
|
19
lib/abi/src/arch/riscv64.rs
Normal file
19
lib/abi/src/arch/riscv64.rs
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
#![allow(missing_docs)]
|
||||||
|
|
||||||
|
use super::FrameOps;
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
#[derive(Clone, Debug, Default)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct SavedFrame {}
|
||||||
|
|
||||||
|
impl FrameOps for SavedFrame {
|
||||||
|
fn set_user_ip(&mut self, value: usize) {
|
||||||
|
let _ = value;
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn user_ip(&self) -> usize {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
@ -10,6 +10,7 @@ use device::{QemuDevice, QemuSerialTarget};
|
|||||||
|
|
||||||
pub mod aarch64;
|
pub mod aarch64;
|
||||||
pub mod i386;
|
pub mod i386;
|
||||||
|
pub mod riscv64;
|
||||||
pub mod x86_64;
|
pub mod x86_64;
|
||||||
|
|
||||||
pub mod device;
|
pub mod device;
|
||||||
@ -82,6 +83,12 @@ impl Qemu<i386::QemuI386> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Qemu<riscv64::QemuRiscv64> {
|
||||||
|
pub fn new_riscv64() -> Self {
|
||||||
|
Qemu::new(riscv64::QemuRiscv64)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<A: Architecture> Qemu<A> {
|
impl<A: Architecture> Qemu<A> {
|
||||||
pub fn new(arch: A) -> Self {
|
pub fn new(arch: A) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
60
lib/qemu/src/riscv64.rs
Normal file
60
lib/qemu/src/riscv64.rs
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
use std::{path::PathBuf, process::Command};
|
||||||
|
|
||||||
|
use crate::{Architecture, IntoArgs};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Cpu {
|
||||||
|
Rv64,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Machine {
|
||||||
|
Virt,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct QemuRiscv64;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Image {
|
||||||
|
pub kernel: PathBuf,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IntoArgs for Machine {
|
||||||
|
fn add_args(&self, command: &mut Command) {
|
||||||
|
command.arg("-M");
|
||||||
|
match self {
|
||||||
|
Self::Virt => command.arg("virt"),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IntoArgs for Cpu {
|
||||||
|
fn add_args(&self, command: &mut Command) {
|
||||||
|
command.arg("-cpu");
|
||||||
|
match self {
|
||||||
|
Self::Rv64 => command.arg("rv64,zicsr=true,zifencei=true"),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IntoArgs for Image {
|
||||||
|
fn add_args(&self, command: &mut Command) {
|
||||||
|
command.arg("-kernel");
|
||||||
|
command.arg(&self.kernel);
|
||||||
|
command.args(["-bios", "none"]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Architecture for QemuRiscv64 {
|
||||||
|
type CpuType = Cpu;
|
||||||
|
type ImageType = Image;
|
||||||
|
type MachineType = Machine;
|
||||||
|
const DEFAULT_COMMAND: &'static str = "qemu-system-riscv64";
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IntoArgs for QemuRiscv64 {
|
||||||
|
fn add_args(&self, command: &mut Command) {
|
||||||
|
let _ = command;
|
||||||
|
}
|
||||||
|
}
|
@ -26,9 +26,14 @@ mod i686;
|
|||||||
#[cfg(any(target_arch = "x86", rust_analyzer))]
|
#[cfg(any(target_arch = "x86", rust_analyzer))]
|
||||||
use i686 as imp;
|
use i686 as imp;
|
||||||
|
|
||||||
#[cfg(any(target_arch = "aarch64", rust_analyzer))]
|
#[cfg(any(target_arch = "riscv64", rust_analyzer))]
|
||||||
|
mod riscv64;
|
||||||
|
#[cfg(any(target_arch = "riscv64", rust_analyzer))]
|
||||||
|
use riscv64 as imp;
|
||||||
|
|
||||||
|
#[cfg(any(target_arch = "aarch64", target_arch = "riscv64", rust_analyzer))]
|
||||||
mod variant1;
|
mod variant1;
|
||||||
#[cfg(any(target_arch = "aarch64", rust_analyzer))]
|
#[cfg(any(target_arch = "aarch64", target_arch = "riscv64", rust_analyzer))]
|
||||||
use variant1 as layout;
|
use variant1 as layout;
|
||||||
|
|
||||||
#[cfg(any(target_arch = "x86", target_arch = "x86_64", rust_analyzer))]
|
#[cfg(any(target_arch = "x86", target_arch = "x86_64", rust_analyzer))]
|
||||||
|
12
lib/runtime/src/process/thread_local/riscv64.rs
Normal file
12
lib/runtime/src/process/thread_local/riscv64.rs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
#![allow(missing_docs)]
|
||||||
|
|
||||||
|
use abi::error::Error;
|
||||||
|
|
||||||
|
pub fn get_thread_pointer() -> usize {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn set_thread_pointer(value: usize) -> Result<(), Error> {
|
||||||
|
let _ = value;
|
||||||
|
todo!()
|
||||||
|
}
|
@ -9,8 +9,11 @@ mod x86_64;
|
|||||||
#[cfg(any(target_arch = "x86", rust_analyzer))]
|
#[cfg(any(target_arch = "x86", rust_analyzer))]
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
mod i686;
|
mod i686;
|
||||||
|
#[cfg(any(target_arch = "riscv64", rust_analyzer))]
|
||||||
|
#[macro_use]
|
||||||
|
mod riscv64;
|
||||||
|
|
||||||
#[allow(missing_docs)]
|
#[allow(missing_docs, unreachable_code)]
|
||||||
mod generated {
|
mod generated {
|
||||||
// Import all the necessary types from generated ABI
|
// Import all the necessary types from generated ABI
|
||||||
use abi::{
|
use abi::{
|
||||||
|
53
lib/runtime/src/sys/riscv64.rs
Normal file
53
lib/runtime/src/sys/riscv64.rs
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
/// 64-bit RISC-V implementations of the syscall macro
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! syscall {
|
||||||
|
($num:expr $(,)?) => {{
|
||||||
|
let _ = $num;
|
||||||
|
todo!()
|
||||||
|
}};
|
||||||
|
($num:expr, $a0:expr $(,)?) => {{
|
||||||
|
let _ = $num;
|
||||||
|
let _ = $a0;
|
||||||
|
todo!()
|
||||||
|
}};
|
||||||
|
($num:expr, $a0:expr, $a1:expr $(,)?) => {{
|
||||||
|
let _ = $num;
|
||||||
|
let _ = $a0;
|
||||||
|
let _ = $a1;
|
||||||
|
todo!()
|
||||||
|
}};
|
||||||
|
($num:expr, $a0:expr, $a1:expr, $a2:expr $(,)?) => {{
|
||||||
|
let _ = $num;
|
||||||
|
let _ = $a0;
|
||||||
|
let _ = $a1;
|
||||||
|
let _ = $a2;
|
||||||
|
todo!()
|
||||||
|
}};
|
||||||
|
($num:expr, $a0:expr, $a1:expr, $a2:expr, $a3:expr $(,)?) => {{
|
||||||
|
let _ = $num;
|
||||||
|
let _ = $a0;
|
||||||
|
let _ = $a1;
|
||||||
|
let _ = $a2;
|
||||||
|
let _ = $a3;
|
||||||
|
todo!()
|
||||||
|
}};
|
||||||
|
($num:expr, $a0:expr, $a1:expr, $a2:expr, $a3:expr, $a4:expr $(,)?) => {{
|
||||||
|
let _ = $num;
|
||||||
|
let _ = $a0;
|
||||||
|
let _ = $a1;
|
||||||
|
let _ = $a2;
|
||||||
|
let _ = $a3;
|
||||||
|
let _ = $a4;
|
||||||
|
todo!()
|
||||||
|
}};
|
||||||
|
($num:expr, $a0:expr, $a1:expr, $a2:expr, $a3:expr, $a4:expr, $a5:expr $(,)?) => {{
|
||||||
|
let _ = $num;
|
||||||
|
let _ = $a0;
|
||||||
|
let _ = $a1;
|
||||||
|
let _ = $a2;
|
||||||
|
let _ = $a3;
|
||||||
|
let _ = $a4;
|
||||||
|
let _ = $a5;
|
||||||
|
todo!()
|
||||||
|
}};
|
||||||
|
}
|
@ -42,6 +42,7 @@ pub struct KernelProcessed(pub KernelBuilt);
|
|||||||
pub struct InitrdGenerated(pub PathBuf);
|
pub struct InitrdGenerated(pub PathBuf);
|
||||||
pub struct ImageBuilt(pub PathBuf);
|
pub struct ImageBuilt(pub PathBuf);
|
||||||
pub enum AllBuilt {
|
pub enum AllBuilt {
|
||||||
|
Riscv64(KernelProcessed),
|
||||||
X86_64(ImageBuilt),
|
X86_64(ImageBuilt),
|
||||||
AArch64(KernelProcessed, InitrdGenerated),
|
AArch64(KernelProcessed, InitrdGenerated),
|
||||||
I686(ImageBuilt),
|
I686(ImageBuilt),
|
||||||
@ -98,12 +99,16 @@ pub fn build_all(env: &BuildEnv) -> Result<AllBuilt, Error> {
|
|||||||
// for module in modules {
|
// for module in modules {
|
||||||
// install_extra.push((module.clone(), module.file_name().unwrap().into()));
|
// install_extra.push((module.clone(), module.file_name().unwrap().into()));
|
||||||
// }
|
// }
|
||||||
|
if env.arch == Arch::riscv64 {
|
||||||
|
return Ok(AllBuilt::Riscv64(kernel));
|
||||||
|
}
|
||||||
|
|
||||||
// Userspace stuff
|
// Userspace stuff
|
||||||
let initrd = userspace::build_initrd(env, install_extra, check)?;
|
let initrd = userspace::build_initrd(env, install_extra, check)?;
|
||||||
|
|
||||||
// Build target-specific image
|
// Build target-specific image
|
||||||
let image = match env.arch {
|
let image = match env.arch {
|
||||||
|
Arch::riscv64 => AllBuilt::Riscv64(kernel),
|
||||||
Arch::aarch64 => AllBuilt::AArch64(kernel, initrd),
|
Arch::aarch64 => AllBuilt::AArch64(kernel, initrd),
|
||||||
Arch::x86_64 => AllBuilt::X86_64(x86_64::build_image(env, kernel, initrd)?),
|
Arch::x86_64 => AllBuilt::X86_64(x86_64::build_image(env, kernel, initrd)?),
|
||||||
Arch::i686 => AllBuilt::I686(i686::build_image(env, kernel, initrd)?),
|
Arch::i686 => AllBuilt::I686(i686::build_image(env, kernel, initrd)?),
|
||||||
|
@ -56,11 +56,16 @@ fn check_commands_aarch64() -> Result<CommandsOk, Error> {
|
|||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_commands_riscv64() -> Result<CommandsOk, Error> {
|
||||||
|
check_command_list([("ld64.lld", "Install LLVM")])
|
||||||
|
}
|
||||||
|
|
||||||
pub fn check_build_env(arch: Arch) -> Result<AllOk, Error> {
|
pub fn check_build_env(arch: Arch) -> Result<AllOk, Error> {
|
||||||
let user_toolchain = check_user_toolchain()?;
|
let user_toolchain = check_user_toolchain()?;
|
||||||
let commands = match arch {
|
let commands = match arch {
|
||||||
Arch::x86_64 => check_commands_x86_64()?,
|
Arch::x86_64 => check_commands_x86_64()?,
|
||||||
Arch::aarch64 => check_commands_aarch64()?,
|
Arch::aarch64 => check_commands_aarch64()?,
|
||||||
|
Arch::riscv64 => check_commands_riscv64()?,
|
||||||
Arch::i686 => check_commands_i686()?,
|
Arch::i686 => check_commands_i686()?,
|
||||||
};
|
};
|
||||||
Ok(AllOk(commands, user_toolchain))
|
Ok(AllOk(commands, user_toolchain))
|
||||||
|
@ -62,6 +62,7 @@ pub enum Profile {
|
|||||||
pub enum Arch {
|
pub enum Arch {
|
||||||
#[default]
|
#[default]
|
||||||
aarch64,
|
aarch64,
|
||||||
|
riscv64,
|
||||||
x86_64,
|
x86_64,
|
||||||
i686,
|
i686,
|
||||||
}
|
}
|
||||||
@ -127,6 +128,7 @@ impl BuildEnv {
|
|||||||
) -> Self {
|
) -> Self {
|
||||||
let kernel_triple = match (arch, board) {
|
let kernel_triple = match (arch, board) {
|
||||||
(Arch::aarch64, Board::virt | Board::default) => "aarch64-unknown-qemu",
|
(Arch::aarch64, Board::virt | Board::default) => "aarch64-unknown-qemu",
|
||||||
|
(Arch::riscv64, Board::virt | Board::default) => "riscv64-unknown-qemu",
|
||||||
(Arch::aarch64, Board::raspi4b) => "aarch64-unknown-raspi4b",
|
(Arch::aarch64, Board::raspi4b) => "aarch64-unknown-raspi4b",
|
||||||
(Arch::x86_64, Board::default) => "x86_64-unknown-none",
|
(Arch::x86_64, Board::default) => "x86_64-unknown-none",
|
||||||
(Arch::i686, Board::default) => "i686-unknown-none",
|
(Arch::i686, Board::default) => "i686-unknown-none",
|
||||||
@ -137,6 +139,7 @@ impl BuildEnv {
|
|||||||
};
|
};
|
||||||
let kernel_linker_script = match arch {
|
let kernel_linker_script = match arch {
|
||||||
Arch::aarch64 => format!("arm/{kernel_triple}.ld"),
|
Arch::aarch64 => format!("arm/{kernel_triple}.ld"),
|
||||||
|
Arch::riscv64 => format!("riscv/{kernel_triple}.ld"),
|
||||||
Arch::i686 | Arch::x86_64 => format!("x86/{kernel_triple}.ld"),
|
Arch::i686 | Arch::x86_64 => format!("x86/{kernel_triple}.ld"),
|
||||||
};
|
};
|
||||||
let kernel_output_dir =
|
let kernel_output_dir =
|
||||||
@ -190,6 +193,7 @@ impl BuildEnv {
|
|||||||
impl XTaskConfig {
|
impl XTaskConfig {
|
||||||
pub fn components(&self, env: &BuildEnv) -> &BuildComponents {
|
pub fn components(&self, env: &BuildEnv) -> &BuildComponents {
|
||||||
match env.arch {
|
match env.arch {
|
||||||
|
Arch::riscv64 => todo!(),
|
||||||
Arch::aarch64 => &self.target.aarch64.components,
|
Arch::aarch64 => &self.target.aarch64.components,
|
||||||
Arch::x86_64 => &self.target.x86_64.components,
|
Arch::x86_64 => &self.target.x86_64.components,
|
||||||
Arch::i686 => &self.target.i686.components,
|
Arch::i686 => &self.target.i686.components,
|
||||||
@ -217,6 +221,7 @@ impl Arch {
|
|||||||
|
|
||||||
pub fn user_triple(&self) -> &str {
|
pub fn user_triple(&self) -> &str {
|
||||||
match self {
|
match self {
|
||||||
|
Self::riscv64 => "riscv64-unknown-yggdrasil",
|
||||||
Self::aarch64 => "aarch64-unknown-yggdrasil",
|
Self::aarch64 => "aarch64-unknown-yggdrasil",
|
||||||
Self::x86_64 => "x86_64-unknown-yggdrasil",
|
Self::x86_64 => "x86_64-unknown-yggdrasil",
|
||||||
Self::i686 => "i686-unknown-yggdrasil",
|
Self::i686 => "i686-unknown-yggdrasil",
|
||||||
@ -225,6 +230,7 @@ impl Arch {
|
|||||||
|
|
||||||
pub fn name(&self) -> &str {
|
pub fn name(&self) -> &str {
|
||||||
match self {
|
match self {
|
||||||
|
Self::riscv64 => "riscv64",
|
||||||
Self::aarch64 => "aarch64",
|
Self::aarch64 => "aarch64",
|
||||||
Self::x86_64 => "x86_64",
|
Self::x86_64 => "x86_64",
|
||||||
Self::i686 => "i686",
|
Self::i686 => "i686",
|
||||||
|
@ -7,7 +7,7 @@ use std::{
|
|||||||
use qemu::{
|
use qemu::{
|
||||||
aarch64,
|
aarch64,
|
||||||
device::{QemuDevice, QemuDrive, QemuNic, QemuSerialTarget},
|
device::{QemuDevice, QemuDrive, QemuNic, QemuSerialTarget},
|
||||||
i386, x86_64, Qemu,
|
i386, riscv64, x86_64, Qemu,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -254,6 +254,27 @@ fn run_i686(
|
|||||||
Ok(qemu.into_command())
|
Ok(qemu.into_command())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn run_riscv64(
|
||||||
|
config: &QemuConfig,
|
||||||
|
qemu_bin: Option<PathBuf>,
|
||||||
|
devices: Vec<QemuDevice>,
|
||||||
|
kernel: PathBuf,
|
||||||
|
) -> Result<Command, Error> {
|
||||||
|
let _ = config;
|
||||||
|
let _ = devices;
|
||||||
|
|
||||||
|
let mut qemu = Qemu::new_riscv64();
|
||||||
|
if let Some(qemu_bin) = qemu_bin {
|
||||||
|
qemu.override_qemu(qemu_bin);
|
||||||
|
}
|
||||||
|
qemu.with_serial(QemuSerialTarget::MonStdio)
|
||||||
|
.with_machine(riscv64::Machine::Virt)
|
||||||
|
.with_cpu(riscv64::Cpu::Rv64)
|
||||||
|
.with_boot_image(riscv64::Image { kernel });
|
||||||
|
|
||||||
|
Ok(qemu.into_command())
|
||||||
|
}
|
||||||
|
|
||||||
fn load_qemu_config<P: AsRef<Path>>(path: P) -> Result<QemuConfig, Error> {
|
fn load_qemu_config<P: AsRef<Path>>(path: P) -> Result<QemuConfig, Error> {
|
||||||
let path = path.as_ref();
|
let path = path.as_ref();
|
||||||
|
|
||||||
@ -326,6 +347,9 @@ pub fn run(
|
|||||||
add_devices_from_config(&mut devices, disk.as_ref(), &config)?;
|
add_devices_from_config(&mut devices, disk.as_ref(), &config)?;
|
||||||
|
|
||||||
let mut command = match built {
|
let mut command = match built {
|
||||||
|
AllBuilt::Riscv64(KernelProcessed(KernelBuilt(kernel))) => {
|
||||||
|
run_riscv64(&config, qemu, devices, kernel)?
|
||||||
|
}
|
||||||
AllBuilt::AArch64(KernelProcessed(KernelBuilt(kernel)), InitrdGenerated(initrd)) => {
|
AllBuilt::AArch64(KernelProcessed(KernelBuilt(kernel)), InitrdGenerated(initrd)) => {
|
||||||
make_kernel_bin(kernel, &kernel_bin)?;
|
make_kernel_bin(kernel, &kernel_bin)?;
|
||||||
run_aarch64(&config, &env, qemu, devices, kernel_bin, initrd)?
|
run_aarch64(&config, &env, qemu, devices, kernel_bin, initrd)?
|
||||||
|
Loading…
x
Reference in New Issue
Block a user