mirror of
https://github.com/FEX-Emu/FEX.git
synced 2026-10-28 13:01:01 +01:00
Some changes
This commit is contained in:
1 parent
d68f54542d
commit
5efe93fac9
5 files changed
+214
-101
No files matched your search
+59
-52
@@ -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
@@ -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
@@ -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
@@ -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);
|
||||
|
||||
@@ -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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user