Some changes

This commit is contained in:
Ryan Houdek committed 2019-09-07 19:23:03 -07:00
1 parent d68f54542d
commit 5efe93fac9
5 files changed
+214 -101

No files matched your search

+59 -52
View File
@@ -26,7 +26,6 @@ ELFContainer::ELFContainer(std::string const &Filename) {
memcpy(&Header, reinterpret_cast<Elf64_Ehdr *>(&RawFile.at(0)),
sizeof(Elf64_Ehdr));
LogMan::Throw::A(Header.e_type == ET_EXEC, "ELF wasn't EXEC");
LogMan::Throw::A(Header.e_phentsize == 56, "PH Entry size wasn't 56");
LogMan::Throw::A(Header.e_shentsize == 64, "PH Entry size wasn't 64");
@@ -39,11 +38,11 @@ ELFContainer::ELFContainer(std::string const &Filename) {
reinterpret_cast<Elf64_Phdr *>(&RawFile.at(Header.e_phoff));
for (uint32_t i = 0; i < Header.e_shnum; ++i) {
memcpy(&SectionHeaders.at(i), &RawShdrs[i], Header.e_shentsize);
SectionHeaders[i] = &RawShdrs[i];
}
for (uint32_t i = 0; i < Header.e_phnum; ++i) {
memcpy(&ProgramHeaders.at(i), &RawPhdrs[i], Header.e_phentsize);
ProgramHeaders[i] = &RawPhdrs[i];
}
CalculateMemoryLayouts();
@@ -54,10 +53,11 @@ ELFContainer::ELFContainer(std::string const &Filename) {
//PrintSectionHeaders();
//PrintProgramHeaders();
//PrintSymbolTable();
LogMan::Throw::A(IsStatic, "Can only handle static programs");
}
ELFContainer::~ELFContainer() {
SymbolMapByAddressRange.clear();
SymbolMapByAddress.clear();
SymbolMap.clear();
Symbols.clear();
@@ -68,14 +68,14 @@ ELFContainer::~ELFContainer() {
void ELFContainer::WriteLoadableSections(MemoryWriter Writer) {
for (uint32_t i = 0; i < ProgramHeaders.size(); ++i) {
Elf64_Phdr const &hdr = ProgramHeaders.at(i);
if (hdr.p_type != PT_LOAD)
Elf64_Phdr const *hdr = ProgramHeaders.at(i);
if (hdr->p_type != PT_LOAD)
continue;
Writer(&RawFile.at(hdr.p_offset), hdr.p_paddr, hdr.p_filesz);
Writer(&RawFile.at(hdr->p_offset), hdr->p_paddr, hdr->p_filesz);
}
}
ELFSymbol const *ELFContainer::GetSymbol(std::string const &Name) {
ELFSymbol const *ELFContainer::GetSymbol(char const *Name) {
auto Sym = SymbolMap.find(Name);
if (Sym == SymbolMap.end())
return nullptr;
@@ -88,9 +88,15 @@ ELFSymbol const *ELFContainer::GetSymbol(uint64_t Address) {
return Sym->second;
}
ELFSymbol const *ELFContainer::GetSymbolInRange(RangeType Address) {
auto Sym = SymbolMapByAddress.lower_bound(Address.first);
auto Sym = SymbolMapByAddress.upper_bound(Address.first);
if (Sym != SymbolMapByAddress.begin())
--Sym;
if (Sym == SymbolMapByAddress.end())
return nullptr;
if ((Sym->second->Address + Sym->second->Size) < Address.first)
return nullptr;
return Sym->second;
}
@@ -99,9 +105,13 @@ void ELFContainer::CalculateMemoryLayouts() {
uint64_t MaxPhysAddr = 0;
uint64_t PhysMemSize = 0;
for (uint32_t i = 0; i < ProgramHeaders.size(); ++i) {
Elf64_Phdr const &hdr = ProgramHeaders.at(i);
MinPhysAddr = std::min(MinPhysAddr, hdr.p_paddr);
MaxPhysAddr = std::max(MaxPhysAddr, hdr.p_paddr + hdr.p_memsz);
Elf64_Phdr const *hdr = ProgramHeaders.at(i);
MinPhysAddr = std::min(MinPhysAddr, hdr->p_paddr);
MaxPhysAddr = std::max(MaxPhysAddr, hdr->p_paddr + hdr->p_memsz);
if (hdr->p_type == PT_INTERP) {
IsStatic = false;
}
}
PhysMemSize = MaxPhysAddr - MinPhysAddr;
@@ -120,7 +130,7 @@ void ELFContainer::CalculateSymbols() {
Elf64_Shdr const *StringTableHeader{nullptr};
char const *StrTab{nullptr};
for (uint32_t i = 0; i < SectionHeaders.size(); ++i) {
Elf64_Shdr const *hdr = &SectionHeaders.at(i);
Elf64_Shdr const *hdr = SectionHeaders.at(i);
if (hdr->sh_type == SHT_SYMTAB) {
SymTabHeader = hdr;
break;
@@ -136,7 +146,7 @@ void ELFContainer::CalculateSymbols() {
LogMan::Throw::A(SymTabHeader->sh_entsize == sizeof(Elf64_Sym),
"Entry size doesn't match symbol entry");
StringTableHeader = &SectionHeaders.at(SymTabHeader->sh_link);
StringTableHeader = SectionHeaders.at(SymTabHeader->sh_link);
StrTab = &RawFile.at(StringTableHeader->sh_offset);
uint64_t NumSymbols = SymTabHeader->sh_size / SymTabHeader->sh_entsize;
@@ -146,19 +156,16 @@ void ELFContainer::CalculateSymbols() {
Elf64_Sym const *Symbol =
reinterpret_cast<Elf64_Sym const *>(&RawFile.at(offset));
if (ELF64_ST_VISIBILITY(Symbol->st_other) != STV_HIDDEN) {
ELFSymbol DefinedSymbol{};
DefinedSymbol.FileOffset = offset;
DefinedSymbol.Address = Symbol->st_value;
DefinedSymbol.Size = Symbol->st_size;
DefinedSymbol.Type = ELF64_ST_TYPE(Symbol->st_info);
DefinedSymbol.Bind = ELF64_ST_BIND(Symbol->st_info);
DefinedSymbol.Name = &StrTab[Symbol->st_name];
ELFSymbol *DefinedSymbol = &Symbols.at(i);
DefinedSymbol->FileOffset = offset;
DefinedSymbol->Address = Symbol->st_value;
DefinedSymbol->Size = Symbol->st_size;
DefinedSymbol->Type = ELF64_ST_TYPE(Symbol->st_info);
DefinedSymbol->Bind = ELF64_ST_BIND(Symbol->st_info);
DefinedSymbol->Name = &StrTab[Symbol->st_name];
Symbols.emplace_back(DefinedSymbol);
auto Sym = &Symbols.back();
SymbolMap[DefinedSymbol.Name] = Sym;
SymbolMapByAddress[DefinedSymbol.Address] = Sym;
SymbolMapByAddressRange[std::make_pair(DefinedSymbol.Address, DefinedSymbol.Address + Symbol->st_size)] = Sym;
SymbolMap[DefinedSymbol->Name] = DefinedSymbol;
SymbolMapByAddress[DefinedSymbol->Address] = DefinedSymbol;
}
}
}
@@ -182,39 +189,39 @@ void ELFContainer::PrintHeader() const {
void ELFContainer::PrintSectionHeaders() const {
LogMan::Throw::A(Header.e_shstrndx < SectionHeaders.size(),
"String index section is wrong index!");
Elf64_Shdr const &StrHeader = SectionHeaders.at(Header.e_shstrndx);
char const *SHStrings = &RawFile.at(StrHeader.sh_offset);
Elf64_Shdr const *StrHeader = SectionHeaders.at(Header.e_shstrndx);
char const *SHStrings = &RawFile.at(StrHeader->sh_offset);
for (uint32_t i = 0; i < SectionHeaders.size(); ++i) {
Elf64_Shdr const &hdr = SectionHeaders.at(i);
Elf64_Shdr const *hdr = SectionHeaders.at(i);
LogMan::Msg::I("Index: %d", i);
LogMan::Msg::I("Name: %s", &SHStrings[hdr.sh_name]);
LogMan::Msg::I("Type: %d", hdr.sh_type);
LogMan::Msg::I("Flags: %d", hdr.sh_flags);
LogMan::Msg::I("Addr: 0x%lx", hdr.sh_addr);
LogMan::Msg::I("Offset: 0x%lx", hdr.sh_offset);
LogMan::Msg::I("Size: %d", hdr.sh_size);
LogMan::Msg::I("Link: %d", hdr.sh_link);
LogMan::Msg::I("Info: %d", hdr.sh_info);
LogMan::Msg::I("AddrAlign: %d", hdr.sh_addralign);
LogMan::Msg::I("Entry Size: %d", hdr.sh_entsize);
LogMan::Msg::I("Name: %s", &SHStrings[hdr->sh_name]);
LogMan::Msg::I("Type: %d", hdr->sh_type);
LogMan::Msg::I("Flags: %d", hdr->sh_flags);
LogMan::Msg::I("Addr: 0x%lx", hdr->sh_addr);
LogMan::Msg::I("Offset: 0x%lx", hdr->sh_offset);
LogMan::Msg::I("Size: %d", hdr->sh_size);
LogMan::Msg::I("Link: %d", hdr->sh_link);
LogMan::Msg::I("Info: %d", hdr->sh_info);
LogMan::Msg::I("AddrAlign: %d", hdr->sh_addralign);
LogMan::Msg::I("Entry Size: %d", hdr->sh_entsize);
}
}
void ELFContainer::PrintProgramHeaders() const {
LogMan::Throw::A(Header.e_shstrndx < SectionHeaders.size(),
"String index section is wrong index!");
Elf64_Shdr const &StrHeader = SectionHeaders.at(Header.e_shstrndx);
char const *SHStrings = &RawFile.at(StrHeader.sh_offset);
Elf64_Shdr const *StrHeader = SectionHeaders.at(Header.e_shstrndx);
char const *SHStrings = &RawFile.at(StrHeader->sh_offset);
for (uint32_t i = 0; i < ProgramHeaders.size(); ++i) {
Elf64_Phdr const &hdr = ProgramHeaders.at(i);
LogMan::Msg::I("Type: %d", hdr.p_type);
LogMan::Msg::I("Flags: %d", hdr.p_flags);
LogMan::Msg::I("Offset: %d", hdr.p_offset);
LogMan::Msg::I("VAddr: 0x%lx", hdr.p_vaddr);
LogMan::Msg::I("PAddr: 0x%lx", hdr.p_paddr);
LogMan::Msg::I("FSize: %d", hdr.p_filesz);
LogMan::Msg::I("MemSize: %d", hdr.p_memsz);
LogMan::Msg::I("Align: %d", hdr.p_align);
Elf64_Phdr const *hdr = ProgramHeaders.at(i);
LogMan::Msg::I("Type: %d", hdr->p_type);
LogMan::Msg::I("Flags: %d", hdr->p_flags);
LogMan::Msg::I("Offset: %d", hdr->p_offset);
LogMan::Msg::I("VAddr: 0x%lx", hdr->p_vaddr);
LogMan::Msg::I("PAddr: 0x%lx", hdr->p_paddr);
LogMan::Msg::I("FSize: %d", hdr->p_filesz);
LogMan::Msg::I("MemSize: %d", hdr->p_memsz);
LogMan::Msg::I("Align: %d", hdr->p_align);
}
}
@@ -224,7 +231,7 @@ void ELFContainer::PrintSymbolTable() const {
Elf64_Shdr const *StringTableHeader{nullptr};
char const *StrTab{nullptr};
for (uint32_t i = 0; i < SectionHeaders.size(); ++i) {
Elf64_Shdr const *hdr = &SectionHeaders.at(i);
Elf64_Shdr const *hdr = SectionHeaders.at(i);
if (hdr->sh_type == SHT_SYMTAB) {
SymTabHeader = hdr;
break;
@@ -240,7 +247,7 @@ void ELFContainer::PrintSymbolTable() const {
LogMan::Throw::A(SymTabHeader->sh_entsize == sizeof(Elf64_Sym),
"Entry size doesn't match symbol entry");
StringTableHeader = &SectionHeaders.at(SymTabHeader->sh_link);
StringTableHeader = SectionHeaders.at(SymTabHeader->sh_link);
StrTab = &RawFile.at(StringTableHeader->sh_offset);
uint64_t NumSymbols = SymTabHeader->sh_size / SymTabHeader->sh_entsize;
+6 -13
View File
@@ -15,7 +15,7 @@ struct ELFSymbol {
uint64_t Size;
uint8_t Type;
uint8_t Bind;
std::string Name;
char const *Name;
};
class ELFContainer {
@@ -36,7 +36,7 @@ public:
using MemoryWriter = std::function<void(void *, uint64_t, uint64_t)>;
void WriteLoadableSections(MemoryWriter Writer);
ELFSymbol const *GetSymbol(std::string const &Name);
ELFSymbol const *GetSymbol(char const *Name);
ELFSymbol const *GetSymbol(uint64_t Address);
using RangeType = std::pair<uint64_t, uint64_t>;
@@ -54,23 +54,16 @@ private:
std::vector<char> RawFile;
Elf64_Ehdr Header;
std::vector<Elf64_Shdr> SectionHeaders;
std::vector<Elf64_Phdr> ProgramHeaders;
std::vector<Elf64_Shdr*> SectionHeaders;
std::vector<Elf64_Phdr*> ProgramHeaders;
std::vector<ELFSymbol> Symbols;
std::unordered_map<std::string, ELFSymbol *> SymbolMap;
std::unordered_map<char const*, ELFSymbol *> SymbolMap;
std::map<uint64_t, ELFSymbol *> SymbolMapByAddress;
struct RangeCompare {
bool operator()(const RangeType& a, const RangeType& b) const {
return a.first == b.first ||
(a.first <= b.first && a.second >= b.second);
}
};
std::map<RangeType, ELFSymbol *, RangeCompare> SymbolMapByAddressRange;
uint64_t MinPhysicalMemoryLocation{0};
uint64_t MaxPhysicalMemoryLocation{0};
uint64_t PhysicalMemorySize{0};
bool IsStatic{true};
};
} // namespace ELFLoader
+6 -8
View File
@@ -10,10 +10,9 @@ void InstallHandler(ThrowHandler Handler) { Handlers.emplace_back(Handler); }
[[noreturn]] void M(const char *fmt, va_list args) {
char Buffer[1024];
vsprintf(Buffer, fmt, args);
std::string Message(Buffer);
for (auto Handler : Handlers) {
Handler(Message);
vsnprintf(Buffer, 1024, fmt, args);
for (auto &Handler : Handlers) {
Handler(Buffer);
}
__builtin_trap();
@@ -26,10 +25,9 @@ void InstallHandler(MsgHandler Handler) { Handlers.emplace_back(Handler); }
void M(DebugLevels Level, const char *fmt, va_list args) {
char Buffer[1024];
vsprintf(Buffer, fmt, args);
std::string Message(Buffer);
for (auto Handler : Handlers) {
Handler(Level, Message);
vsnprintf(Buffer, 1024, fmt, args);
for (auto &Handler : Handlers) {
Handler(Level, Buffer);
}
}
+2 -3
View File
@@ -17,7 +17,7 @@ enum DebugLevels {
constexpr DebugLevels MSG_LEVEL = INFO;
namespace Throw {
using ThrowHandler = std::function<void(std::string const &Message)>;
using ThrowHandler = void(*)(char const *Message);
void InstallHandler(ThrowHandler Handler);
[[noreturn]] void M(const char *fmt, va_list args);
@@ -38,8 +38,7 @@ static inline void A(bool Value, const char *fmt, ...) {
} // namespace Throw
namespace Msg {
using MsgHandler =
std::function<void(DebugLevels Level, std::string const &Message)>;
using MsgHandler = void(*)(DebugLevels Level, char const *Message);
void InstallHandler(MsgHandler Handler);
void M(DebugLevels Level, const char *fmt, va_list args);
+141 -25
View File
@@ -25,6 +25,9 @@ public:
void *MapRegionFlags(size_t Offset, size_t Size, uint32_t flags, bool Fixed);
void *MapRegion(size_t Offset, size_t Size, bool Fixed);
void *MapRegionMirror(size_t BasePtr, size_t Offset, size_t Size, uint32_t flags, bool Fixed);
void *FakeMapRegion(size_t Offset);
private:
int SHMfd;
size_t SHMSize;
@@ -35,6 +38,7 @@ void *Memmap::MapRegion(size_t Offset, size_t Size, bool Fixed) {
}
void *Memmap::MapRegionFlags(size_t Offset, size_t Size, uint32_t flags, bool Fixed) {
return mmap(0, Size, flags, MAP_ANONYMOUS | MAP_SHARED, -1, 0);
uintptr_t PtrOffset = reinterpret_cast<uintptr_t>(Base) + Offset;
void *Ptr = mmap(reinterpret_cast<void*>(PtrOffset), Size, flags,
MAP_SHARED | (Fixed ? MAP_FIXED : 0), SHMfd, Offset);
@@ -43,10 +47,30 @@ void *Memmap::MapRegionFlags(size_t Offset, size_t Size, uint32_t flags, bool Fi
LogMan::Msg::A("Failed to map memory region [0x%lx, 0x%lx) - %d", Offset, Size, Fixed);
return nullptr;
}
LogMan::Msg::D("Mapped [0x%0lx, 0x%0lx) to 0x%0lx on host", Offset, Offset + Size, Ptr);
return Ptr;
}
void *Memmap::MapRegionMirror(size_t BasePtr, size_t Offset, size_t Size, uint32_t flags, bool Fixed) {
uintptr_t PtrOffset = reinterpret_cast<uintptr_t>(Base) + BasePtr;
void *Ptr = mmap(reinterpret_cast<void*>(PtrOffset), Size, flags,
MAP_SHARED | (Fixed ? MAP_FIXED : 0), SHMfd, Offset);
if (Ptr == MAP_FAILED) {
LogMan::Msg::A("Failed to map memory region [0x%lx, 0x%lx) - %d", Offset, Size, Fixed);
return nullptr;
}
LogMan::Msg::D("Mapped [0x%0lx, 0x%0lx) to 0x%0lx on host", Offset, Offset + Size, Ptr);
return Ptr;
}
void *Memmap::FakeMapRegion(size_t Offset) {
uintptr_t PtrOffset = reinterpret_cast<uintptr_t>(Base) + Offset;
return reinterpret_cast<void*>(PtrOffset);
}
bool Memmap::AllocateSHMRegion(size_t Size) {
const std::string SHMName = "VM" + std::to_string(getpid());
SHMfd = shm_open(SHMName.c_str(), O_RDWR | O_CREAT | O_EXCL, 0600);
@@ -202,6 +226,7 @@ namespace SU::VM {
int VM_FD{-1};
int VCPU_FD{-1};
constexpr static uint64_t VirtualBase = 0x0000'0001'0000'0000;
// This is the size of the user's memory region
uint64_t PhysicalUserMemorySize;
@@ -224,8 +249,12 @@ namespace SU::VM {
MemoryRegion APICRegion {
.RegionSize = 4096,
};
MemoryRegion LongQuirkRegion {
.RegionSize = 4096,
};
bool SetupCPUInLongMode();
bool SetupMemory();
bool HandleKVMLongModeQuirk();
Memmap Mapper;
};
@@ -251,6 +280,7 @@ namespace SU::VM {
// [IDTRegion, IDTRegion + Size)
// [GDTRegion, GDTRegion + Size)
// [APICRegion, APICRegion + Size)
// [LongQuirkRegion, LongQuirkRegion + Size)
// [PML4, PML4 + Size)
//
// ============================
@@ -258,7 +288,6 @@ namespace SU::VM {
// ============================
// Virtual memory map directly mirrors the physical mapping
uint64_t VirtualBase = 0x0000'00F0'0000'0000;
uint64_t PhysicalMemoryBase = 0;
// Calculate the amount of physical memory backing we need
PhysicalMemorySize = PhysicalUserMemorySize;
@@ -275,6 +304,10 @@ namespace SU::VM {
APICRegion.VirtualBase = VirtualBase + APICRegion.PhysicalBase; // Mapped to the same place
PhysicalMemorySize += APICRegion.RegionSize;
LongQuirkRegion.PhysicalBase = PhysicalMemorySize;
LongQuirkRegion.VirtualBase = VirtualBase + LongQuirkRegion.PhysicalBase; // Mapped to the same place
PhysicalMemorySize += LongQuirkRegion.RegionSize;
// Physical and virtual map directly atm
PML4.SetPhysicalAddress(PhysicalMemorySize);
PML4.SetVirtualAddress(VirtualBase + PhysicalMemorySize);
@@ -284,7 +317,7 @@ namespace SU::VM {
// Align up just to make sure we are page aligned
PhysicalMemorySize = AlignUp(PhysicalMemorySize, 4096);
Mapper.AllocateSHMRegion(1ULL << 36);
Mapper.AllocateSHMRegion(1ULL << 37);
// Physical memory is just [0, PhysicalMemorySize)
// Just map physical zero to virtual zero
@@ -560,18 +593,46 @@ namespace SU::VM {
return false;
}
uint64_t *APICRegisters = (uint64_t*)APICRegion.MappedLocation;
for (unsigned i = 0; i < 0x54; ++i) {
APICRegisters[i] = ~0ULL;
}
}
// Set up our memory region for working around a KVM quirk
{
LongQuirkRegion.MappedLocation = Mapper.MapRegion(LongQuirkRegion.PhysicalBase, LongQuirkRegion.RegionSize, true);
LogMan::Throw::A(LongQuirkRegion.MappedLocation != (void*)-1ULL, "Couldn't Allocate");
// Map this memory to the guest VM
kvm_userspace_memory_region Region = {
.slot = MemorySlot++,
.flags = 0,
.guest_phys_addr = LongQuirkRegion.PhysicalBase,
.memory_size = LongQuirkRegion.RegionSize,
.userspace_addr = (uint64_t)LongQuirkRegion.MappedLocation,
};
if (ioctl(VM_FD, KVM_SET_USER_MEMORY_REGION, &Region) == -1) {
printf("Couldn't set guestPD region\n");
return false;
}
uint8_t *LongQuirkMemory = (uint8_t*)LongQuirkRegion.MappedLocation;
uint8_t Code[] = {
0xEB,
0x00, // JMP +0
0xF4,
0xF4,
0xF4, // HLT
};
memcpy(LongQuirkMemory, Code, sizeof(Code));
}
return true;
}
bool KVMInstance::SetupCPUInLongMode() {
kvm_sregs SpecialRegisters = {
.cs = {
.base = 0, // Ignored in 64bit mode
@@ -599,14 +660,22 @@ namespace SU::VM {
},
.cr0 = (1U << 0) | // Protected Mode enable. Required for 64bit mode
// (1U << 1) | // Monitor coprocessor
(0U << 2) | // EM bit. 0 means State x87 FPU is present
(0U << 3) | // TS bit. If set causes a device not available exception
(1U << 31) | // (PG) Enable paging bit. Required for 64bit mode
0,
.cr3 = PML4.GetPhysicalAddress(), // PDBR in PAE mode. Required for 64bit mode
.cr3 = PML4.GetPhysicalAddress() | // PDBR in PAE mode. Required for 64bit mode
// (1U << 4) | // Page cache disable
0,
.cr4 = (1U << 5) | // PAE. Required for 64bit mode
// (1U << 0) | // (VME) VM86 extensions
// (1U << 1) | // (PVI) Virtual interrupt flags
// (1U << 3) | // (DE) Debug extensions
// (1U << 6) | // (MCE) Machine check enable
// (1U << 7) | // (PGE) Global page enable
(1U << 9) | // OSFXSR. Required to enable SSE
// (1U << 18) | // XXX: OSXSave. Required to enable AVX. Requires setting the guest CPUID to say it supports xsave
// (1U << 18) | // XXX: OSXSave. Required to enable AVX. Requires setting the guest CPUID to say it supports xsave
0,
.efer = (1U << 10) | // (LMA) Long Mode Active.
(1U << 8) | // (LME) Long Mode Enable
@@ -620,10 +689,10 @@ namespace SU::VM {
.limit = (uint16_t)IDTRegion.RegionSize,
},
.apic_base = (1 << 11) | // (AE) APIC Enable
// (APICRegion.PhysicalBase >> 12 << 32), // ABA, APIC Base Address. ABA is zext by 12 bits to form a 52bit physical address
// (APICRegion.PhysicalBase >> 12 << 32), // ABA, APIC Base Address. ABA is zext by 12 bits to form a 52bit physical address
0,
// Do we need the LDT(Local Descriptor Table) and TR (Task Register)?
.tr = {
.tr = {
.base = 0,
.limit = 0,
},
@@ -632,14 +701,16 @@ namespace SU::VM {
.base = 0,
.limit = 0,
},
};
};
kvm_regs Registers = {
.rip = ~0ULL,
.rsp = 0xFF0,
.rflags = 0x2 | // 0x2 is the default state of rflags
(1 << 9) | // By default enable hardware interrupts
(1 << 19), // By default enable virtual hardware interrupts
(1U << 9) | // By default enable hardware interrupts
(1U << 19) | // By default enable virtual hardware interrupts
(1U << 21) | // CPU ID detection
0,
};
if (ioctl(VCPU_FD, KVM_SET_SREGS, &SpecialRegisters) == -1) {
@@ -654,6 +725,60 @@ namespace SU::VM {
return true;
}
bool KVMInstance::HandleKVMLongModeQuirk() {
uint64_t TestRIP = LongQuirkRegion.VirtualBase + 3;
uint64_t MAXRIP = LongQuirkRegion.VirtualBase + 0x10;
for (uint32_t tries = 0; tries < 4; ++tries) {
fprintf(stderr, "Trie: %d\n", tries);
kvm_regs Registers = {
.rip = LongQuirkRegion.VirtualBase,
.rsp = 0xFF0,
.rflags = 0x2 | // 0x2 is the default state of rflags
(1U << 9) | // By default enable hardware interrupts
(1U << 19) | // By default enable virtual hardware interrupts
(1U << 21) | // CPU ID detection
0,
};
if (ioctl(VCPU_FD, KVM_SET_REGS, &Registers) == -1) {
fprintf(stderr, "[Quirk] Couldn't set kvm_regs\n");
return false;
}
if (!SetStepping(true)) {
fprintf(stderr, "[Quirk] Couldn't set stepping\n");
return false;
}
do {
if (!Run()) {
fprintf(stderr, "[Quirk] Couldn't step\n");
return false;
}
auto Regs = GetRegisterState();
if (Regs.rip > MAXRIP) {
break;
}
} while (ExitReason() == 4);
auto Regs = GetRegisterState();
if (Regs.rip == TestRIP) {
break;
}
}
auto Regs = GetRegisterState();
if (Regs.rip != TestRIP) {
fprintf(stderr, "[Quirk] Expected RIP: 0x%lx but got 0x%lx\n", TestRIP, Regs.rip);
return false;
}
return true;
}
bool KVMInstance::Initialize() {
int APIVersion;
int VCPUSize;
@@ -722,6 +847,11 @@ namespace SU::VM {
goto err;
}
if (!HandleKVMLongModeQuirk()) {
fprintf(stderr, "Couldn't work around KVM long mode enable quirk");
goto err;
}
return true;
err:
if (VCPU_FD != -1) {
@@ -898,20 +1028,6 @@ err:
for (int i = 0; i < (KVM_NR_INTERRUPTS + 63) / 64; ++i) {
LogMan::Msg::D("Interrupt: %d: 0x%016llx", Registers.interrupt_bitmap[i]);
}
void *PhysBase = VM_Addr;
uint8_t *GuestData = reinterpret_cast<uint8_t*>(PhysBase);
uint64_t Offset = State.rip - 0x1000'0000ULL;
uint64_t Size = 16;
LogMan::Msg::D("Mem: [%016llx, %016llx)", Offset, Offset + Size);
for (uint64_t i = 0; i < 16 * 3; i += 16) {
LogMan::Msg::D("%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
GuestData[Offset + i + 0], GuestData[Offset + i + 1], GuestData[Offset + i + 2], GuestData[Offset + i + 3],
GuestData[Offset + i + 4], GuestData[Offset + i + 5], GuestData[Offset + i + 6], GuestData[Offset + i + 7],
GuestData[Offset + i + 8], GuestData[Offset + i + 9], GuestData[Offset + i + 10], GuestData[Offset + i + 11],
GuestData[Offset + i + 12], GuestData[Offset + i + 13], GuestData[Offset + i + 14], GuestData[Offset + i + 15]);
}
}
}