-
-
Notifications
You must be signed in to change notification settings - Fork 67
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Co-authored-by: wheremyfoodat <[email protected]>
- Loading branch information
1 parent
a98fcfc
commit 1f97b82
Showing
2 changed files
with
162 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,154 @@ | ||
#pragma once | ||
|
||
#include <fcntl.h> | ||
#include <linux/kvm.h> | ||
#include <sys/ioctl.h> | ||
#include <sys/types.h> | ||
|
||
#include "helpers.hpp" | ||
#include "kernel.hpp" | ||
#include "memory.hpp" | ||
|
||
#define AARCH64_CORE_REG(x) (KVM_REG_ARM64 | KVM_REG_SIZE_U64 | KVM_REG_ARM_CORE | KVM_REG_ARM_CORE_REG(x)) | ||
|
||
struct Environment { | ||
Environment(Memory& mem, Kernel& kernel) : mem(mem), kernel(kernel) { | ||
u32 currentMemorySlot = 0; | ||
|
||
kvmDescriptor = open("/dev/kvm", O_RDWR); | ||
if (kvmDescriptor < 0) { | ||
Helpers::panic("Failed to open /dev/kvm"); | ||
} | ||
|
||
vmDescriptor = ioctl(kvmDescriptor, KVM_CREATE_VM, 0); | ||
if (vmDescriptor < 0) { | ||
Helpers::panic("Failed to create KVM VM"); | ||
} | ||
|
||
if (ioctl(vmDescriptor, KVM_CHECK_EXTENSION, KVM_CAP_ARM_EL1_32BIT) <= 0) { | ||
Helpers::panic("CPU doesn't support EL1 32-bit mode, KVM won't work on this CPU"); | ||
} | ||
|
||
kvm_userspace_memory_region vramRegion = { | ||
.slot = currentMemorySlot++, | ||
.flags = 0, | ||
.guest_phys_addr = PhysicalAddrs::VRAM, | ||
.memory_size = PhysicalAddrs::VRAMSize, | ||
.userspace_addr = (uint64_t)mem.getVRAM()}; | ||
if (ioctl(vmDescriptor, KVM_SET_USER_MEMORY_REGION, &vramRegion) < 0) { | ||
Helpers::panic("Failed to set VRAM memory region"); | ||
} | ||
|
||
kvm_userspace_memory_region dspRegion = { | ||
.slot = currentMemorySlot++, | ||
.flags = 0, | ||
.guest_phys_addr = PhysicalAddrs::DSPMem, | ||
.memory_size = PhysicalAddrs::DSPMemSize, | ||
.userspace_addr = (uint64_t)mem.getDSPMem()}; | ||
if (ioctl(vmDescriptor, KVM_SET_USER_MEMORY_REGION, &dspRegion) < 0) { | ||
Helpers::panic("Failed to set DSP memory region"); | ||
} | ||
|
||
kvm_userspace_memory_region fcramRegion = { | ||
.slot = currentMemorySlot++, | ||
.flags = 0, | ||
.guest_phys_addr = PhysicalAddrs::FCRAM, | ||
.memory_size = PhysicalAddrs::FCRAMSize * 2, | ||
.userspace_addr = (uint64_t)mem.getFCRAM()}; | ||
if (ioctl(vmDescriptor, KVM_SET_USER_MEMORY_REGION, &fcramRegion) < 0) { | ||
Helpers::panic("Failed to set FCRAM memory region"); | ||
} | ||
|
||
cpuDescriptor = ioctl(vmDescriptor, KVM_CREATE_VCPU, 0); | ||
if (cpuDescriptor < 0) { | ||
Helpers::panic("Failed to create VCPU"); | ||
} | ||
|
||
int mmapSize = ioctl(kvmDescriptor, KVM_GET_VCPU_MMAP_SIZE, 0); | ||
if (mmapSize < 0) { | ||
Helpers::panic("Failed to get KVM shared memory size"); | ||
} | ||
|
||
runInfo = (kvm_run*)mmap(nullptr, mmapSize, PROT_READ | PROT_WRITE, MAP_SHARED, cpuDescriptor, 0); | ||
if (runInfo == MAP_FAILED) { | ||
Helpers::panic("Failed to map KVM shared memory"); | ||
} | ||
|
||
kvm_vcpu_init initParams; | ||
if (ioctl(vmDescriptor, KVM_ARM_PREFERRED_TARGET, &initParams) < 0) { | ||
Helpers::panic("Failed to fetch initialization parameters for vCPU"); | ||
} | ||
initParams.features[0] |= 1 << KVM_ARM_VCPU_EL1_32BIT; | ||
initParams.features[0] |= 1 << KVM_ARM_VCPU_PSCI_0_2; | ||
|
||
if (ioctl(cpuDescriptor, KVM_ARM_VCPU_INIT, initParams) < 0) { | ||
Helpers::panic("Failed to initialize vCPU"); | ||
} | ||
|
||
kvm_reg_list tempRegList; | ||
tempRegList.n = 0; | ||
ioctl(cpuDescriptor, KVM_GET_REG_LIST, &tempRegList); | ||
|
||
regList = (kvm_reg_list*)malloc(sizeof(kvm_reg_list) + tempRegList.n * sizeof(u64)); | ||
regList->n = tempRegList.n; | ||
if (ioctl(cpuDescriptor, KVM_GET_REG_LIST, regList) < 0) { | ||
Helpers::panic("Failed to get register list"); | ||
} | ||
} | ||
|
||
void setPC(u32 pc) { | ||
u64 val = (u64)pc; | ||
kvm_one_reg reg; | ||
|
||
reg.id = AARCH64_CORE_REG(regs.pc); | ||
reg.addr = (u64)&val; | ||
|
||
if (ioctl(cpuDescriptor, KVM_SET_ONE_REG, ®) < 0) [[unlikely]] { | ||
printf("KVM::VirtualCPU::SetPC failed\n"); | ||
} | ||
} | ||
|
||
void run() { | ||
if (ioctl(cpuDescriptor, KVM_RUN, 0) < 0) { | ||
Helpers::panic("Failed to run vCPU"); | ||
} | ||
} | ||
|
||
Memory& mem; | ||
Kernel& kernel; | ||
kvm_run* runInfo = nullptr; | ||
kvm_reg_list* regList = nullptr; | ||
int kvmDescriptor = -1; | ||
int vmDescriptor = -1; | ||
int cpuDescriptor = -1; | ||
}; | ||
|
||
class CPU { | ||
Environment env; | ||
Memory& mem; | ||
|
||
public: | ||
CPU(Memory& mem, Kernel& kernel); | ||
void reset(); | ||
|
||
void setReg(int index, u32 value); | ||
u32 getReg(int index); | ||
|
||
std::span<u32, 16> regs(); | ||
std::span<u32, 32> fprs(); | ||
|
||
void setCPSR(u32 value); | ||
u32 getCPSR(); | ||
void setFPSCR(u32 value); | ||
u32 getFPSCR(); | ||
void setTLSBase(u32 value); | ||
|
||
u64 getTicks(); | ||
u64& getTicksRef(); | ||
|
||
void clearCache(); | ||
|
||
void runFrame(); | ||
}; | ||
|
||
#undef AARCH64_CORE_REG |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters