diff --git a/Cargo.lock b/Cargo.lock index 2547d9bd92..d3878e02f0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -125,8 +125,7 @@ dependencies = [ [[package]] name = "arm_gicv2" version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47d25e73c949c69f75d1b9dba39c5475523403b31eb8c2fdc99da4dc33bc1aca" +source = "git+https://github.com/arceos-hypervisor/arm_gicv2#dfe5f164b94cdd07081c2fe74a0cfe4bef2852c9" dependencies = [ "tock-registers", ] @@ -375,6 +374,8 @@ dependencies = [ "axlog", "bitflags 2.6.0", "cfg-if", + "cortex-a", + "crate_interface", "dw_apb_uart", "handler_table", "int_ratio", @@ -697,6 +698,15 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f8f80099a98041a3d1622845c271458a2d73e688351bf3cb999266764b81d48" +[[package]] +name = "cortex-a" +version = "8.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8256fd5103e10027467cc7a97c9ff27fcc4547ea24864da0aff2e7aef6e18e28" +dependencies = [ + "tock-registers", +] + [[package]] name = "cpumask" version = "0.1.0" @@ -1100,9 +1110,9 @@ checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" [[package]] name = "percpu" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b18ccf6b20ed7e535732172ec446134690500417e1142625dc026e7e19b3d78" +checksum = "bb9f741dad8f795c2161b4ecde6934b2ee661697ccb7f8ba3752392cd82e9cc9" dependencies = [ "cfg-if", "kernel_guard", @@ -1113,9 +1123,9 @@ dependencies = [ [[package]] name = "percpu_macros" -version = "0.1.2" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37bd51d4112e25524bd18b8a0a4bd2526f35686316ccfe7f6b890bf57b455578" +checksum = "ef783de4aeafcd0832cb685908773d2cf2b5875d262cfd2708b4bb29732a6d02" dependencies = [ "proc-macro2", "quote", diff --git a/Makefile b/Makefile index 3d0dd587b0..c0ad73828a 100644 --- a/Makefile +++ b/Makefile @@ -96,7 +96,8 @@ endif ifeq ($(ARCH), x86_64) # Don't enable kvm for WSL/WSL2. - ACCEL ?= $(if $(findstring -microsoft, $(shell uname -r | tr '[:upper:]' '[:lower:]')),n,y) + # It seems to work fine on 5.15.146.1-microsoft-standard-WSL2 + # ACCEL ?= $(if $(findstring -microsoft, $(shell uname -r | tr '[:upper:]' '[:lower:]')),n,y) PLATFORM_NAME ?= x86_64-qemu-q35 else ifeq ($(ARCH), riscv64) ACCEL ?= n @@ -162,6 +163,8 @@ ifeq ($(PLATFORM_NAME), aarch64-raspi4) include scripts/make/raspi4.mk else ifeq ($(PLATFORM_NAME), aarch64-bsta1000b) include scripts/make/bsta1000b-fada.mk +else ifeq ($(PLATFORM_NAME), aarch64-rk3588j) + include scripts/make/rk3588.mk endif build: $(OUT_DIR) $(OUT_BIN) diff --git a/api/axfeat/Cargo.toml b/api/axfeat/Cargo.toml index 412fdb8027..dd57888967 100644 --- a/api/axfeat/Cargo.toml +++ b/api/axfeat/Cargo.toml @@ -56,6 +56,9 @@ driver-ramdisk = ["axdriver?/ramdisk", "axfs?/use-ramdisk"] driver-ixgbe = ["axdriver?/ixgbe"] driver-bcm2835-sdhci = ["axdriver?/bcm2835-sdhci"] +#Hypervisor support +hv = ["axhal/hv"] + # Logging log-level-off = ["axlog/log-level-off"] log-level-error = ["axlog/log-level-error"] diff --git a/doc/figures/RKDevTool3.3.png b/doc/figures/RKDevTool3.3.png new file mode 100644 index 0000000000..d390f4219b Binary files /dev/null and b/doc/figures/RKDevTool3.3.png differ diff --git a/doc/platform_rk3588.md b/doc/platform_rk3588.md new file mode 100644 index 0000000000..5e3cc5a873 --- /dev/null +++ b/doc/platform_rk3588.md @@ -0,0 +1,9 @@ +# How to run ArceOS on rk3588 + +1. Use Command `make ARCH=aarch64 PLATFORM=aarch64-rk3588j A=$(pwd)/examples/helloworld kernel` to build the kernel image `boot.img`. +2. Download the [RKDevTool](https://download.t-firefly.com/product/Board/RK3588/Tool/Window/RKDevTool_Release_v3.31.zip). + >This tool has only been tested on [Pji's](https://www.pji.net.cn/) Electronic Control Unit of RK3588. Other RK3588 development boards require independent testing. +3. Set the path of `boot.img` in **boot** and connect the RK3588 board. +4. Press the `Run` button to flash the image to the RK3588 board. + +![RKDevTool](./figures/RKDevTool3.3.png) \ No newline at end of file diff --git a/modules/axconfig/build.rs b/modules/axconfig/build.rs index e8a28b11e0..eff60026be 100644 --- a/modules/axconfig/build.rs +++ b/modules/axconfig/build.rs @@ -23,7 +23,9 @@ fn resolve_config_path(platform: Option<&str>) -> Result { config_dir.join(format!("{plat}.toml")) } Some(plat) => { - let path = PathBuf::from(&plat); + let plat_path = std::env::var("AX_PLATFORM_PATH").unwrap_or(plat.to_string()); + let path = PathBuf::from(&plat_path); + println!("Using custom platform config file: {}", path.display()); if path.is_absolute() { path } else { diff --git a/modules/axhal/Cargo.toml b/modules/axhal/Cargo.toml index 5c48b0153f..1ea552db1b 100644 --- a/modules/axhal/Cargo.toml +++ b/modules/axhal/Cargo.toml @@ -18,6 +18,7 @@ irq = [] tls = ["alloc"] rtc = ["x86_rtc", "riscv_goldfish", "arm_pl031"] default = [] +hv = ["paging", "cortex-a", "percpu/arm-el2", "page_table_entry/arm-el2", "arm_gicv2/el2", "dep:crate_interface"] [dependencies] log = "=0.4.21" @@ -37,6 +38,7 @@ page_table_multiarch = { version = "0.4", optional = true } axlog = { workspace = true } axconfig = { workspace = true } axalloc = { workspace = true, optional = true } +cortex-a = { version = "8.1.1", optional = true } [target.'cfg(target_arch = "x86_64")'.dependencies] x86 = "0.52" @@ -53,7 +55,8 @@ riscv_goldfish = { version = "0.1", optional = true } [target.'cfg(target_arch = "aarch64")'.dependencies] aarch64-cpu = "9.4" tock-registers = "0.8" -arm_gicv2 = "0.1" +arm_gicv2 = { git = "https://github.com/arceos-hypervisor/arm_gicv2" } +crate_interface = { version = "0.1.3", optional = true } arm_pl011 = "0.1" arm_pl031 = { version = "0.2", optional = true } dw_apb_uart = "0.1" diff --git a/modules/axhal/build.rs b/modules/axhal/build.rs index c40f60359c..a738d8b94f 100644 --- a/modules/axhal/build.rs +++ b/modules/axhal/build.rs @@ -5,6 +5,7 @@ const BUILTIN_PLATFORMS: &[&str] = &[ "aarch64-bsta1000b", "aarch64-qemu-virt", "aarch64-raspi4", + "aarch64-rk3588j", "riscv64-qemu-virt", "x86_64-pc-oslab", "x86_64-qemu-q35", @@ -14,6 +15,7 @@ const BUILTIN_PLATFORM_FAMILIES: &[&str] = &[ "aarch64-bsta1000b", "aarch64-qemu-virt", "aarch64-raspi", + "aarch64-rk3588j", "riscv64-qemu-virt", "x86-pc", ]; diff --git a/modules/axhal/src/arch/aarch64/mod.rs b/modules/axhal/src/arch/aarch64/mod.rs index 160dabdd12..15517fa3dc 100644 --- a/modules/axhal/src/arch/aarch64/mod.rs +++ b/modules/axhal/src/arch/aarch64/mod.rs @@ -3,6 +3,10 @@ pub(crate) mod trap; use core::arch::asm; +#[cfg(feature = "hv")] +use aarch64_cpu::registers::{TTBR0_EL2, VBAR_EL2}; +//Todo: remove this, when hv is enabled, `TTBR1_EL1` is not used. +#[cfg_attr(feature = "hv", allow(unused_imports))] use aarch64_cpu::registers::{DAIF, TPIDR_EL0, TTBR0_EL1, TTBR1_EL1, VBAR_EL1}; use memory_addr::{PhysAddr, VirtAddr}; use tock_registers::interfaces::{Readable, Writeable}; @@ -47,8 +51,13 @@ pub fn halt() { /// Returns the physical address of the page table root. #[inline] pub fn read_page_table_root() -> PhysAddr { + #[cfg(not(feature = "hv"))] let root = TTBR1_EL1.get(); - pa!(root as usize) + + #[cfg(feature = "hv")] + let root = TTBR0_EL2.get(); + + PhysAddr::from(root as usize) } /// Reads the `TTBR0_EL1` register. @@ -66,8 +75,17 @@ pub unsafe fn write_page_table_root(root_paddr: PhysAddr) { let old_root = read_page_table_root(); trace!("set page table root: {:#x} => {:#x}", old_root, root_paddr); if old_root != root_paddr { - // kernel space page table use TTBR1 (0xffff_0000_0000_0000..0xffff_ffff_ffff_ffff) - TTBR1_EL1.set(root_paddr.as_usize() as _); + #[cfg(not(feature = "hv"))] + { + // kernel space page table use TTBR1 (0xffff_0000_0000_0000..0xffff_ffff_ffff_ffff) + TTBR1_EL1.set(root_paddr.as_usize() as _); + } + + #[cfg(feature = "hv")] + { + // kernel space page table at EL2 use TTBR0_EL2 (0x0000_0000_0000_0000..0x0000_ffff_ffff_ffff) + TTBR0_EL2.set(root_paddr.as_usize() as _); + } flush_tlb(None); } } @@ -90,10 +108,24 @@ pub unsafe fn write_page_table_root0(root_paddr: PhysAddr) { pub fn flush_tlb(vaddr: Option) { unsafe { if let Some(vaddr) = vaddr { - asm!("tlbi vaae1is, {}; dsb sy; isb", in(reg) vaddr.as_usize()) + #[cfg(not(feature = "hv"))] + { + asm!("tlbi vaae1is, {}; dsb sy; isb", in(reg) vaddr.as_usize()) + } + #[cfg(feature = "hv")] + { + asm!("tlbi vae2is, {}; dsb sy; isb", in(reg) vaddr.as_usize()) + } } else { // flush the entire TLB - asm!("tlbi vmalle1; dsb sy; isb") + #[cfg(not(feature = "hv"))] + { + asm!("tlbi vmalle1; dsb sy; isb") + } + #[cfg(feature = "hv")] + { + asm!("tlbi alle2is; dsb sy; isb") + } } } } @@ -106,8 +138,11 @@ pub fn flush_icache_all() { /// Sets the base address of the exception vector (writes `VBAR_EL1`). #[inline] -pub fn set_exception_vector_base(vbar_el1: usize) { - VBAR_EL1.set(vbar_el1 as _); +pub fn set_exception_vector_base(vbar: usize) { + #[cfg(not(feature = "hv"))] + VBAR_EL1.set(vbar as _); + #[cfg(feature = "hv")] + VBAR_EL2.set(vbar as _); } /// Flushes the data cache line (64 bytes) at the given virtual address diff --git a/modules/axhal/src/irq.rs b/modules/axhal/src/irq.rs index fdaa788462..7721005032 100644 --- a/modules/axhal/src/irq.rs +++ b/modules/axhal/src/irq.rs @@ -7,6 +7,9 @@ use crate::trap::{register_trap_handler, IRQ}; pub use crate::platform::irq::{register_handler, set_enable}; +#[cfg(target_arch = "aarch64")] +pub use crate::platform::irq::{fetch_irq, GicInterface}; + /// The type if an IRQ handler. pub type IrqHandler = handler_table::Handler; @@ -35,8 +38,13 @@ pub(crate) fn register_handler_common(irq_num: usize, handler: IrqHandler) -> bo false } +/// Core IRQ handling routine, registered at `axhal::trap::IRQ`, +/// which dispatches IRQs to registered handlers. +/// +/// Note: this function is denoted as public here because it'll be called by the +/// hypervisor for hypervisor reserved IRQ handling. #[register_trap_handler(IRQ)] -fn handler_irq(irq_num: usize) -> bool { +pub fn handler_irq(irq_num: usize) -> bool { let guard = kernel_guard::NoPreempt::new(); dispatch_irq(irq_num); drop(guard); // rescheduling may occur when preemption is re-enabled. diff --git a/modules/axhal/src/lib.rs b/modules/axhal/src/lib.rs index 0601b93b3d..eff8abbc66 100644 --- a/modules/axhal/src/lib.rs +++ b/modules/axhal/src/lib.rs @@ -61,6 +61,16 @@ pub mod paging; pub mod console { pub use super::platform::console::*; + /// Writes a byte to the console. + pub fn console_putchar(c: u8) { + putchar(c) + } + + /// Reads a byte from the console, or returns [`None`] if no input is available. + pub fn console_getchar() -> Option { + getchar() + } + /// Write a slice of bytes to the console. pub fn write_bytes(bytes: &[u8]) { for c in bytes { diff --git a/modules/axhal/src/platform/aarch64_common/boot_el2.rs b/modules/axhal/src/platform/aarch64_common/boot_el2.rs new file mode 100644 index 0000000000..fd15e6ac36 --- /dev/null +++ b/modules/axhal/src/platform/aarch64_common/boot_el2.rs @@ -0,0 +1,209 @@ +use core::ptr::addr_of_mut; + +use aarch64_cpu::{asm, asm::barrier, registers::*}; +use memory_addr::PhysAddr; +use page_table_entry::aarch64::A64PTE; +use tock_registers::interfaces::{ReadWriteable, Readable, Writeable}; + +use axconfig::TASK_STACK_SIZE; + +#[link_section = ".bss.stack"] +static mut BOOT_STACK: [u8; TASK_STACK_SIZE] = [0; TASK_STACK_SIZE]; + +#[link_section = ".data.boot_page_table"] +static mut BOOT_PT_L0: [A64PTE; 512] = [A64PTE::empty(); 512]; + +#[link_section = ".data.boot_page_table"] +static mut BOOT_PT_L1: [A64PTE; 512] = [A64PTE::empty(); 512]; + +unsafe fn switch_to_el2() { + SPSel.write(SPSel::SP::ELx); + let current_el = CurrentEL.read(CurrentEL::EL); + + if current_el == 3 { + SCR_EL3.write( + SCR_EL3::NS::NonSecure + SCR_EL3::HCE::HvcEnabled + SCR_EL3::RW::NextELIsAarch64, + ); + SPSR_EL3.write( + SPSR_EL3::M::EL2h + + SPSR_EL3::D::Masked + + SPSR_EL3::A::Masked + + SPSR_EL3::I::Masked + + SPSR_EL3::F::Masked, + ); + ELR_EL3.set(LR.get()); + asm::eret(); + } +} + +unsafe fn init_mmu_el2() { + // Set EL1 to 64bit. + // Enable `IMO` and `FMO` to make sure that: + // * Physical IRQ interrupts are taken to EL2; + // * Virtual IRQ interrupts are enabled; + // * Physical FIQ interrupts are taken to EL2; + // * Virtual FIQ interrupts are enabled. + HCR_EL2.modify( + HCR_EL2::VM::Enable + + HCR_EL2::RW::EL1IsAarch64 + + HCR_EL2::IMO::EnableVirtualIRQ // Physical IRQ Routing. + + HCR_EL2::FMO::EnableVirtualFIQ // Physical FIQ Routing. + + HCR_EL2::TSC::EnableTrapEl1SmcToEl2, + ); + + // Device-nGnRE memory + let attr0 = MAIR_EL2::Attr0_Device::nonGathering_nonReordering_EarlyWriteAck; + // Normal memory + let attr1 = MAIR_EL2::Attr1_Normal_Inner::WriteBack_NonTransient_ReadWriteAlloc + + MAIR_EL2::Attr1_Normal_Outer::WriteBack_NonTransient_ReadWriteAlloc; + MAIR_EL2.write(attr0 + attr1); // 0xff_04 + + // Enable TTBR0 and TTBR1 walks, page size = 4K, vaddr size = 48 bits, paddr size = 40 bits. + let tcr_flags0 = TCR_EL2::TG0::KiB_4 + + TCR_EL2::SH0::Inner + + TCR_EL2::ORGN0::WriteBack_ReadAlloc_WriteAlloc_Cacheable + + TCR_EL2::IRGN0::WriteBack_ReadAlloc_WriteAlloc_Cacheable + + TCR_EL2::T0SZ.val(16); + TCR_EL2.write(TCR_EL2::PS::Bits_40 + tcr_flags0); + barrier::isb(barrier::SY); + + let root_paddr = PhysAddr::from(BOOT_PT_L0.as_ptr() as usize).as_usize() as _; + TTBR0_EL2.set(root_paddr); + + // Flush the entire TLB + crate::arch::flush_tlb(None); + + // Enable the MMU and turn on I-cache and D-cache + SCTLR_EL2.modify(SCTLR_EL2::M::Enable + SCTLR_EL2::C::Cacheable + SCTLR_EL2::I::Cacheable); + barrier::isb(barrier::SY); +} + +unsafe fn enable_fp() { + if cfg!(feature = "fp_simd") { + CPACR_EL1.write(CPACR_EL1::FPEN::TrapNothing); + barrier::isb(barrier::SY); + } +} + +unsafe fn init_boot_page_table() { + crate::platform::mem::init_boot_page_table(addr_of_mut!(BOOT_PT_L0), addr_of_mut!(BOOT_PT_L1)); +} + +unsafe fn cache_invalidate(cache_level: usize) { + core::arch::asm!( + r#" + msr csselr_el1, {0} + mrs x4, ccsidr_el1 // read cache size id. + and x1, x4, #0x7 + add x1, x1, #0x4 // x1 = cache line size. + ldr x3, =0x7fff + and x2, x3, x4, lsr #13 // x2 = cache set number – 1. + ldr x3, =0x3ff + and x3, x3, x4, lsr #3 // x3 = cache associativity number – 1. + clz w4, w3 // x4 = way position in the cisw instruction. + mov x5, #0 // x5 = way counter way_loop. + // way_loop: + 1: + mov x6, #0 // x6 = set counter set_loop. + // set_loop: + 2: + lsl x7, x5, x4 + orr x7, {0}, x7 // set way. + lsl x8, x6, x1 + orr x7, x7, x8 // set set. + dc cisw, x7 // clean and invalidate cache line. + add x6, x6, #1 // increment set counter. + cmp x6, x2 // last set reached yet? + ble 2b // if not, iterate set_loop, + add x5, x5, #1 // else, next way. + cmp x5, x3 // last way reached yet? + ble 1b // if not, iterate way_loop + "#, + in(reg) cache_level, + options(nostack) + ); +} + +/// The earliest entry point for the primary CPU. +#[naked] +#[no_mangle] +#[link_section = ".text.boot"] +unsafe extern "C" fn _start() -> ! { + // PC = 0x8_0000 + // X0 = dtb + core::arch::asm!(" + // disable cache and MMU + mrs x1, sctlr_el2 + bic x1, x1, #0xf + msr sctlr_el2, x1 + + // cache_invalidate(0): clear dl1$ + mov x0, #0 + bl {cache_invalidate} + mov x0, #2 + bl {cache_invalidate} + + mrs x19, mpidr_el1 + and x19, x19, #0xffffff // get current CPU id + mov x20, x0 // save DTB pointer + + adrp x8, {boot_stack} // setup boot stack + add x8, x8, {boot_stack_size} + mov sp, x8 + + bl {switch_to_el2} // switch to EL2 + bl {enable_fp} // enable fp/neon + bl {init_boot_page_table} + bl {init_mmu_el2} + + mov x8, {phys_virt_offset} // set SP to the high address + add sp, sp, x8 + + mov x0, x19 // call rust_entry(cpu_id, dtb) + mov x1, x20 + ldr x8, ={entry} + blr x8 + b .", + cache_invalidate = sym cache_invalidate, + init_boot_page_table = sym init_boot_page_table, + init_mmu_el2 = sym init_mmu_el2, + switch_to_el2 = sym switch_to_el2, + enable_fp = sym enable_fp, + boot_stack = sym BOOT_STACK, + boot_stack_size = const TASK_STACK_SIZE, + phys_virt_offset = const axconfig::PHYS_VIRT_OFFSET, + entry = sym crate::platform::rust_entry, + options(noreturn), + ); +} + +/// The earliest entry point for the secondary CPUs. +#[cfg(feature = "smp")] +#[naked] +#[no_mangle] +#[link_section = ".text.boot"] +unsafe extern "C" fn _start_secondary() -> ! { + core::arch::asm!(" + mrs x19, mpidr_el1 + and x19, x19, #0xffffff // get current CPU id + + mov sp, x0 + bl {switch_to_el2} + bl {init_mmu_el2} + bl {enable_fp} + + mov x8, {phys_virt_offset} // set SP to the high address + add sp, sp, x8 + + mov x0, x19 // call rust_entry_secondary(cpu_id) + ldr x8, ={entry} + blr x8 + b .", + switch_to_el2 = sym switch_to_el2, + init_mmu_el2 = sym init_mmu_el2, + enable_fp = sym enable_fp, + phys_virt_offset = const axconfig::PHYS_VIRT_OFFSET, + entry = sym crate::platform::rust_entry_secondary, + options(noreturn), + ) +} diff --git a/modules/axhal/src/platform/aarch64_common/generic_timer.rs b/modules/axhal/src/platform/aarch64_common/generic_timer.rs index 61da059d0b..8707d55ed1 100644 --- a/modules/axhal/src/platform/aarch64_common/generic_timer.rs +++ b/modules/axhal/src/platform/aarch64_common/generic_timer.rs @@ -34,8 +34,8 @@ pub fn epochoffset_nanos() -> u64 { /// Set a one-shot timer. /// -/// A timer interrupt will be triggered at the specified monotonic time deadline (in nanoseconds). -#[cfg(feature = "irq")] +/// A timer interrupt will be triggered at the given deadline (in nanoseconds). +#[cfg(all(feature = "irq", not(feature = "hv")))] pub fn set_oneshot_timer(deadline_ns: u64) { let cnptct = CNTPCT_EL0.get(); let cnptct_deadline = nanos_to_ticks(deadline_ns); @@ -48,6 +48,23 @@ pub fn set_oneshot_timer(deadline_ns: u64) { } } +#[cfg(all(feature = "irq", feature = "hv"))] +pub fn set_oneshot_timer(deadline_ns: u64) { + let cnptct = CNTPCT_EL0.get(); + let cnptct_deadline = nanos_to_ticks(deadline_ns); + if cnptct < cnptct_deadline { + let interval = cnptct_deadline - cnptct; + debug_assert!(interval <= u32::MAX as u64); + unsafe { + core::arch::asm!("msr CNTHP_TVAL_EL2, {}", in(reg) interval); + } + } else { + unsafe { + core::arch::asm!("msr CNTHP_TVAL_EL2, {0:x}", in(reg) 0); + } + } +} + /// Early stage initialization: stores the timer frequency. pub(crate) fn init_early() { let freq = CNTFRQ_EL0.get(); @@ -77,10 +94,21 @@ pub(crate) fn init_early() { } pub(crate) fn init_percpu() { - #[cfg(feature = "irq")] + #[cfg(all(feature = "irq", not(feature = "hv")))] { CNTP_CTL_EL0.write(CNTP_CTL_EL0::ENABLE::SET); CNTP_TVAL_EL0.set(0); - crate::platform::irq::set_enable(crate::platform::irq::TIMER_IRQ_NUM, true); } + #[cfg(all(feature = "irq", feature = "hv"))] + { + unsafe { + // ENABLE, bit [0], Enables the timer. + // * 0b0: Timer disabled. + // * 0b1: Timer enabled. + core::arch::asm!("msr CNTHP_CTL_EL2, {0:x}", in(reg) 0b1); + core::arch::asm!("msr CNTHP_TVAL_EL2, {0:x}", in(reg) 0); + } + } + #[cfg(feature = "irq")] + crate::platform::irq::set_enable(crate::platform::irq::TIMER_IRQ_NUM, true); } diff --git a/modules/axhal/src/platform/aarch64_common/gic.rs b/modules/axhal/src/platform/aarch64_common/gic.rs index 80a9f86218..eb0bf8fa1e 100644 --- a/modules/axhal/src/platform/aarch64_common/gic.rs +++ b/modules/axhal/src/platform/aarch64_common/gic.rs @@ -1,23 +1,35 @@ use crate::{irq::IrqHandler, mem::phys_to_virt}; -use arm_gicv2::{translate_irq, GicCpuInterface, GicDistributor, InterruptType}; +use arm_gicv2::{ + translate_irq, GicCpuInterface, GicDistributor, GicHypervisorInterface, InterruptType, +}; use kspin::SpinNoIrq; use memory_addr::PhysAddr; /// The maximum number of IRQs. pub const MAX_IRQ_COUNT: usize = 1024; +#[cfg(not(feature = "hv"))] /// The timer IRQ number. pub const TIMER_IRQ_NUM: usize = translate_irq(14, InterruptType::PPI).unwrap(); +#[cfg(feature = "hv")] +/// Non-secure EL2 Physical Timer irq number. +pub const TIMER_IRQ_NUM: usize = translate_irq(10, InterruptType::PPI).unwrap(); + /// The UART IRQ number. pub const UART_IRQ_NUM: usize = translate_irq(axconfig::UART_IRQ, InterruptType::SPI).unwrap(); const GICD_BASE: PhysAddr = pa!(axconfig::GICD_PADDR); const GICC_BASE: PhysAddr = pa!(axconfig::GICC_PADDR); +const GICH_BASE: PhysAddr = pa!(axconfig::GICH_PADDR); static GICD: SpinNoIrq = SpinNoIrq::new(GicDistributor::new(phys_to_virt(GICD_BASE).as_mut_ptr())); +static GICH: SpinNoIrq = SpinNoIrq::new(GicHypervisorInterface::new( + phys_to_virt(GICH_BASE).as_mut_ptr(), +)); + // per-CPU, no lock static GICC: GicCpuInterface = GicCpuInterface::new(phys_to_virt(GICC_BASE).as_mut_ptr()); @@ -36,13 +48,24 @@ pub fn register_handler(irq_num: usize, handler: IrqHandler) -> bool { crate::irq::register_handler_common(irq_num, handler) } +/// Fetches the IRQ number. +pub fn fetch_irq() -> usize { + GICC.iar() as usize +} + /// Dispatches the IRQ. /// /// This function is called by the common interrupt handler. It looks /// up in the IRQ handler table and calls the corresponding handler. If /// necessary, it also acknowledges the interrupt controller after handling. -pub fn dispatch_irq(_unused: usize) { - GICC.handle_irq(|irq_num| crate::irq::dispatch_irq_common(irq_num as _)); +pub fn dispatch_irq(irq_no: usize) { + if irq_no == 0 { + GICC.handle_irq(|irq_num| crate::irq::dispatch_irq_common(irq_num as _)); + } else { + crate::irq::dispatch_irq_common(irq_no as _); + GICC.eoi(irq_no as _); + GICC.dir(irq_no as _); + } } /// Initializes GICD, GICC on the primary CPU. @@ -57,3 +80,20 @@ pub(crate) fn init_primary() { pub(crate) fn init_secondary() { GICC.init(); } + +pub struct GicInterface {} + +/// Sets the value of a List Register (LR) at the specified index. +/// +/// This function locks the Generic Interrupt Controller Hypervisor (GICH) interface +/// and sets the specified List Register to the provided value. +/// +/// # Arguments +/// +/// * `idx` - The index of the List Register to set. +/// * `lr` - The value to set in the List Register. +impl GicInterface { + pub fn set_lr(&self, idx: usize, lr: u32) { + GICH.lock().set_lr(idx, lr); + } +} diff --git a/modules/axhal/src/platform/aarch64_common/mod.rs b/modules/axhal/src/platform/aarch64_common/mod.rs index c585541fe8..8a2a450930 100644 --- a/modules/axhal/src/platform/aarch64_common/mod.rs +++ b/modules/axhal/src/platform/aarch64_common/mod.rs @@ -1,4 +1,8 @@ +#[cfg(not(feature = "hv"))] mod boot; +#[cfg(feature = "hv")] +// Todo: maybe we can enter el2 in arm_vcpu? +mod boot_el2; pub mod generic_timer; #[cfg(not(platform_family = "aarch64-raspi"))] @@ -7,5 +11,8 @@ pub mod psci; #[cfg(feature = "irq")] pub mod gic; -#[cfg(not(platform_family = "aarch64-bsta1000b"))] +#[cfg(not(any( + platform_family = "aarch64-bsta1000b", + platform_family = "aarch64-rk3588j" +)))] pub mod pl011; diff --git a/modules/axhal/src/platform/aarch64_qemu_virt/mod.rs b/modules/axhal/src/platform/aarch64_qemu_virt/mod.rs index 2a452fa08e..8f382f650a 100644 --- a/modules/axhal/src/platform/aarch64_qemu_virt/mod.rs +++ b/modules/axhal/src/platform/aarch64_qemu_virt/mod.rs @@ -30,6 +30,7 @@ extern "C" { pub(crate) unsafe extern "C" fn rust_entry(cpu_id: usize, dtb: usize) { crate::mem::clear_bss(); crate::arch::set_exception_vector_base(exception_vector_base as usize); + #[cfg(not(feature = "hv"))] crate::arch::write_page_table_root0(0.into()); // disable low address access crate::cpu::init_primary(cpu_id); super::aarch64_common::pl011::init_early(); @@ -38,8 +39,10 @@ pub(crate) unsafe extern "C" fn rust_entry(cpu_id: usize, dtb: usize) { } #[cfg(feature = "smp")] +#[allow(dead_code)] // FIXME: temporariy allowd to bypass clippy warnings. pub(crate) unsafe extern "C" fn rust_entry_secondary(cpu_id: usize) { crate::arch::set_exception_vector_base(exception_vector_base as usize); + #[cfg(not(feature = "hv"))] crate::arch::write_page_table_root0(0.into()); // disable low address access crate::cpu::init_secondary(cpu_id); rust_main_secondary(cpu_id); diff --git a/modules/axhal/src/platform/aarch64_rk3588j/dw_apb_uart.rs b/modules/axhal/src/platform/aarch64_rk3588j/dw_apb_uart.rs new file mode 100644 index 0000000000..6d9de293be --- /dev/null +++ b/modules/axhal/src/platform/aarch64_rk3588j/dw_apb_uart.rs @@ -0,0 +1,147 @@ +//! Definitions for snps,dw-apb-uart serial driver. +//! Uart snps,dw-apb-uart driver in Rust for BST A1000b FADA board. +use crate::mem::phys_to_virt; +use kspin::SpinNoIrq; +use memory_addr::PhysAddr; + +use tock_registers::{ + interfaces::{Readable, Writeable}, + register_structs, + registers::{ReadOnly, ReadWrite}, +}; + +register_structs! { + DW8250Regs { + /// Get or Put Register. + (0x00 => rbr: ReadWrite), + (0x04 => ier: ReadWrite), + (0x08 => fcr: ReadWrite), + (0x0c => lcr: ReadWrite), + (0x10 => mcr: ReadWrite), + (0x14 => lsr: ReadOnly), + (0x18 => msr: ReadOnly), + (0x1c => scr: ReadWrite), + (0x20 => lpdll: ReadWrite), + (0x24 => _reserved0), + /// Uart Status Register. + (0x7c => usr: ReadOnly), + (0x80 => _reserved1), + (0xc0 => dlf: ReadWrite), + (0xc4 => @END), + } +} + +/// dw-apb-uart serial driver: DW8250 +pub struct DW8250 { + base_vaddr: usize, +} + +impl DW8250 { + /// New a DW8250 + pub const fn new(base_vaddr: usize) -> Self { + Self { base_vaddr } + } + + const fn regs(&self) -> &DW8250Regs { + unsafe { &*(self.base_vaddr as *const _) } + } + + /// DW8250 initialize + pub fn init(&mut self) { + const UART_SRC_CLK: u32 = 25000000; + const BST_UART_DLF_LEN: u32 = 6; + const BAUDRATE: u32 = 115200; + //const BAUDRATE: u32 = 38400; + + let get_baud_divider = |baudrate| (UART_SRC_CLK << (BST_UART_DLF_LEN - 4)) / baudrate; + let divider = get_baud_divider(BAUDRATE); + + // Waiting to be no USR_BUSY. + while self.regs().usr.get() & 0b1 != 0 {} + + // bst_serial_hw_init_clk_rst + + /* Disable interrupts and Enable FIFOs */ + self.regs().ier.set(0); + self.regs().fcr.set(1); + + /* Disable flow ctrl */ + self.regs().mcr.set(0); + + /* Clear MCR_RTS */ + self.regs().mcr.set(self.regs().mcr.get() | (1 << 1)); + + /* Enable access DLL & DLH. Set LCR_DLAB */ + self.regs().lcr.set(self.regs().lcr.get() | (1 << 7)); + + /* Set baud rate. Set DLL, DLH, DLF */ + self.regs().rbr.set((divider >> BST_UART_DLF_LEN) & 0xff); + self.regs() + .ier + .set((divider >> (BST_UART_DLF_LEN + 8)) & 0xff); + self.regs().dlf.set(divider & ((1 << BST_UART_DLF_LEN) - 1)); + + /* Clear DLAB bit */ + self.regs().lcr.set(self.regs().lcr.get() & !(1 << 7)); + + /* Set data length to 8 bit, 1 stop bit, no parity. Set LCR_WLS1 | LCR_WLS0 */ + self.regs().lcr.set(self.regs().lcr.get() | 0b11); + } + + /// DW8250 serial output + pub fn putchar(&mut self, c: u8) { + // Check LSR_TEMT + // Wait for last character to go. + while self.regs().lsr.get() & (1 << 6) == 0 {} + self.regs().rbr.set(c as u32); + } + + /// DW8250 serial input + pub fn getchar(&mut self) -> Option { + // Check LSR_DR + // Wait for a character to arrive. + if self.regs().lsr.get() & 0b1 != 0 { + Some((self.regs().rbr.get() & 0xff) as u8) + } else { + None + } + } + + /// DW8250 serial interrupt enable or disable + pub fn set_ier(&mut self, enable: bool) { + if enable { + // Enable interrupts + self.regs().ier.set(1); + } else { + // Disable interrupts + self.regs().ier.set(0); + } + } +} + +const UART_BASE: PhysAddr = pa!(axconfig::UART_PADDR); + +pub static UART: SpinNoIrq = + SpinNoIrq::new(DW8250::new(phys_to_virt(UART_BASE).as_usize())); + +/// Writes a byte to the console. +pub fn putchar(c: u8) { + let mut uart = UART.lock(); + match c { + b'\r' | b'\n' => { + uart.putchar(b'\r'); + uart.putchar(b'\n'); + } + c => uart.putchar(c), + } +} + +/// Reads a byte from the console, or returns [`None`] if no input is available. +pub fn getchar() -> Option { + UART.lock().getchar() +} + +/// UART simply initialize +pub fn init_early() { + UART.lock().init(); +} diff --git a/modules/axhal/src/platform/aarch64_rk3588j/mem.rs b/modules/axhal/src/platform/aarch64_rk3588j/mem.rs new file mode 100644 index 0000000000..d7cf3415ee --- /dev/null +++ b/modules/axhal/src/platform/aarch64_rk3588j/mem.rs @@ -0,0 +1,68 @@ +use crate::mem::{MemRegion, MemRegionFlags, PhysAddr}; +use page_table_entry::{aarch64::A64PTE, GenericPTE, MappingFlags}; + +/// Returns (rk3588j only) memory regions. +pub(crate) fn default_rk3588j_regions() -> impl Iterator { + [ + MemRegion { + paddr: PhysAddr::from(0x9400000), + size: 0xe6c00000, + flags: MemRegionFlags::RESERVED | MemRegionFlags::READ | MemRegionFlags::WRITE, + name: "free memory", + }, + MemRegion { + paddr: PhysAddr::from(0x1f0000000), + size: 0x10000000, + flags: MemRegionFlags::FREE | MemRegionFlags::READ | MemRegionFlags::WRITE, + name: "free memory", + }, + ] + .into_iter() +} + +/// Returns platform-specific memory regions. +pub(crate) fn platform_regions() -> impl Iterator { + crate::mem::default_free_regions() + .chain(default_rk3588j_regions()) + .chain(crate::mem::default_mmio_regions()) +} + +pub(crate) unsafe fn init_boot_page_table( + boot_pt_l0: *mut [A64PTE; 512], + boot_pt_l1: *mut [A64PTE; 512], +) { + let boot_pt_l0 = &mut *boot_pt_l0; + let boot_pt_l1 = &mut *boot_pt_l1; + boot_pt_l0[0] = A64PTE::new_table(PhysAddr::from(boot_pt_l1.as_ptr() as usize)); + + boot_pt_l1[0] = A64PTE::new_page( + PhysAddr::from(0), + MappingFlags::READ | MappingFlags::WRITE | MappingFlags::EXECUTE, + true, + ); + boot_pt_l1[1] = A64PTE::new_page( + PhysAddr::from(0x4000_0000), + MappingFlags::READ | MappingFlags::WRITE | MappingFlags::EXECUTE, + true, + ); + boot_pt_l1[2] = A64PTE::new_page( + PhysAddr::from(0x8000_0000), + MappingFlags::READ | MappingFlags::WRITE | MappingFlags::EXECUTE, + true, + ); + boot_pt_l1[3] = A64PTE::new_page( + PhysAddr::from(0xC000_0000), + MappingFlags::READ | MappingFlags::WRITE | MappingFlags::DEVICE, + true, + ); + boot_pt_l1[7] = A64PTE::new_page( + PhysAddr::from(0x1_C000_0000), + MappingFlags::READ | MappingFlags::WRITE | MappingFlags::EXECUTE, + true, + ); + boot_pt_l1[8] = A64PTE::new_page( + PhysAddr::from(0x1_F000_0000), + MappingFlags::READ | MappingFlags::WRITE | MappingFlags::EXECUTE, + true, + ); +} diff --git a/modules/axhal/src/platform/aarch64_rk3588j/mod.rs b/modules/axhal/src/platform/aarch64_rk3588j/mod.rs new file mode 100644 index 0000000000..c59047bd78 --- /dev/null +++ b/modules/axhal/src/platform/aarch64_rk3588j/mod.rs @@ -0,0 +1,66 @@ +pub mod dw_apb_uart; +pub mod mem; + +#[cfg(feature = "smp")] +pub mod mp; + +#[cfg(feature = "irq")] +pub mod irq { + pub use crate::platform::aarch64_common::gic::*; +} + +pub mod console { + pub use super::dw_apb_uart::*; +} + +pub mod time { + pub use crate::platform::aarch64_common::generic_timer::*; +} + +pub mod misc { + pub use crate::platform::aarch64_common::psci::system_off as terminate; +} + +extern "C" { + fn exception_vector_base(); + fn rust_main(cpu_id: usize, dtb: usize); + #[cfg(feature = "smp")] + fn rust_main_secondary(cpu_id: usize); +} + +pub(crate) unsafe extern "C" fn rust_entry(cpu_id: usize, dtb: usize) { + crate::mem::clear_bss(); + crate::arch::set_exception_vector_base(exception_vector_base as usize); + #[cfg(not(feature = "hv"))] + crate::arch::write_page_table_root0(0.into()); // disable low address access + crate::cpu::init_primary(cpu_id); + super::dw_apb_uart::init_early(); + super::aarch64_common::generic_timer::init_early(); + rust_main(cpu_id, dtb); +} + +#[cfg(feature = "smp")] +#[allow(dead_code)] // FIXME: temporariy allowd to bypass clippy warnings. +pub(crate) unsafe extern "C" fn rust_entry_secondary(cpu_id: usize) { + crate::arch::set_exception_vector_base(exception_vector_base as usize); + crate::arch::write_page_table_root0(0.into()); // disable low address access + crate::cpu::init_secondary(cpu_id); + rust_main_secondary(cpu_id); +} + +/// Initializes the platform devices for the primary CPU. +/// +/// For example, the interrupt controller and the timer. +pub fn platform_init() { + #[cfg(feature = "irq")] + super::aarch64_common::gic::init_primary(); + super::aarch64_common::generic_timer::init_percpu(); +} + +/// Initializes the platform devices for secondary CPUs. +#[cfg(feature = "smp")] +pub fn platform_init_secondary() { + #[cfg(feature = "irq")] + super::aarch64_common::gic::init_secondary(); + super::aarch64_common::generic_timer::init_percpu(); +} diff --git a/modules/axhal/src/platform/aarch64_rk3588j/mp.rs b/modules/axhal/src/platform/aarch64_rk3588j/mp.rs new file mode 100644 index 0000000000..01f84fc4c1 --- /dev/null +++ b/modules/axhal/src/platform/aarch64_rk3588j/mp.rs @@ -0,0 +1,20 @@ +use crate::mem::{virt_to_phys, PhysAddr, VirtAddr}; + +/// Hart number of rk3588 board +pub const MAX_HARTS: usize = 8; +/// CPU HWID from cpu device tree nodes with "reg" property +pub const CPU_HWID: [usize; MAX_HARTS] = [0x00, 0x100, 0x200, 0x300, 0x400, 0x500, 0x600, 0x700]; + +/// Starts the given secondary CPU with its boot stack. +pub fn start_secondary_cpu(cpu_id: usize, stack_top: PhysAddr) { + assert!(cpu_id < MAX_HARTS, "No support for rk3588 core {}", cpu_id); + extern "C" { + fn _start_secondary(); + } + let entry = virt_to_phys(VirtAddr::from(_start_secondary as usize)); + crate::platform::aarch64_common::psci::cpu_on( + CPU_HWID[cpu_id], + entry.as_usize(), + stack_top.as_usize(), + ); +} diff --git a/modules/axhal/src/platform/dummy/mod.rs b/modules/axhal/src/platform/dummy/mod.rs index 389f14c778..e8f10394c3 100644 --- a/modules/axhal/src/platform/dummy/mod.rs +++ b/modules/axhal/src/platform/dummy/mod.rs @@ -82,6 +82,11 @@ pub mod irq { /// up in the IRQ handler table and calls the corresponding handler. If /// necessary, it also acknowledges the interrupt controller after handling. pub fn dispatch_irq(irq_num: usize) {} + + /// Fetches the IRQ number. + pub fn fetch_irq() -> usize { + 0 + } } /// Initializes the platform devices for the primary CPU. diff --git a/modules/axhal/src/platform/mod.rs b/modules/axhal/src/platform/mod.rs index a39151c47f..cd330b2a10 100644 --- a/modules/axhal/src/platform/mod.rs +++ b/modules/axhal/src/platform/mod.rs @@ -22,6 +22,9 @@ cfg_if::cfg_if! { } else if #[cfg(all(target_arch = "aarch64", platform_family = "aarch64-bsta1000b"))] { mod aarch64_bsta1000b; pub use self::aarch64_bsta1000b::*; + } else if #[cfg(all(target_arch = "aarch64", platform_family = "aarch64-rk3588j"))] { + mod aarch64_rk3588j; + pub use self::aarch64_rk3588j::*; } else { mod dummy; pub use self::dummy::*; diff --git a/modules/axruntime/Cargo.toml b/modules/axruntime/Cargo.toml index c26237b718..79de400b6b 100644 --- a/modules/axruntime/Cargo.toml +++ b/modules/axruntime/Cargo.toml @@ -37,7 +37,7 @@ axdisplay = { workspace = true, optional = true } axtask = { workspace = true, optional = true } crate_interface = "0.1" -percpu = { version = "0.1", optional = true } +percpu = { version = "0.1.4", optional = true } kernel_guard = { version = "0.1", optional = true } chrono = { version = "0.4.38", default-features = false } diff --git a/modules/axtask/Cargo.toml b/modules/axtask/Cargo.toml index 73df17334c..393f8ca943 100644 --- a/modules/axtask/Cargo.toml +++ b/modules/axtask/Cargo.toml @@ -40,7 +40,7 @@ cfg-if = "1.0" log = "=0.4.21" axhal = { workspace = true } axconfig = { workspace = true, optional = true } -percpu = { version = "0.1", optional = true } +percpu = { version = "0.1.4", optional = true } kspin = { version = "0.1", optional = true } lazyinit = { version = "0.2", optional = true } memory_addr = { version = "0.3", optional = true } diff --git a/platforms/aarch64-rk3588j.toml b/platforms/aarch64-rk3588j.toml new file mode 100644 index 0000000000..61d0793234 --- /dev/null +++ b/platforms/aarch64-rk3588j.toml @@ -0,0 +1,68 @@ +# Architecture identifier. +arch = "aarch64" +# Platform identifier. +platform = "aarch64-rk3588j" +# Platform family. +family = "aarch64-rk3588j" + +# Base address of the whole physical memory. +phys-memory-base = "0x20_0000" +# Size of the whole physical memory. +phys-memory-size = "0x800_0000" # 128M +# Base physical address of the kernel image. +kernel-base-paddr = "0x48_0000" +# Base virtual address of the kernel image. +kernel-base-vaddr = "0x0000_0000_0048_0000" +# Linear mapping offset, for quick conversions between physical and virtual +# addresses. +phys-virt-offset = "0xffff_0000_0000_0000" +# Kernel address space base. +kernel-aspace-base = "0xffff_0000_0000_0000" +# Kernel address space size. +kernel-aspace-size = "0x0000_ffff_ffff_f000" +# MMIO regions with format (`base_paddr`, `size`). +mmio-regions = [ + # ["0x0900_0000", "0x1000"], # PL011 UART + # ["0x0800_0000", "0x5_0000"], # GICv2 with Virtualization (GICV@0x0803_0000, GICH@0x0804_0000) + # ["0x0a00_0000", "0x4000"], # VirtIO + # ["0x1000_0000", "0x2eff_0000"], # PCI memory ranges (ranges 1: 32-bit MMIO space) + # ["0x40_1000_0000", "0x1000_0000"], # PCI config space + ["0xfeb50000", "0x1000"], # uart8250 UART0 + ["0xfe600000", "0x10000"], # gic-v3 gicd + ["0xfe680000", "0x100000"], # gic-v3 gicr + ["0xa41000000", "0x400000"], + ["0xa40c00000", "0x400000"], + ["0xf4000000","0x1000000"], + ["0xf3000000","0x1000000"], +] +# VirtIO MMIO regions with format (`base_paddr`, `size`). +virtio-mmio-regions = [] + +# Base physical address of the PCIe ECAM space. +pci-ecam-base = "0xf4000000" +# End PCI bus number (`bus-range` property in device tree). +pci-bus-end = "0xff" +# PCI device memory ranges (`ranges` property in device tree). +pci-ranges = [] +# UART Address +uart-paddr = "0xfeb5_0000" +uart-irq = "0x14d" + +# GICC Address +gicd-paddr = "0xfe600000" +# GICR Address +gicc-paddr = "0xfe680000" +gicr-paddr = "0xfe680000" + +# PSCI +psci-method = "smc" + +# pl031@9010000 { +# clock-names = "apb_pclk"; +# clocks = <0x8000>; +# interrupts = <0x00 0x02 0x04>; +# reg = <0x00 0x9010000 0x00 0x1000>; +# compatible = "arm,pl031\0arm,primecell"; +# }; +# RTC (PL031) Address +# rtc-paddr = "0x901_0000" \ No newline at end of file diff --git a/scripts/make/qemu.mk b/scripts/make/qemu.mk index fd2c78b9a6..ba52b4f829 100644 --- a/scripts/make/qemu.mk +++ b/scripts/make/qemu.mk @@ -24,7 +24,7 @@ qemu_args-aarch64 := \ -machine virt \ -kernel $(OUT_BIN) -qemu_args-y := -m 128M -smp $(SMP) $(qemu_args-$(ARCH)) +qemu_args-y := -m 2G -smp $(SMP) $(qemu_args-$(ARCH)) qemu_args-$(BLK) += \ -device virtio-blk-$(vdev-suffix),drive=disk0 \ diff --git a/scripts/make/rk3588.mk b/scripts/make/rk3588.mk new file mode 100644 index 0000000000..49c0a44434 --- /dev/null +++ b/scripts/make/rk3588.mk @@ -0,0 +1,13 @@ +RK3588_GITHUB_URL = https://github.com/arceos-hypervisor/platform_tools/releases/download/latest/rk3588.zip +RK3588_MKIMG_FILE = ./tools/rk3588/mkimg +check-download: +ifeq ("$(wildcard $(RK3588_MKIMG_FILE))","") + @echo "file not found, downloading from $(RK3588_GITHUB_URL)..."; + wget $(RK3588_GITHUB_URL); + unzip -o rk3588.zip -d tools; + rm rk3588.zip; +endif + +kernel: check-download build + $(RK3588_MKIMG_FILE) --dtb rk3588-firefly-itx-3588j.dtb --img $(OUT_BIN) + @echo 'Built the FIT-uImage boot.img' diff --git a/ulib/axstd/Cargo.toml b/ulib/axstd/Cargo.toml index b78282f5c0..40b1d6f8d3 100644 --- a/ulib/axstd/Cargo.toml +++ b/ulib/axstd/Cargo.toml @@ -64,6 +64,9 @@ driver-ramdisk = ["axfeat/driver-ramdisk"] driver-ixgbe = ["axfeat/driver-ixgbe"] driver-bcm2835-sdhci = ["axfeat/driver-bcm2835-sdhci"] +# Hypervisor support +hv = ["axfeat/hv"] + # Logging log-level-off = ["axfeat/log-level-off"] log-level-error = ["axfeat/log-level-error"]