diff --git a/src/.gitignore b/src/.gitignore index bb9caa138e939a38767fd94b6b9cb65b42761ca7..7950c318666175c12cff4f196399aa22b504f2bf 100644 --- a/src/.gitignore +++ b/src/.gitignore @@ -13,4 +13,7 @@ fixdep init/rootfs.c build -drivers/block/romdisk.S \ No newline at end of file +drivers/block/romdisk.S + +# xhyp Guest OS image +*.bin \ No newline at end of file diff --git a/src/Kconfig b/src/Kconfig index 99a5bb135eebf740189b9d8c88f7812f446c40e0..267f51b4d2ca0c91aadb932de00de78e59370709 100644 --- a/src/Kconfig +++ b/src/Kconfig @@ -49,6 +49,11 @@ menu "OS Kernel" # Time or timer # source "src/time/Kconfig" + + # + # xhyp or virtualization + # + source "src/xhyp/Kconfig" endmenu # diff --git a/src/Makefile b/src/Makefile index 82c6b04a29e1c042b66ee673ef3698d00c6149e0..a9b4e630b3fe9f8cc8614bb51ecc03fd422b3f2b 100644 --- a/src/Makefile +++ b/src/Makefile @@ -120,6 +120,7 @@ SRCDIRS += fs/ SRCDIRS += test/ SRCDIRS += time/ SRCDIRS += ipc/ +SRCDIRS += xhyp/ # # XBuild variables diff --git a/src/arch/riscv64/Makefile b/src/arch/riscv64/Makefile index 3c787084c7299312ead18ab0e31a1b7a7cc306ff..8a578ba2330a3aa0b6d01bfba8ba33d2b2d66b4c 100644 --- a/src/arch/riscv64/Makefile +++ b/src/arch/riscv64/Makefile @@ -1,3 +1,4 @@ SRC += kernel/ SRC += port/ SRC += utils/ +SRC += xhyp/ diff --git a/src/arch/riscv64/include/arch/xhyp_arch.h b/src/arch/riscv64/include/arch/xhyp_arch.h new file mode 100644 index 0000000000000000000000000000000000000000..3deaa74ef5a33bef07b3b0dbbf4defab638434f5 --- /dev/null +++ b/src/arch/riscv64/include/arch/xhyp_arch.h @@ -0,0 +1,116 @@ +/** + * Copyright (c) 2018-2023, NXOS Development Team + * SPDX-License-Identifier: Apache-2.0 + * + * Contains: Arch xhyp + * + * Change Logs: + * Date Author Notes + * 2023-09-06 Suqier Init + */ + +#ifndef __ARCH_XHYP__ +#define __ARCH_XHYP__ + +#include + +#ifdef CONFIG_NX_XHYP +#include +#include + +#include +#include + +#define CSR_VSSTATUS 0x200 +#define CSR_VSIE 0x204 +#define CSR_VSTVEC 0x205 +#define CSR_VSSCRATCH 0x240 +#define CSR_VSEPC 0x241 +#define CSR_VSCAUSE 0x242 +#define CSR_VSTVAL 0x243 +#define CSR_VSIP 0x244 +#define CSR_VSATP 0x280 + +#define HSTATUS_VSXL_OFF (32) +#define HSTATUS_VSXL_32 (1ULL << HSTATUS_VSXL_OFF) +#define HSTATUS_VSXL_64 (2ULL << HSTATUS_VSXL_OFF) + +#define HCOUNTEREN_CY (1ULL << 0) +#define HCOUNTEREN_TM (1ULL << 1) +#define HCOUNTEREN_IR (1ULL << 2) + +#define VSSTATUS_SD (1ULL << 63) +#define VSSTATUS_FS_OFF (13) +#define VSSTATUS_FS_DIRTY (3ULL << VSSTATUS_FS_OFF) +#define VSSTATUS_XS_OFF (15) +#define VSSTATUS_XS_DIRTY (3ULL << VSSTATUS_XS_OFF) + +struct vcpuArch +{ + NX_UArch hstatus; + NX_UArch hcounteren; + NX_UArch htimedelta; + NX_UArch vsstatus; + NX_UArch hie; + NX_UArch vstvec; + NX_UArch vsscratch; + NX_UArch vsepc; + NX_UArch vscause; + NX_UArch vstval; + NX_UArch hvip; + NX_UArch vsatp; +}; +typedef struct vcpuArch vcpuArch; + +struct vcpu; + +/* for init */ +NX_Error VcpuArchInit(struct vcpu * vcpu); + +/* for switch */ +void HostToGuestArchHandler(struct vcpu * vcpu); +void GuestToHostArchHandler(struct vcpu * vcpu); +void VcpuToVcpuArchHandler(struct vcpu * prev, struct vcpu * next); +void GuestToGuestArchHandler(struct vcpu * prev, struct vcpu * next); + +/* hlv/hsv */ +NX_U64 Hlvwu(NX_U64 addr); +NX_U64 Hlvxwu(NX_U64 addr); +void Hsvw(NX_U64 addr, NX_U64 value); + +/* MMIO */ +#define UART_DAT (UART0_PHY_ADDR) +#define UART_IER (UART0_PHY_ADDR + 0x01) +#define UART_LSR (UART0_PHY_ADDR + 0x05) + +struct emulate_MMIO_Info +{ + NX_HalTrapFrame *frame; + NX_Addr addr; + NX_U32 reg; + NX_U32 width; + NX_Bool write; + NX_Bool signExt; +}; +typedef struct emulate_MMIO_Info NX_EMI; + +void printEmi(const NX_EMI * emi); + +NX_Bool Is_UART_MMIO_Range(NX_Addr faultAddr); +NX_Bool Is_PLIC_claimBasic(NX_Addr faultAddr); +NX_Bool Is_PLIC_claimRange(NX_Addr faultAddr); +NX_Bool Is_PLIC_MMIO_Range(NX_Addr faultAddr); +NX_Bool Is_MMIO_Range(NX_Addr faultAddr); + +NX_U64 EmulateReadReg(NX_HalTrapFrame * frame, int reg); +void EmulateWriteReg(NX_HalTrapFrame * frame, int reg, NX_U64 val); +void Emulate_MMIO_Reg8(NX_EMI * emi); +void Emulate_UART(NX_EMI * emi); +void Emulate_PLIC_basic(NX_EMI * emi); +void Emulate_PLIC_claim(NX_EMI * emi); +void Emulate_PLIC(NX_EMI * emi); +void Emulate_MMIO_Device(NX_Addr faultAddr, NX_U64 InsValue, NX_HalTrapFrame * frame); + +#endif /* CONFIG_NX_XHYP */ + +#endif /* __ARCH_XHYP__ */ diff --git a/src/arch/riscv64/include/regs.h b/src/arch/riscv64/include/regs.h index ac7391acfc81e0ed63bd3c1d7d1d7b4e0f2e975d..019909d537030a43a9956b68f785980e0b6d31fd 100644 --- a/src/arch/riscv64/include/regs.h +++ b/src/arch/riscv64/include/regs.h @@ -28,6 +28,7 @@ #define SCAUSE_INTERRUPT (1UL << (RISCV_XLEN - 1)) #define SCAUSE_S_SOFTWARE_INTR 1 #define SCAUSE_S_TIMER_INTR 5 +#define SCAUSE_VS_TIMER_INTR 6 #define SCAUSE_S_EXTERNAL_INTR 9 #define IRQ_S_SOFT 1 @@ -52,6 +53,58 @@ #define REGSZ 8 +/* + * xhyp regs - Virtualization + */ +#ifdef CONFIG_NX_XHYP +/* VS csr */ +#define CSR_VSSTATUS 0x200 +#define CSR_VSIE 0x204 +#define CSR_VSTVEC 0x205 +#define CSR_VSSCRATCH 0x240 +#define CSR_VSEPC 0x241 +#define CSR_VSCAUSE 0x242 +#define CSR_VSTVAL 0x243 +#define CSR_VSIP 0x244 +#define CSR_VSATP 0x280 + +/* HS csr */ +#define CSR_HSTATUS 0x600 +#define HSTATUS_SPV_SHIFT 7 +#define HSTATUS_SPV (1UL << HSTATUS_SPV_SHIFT) +#define HSTATUS_SPVP_SHIFT 8 +#define HSTATUS_SPVP (1UL << HSTATUS_SPVP_SHIFT) +#define HSTATUS_VSXL_SHIFT 32 +#define HSTATUS_VSXL (2UL << HSTATUS_VSXL_SHIFT) + +#define CSR_HEDELEG 0x602 +#define CSR_HIDELEG 0x603 +#define CSR_HIE 0x604 +#define CSR_HTIMEDELTA 0x605 +#define CSR_HTIMEDELTAH 0x615 +#define CSR_HCOUNTEREN 0x606 +#define CSR_HGEIE 0x607 +#define CSR_HTVAL 0x643 +#define CSR_HIP 0x644 +#define CSR_HVIP 0x645 +#define CSR_HTINST 0x64A +#define CSR_HGATP 0x680 +#define CSR_HGEIP 0xE07 + +/* virtual interrupt or excepition */ +#define HVIP_VS_EIP (10) +#define HVIP_VS_TIP (6) +#define HVIP_VS_SIP (2) +#define HIP_SG_EIP (12) +#define HIP_VS_EIP (10) +#define HIP_VS_TIP (6) +#define HIP_VS_SIP (2) +#define HIE_SG_EIP (12) +#define HIE_VS_EIP (10) +#define HIE_VS_TIE (6) +#define HIE_VS_SIE (1) +#endif /* CONFIG_NX_XHYP */ + #ifndef __ASSEMBLY__ /* csr registers read/write */ #define ReadCSR(reg) ({ NX_U64 __tmp; \ diff --git a/src/arch/riscv64/kernel/interrupt.S b/src/arch/riscv64/kernel/interrupt.S index ff96ee88831ea5a8b1f5f9a39a34ca61d917381e..44e76532845eac7da4eb1abd40b274c7e88bf1c4 100644 --- a/src/arch/riscv64/kernel/interrupt.S +++ b/src/arch/riscv64/kernel/interrupt.S @@ -19,6 +19,8 @@ .extern TrapDispatch .extern TrapSwitchStack .extern NX_IRQ_OverCheck +.extern SaveHstatus +.extern RestoreHstatus .extern gStackTop0 .extern gStackTop1 @@ -74,10 +76,21 @@ NX_FUNC(TrapEntry) call TrapSwitchStack mv sp, a0 /* a0 saved new stack */ +#ifdef CONFIG_NX_XHYP + /* save hstatus */ + call SaveHstatus +#endif /*CONFIG_NX_XHYP */ + /* call handler */ mv a0, sp call TrapDispatch +#ifdef CONFIG_NX_XHYP + /* restore hstatus */ + call RestoreHstatus +#endif /*CONFIG_NX_XHYP */ + + /* irq over check */ mv a0, sp /* sp arg */ call NX_IRQ_OverCheck diff --git a/src/arch/riscv64/kernel/trap.c b/src/arch/riscv64/kernel/trap.c index 937a3a39ce28b5ec1b66733665d49ff63d36620a..4e7b02e0cd08af2b8e8600d618521bec28f1d9b3 100644 --- a/src/arch/riscv64/kernel/trap.c +++ b/src/arch/riscv64/kernel/trap.c @@ -21,6 +21,11 @@ #include #include +#ifdef CONFIG_NX_XHYP +#include +#include +#endif /* CONFIG_NX_XHYP */ + #include #include #include @@ -43,6 +48,17 @@ #define RISCV_LOAD_PAGE_FAULT 13 #define RISCV_RESERVED_14 14 #define RISCV_STORE_PAGE_FAULT 15 +#define RISCV_RESERVED_16 16 +#define RISCV_RESERVED_17 17 +#define RISCV_RESERVED_18 18 +#define RISCV_RESERVED_19 19 + +#ifdef CONFIG_NX_XHYP +#define RSICV_VM_INS_PAGE_MISS 20 +#define RSICV_VM_LOAD_PAGE_FAULT 21 +#define RSICV_VM_VIRT_INS_FAULT 22 +#define RSICV_VM_STORE_PAGE_FAULT 23 +#endif /* CONFIG_NX_XHYP */ /* trap name for riscv */ NX_PRIVATE const char *interruptName[] = @@ -78,12 +94,27 @@ NX_PRIVATE const char *exceptionName[] = "Instruction Page Fault", "Load Page Fault", "Reserved-14", - "Store/AMO Page Fault" + "Store/AMO Page Fault", + "Reserved-16", + "Reserved-17", + "Reserved-18", + "Reserved-19", + +#ifdef CONFIG_NX_XHYP + "Virtual Machine Instruction Page Miss", + "Virtual Machine Load Page Fault", + "Virtual Instruction Fault", + "Virtual Machine Store Page Fault", +#endif /* CONFIG_NX_XHYP */ }; NX_IMPORT NX_Error NX_HalHandlePageFault(NX_Thread * thread, NX_HalTrapFrame * frame, NX_Addr faultAddr); NX_IMPORT void NX_HalProcessSyscallDispatch(NX_HalTrapFrame *frame); +#ifdef CONFIG_NX_XHYP +NX_IRQ_Number gVirqNo; +#endif /* CONFIG_NX_XHYP */ + void TrapFrameDump(NX_HalTrapFrame *frame) { NX_LOG_RAW("------------ Trap frame Dump ------------\n"); @@ -197,10 +228,98 @@ void CPU_InitTrap(NX_UArch coreId) SetCSR(sie, SIE_SSIE); } +#ifdef CONFIG_NX_XHYP +void NX_VmHandlePageFault(NX_HalTrapFrame *frame) +{ + NX_Addr faultAddr; + NX_U64 htval, stval, scause; + + htval = ReadCSR(0x643); + stval = ReadCSR(stval); + scause = ReadCSR(scause); + faultAddr = (htval << 2) | (stval & 0x3); + + if (scause == RSICV_VM_LOAD_PAGE_FAULT || scause == RSICV_VM_STORE_PAGE_FAULT) + { + NX_Addr InsAddr = ReadCSR(sepc); + NX_U64 InsValue = Hlvxwu(InsAddr); + + if (Is_MMIO_Range(faultAddr)) + { + Emulate_MMIO_Device(faultAddr, InsValue, frame); + frame->epc += 4; + return; + } + } +} + +void TrapInject(NX_IRQ_Number irqno) +{ + ClearCSR(sie, SIE_SEIE); + NX_LOG_D("ClearCSR SIE_SEIE, 0x%lx", ReadCSR(sie)); + + do + { + NX_LOG_D("PLIC_Claim irqno = %d", irqno); + gVirqNo = irqno; + WriteCSR(0x645, 1UL << HVIP_VS_EIP); + NX_LOG_I("WriteCSR HVIP, 0x%lx", ReadCSR(0x645)); + + PLIC_Complete(NX_SMP_GetBootCore(), irqno); + irqno = PLIC_Claim(NX_SMP_GetBootCore()); + NX_LOG_D("PLIC_Complete irqno = %d", irqno); + } while ((irqno = PLIC_Claim(NX_SMP_GetBootCore()))); + + NX_LOG_D("irqno = %d", irqno); + SetCSR(sie, SIE_SEIE); + NX_LOG_D("SetCSR SIE_SEIE, 0x%lx", ReadCSR(sie)); +} + +void SaveHstatus(void) +{ + NX_Thread * self = NX_ThreadSelf(); + NX_VCPU * vcpu = NX_NULL; + + /* save hstatus before handle exception */ + if (self->userArg != NX_NULL) + { + vcpu = (NX_VCPU *)self->userArg; + vcpu->arch->hstatus = (HSTATUS_VSXL | HSTATUS_SPVP | HSTATUS_SPV); + NX_LOG_D("self name = %s, hstatus = 0x%lx saved, cause = 0x%lx", \ + self->name, vcpu->arch->hstatus, ReadCSR(scause)); + } + + return; +} + +void RestoreHstatus(void) +{ + NX_Thread * self = NX_ThreadSelf(); + NX_VCPU * vcpu = NX_NULL; + + /* restore hstatus before exit */ + if (self->userArg != NX_NULL) + { + vcpu = (NX_VCPU *)self->userArg; + WriteCSR(0x600, vcpu->arch->hstatus); + NX_LOG_D("self name = %s, hstatus = 0x%lx restore, cause = 0x%lx", \ + self->name, ReadCSR(0x600), ReadCSR(scause)); + } + + return; +} +#endif /* CONFIG_NX_XHYP */ + void TrapDispatch(NX_HalTrapFrame *frame) { NX_U64 cause = ReadCSR(scause); NX_U64 stval = ReadCSR(stval); + NX_U64 sstatus = ReadCSR(sstatus); +#ifdef CONFIG_NX_XHYP + NX_U64 htval = ReadCSR(0x643); + NX_U64 htinst = ReadCSR(0x64A); + NX_U64 hstatus = ReadCSR(0x600); +#endif /* CONFIG_NX_XHYP */ NX_Thread * self = NX_NULL; const char *msg = NX_NULL; @@ -224,7 +343,17 @@ void TrapDispatch(NX_HalTrapFrame *frame) if (irqno != 0) { NX_IRQ_Enter(); - NX_IRQ_Handle(irqno); +#ifdef CONFIG_NX_XHYP + if (hstatus & HSTATUS_SPV) + { + NX_LOG_D("TrapInject - irqno = %d", irqno); + TrapInject(irqno); + } + else +#endif /* CONFIG_NX_XHYP */ + { + NX_IRQ_Handle(irqno); + } NX_IRQ_Exit(); } return; @@ -271,14 +400,32 @@ void TrapDispatch(NX_HalTrapFrame *frame) return; case RISCV_STORE_PAGE_FAULT: case RISCV_LOAD_PAGE_FAULT: + NX_LOG_E("riscv exception %s occur", msg); + NX_LOG_E("scause:0x%p, stval:0x%p, sepc:0x%p", \ + cause, stval, frame->epc); if (NX_HalHandlePageFault(self, frame, stval) == NX_EOK) { return; } break; case RISCV_ILLEGAL_INS: - NX_LOG_E("riscv exception %s occur", msg); - NX_SignalSend(self->tid, NX_SIGNAL_ILLEGAL, NX_NULL, NX_NULL); +#ifdef CONFIG_NX_XHYP + if (hstatus & HSTATUS_SPV) + { + /* read instruction */ + NX_LOG_I("riscv exception %s occur from VM, read instruction", msg); + if (stval == 0) + { + NX_LOG_I("riscv exception %s occur from VM, read instruction", msg); + // stval = __cpu_vcpu_unpriv_read_insn(regs->sepc, &trap); + } + } + else +#endif /* CONFIG_NX_XHYP */ + { + NX_LOG_E("riscv exception %s occur, %s", msg, self->name); + NX_SignalSend(self->tid, NX_SIGNAL_ILLEGAL, NX_NULL, NX_NULL); + } return; case RISCV_BREAKPOINT: NX_LOG_E("riscv exception %s occur", msg); @@ -300,6 +447,13 @@ void TrapDispatch(NX_HalTrapFrame *frame) NX_LOG_E("riscv exception %s occur", msg); NX_SignalSend(self->tid, NX_SIGNAL_KILL, NX_NULL, NX_NULL); return; +#ifdef CONFIG_NX_XHYP + case RSICV_VM_INS_PAGE_MISS: + case RSICV_VM_LOAD_PAGE_FAULT: + case RSICV_VM_STORE_PAGE_FAULT: + NX_VmHandlePageFault(frame); + return; +#endif /* CONFIG_NX_XHYP */ default: break; } @@ -308,6 +462,7 @@ void TrapDispatch(NX_HalTrapFrame *frame) } NX_LOG_E("scause:0x%p, stval:0x%p, sepc:0x%p", cause, stval, frame->epc); + TrapFrameDump(frame); /* print call stack */ diff --git a/src/arch/riscv64/port/mmu.c b/src/arch/riscv64/port/mmu.c index e31f30a0090abfedc45edd4c1fdf62bb50f79d14..59d5f549ac52e944b0c93e774ca862da5e920c3d 100644 --- a/src/arch/riscv64/port/mmu.c +++ b/src/arch/riscv64/port/mmu.c @@ -46,6 +46,13 @@ #define MAKE_SATP_MODE (MMU_MODE_SV39 << MMU_MODE_BIT_SHIFT) #define GET_ADDR_FROM_SATP(satp) ((((NX_Addr)satp) << NX_PAGE_SHIFT)) +#ifdef CONFIG_NX_XHYP +/* hgatp */ +#define MAKE_HGATP_ADDR(pageTable) (((NX_Addr)pageTable) >> NX_PAGE_SHIFT) +#define MAKE_HGATP_MODE (MMU_MODE_SV39 << MMU_MODE_BIT_SHIFT) +#define GET_ADDR_FROM_HGATP(hgatp) ((((NX_Addr)hgatp) << NX_PAGE_SHIFT)) +#endif /* CONFIG_NX_XHYP */ + NX_INLINE void SFenceVMA() { NX_CASM("sfence.vma"); @@ -401,3 +408,61 @@ NX_INTERFACE struct NX_MmuOps NX_MmuOpsInterface = .vir2Phy = NX_HalVir2Phy, .flush = NX_HalFlush, }; + +/* + * NX_XHYP - Virtualization + */ +#ifdef CONFIG_NX_XHYP + +NX_INLINE void Hfence() +{ + /* hfence.vvma */ + NX_CASM(".insn r 0x73, 0x0, 0x31, x0, x0, x0\n\t" ::: "memory"); + /* hfence.gvma */ + NX_CASM(".insn r 0x73, 0x0, 0x11, x0, x0, x0\n\t" ::: "memory"); +} + +#define MMU_Stage2FlushTLB() Hfence() + +/* @temp */ +NX_PRIVATE void NX_HalStage2SetPageTable(NX_Addr addr) +{ + NX_U64 hgatp = (NX_U64)MAKE_HGATP_ADDR(addr); + hgatp |= (8ULL << 60); + WriteCSR(0x680, hgatp); + NX_LOG_I("HGATP = 0x%lx", ReadCSR(0x680)); + + MMU_Stage2FlushTLB(); +} + +NX_PRIVATE NX_Addr NX_HalStage2GetPageTable(void) +{ + NX_Addr addr = ReadCSR(0x680); + return (NX_Addr)GET_ADDR_FROM_HGATP(addr); +} + +NX_PRIVATE void NX_HalStage2Enable(void) +{ + NX_Addr hgatp = ReadCSR(0x680); + hgatp |= MAKE_HGATP_MODE; + WriteCSR(0x680, hgatp); + MMU_Stage2FlushTLB(); +} + +NX_PRIVATE void NX_HalStage2Flush(void) +{ + MMU_Stage2FlushTLB(); +} + +NX_INTERFACE struct NX_MmuOps NX_MmuOpsStage2Interface = +{ + .setPageTable = NX_HalStage2SetPageTable, + .getPageTable = NX_HalStage2GetPageTable, + .enable = NX_HalStage2Enable, + .mapPage = NX_HalMapPage, + .mapPageWithPhy = NX_HalMapPageWithPhy, + .unmapPage = NX_HalUnmapPage, + .vir2Phy = NX_HalVir2Phy, + .flush = NX_HalStage2Flush, +}; +#endif /* CONFIG_NX_XHYP */ diff --git a/src/arch/riscv64/port/vmm.c b/src/arch/riscv64/port/vmm.c new file mode 100644 index 0000000000000000000000000000000000000000..853d202dab9320bcacd3f525ede73284f3fdce2e --- /dev/null +++ b/src/arch/riscv64/port/vmm.c @@ -0,0 +1,34 @@ +/** + * Copyright (c) 2018-2023, NXOS Development Team + * SPDX-License-Identifier: Apache-2.0 + * + * Contains: HAL xhyp support & MMIO framework + * + * Change Logs: + * Date Author Notes + * 2023-09-10 Suqier Init + */ + +#include + +NX_U64 Hlvwu(NX_U64 addr) +{ + NX_U64 value; + NX_CASM(".insn r 0x73, 0x4, 0x34, %0, %1, x1\n\t" + : "=r"(value): "r"(addr) : "memory", "x1"); + return value; +} + +NX_U64 Hlvxwu(NX_U64 addr) +{ + NX_U64 value; + NX_CASM(".insn r 0x73, 0x4, 0x34, %0, %1, x3\n\t" + : "=r"(value): "r"(addr) : "memory", "x3"); + return value; +} + +void Hsvw(NX_U64 addr, NX_U64 value) +{ + NX_CASM(".insn r 0x73, 0x4, 0x35, x0, %1, %0\n\t" + : "+r"(value): "r"(addr) : "memory"); +} diff --git a/src/arch/riscv64/xhyp/Makefile b/src/arch/riscv64/xhyp/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..b10ebaec2b0f579dbbc6d1325d88fe61a9305922 --- /dev/null +++ b/src/arch/riscv64/xhyp/Makefile @@ -0,0 +1,2 @@ +SRC += *.c +SRC += *.S diff --git a/src/arch/riscv64/xhyp/jump.S b/src/arch/riscv64/xhyp/jump.S new file mode 100644 index 0000000000000000000000000000000000000000..b60f2f14e1c16e5645d5eb72332dc810d0da0b66 --- /dev/null +++ b/src/arch/riscv64/xhyp/jump.S @@ -0,0 +1,24 @@ +/** + * Copyright (c) 2018-2023, NXOS Development Team + * SPDX-License-Identifier: Apache-2.0 + * + * Contains: Xhyp support + * + * Change Logs: + * Date Author Notes + * 2023-09-15 Suqier Init + */ + +.text + +#define __ASSEMBLY__ +#include +#include +#include + +NX_FUNC(NX_JumpIntoVm) + LOAD sp, (a0) /* sp = *nextSP */ + + RESTORE_CONTEXT + sret +NX_ENDFUNC(NX_JumpIntoVm) \ No newline at end of file diff --git a/src/arch/riscv64/xhyp/xhyp_arch.c b/src/arch/riscv64/xhyp/xhyp_arch.c new file mode 100644 index 0000000000000000000000000000000000000000..044584d1b1b512539bb7757a64d0e8ec1067a91b --- /dev/null +++ b/src/arch/riscv64/xhyp/xhyp_arch.c @@ -0,0 +1,315 @@ +/** + * Copyright (c) 2018-2023, NXOS Development Team + * SPDX-License-Identifier: Apache-2.0 + * + * Contains: xhyp(nxos virtalization) helper function + * + * Change Logs: + * Date Author Notes + * 2023-08-14 Suqier Init + */ + +#include +#include +#include + +#include +#include +#include +#include + +#ifdef CONFIG_NX_XHYP +#include + +#define NX_LOG_LEVEL NX_LOG_INFO +#define NX_LOG_NAME "xhyp" +#include + +NX_IMPORT NX_IRQ_Number gVirqNo; + +/* for init */ +NX_Error VcpuArchInit(struct vcpu * vcpu) +{ + NX_ASSERT(vcpu); + + vcpu->arch = (struct vcpuArch *)NX_MemAllocEx(vcpuArch); + if (vcpu->arch == NX_NULL) + { + NX_LOG_E("Allocate memory for vcpu->arch failure."); + return -NX_ENOMEM; + } + else + { + /* init arch */ + NX_MemSet((void *)vcpu->arch, 0, sizeof(struct vcpuArch)); + + vcpu->arch->hstatus = HSTATUS_SPV | HSTATUS_SPVP | HSTATUS_VSXL_64; + vcpu->arch->hcounteren = HCOUNTEREN_TM; + vcpu->arch->vsstatus = VSSTATUS_SD | VSSTATUS_FS_DIRTY | VSSTATUS_XS_DIRTY; + vcpu->arch->hvip = 0; + } + + NX_LOG_I("vcpu arch init ok"); + return NX_EOK; +} + +/* for switch */ +void HostToGuestArchHandler(struct vcpu * vcpu) +{ + /* restore vcpu state(h mode regs) and switch into VS mode */ + NX_LOG_D("host to guest"); + NX_ASSERT(vcpu); + + /* @temp + * set register + */ + WriteCSR(0x600, vcpu->arch->hstatus); + WriteCSR(0x645, vcpu->arch->hvip); + WriteCSR(0x606, vcpu->arch->hcounteren); + WriteCSR(0x200, vcpu->arch->vsstatus); + NX_LOG_D("hstatus = 0x%lx, hvip = 0x%lx, hcounteren = 0x%lx, vsstatus = 0x%lx", + vcpu->arch->hstatus, vcpu->arch->hvip, + vcpu->arch->hcounteren, vcpu->arch->vsstatus); + + /* CSR_HIDELEG */ + NX_U64 val = 1UL << HVIP_VS_EIP; + WriteCSR(0x603, val); + + NX_LOG_D("host to guest over"); +} + +void GuestToHostArchHandler(struct vcpu * vcpu) +{ + /* save vcpu state(h mode regs) and switch back to HS mode */ + NX_LOG_D("guest to host"); + NX_ASSERT(vcpu); + + vcpu->arch->hstatus = ReadCSR(0x600); + vcpu->arch->hcounteren = ReadCSR(0x606); + vcpu->arch->vsstatus = ReadCSR(0x200); + vcpu->arch->hvip = ReadCSR(0x645); + NX_LOG_D("hstatus = 0x%lx, hvip = 0x%lx, hcounteren = 0x%lx, vsstatus = 0x%lx", + vcpu->arch->hstatus, vcpu->arch->hvip, + vcpu->arch->hcounteren, vcpu->arch->vsstatus); +} + +void VcpuToVcpuArchHandler(struct vcpu * prev, struct vcpu * next) +{ + NX_LOG_D("vcpu to vcpu"); + GuestToHostArchHandler(prev); + HostToGuestArchHandler(next); + NX_LOG_D("vcpu to vcpu over"); +} + +void GuestToGuestArchHandler(struct vcpu * prev, struct vcpu * next) +{ + NX_LOG_D("guest to guest"); + GuestToHostArchHandler(prev); + HostToGuestArchHandler(next); + NX_LOG_D("guest to guest over"); +} + +/* + * MMIO + */ +#define VUART_BASE 0x10000000 +#define VUART_SIZE 0x1000 + +#define COMPRESSED_INS(ins) (!((ins & 3) == 3)) +#define INS_OPCODE(ins) ((ins) & 0x7F) +#define LD_OPCODE (0x03) +#define SD_OPCODE (0x23) +#define INS_FUNCT3(ins) (((ins) >> 12) & 0x07) +#define INS_RS2(ins) (((ins) >> 20) & 0x1F) +#define INS_RD(ins) (((ins) >> 7) & 0x1F) + +void printEmi(const NX_EMI * emi) +{ + NX_LOG_I("=====EMI====="); + NX_LOG_I("addr : 0x%lx", emi->addr); + NX_LOG_I("reg : %d", emi->reg); + NX_LOG_I("width: %d", emi->width); + NX_LOG_I("write: %d", emi->write); + NX_LOG_I("=====Over===="); +} + +NX_Bool Is_UART_MMIO_Range(NX_Addr faultAddr) +{ + return ((faultAddr >= UART0_PHY_ADDR) && (faultAddr < UART0_PHY_ADDR + NX_PAGE_SIZE)); +} + +NX_Bool Is_PLIC_claimBasic(NX_Addr faultAddr) +{ + return ((faultAddr >= RISCV_PLIC_PADDR) && (faultAddr < RISCV_PLIC_PADDR + PLIC_MEMSZ0)); +} + +NX_Bool Is_PLIC_claimRange(NX_Addr faultAddr) +{ + return ((faultAddr >= RISCV_PLIC_PADDR + 0x200000) && (faultAddr < RISCV_PLIC_PADDR + 0x200000 + PLIC_MEMSZ1)); +} + +NX_Bool Is_PLIC_MMIO_Range(NX_Addr faultAddr) +{ + /* @temp: get from fdt later */ + return Is_PLIC_claimBasic(faultAddr) || Is_PLIC_claimRange(faultAddr); +} + +NX_Bool Is_MMIO_Range(NX_Addr faultAddr) +{ + /* @temp: get from fdt later */ + if (Is_UART_MMIO_Range(faultAddr) || Is_PLIC_MMIO_Range(faultAddr)) + return NX_True; + else + return NX_False; +} + +NX_U64 EmulateReadReg(NX_HalTrapFrame * frame, int reg) +{ + if ((reg <= 0) || (reg > 31)) + return 0; + + return *(NX_U64 *)((NX_U64)frame + reg * 8); +} + +void EmulateWriteReg(NX_HalTrapFrame * frame, int reg, NX_U64 val) +{ + if ((reg <= 0) || (reg > 31)) + return; + + *(NX_U64 *)((NX_U64)frame + reg * 8) = val; +} + +void Emulate_MMIO_Reg8(NX_EMI * emi) +{ + NX_U8 val; + + if (emi->write) + { + val = EmulateReadReg(emi->frame, emi->reg); + Write8(emi->addr, val); + } + else + { + val = Read8(emi->addr); + EmulateWriteReg(emi->frame, emi->reg, val); + } +} + +void Emulate_UART(NX_EMI * emi) +{ + Emulate_MMIO_Reg8(emi); +} + +void Emulate_MMIO_Reg32(NX_EMI * emi) +{ + NX_U32 val; + + if (emi->write) + { + val = EmulateReadReg(emi->frame, emi->reg); + Write32(emi->addr, val); + } + else + { + val = Read32(emi->addr); + EmulateWriteReg(emi->frame, emi->reg, val); + } +} + +void Emulate_PLIC_basic(NX_EMI * emi) +{ + Emulate_MMIO_Reg32(emi); +} + +void Emulate_PLIC_claim(NX_EMI * emi) +{ + NX_Addr faultAddr = emi->addr; + int reg = faultAddr & 0xf; + + switch (reg) + { + case 0: //PLIC_MTHRESHOLD + Emulate_MMIO_Reg32(emi); + break; + case 4: //PLIC_MCLAIM + { + if (emi->write) + { + gVirqNo = 0; + } + else + { + /* @temp */ + gVirqNo = 10; + EmulateWriteReg(emi->frame, emi->reg, gVirqNo); + } + } + break; + } +} + +void Emulate_PLIC(NX_EMI * emi) +{ + NX_Addr faultAddr = emi->addr; + + if (Is_PLIC_claimBasic(faultAddr)) + { + Emulate_PLIC_basic(emi); + } + else + { + Emulate_PLIC_claim(emi); + } +} + +void Emulate_MMIO_Device(NX_Addr faultAddr, NX_U64 InsValue, NX_HalTrapFrame * frame) +{ + if (INS_OPCODE(InsValue) != LD_OPCODE && INS_OPCODE(InsValue) != SD_OPCODE) + { + NX_LOG_I("instruction opcode not right"); + return; + } + + /* parse InsValue */ + NX_EMI emi = + { + .frame = frame, + .addr = faultAddr, + .reg = 0, + .width = 0, + .write = NX_False, + .signExt = NX_False, + }; + + int funct3 = INS_FUNCT3(InsValue); + switch(funct3 & 0x3) + { + case 0: + emi.width = 1; + break; + case 1: + emi.width = 2; + break; + case 2: + emi.width = 4; + break; + case 3: + emi.width = 8; + break; + } + + emi.write = (INS_OPCODE(InsValue) == SD_OPCODE); + + emi.reg = emi.write ? INS_RS2(InsValue) : INS_RD(InsValue); + emi.signExt = !(funct3 & 0x4); + + if (Is_UART_MMIO_Range(faultAddr)) + { + Emulate_UART(&emi); + } + else if (Is_PLIC_MMIO_Range(faultAddr)) + { + Emulate_PLIC(&emi); + } +} +#endif /* CONFIG_NX_XHYP */ \ No newline at end of file diff --git a/src/include/base/malloc.h b/src/include/base/malloc.h index eeaa50dd957fedadc898bebd6d5f998e9ddbbf8d..47a6eb95d030dbd0ba2aabbefebe6ded626c58d0 100644 --- a/src/include/base/malloc.h +++ b/src/include/base/malloc.h @@ -20,6 +20,4 @@ #define NX_MemFree(ptr) NX_HeapFree(ptr) #define NX_MemFreeSafety(ptr) NX_HeapFreeSatety(ptr) -#define NX_MemAllocAlign(size, align) NX_MemAlloc(size) - #endif /* __MM_ALLOC__ */ diff --git a/src/include/base/mmu.h b/src/include/base/mmu.h index 128c9d22b5c8c76f25a62e3033be64c3d8ef3c0e..dad5c4bcfd329eb0d352e269de3d3b53a2e52d8e 100644 --- a/src/include/base/mmu.h +++ b/src/include/base/mmu.h @@ -61,4 +61,16 @@ NX_INLINE void * NX_MmuGetKernelTable(void) return gKernelMmu.table; } +NX_INTERFACE NX_IMPORT struct NX_MmuOps NX_MmuOpsStage2Interface; + +#define NX_MmuStage2SetPageTable(addr) NX_MmuOpsStage2Interface.setPageTable(addr) +#define NX_MmuStage2GetPageTable() NX_MmuOpsStage2Interface.getPageTable() +#define NX_MmuStage2Enable() NX_MmuOpsStage2Interface.enable() +#define NX_MmuStage2MapPage(mmu, virAddr, size, attr) NX_MmuOpsStage2Interface.mapPage(mmu, virAddr, size, attr) +#define NX_MmuStage2MapPageWithPhy(mmu, virAddr, phyAddr, size, attr) \ + NX_MmuOpsStage2Interface.mapPageWithPhy(mmu, virAddr, phyAddr, size, attr) +#define NX_MmuStage2UnmapPage(mmu, virAddr, size, freeLeaf) NX_MmuOpsStage2Interface.unmapPage(mmu, virAddr, size, freeLeaf) +#define NX_MmuStage2Vir2Phy(mmu, virAddr) NX_MmuOpsStage2Interface.vir2Phy(mmu, virAddr) +#define NX_MmuStage2Flush() NX_MmuOpsStage2Interface.flush() + #endif /* __MM_MMU__ */ diff --git a/src/include/base/switch.h b/src/include/base/switch.h new file mode 100644 index 0000000000000000000000000000000000000000..d620fb27bad1348f4a7f337c5360bec4dbf25722 --- /dev/null +++ b/src/include/base/switch.h @@ -0,0 +1,39 @@ +/** + * Copyright (c) 2018-2023, NXOS Development Team + * SPDX-License-Identifier: Apache-2.0 + * + * Contains: xhyp vcpu thread switch + * + * Change Logs: + * Date Author Notes + * 2023-09-07 Suqier Init + */ + +#ifndef __XHYP_SWITCH_H_ +#define __XHYP_SWITCH_H_ +#ifdef CONFIG_NX_XHYP + +#include + +#include "hooks.h" + +/* Define switch processes. */ +#define HOST_TO_GUEST 1 /* From Host switch into Guest vCPU */ +#define GUEST_TO_HOST 2 /* From Guest vCPU switch out Host */ +#define VCPU_TO_VCPU 3 /* From vCPU_1 to vCPU_2 in the same Guest */ +#define GUEST_TO_GUEST 4 /* From Guest_1 to Guest_2 */ +#define HOST_TO_HOST 5 /* Thread switch in Host */ + +NX_Bool IsVcpuThread(NX_Thread * tid); +NX_U32 GetVmIdFromVcpuThread(NX_Thread * tid); +NX_Bool IsVcpuSameVm(NX_Thread * prev, NX_Thread * next); +NX_U8 ThisSwitchType(NX_Thread * prev, NX_Thread * next); + +/* Different type of switch handler. */ +void HostToGuestHandler(NX_VCPU * vcpu); +void GuestToHostHandler(NX_VCPU * vcpu); +void VcpuToVcpuHandler(NX_VCPU * prev, NX_VCPU * next); +void GuestToGuestHandler(NX_VCPU * prev, NX_VCPU * next); +#endif /* __XHYP_SWITCH_H_ */ + +#endif /* __XHYP_SWITCH_H_ */ diff --git a/src/include/base/vm.h b/src/include/base/vm.h new file mode 100644 index 0000000000000000000000000000000000000000..9daf7b6ad83475959c59d12d5c6e3ab0aeabcd14 --- /dev/null +++ b/src/include/base/vm.h @@ -0,0 +1,180 @@ +/** + * Copyright (c) 2018-2023, NXOS Development Team + * SPDX-License-Identifier: Apache-2.0 + * + * Contains: xhyp(nxos virtalization) virtual machine(VM) + * + * Change Logs: + * Date Author Notes + * 2023-08-12 Suqier Init + */ + +#ifndef __XHYP_VM_H__ +#define __XHYP_VM_H__ + +#include + +#ifdef CONFIG_NX_XHYP +#include +#include +#include +#include +#include + +#define NX_XHYP_NAME_LEN 32 +#define NX_XHYP_FILEPATH_LEN 128 + +#ifdef CONFIG_NX_XHYP_VM_NUM +#define NX_XHYP_VM_NUM CONFIG_NX_XHYP_VM_NUM +#else +#define NX_XHYP_VM_NUM 4 +#endif + +#ifdef CONFIG_NX_XHYP_VCPU_NUM +#define NX_XHYP_VCPU_NUM CONFIG_NX_XHYP_VCPU_NUM +#else +#define NX_XHYP_VCPU_NUM 1 +#endif + +#define MEM_BLOCK_SIZE (0x200000) +#define MEM_BLOCK_SHIFT (21) + +/* OS type related */ +typedef enum NX_OsType +{ + NX_OS_NXOS = 0, + NX_OS_LINUX, + NX_OS_OTHERS, + NX_OS_TYPE_NR +} NX_OsType; + +NX_PRIVATE const char *__NX_OsTypeString[] = +{ + "NXOS", + "LINUX", + "OTHERS" +}; + +NX_INLINE const char *NX_OsTypeToString(NX_OsType type) +{ + if (type < NX_OS_NXOS || type >= NX_OS_TYPE_NR) + { + return "unknown type"; + } + return __NX_OsTypeString[type]; +} + +/* vcpu related */ +typedef enum NX_VcpuState +{ + NX_VCPU_UNKNOWN = 0, + NX_VCPU_OFFLINE, + NX_VCPU_ONLINE, + NX_VCPU_SUSPEND, + NX_VCPU_NEVER_RUN, + NX_VCPU_STATE_NR, +} NX_VcpuState; + +typedef struct vcpu +{ + NX_U32 id; + NX_U32 status; + // NX_U32 affinity; + + NX_Thread * tid; + struct virtualMachine * vm; /* this vcpu belongs to. */ + + struct vcpuArch * arch; +} NX_VCPU; + +/* VM memory struct related */ +typedef struct memoryManage +{ + NX_U64 memSize; + NX_U64 memUsed; + + NX_Mmu vmMmu; + + NX_Spin lock; + + struct virtualMachine * vm; /* this mm_struct belongs to. */ +} NX_MM; + +/* VM state related */ +typedef enum NX_VmState +{ + NX_VM_UNKNOWN = 0, + NX_VM_NEVER_RUN, + NX_VM_RUNNING, + NX_VM_PAUSE, + NX_VM_STOP, + NX_VM_STATE_NR, +} NX_VmState; + +NX_PRIVATE const char *__NX_VmStateString[] = +{ + "UNKNOWN", + "NEVER RUN", + "RUNNING", + "PAUSE", + "STOP" +}; + +NX_INLINE const char *NX_VmStateToString(NX_VmState stat) +{ + if (stat < NX_VM_NEVER_RUN || stat >= NX_VM_STATE_NR) + { + return "unknown state"; + } + return __NX_VmStateString[stat]; +} + +/* VM related */ +typedef struct virtualMachine +{ + /* basic info of VM */ + NX_U32 id; + NX_VmState status; + NX_OsType osType; + + /* OS info */ + NX_Addr entryPoint; /* OS entry point */ + NX_Addr imageAddr; + NX_Size imageSize; + + /* vcpu */ + // NX_U32 vcpusAffinity[NX_XHYP_VCPU_NUM]; + NX_U32 vcpuNum; + NX_VCPU vcpus[NX_XHYP_VCPU_NUM]; + /* @temp */ + struct vcpuArch * arch; + + /* memory */ + NX_MM mm; + + /* vTimer */ + + /* others */ + char name[NX_XHYP_NAME_LEN]; +} NX_VM; + +typedef struct +{ + char name[NX_XHYP_NAME_LEN]; + NX_U32 osType; + NX_U32 vcpuNum; + NX_U32 memSize; + char filePath[NX_XHYP_FILEPATH_LEN]; +} VmConfig; + +void VcpuInit(NX_VCPU * vcpu, NX_U32 id, NX_VM * vm); + +void MmInit(NX_VM * vm); +void NX_LoadGuestOs(NX_VM * vm); +void VmInit(NX_VM * vm); +void VcpuGo(NX_VCPU * vcpu); +void VmGo(NX_VM * vm); + +#endif /* CONFIG_NX_XHYP */ + +#endif /* __XHYP_VM_H__ */ diff --git a/src/include/base/xhyp.h b/src/include/base/xhyp.h new file mode 100644 index 0000000000000000000000000000000000000000..0a32ca9e759835ae537db2401447b194718fec18 --- /dev/null +++ b/src/include/base/xhyp.h @@ -0,0 +1,51 @@ +/** + * Copyright (c) 2018-2023, NXOS Development Team + * SPDX-License-Identifier: Apache-2.0 + * + * Contains: xhyp(nxos virtalization) VM manage + * + * Change Logs: + * Date Author Notes + * 2023-08-12 Suqier Init + */ + +#ifndef __XHYP_XHYP_H__ +#define __XHYP_XHYP_H__ + +#include + +#ifdef CONFIG_NX_XHYP +#include + +#define NX_XHYP_CMD_GET_INFO (0x01) +#define NX_XHYP_CMD_LIST_VM (0x02) +#define NX_XHYP_CMD_NEW_VM (0x03) +#define NX_XHYP_CMD_RUN_VM (0x04) +#define NX_XHYP_CMD_PAUSE_VM (0x05) +#define NX_XHYP_CMD_STOP_VM (0x06) +#define NX_XHYP_CMD_DELETE_VM (0x07) + +typedef struct +{ + NX_Size bitmap; + NX_U32 totalVm; + NX_U32 currentVm; + NX_U32 nextVm; + + NX_VM vms[NX_XHYP_VM_NUM]; + + NX_Spin xhypLock; +} NX_Xhyp; +NX_IMPORT NX_Xhyp gXhypInfo; + +/* interface for PowerBox, run VM dynamicly */ +void XhypListVm(void); +void XhypNewVm(void *arg); +void XhypRunVm(void *arg); +void XhypPauseVm(void *arg); +void XhypStopVm(void *arg); +void XhypDeleteVm(void *arg); + +#endif /* CONFIG_NX_XHYP */ + +#endif /* __XHYP_XHYP_H__ */ diff --git a/src/include/nxos.h b/src/include/nxos.h index 18a547fd908ff06c0d8c1067a39bdd8a7881b2b0..752d9b39ec15a504445f2cb54668bfc523781f5a 100644 --- a/src/include/nxos.h +++ b/src/include/nxos.h @@ -71,7 +71,9 @@ #include #include #include +#include #include #include +#include #endif /* __NXOS_ALL__ */ diff --git a/src/init/main.c b/src/init/main.c index 1dd0b9f0b7868749e5636f204957b0eeea884bf0..4396010a53e996ae46ceee84e4d401efe5235ca0 100644 --- a/src/init/main.c +++ b/src/init/main.c @@ -26,6 +26,9 @@ #include #include +#include +#include + /** * see http://asciiarts.net * Text: "NXOS", Font: standard.flf @@ -66,6 +69,7 @@ NX_PRIVATE void ShowLogVersion(void) int NX_Main(NX_UArch coreId) { + NX_LOG_I("coreId = %d", coreId); NX_IRQ_Disable(); if (NX_AtomicGet(&gActivedCoreCount) == 0) { @@ -135,6 +139,7 @@ int NX_Main(NX_UArch coreId) NX_SMP_Stage2(coreId); } + /* start sched */ NX_SchedToFirstThread(); /* should never be here */ diff --git a/src/platform/qemu_riscv64/cmd.mk b/src/platform/qemu_riscv64/cmd.mk index 52af4aa66aaac95bae3c1719262765233d5ac7f1..2da7b28ee54e78e8a9071890f8b254d7c65da2d6 100644 --- a/src/platform/qemu_riscv64/cmd.mk +++ b/src/platform/qemu_riscv64/cmd.mk @@ -20,6 +20,8 @@ QEMU_WINDOW ?= n TOOL_DIR := tools RUSTSBI_DIR := $(TOOL_DIR)/SBI SBI := $(TOOL_DIR)/SBI/opensbi-qemu +GOS := $(TOOL_DIR)/gos.bin +GOS_ADDR := 0x80E00000 RM := rm # @@ -46,6 +48,9 @@ QEMU_ARGS += -kernel $(NXOS_NAME).elf QEMU_ARGS += -bios $(SBI) QEMU_ARGS += -smp $(CORES) +# for xhyp +QEMU_ARGS += -device loader,file=$(GOS),addr=$(GOS_ADDR) + ifeq ($(QEMU_WINDOW),y) QEMU_ARGS += -serial stdio else @@ -65,7 +70,9 @@ endif # Run OS in QEMU # run: + @echo $(QEMU) $(QEMU_ARGS) $(QEMU) $(QEMU_ARGS) + # $(QEMU) $(QEMU_ARGS) -S -s # # Clear target file diff --git a/src/sched/sched.c b/src/sched/sched.c index d91cdbe0a61d7372d1653b38a4443611e4042929..5316c18ca2be52257cd627c891b445c214b0e4bf 100644 --- a/src/sched/sched.c +++ b/src/sched/sched.c @@ -20,6 +20,7 @@ #include #include #include +#include NX_IMPORT NX_Atomic gActivedCoreCount; diff --git a/src/xhyp/Kconfig b/src/xhyp/Kconfig new file mode 100644 index 0000000000000000000000000000000000000000..efe9314554ae8e070ec30ac3d03bd2ac389236a2 --- /dev/null +++ b/src/xhyp/Kconfig @@ -0,0 +1,46 @@ +menu "xhyp - nxos virtualization" +config NX_XHYP + bool "Using NXOS as hypervisor" + default y + +if NX_XHYP + config NX_XHYP_VM_NUM + int "Maximum numbers of VMs that can run simultaneously" + default 4 + + config NX_XHYP_VCPU_NUM + int "Maximum numbers of vCPUs per VM" + default 1 + + config NX_XHYP_OS_CONFIG + bool "Static configure OS, not using DTB" + default y + + if NX_XHYP_OS_CONFIG + config NX_XHYP_OS_VCPU_NUM + int "OS default config: vCPU number" + default 1 + + config NX_XHYP_OS_MEM_SIZE + int "OS default config: memory size(MB)" + default 32 + + config NX_XHYP_OS_TYPE + int "OS default config: OS type info" + default 2 + + config NX_XHYP_OS_ENTRY_POINT + hex "OS default config: OS entry point" + default 0x80200000 + + config NX_XHYP_OS_IMAGE_ADDR + hex "OS default config: OS image address" + default 0x80E00000 + + config NX_XHYP_OS_IMAGE_SIZE + int "OS default config: OS image size" + default 32768 + endif +endif + +endmenu \ No newline at end of file diff --git a/src/xhyp/Makefile b/src/xhyp/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..030603e653fac1350ad98585d5e74aba43602955 --- /dev/null +++ b/src/xhyp/Makefile @@ -0,0 +1 @@ +SRC += *.c diff --git a/src/xhyp/switch.c b/src/xhyp/switch.c new file mode 100644 index 0000000000000000000000000000000000000000..49d152deb60661ec2847fb9f73f848d068677912 --- /dev/null +++ b/src/xhyp/switch.c @@ -0,0 +1,129 @@ +/** + * Copyright (c) 2018-2023, NXOS Development Team + * SPDX-License-Identifier: Apache-2.0 + * + * Contains: xhyp vcpu thread switch + * + * Change Logs: + * Date Author Notes + * 2023-09-07 Suqier Init + */ + +#include +#include +#include +#include + +#ifdef CONFIG_NX_XHYP + +#define NX_LOG_LEVEL NX_LOG_INFO +#define NX_LOG_NAME "xhyp" +#include + +NX_Bool IsVcpuThread(NX_Thread * tid) +{ + NX_VCPU * vcpu = tid->userArg; + + if (vcpu == NX_NULL) + return NX_False; + else + return (vcpu->tid == tid); +} + +NX_U32 GetVmIdFromVcpuThread(NX_Thread * tid) +{ + NX_ASSERT(IsVcpuThread(tid)); + + NX_VCPU * vcpu = tid->userArg; + return vcpu->vm->id; +} + +NX_Bool IsVcpuSameVm(NX_Thread * prev, NX_Thread * next) +{ + NX_ASSERT(IsVcpuThread(prev) && IsVcpuThread(next)); + + return (GetVmIdFromVcpuThread(prev) == GetVmIdFromVcpuThread(next)); +} + +NX_U8 ThisSwitchType(NX_Thread * prev, NX_Thread * next) +{ + NX_ASSERT(prev && next); + + NX_Bool isPrevVcpu = IsVcpuThread(prev); + NX_Bool isNextVcpu = IsVcpuThread(next); + + if (isPrevVcpu == NX_False && isNextVcpu == NX_False) + return HOST_TO_HOST; + else + { + if (isPrevVcpu && isNextVcpu) + { + if(IsVcpuSameVm(prev, next)) + return VCPU_TO_VCPU; + else + return GUEST_TO_GUEST; + } + else + { + if (isPrevVcpu) + return GUEST_TO_HOST; + else + return HOST_TO_GUEST; + } + } +} + +void HostToGuestHandler(NX_VCPU * vcpu) +{ + HostToGuestArchHandler(vcpu); +} + +void GuestToHostHandler(NX_VCPU * vcpu) +{ + GuestToHostArchHandler(vcpu); +} + +void VcpuToVcpuHandler(NX_VCPU * prev, NX_VCPU * next) +{ + VcpuToVcpuArchHandler(prev, next); +} + +void GuestToGuestHandler(NX_VCPU * prev, NX_VCPU * next) +{ + GuestToGuestArchHandler(prev, next); +} + +void NX_ContextSwitchHook(NX_Thread * prev, NX_Thread * next) +{ + /* + * According thread switch type to choose different switch handler. + */ + NX_U8 switchType = ThisSwitchType(prev, next); + if (switchType != HOST_TO_HOST) + { + NX_LOG_I("%s -> %s", prev->name, next->name); + } + + switch (switchType) + { + case HOST_TO_GUEST: + HostToGuestHandler((NX_VCPU *)next->userArg); + break; + case GUEST_TO_HOST: + GuestToHostHandler((NX_VCPU *)prev->userArg); + break; + case VCPU_TO_VCPU: + VcpuToVcpuHandler((NX_VCPU *)prev->userArg, (NX_VCPU *)next->userArg); + break; + case GUEST_TO_GUEST: + GuestToGuestHandler((NX_VCPU *)prev->userArg, (NX_VCPU *)next->userArg); + break; + case HOST_TO_HOST: + /* Do nothing. */ + break; + default: + break; + } +} + +#endif /* CONFIG_NX_XHYP */ diff --git a/src/xhyp/vm.c b/src/xhyp/vm.c new file mode 100644 index 0000000000000000000000000000000000000000..a42ade9181e3170806f7dca5103121fb91db97bd --- /dev/null +++ b/src/xhyp/vm.c @@ -0,0 +1,176 @@ +/** + * Copyright (c) 2018-2023, NXOS Development Team + * SPDX-License-Identifier: Apache-2.0 + * + * Contains: xhyp vm maintain + * + * Change Logs: + * Date Author Notes + * 2023-08-18 Suqier Init + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define NX_LOG_LEVEL NX_LOG_INFO +#define NX_LOG_NAME "xhyp" +#include + +#ifdef CONFIG_NX_XHYP + +#define XHYP_MEM_BASE 0x80000000 + +NX_PRIVATE NX_U64 + xhypVmTable[NX_XHYP_VM_NUM][4 * NX_PAGE_SIZE / sizeof(NX_U64)] NX_CALIGN(4 * NX_PAGE_SIZE); + +void VcpuInit(NX_VCPU *vcpu, NX_U32 id, NX_VM *vm) +{ + if (vcpu != NX_NULL && vm != NX_NULL) + { + vcpu->id = id; + vcpu->vm = vm; + vcpu->status = NX_VCPU_NEVER_RUN; + + char name[NX_THREAD_NAME_LEN]; + NX_MemZero(name, NX_THREAD_NAME_LEN); + NX_SNPrintf(name, NX_THREAD_NAME_LEN, "m%d_c%d", vm->id, id); + NX_LOG_D("NX_ThreadCreate: %s for new a VM", name); + vcpu->tid = NX_ThreadCreate(name, (void *)(vm->entryPoint), + NX_NULL, NX_THREAD_CREATE_SUSPEND); + if (vcpu->tid == NX_NULL) + { + NX_LOG_E("vcpu %s create failure", name); + } + else + { + vm->vcpus[id] = *vcpu; + NX_LOG_I("vcpu %s create success, tid = 0x%08x", name, vcpu->tid); + vcpu->tid->userArg = vcpu; + + VcpuArchInit(vcpu); + } + } + else + { + NX_LOG_E("vcpu pointer null"); + } +} + +void MmInit(NX_VM *vm) +{ + if (vm == NX_NULL) + { + NX_LOG_E("vm pointer null"); + } + else + { + /* memory struct init */ + NX_MM *mm = &vm->mm; + mm->vm = vm; + NX_SpinInit(&mm->lock); + + /* @temp */ + NX_LOG_I("mm->memSize = 0x%p", mm->memSize * NX_MB); + NX_MmuInit(&mm->vmMmu, (void *)xhypVmTable[vm->id], XHYP_MEM_BASE, mm->memSize * NX_MB, 0); + NX_LOG_I("vm mmu init: xhypVmTable[%d] = 0x%p", vm->id, xhypVmTable[vm->id]); + NX_LOG_D("vm mmu init: xhypVmTable[%d] = 0x%p", vm->id, mm->vmMmu.table); + + /* init stage2 memory setting */ + NX_MmuStage2Enable(); + NX_MmuStage2SetPageTable((NX_Addr)mm->vmMmu.table); + + /* memory normal memory */ + NX_MmuStage2MapPage(&mm->vmMmu, XHYP_MEM_BASE, mm->memSize * NX_MB, NX_PAGE_ATTR_USER); + NX_LOG_D("mmu stage2 map memory: start = 0x%p, size = 0x%p", XHYP_MEM_BASE, mm->memSize * NX_MB); + } +} + +void NX_LoadGuestOs(NX_VM *vm) +{ + NX_Addr vaddr = vm->entryPoint, paddr, vaddrSelf, imageAddr = vm->imageAddr; + NX_Size size = vm->imageSize, chunk; + + while (size > 0) + { + /* use mmu translate to phy addr */ + paddr = (NX_Addr)NX_MmuStage2Vir2Phy(&vm->mm.vmMmu, vaddr); + NX_ASSERT(paddr); + vaddrSelf = NX_Phy2Virt(paddr); /* translate physic addr to kernel virtual addr to access */ + + chunk = (size < NX_PAGE_SIZE) ? size : NX_PAGE_SIZE; + NX_MemCopy((void *)vaddrSelf, (void *)imageAddr, chunk); + NX_LOG_D("NX_LoadGuestOs: from 0x%lx to 0x%lx, size = 0x%lx", imageAddr, vaddrSelf, chunk); + + size -= chunk; + vaddr += chunk; + imageAddr += chunk; + } + NX_LOG_I("load guest os image ok"); +} + +void VmInit(NX_VM *vm) +{ + /* vcpu */ + for (NX_Size i = 0; i < vm->vcpuNum; i++) + { + VcpuInit(&vm->vcpus[i], i, vm); + } + + /* memory */ + NX_LOG_D("memory init"); + MmInit(vm); + + /* load OS image file */ + NX_LOG_D("load guest os"); + NX_LoadGuestOs(vm); + + /* vPIL */ + + /* more todo... */ + NX_LOG_I("init vm ok"); +} + +void VcpuGo(NX_VCPU *vcpu) +{ + NX_ASSERT(vcpu->tid); + + switch (vcpu->status) + { + case NX_VCPU_ONLINE: + NX_SchedToFirstThread(); + break; + case NX_VCPU_SUSPEND: + vcpu->status = NX_VCPU_ONLINE; + NX_ThreadUnblock(vcpu->tid); + break; + case NX_VCPU_OFFLINE: + case NX_VCPU_NEVER_RUN: + vcpu->status = NX_VCPU_ONLINE; + NX_ThreadStart(vcpu->tid); + break; + case NX_VCPU_UNKNOWN: + default: + NX_LOG_E("%dth VM: Run %dth vCPU failure\n", vcpu->vm->id, vcpu->id); + break; + } +} + +void VmGo(NX_VM *vm) +{ + NX_VCPU *vcpu = &vm->vcpus[0]; + if (vcpu) + { + VcpuGo(vcpu); + vm->status = NX_VM_RUNNING; + } +} + +#endif /* CONFIG_NX_XHYP */ diff --git a/src/xhyp/xhyp.c b/src/xhyp/xhyp.c new file mode 100644 index 0000000000000000000000000000000000000000..c94c4fa53d1f4d0c4be2d7609a2a909bcedde6e2 --- /dev/null +++ b/src/xhyp/xhyp.c @@ -0,0 +1,301 @@ +/** + * Copyright (c) 2018-2023, NXOS Development Team + * SPDX-License-Identifier: Apache-2.0 + * + * Contains: command "xhyp" implementation + * + * Change Logs: + * Date Author Notes + * 2023-08-14 Suqier Init + */ + +#include +#include +#include +#include +#include +#include + +#include + +#ifdef CONFIG_NX_XHYP +#include +#include +#include + +#define DRV_NAME "xhyp driver" +#define DRV_VERSION "0.1" +#define DEV_NAME "xhyp" + +#define NX_LOG_LEVEL NX_LOG_DBG +#define NX_LOG_NAME "xhyp" +#include + +NX_Xhyp gXhypInfo; + +/* + * Interface for PowerBox + * Run VM dynamicly + */ +NX_INLINE void XhypShowVersion(void) +{ + NX_Printf("%s - version: %s", DEV_NAME, DRV_VERSION); +} + +void XhypListVm(void) +{ + NX_Printf(" VMID STATE OS_TYPE VCPU MEM(M) NAME\r\n"); + for (NX_Size i = 0; i < NX_XHYP_VM_NUM; i++) + { + NX_VM * vm = &gXhypInfo.vms[i]; + if (gXhypInfo.bitmap & (1UL << i) && vm) + { + char *fmt; + + if (i == gXhypInfo.currentVm) + fmt = "\033[34m%8d %s %s %6d %6d %s\n\033[0m"; + else + fmt = "%8d %s %s %6d %6d %s\n"; + + NX_Printf(fmt, vm->id, + NX_VmStateToString(vm->status), + NX_OsTypeToString(vm->osType), + vm->vcpuNum, vm->mm.memSize, vm->name); + } + } +} + +void XhypNewVm(void *arg) +{ + /* parse input args */ + int configIndex = NX_StrToUL((const char *)arg, NX_NULL, 10); + NX_LOG_D("configIndex: %d for new a VM", configIndex); + if (configIndex < 0 || configIndex >= NX_OS_TYPE_NR) + { + NX_LOG_E("invalid arg: %s for new a VM", arg); + return; + } + + /* allocate VM id */ + NX_U32 vmIndex; + if (gXhypInfo.nextVm == NX_XHYP_VM_NUM) + { + NX_LOG_E("the number of VM is full"); + return; + } + else + { + vmIndex = gXhypInfo.nextVm; + gXhypInfo.totalVm = vmIndex; + gXhypInfo.bitmap |= (1UL << gXhypInfo.nextVm); + for (NX_Size i = 0; i <= NX_XHYP_VM_NUM; i++) + { + if ((gXhypInfo.bitmap & (1UL << i)) == NX_False) + { + gXhypInfo.nextVm = i; + break; + } + } + } + + /* init VM info */ + gXhypInfo.vms[vmIndex].id = vmIndex; + gXhypInfo.vms[vmIndex].status = NX_VM_NEVER_RUN; + + gXhypInfo.vms[vmIndex].vcpuNum = CONFIG_NX_XHYP_OS_VCPU_NUM; + gXhypInfo.vms[vmIndex].mm.memSize = CONFIG_NX_XHYP_OS_MEM_SIZE; + + gXhypInfo.vms[vmIndex].osType = CONFIG_NX_XHYP_OS_TYPE; + gXhypInfo.vms[vmIndex].entryPoint = CONFIG_NX_XHYP_OS_ENTRY_POINT; + gXhypInfo.vms[vmIndex].imageAddr = CONFIG_NX_XHYP_OS_IMAGE_ADDR; + gXhypInfo.vms[vmIndex].imageSize = CONFIG_NX_XHYP_OS_IMAGE_SIZE; + + NX_LOG_I("New vmid = %d, start command: xhyp -r %d", vmIndex, vmIndex); +} + +void XhypRunVm(void *arg) +{ + unsigned long configIndex = NX_StrToUL((const char *)arg, 0, 10); + NX_LOG_D("configIndex: %d for run a VM", configIndex); + if (configIndex < 0 || configIndex >= NX_XHYP_VM_NUM) + { + NX_LOG_E("invalid arg: %s for run a VM", arg); + return; + } + ClearCSR(sie, SIE_STIE); + + NX_VM * vm = &gXhypInfo.vms[configIndex]; + switch (vm->status) + { + case NX_VM_NEVER_RUN: + VmInit(vm); + NX_LOG_I("%dth VM start running", configIndex); + VmGo(vm); + break; + case NX_VM_RUNNING: + NX_LOG_I("%dth VM is running", configIndex); + break; + case NX_VM_PAUSE: + case NX_VM_STOP: + /* start schedule vcpus. */ + vm->status = NX_VM_RUNNING; + NX_LOG_I("%dth VM start", configIndex); + VmGo(vm); + break; + default: + NX_LOG_E("%dth Unknown VM state", configIndex); + break; + } +} + +void XhypPauseVm(void *arg) +{ + int configIndex = NX_StrToUL((const char *)arg, NX_NULL, 10); + NX_LOG_D("configIndex: %d for pause a VM", configIndex); + if (configIndex < 0 || configIndex >= NX_XHYP_VM_NUM) + { + NX_LOG_E("invalid arg: %s for pause a VM", arg); + return; + } +} + +void XhypStopVm(void *arg) +{ + int configIndex = NX_StrToUL((const char *)arg, NX_NULL, 10); + NX_LOG_D("configIndex: %d for stop a VM", configIndex); + if (configIndex < 0 || configIndex >= NX_XHYP_VM_NUM) + { + NX_LOG_E("invalid arg: %s for stop a VM", arg); + return; + } +} + +void XhypDeleteVm(void *arg) +{ + int configIndex = NX_StrToUL((const char *)arg, NX_NULL, 10); + NX_LOG_D("configIndex: %d for delete a VM", configIndex); + if (configIndex < 0 || configIndex >= NX_XHYP_VM_NUM) + { + NX_LOG_E("invalid arg: %s for delete a VM", arg); + return; + } +} + +NX_PRIVATE NX_Error XhypOpen(struct NX_Device *device, NX_U32 flags) +{ + return NX_EOK; +} + +NX_PRIVATE NX_Error XhypClose(struct NX_Device *device) +{ + return NX_EOK; +} + +NX_PRIVATE NX_Error XhypRead(struct NX_Device *device, void *buf, NX_Offset off, NX_Size len, NX_Size *outLen) +{ + if (outLen) + { + *outLen = len; + } + return NX_EOK; +} + +NX_PRIVATE NX_Error XhypWrite(struct NX_Device *device, void *buf, NX_Offset off, NX_Size len, NX_Size *outLen) +{ + if (outLen) + { + *outLen = len; + } + return NX_EOK; +} + +NX_PRIVATE NX_Error XhypControl(struct NX_Device *device, NX_U32 cmd, void *arg) +{ + switch (cmd) + { + case NX_XHYP_CMD_GET_INFO: + XhypShowVersion(); + break; + case NX_XHYP_CMD_LIST_VM: + XhypListVm(); + break; + case NX_XHYP_CMD_NEW_VM: + XhypNewVm(arg); + break; + case NX_XHYP_CMD_RUN_VM: + XhypRunVm(arg); + break; + case NX_XHYP_CMD_PAUSE_VM: + XhypPauseVm(arg); + break; + case NX_XHYP_CMD_STOP_VM: + XhypStopVm(arg); + break; + case NX_XHYP_CMD_DELETE_VM: + XhypDeleteVm(arg); + break; + + default: + return NX_EINVAL; + } + + return NX_EOK; +} + +NX_PRIVATE NX_DriverOps XhypDriverOps = { + .open = XhypOpen, + .close = XhypClose, + .read = XhypRead, + .write = XhypWrite, + .control = XhypControl, +}; + +NX_PRIVATE void XhypDriverInit(void) +{ + NX_Device *device; + + NX_Driver *driver = NX_DriverCreate(DRV_NAME, NX_DEVICE_TYPE_VIRT, 0, &XhypDriverOps); + if (driver == NX_NULL) + { + NX_LOG_E("create drive for %s failed!", DEV_NAME); + return; + } + + if (NX_DriverAttachDevice(driver, DEV_NAME, &device) != NX_EOK) + { + NX_LOG_E("attach device %s failed!", DEV_NAME); + NX_DriverDestroy(driver); + return; + } + + /* gXhypInfo init */ + gXhypInfo.bitmap = 0UL; + gXhypInfo.totalVm = NX_XHYP_VM_NUM; + gXhypInfo.currentVm = 0; + gXhypInfo.nextVm = 0; + + NX_MemZero(&gXhypInfo.vms, sizeof(NX_VM) * NX_XHYP_VM_NUM); + NX_SpinInit(&gXhypInfo.xhypLock); + + device->extension = &gXhypInfo; + + if (NX_DriverRegister(driver) != NX_EOK) + { + NX_LOG_E("register driver %s failed!", DRV_NAME); + NX_DriverDetachDevice(driver, DEV_NAME); + NX_DriverDestroy(driver); + return; + } + + NX_LOG_I("register driver %s succeeded!", DEV_NAME); +} + +NX_PRIVATE void XhypDriverExit(void) +{ + NX_DriverCleanup(DRV_NAME); +} + +NX_DRV_INIT(XhypDriverInit); +NX_DRV_EXIT(XhypDriverExit); + +#endif /* CONFIG_NX_XHYP */