Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/hoshimin/arch

A bunch of architectural headers for i386 and AMD64
https://github.com/hoshimin/arch

amd-v arch eflags gdt global-descriptor-table idt intel interrupts layout msr pte registers ring0 segmentation svm vmx vt-x x86

Last synced: 5 days ago
JSON representation

A bunch of architectural headers for i386 and AMD64

Awesome Lists containing this project

README

        

# 🧩 Arch
It's a bit-perfect (and maybe the most complete in some cases) bunch of architectural headers for i386/AMD64 platform written in C++17.

### 📜 Supported structures and layouts:
* **Memory paging** for all possible regimes and page sizes:
- Regimes:
- Legacy Non-PAE with and without CR4.PSE (4Kb and 4Mb pages).
- Legacy PAE (4Kb and 2Mb pages).
- Long-mode 4-Level (4Kb, 2Mb and 1Gb pages).
- Long-mode 5-Level (4Kb, 2Mb and 1Gb pages).
- With definitions for all possible page tables and entries:
- PML5 table with PML5E entries introduced with Intel 10th Gen (Ice Lake) and AMD Epyc 7xxx "Genoa" (Zen4).
- PML4 table with PML4E entries.
- PDP table with PDPE entries (also known as PDPT table and PDPTE entries in Intel terms) including PageSize forms.
- PD table with PDE entries including PageSize forms.
- PT table with PTE entries.
* **Segmentation**:
- GDT - Global Descriptor Table.
- IDT - Interrupt Descriptor Table.
- LDT - Local Descriptor Table.
- TSS - Task State Segment.
- Segment selector (format of CS, DS, GS, FS, ES, SS and TR registers).
- Descriptor table register (IDTR, GDTR and LDTR registers).
- Descriptors (system- and user-segments and gates for all possible interpretations).
* **System registers**:
- EFlags.
- Control registers: CR0, CR, CR3, CR4, CR8.
- Debug registers: DR0..DR7.
* **Interrupt vectors**.
* **CPUID** with some leaves specific for Intel and AMD.
* **MSRs** (Model Specific Registers) for Intel and AMD:
- All possible MSR addresses for Intel and AMD.
- Layouts for some of them (including Memory Type Range Registers (MTRRs) for Intel).
* Architectural **intrinsics** for MSVC and CLang.
* **Virtualization**:
- Intel VT-x (also known as Intel VMX):
- VMCS - Virtual Machine Control Structure.
- Exit reasons.
- EPT tables.
- MSR permission map.
- VMENTRY configuration.
- VMEXIT qualification.
- AMD-V (also known as AMD SVM):
- VMCB - Virtual Machine Control Block.
- Exit reasons.
- NPT - Nested Page Tables (also known as AMD-RVI) which are the same as normal page tables.
- MSR permission map.
- Event injection layout.
- A bit of Hyper-V:
- Hypercall layout.
- Hypercall result values.
- Hypercall codes.
- Hypervisor status.
- Synthetic MSRs.

### 🏗️ Requirements:
* MSVC or Clang (GCC has not tested).
* C++17 or above.
* Both usermode and kernelmode are supported.

### ✍️ How to?
Just add the folder `Arch/include` to additional headers path and you're ready to go!
Let's start with CPUID example:
```cpp
#include

int main()
{
const auto basicInfo = Cpuid::Cpuid::query();
if (basicInfo->isIntel())
{
const auto features = Cpuid::Cpuid::query();
printf("SSE 4.2 is supported: %u\n", features->SSE42);
}
else if (basicInfo->isAmd())
{
const auto features = Cpuid::Cpuid::query();
printf("SSE 4.2 is supported: %u\n", features->SSE42);
}
else
{
/* Unknown CPU */
}
}
```

All right, let's go to kernel and try MSRs and control registers:
```cpp
#include

void test()
{
const auto efer = Msr::Msr::read();

if (efer->LME && efer->LMA) // Is long-mode enabled and active?
{
const auto cr3 = Regs::Native::Cr3::query();
const auto cr4 = Regs::Native::Cr4::query();
if (cr4->layout.LA57)
{
// 5-Level paging:
const auto pml5pfn = cr3->paging5Level.PML5;
...
}
else
{
// 4-Level paging:
const auto pml4pfn = cr3->paging4Level.PML4;
...
}
}
}
```


Well done! Let's try page traversal through a page table.
Suppose we're in long 4-Level paging mode and the page is presented - checks for presense of a page were omitted for the simplicity:
```cpp
#include
#include

template
typename Type::Layout* phys2virt(const Type phys)
{
return MmGetVirtualForPhysical(PHYSICAL_ADDRESS{ .QuadPart = static_cast(phys); });
}

unsigned long long getPhysicalAddress(void* virtualAddress)
{
constexpr auto k_mode = Pte::Mode::longMode4Level;

using LinearAddress = Pte::LinearAddress;
using Tables = Pte::Tables;

const LinearAddress addr{ .raw = reinterpret_cast(virtualAddress) };
const auto cr3Pfn = Regs::Native::Cr3::query()->paging4Level.PML4;

const auto* const pml4e = phys2virt(Tables::pml4e(cr3Pfn, addr));
const auto* const pdpe = phys2virt(pml4e->pdpe(addr));
switch (pdpe->pageSize())
{
case Pte::PageSize::nonPse:
{
const auto* const pde = phys2virt(pdpe->nonPse.pde(addr));
switch (pde->pageSize())
{
case Pte::PageSize::nonPse:
{
// 4Kb:
const auto* const pte = phys2virt(pde->nonPse.pte(addr));
const auto phys = pte->physicalAddress(addr);
return phys.physicalAddress;
}
case Pte::PageSize::pse:
{
// 2Mb:
const auto phys = pde->pse.physicalAddress(addr);
return phys.physicalAddress;
}
}
break;
}
case Pte::PageSize::pse:
{
// 1Gb:
const auto phys = pdpe->pse.physicalAddress(addr);
return phys.physicalAddress;
}
}

return 0; // Invalid translation
}
```