Skip to content

Commit

Permalink
Add cpu_kvm.hpp file
Browse files Browse the repository at this point in the history
Co-authored-by: wheremyfoodat <[email protected]>
  • Loading branch information
OFFTKP and wheremyfoodat committed Nov 18, 2023
1 parent a98fcfc commit 1f97b82
Show file tree
Hide file tree
Showing 2 changed files with 162 additions and 2 deletions.
154 changes: 154 additions & 0 deletions include/cpu_kvm.hpp
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, &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
10 changes: 8 additions & 2 deletions include/memory.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,14 @@
namespace PhysicalAddrs {
enum : u32 {
VRAM = 0x18000000,
VRAMEnd = VRAM + 0x005FFFFF,
VRAMSize = 0x00600000,
VRAMEnd = VRAM + VRAMSize - 1,
FCRAM = 0x20000000,
FCRAMEnd = FCRAM + 0x07FFFFFF
FCRAMSize = 0x08000000,
FCRAMEnd = FCRAM + FCRAMSize - 1,
DSPMem = 0x1FF00000,
DSPMemSize = 0x00080000,
DSPMemEnd = DSPMem + DSPMemSize - 1
};
}

Expand Down Expand Up @@ -278,6 +283,7 @@ class Memory {
u8* getDSPDataMem() { return &dspRam[DSP_DATA_MEMORY_OFFSET]; }
u8* getDSPCodeMem() { return &dspRam[DSP_CODE_MEMORY_OFFSET]; }
u32 getUsedUserMem() { return usedUserMemory; }
u8* getVRAM() { return vram; }

void setVRAM(u8* pointer) { vram = pointer; }
bool allocateMainThreadStack(u32 size);
Expand Down

0 comments on commit 1f97b82

Please sign in to comment.