Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
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
- Host: GitHub
- URL: https://github.com/hoshimin/arch
- Owner: HoShiMin
- License: mit
- Created: 2023-01-05T21:28:54.000Z (almost 2 years ago)
- Default Branch: main
- Last Pushed: 2023-10-07T17:24:17.000Z (about 1 year ago)
- Last Synced: 2023-10-07T18:29:31.729Z (about 1 year ago)
- Topics: amd-v, arch, eflags, gdt, global-descriptor-table, idt, intel, interrupts, layout, msr, pte, registers, ring0, segmentation, svm, vmx, vt-x, x86
- Language: C++
- Homepage:
- Size: 102 KB
- Stars: 24
- Watchers: 6
- Forks: 6
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
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
#includeint 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
#includevoid 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
#includetemplate
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
}
```