From b6627f53bf459334446bb1e2c51728a764c8651d Mon Sep 17 00:00:00 2001 From: johannst Date: Fri, 14 Mar 2025 01:19:37 +0000 Subject: deploy: cb9e06f3a5bd9d42494e6abdaf61fb3fe19d4ea4 --- arch/arm64.html | 6 ++-- arch/armv7.html | 6 ++-- arch/armv8.html | 6 ++-- arch/cache.html | 6 ++-- arch/index.html | 6 ++-- arch/riscv.html | 6 ++-- arch/x86/cpuid/Makefile | 5 ++++ arch/x86/cpuid/cpuid.c | 47 +++++++++++++++++++++++++++++++ arch/x86/seg/Makefile | 5 ++++ arch/x86/seg/seg.c | 75 +++++++++++++++++++++++++++++++++++++++++++++++++ arch/x86_64.html | 29 +++++++++++++++---- 11 files changed, 174 insertions(+), 23 deletions(-) create mode 100644 arch/x86/cpuid/Makefile create mode 100644 arch/x86/cpuid/cpuid.c create mode 100644 arch/x86/seg/Makefile create mode 100644 arch/x86/seg/seg.c (limited to 'arch') diff --git a/arch/arm64.html b/arch/arm64.html index 5ff278e..7fa358f 100644 --- a/arch/arm64.html +++ b/arch/arm64.html @@ -24,9 +24,9 @@ - - - + + + diff --git a/arch/armv7.html b/arch/armv7.html index 70117c5..077a2e7 100644 --- a/arch/armv7.html +++ b/arch/armv7.html @@ -24,9 +24,9 @@ - - - + + + diff --git a/arch/armv8.html b/arch/armv8.html index 7c8253c..c0ea816 100644 --- a/arch/armv8.html +++ b/arch/armv8.html @@ -24,9 +24,9 @@ - - - + + + diff --git a/arch/cache.html b/arch/cache.html index 75dcba5..2ff50e3 100644 --- a/arch/cache.html +++ b/arch/cache.html @@ -24,9 +24,9 @@ - - - + + + diff --git a/arch/index.html b/arch/index.html index 1a364d7..9b1e52d 100644 --- a/arch/index.html +++ b/arch/index.html @@ -24,9 +24,9 @@ - - - + + + diff --git a/arch/riscv.html b/arch/riscv.html index aafe43a..c99e952 100644 --- a/arch/riscv.html +++ b/arch/riscv.html @@ -24,9 +24,9 @@ - - - + + + diff --git a/arch/x86/cpuid/Makefile b/arch/x86/cpuid/Makefile new file mode 100644 index 0000000..577d96a --- /dev/null +++ b/arch/x86/cpuid/Makefile @@ -0,0 +1,5 @@ +a.out: cpuid.c + gcc -g cpuid.c + +clean: + $(RM) a.out diff --git a/arch/x86/cpuid/cpuid.c b/arch/x86/cpuid/cpuid.c new file mode 100644 index 0000000..ab4a7a4 --- /dev/null +++ b/arch/x86/cpuid/cpuid.c @@ -0,0 +1,47 @@ +#include +#include + +typedef struct { + uint32_t eax, ebx, ecx, edx; +} cpuid_t; + +// in: eax is the cpuid leaf number +static inline cpuid_t cpuid(uint32_t eax) { + cpuid_t r; + asm volatile("cpuid" + : "=a"(r.eax), "=b"(r.ebx), "=c"(r.ecx), "=d"(r.edx) + : "a"(eax), "c"(0)); + return r; +}; + +// in: eax is the cpuid leaf number +// in: ecx is the cpuid sub-leaf number +static inline cpuid_t cpuid_subleaf(uint32_t eax, uint32_t ecx) { + cpuid_t r; + asm volatile("cpuid" + : "=a"(r.eax), "=b"(r.ebx), "=c"(r.ecx), "=d"(r.edx) + : "a"(eax), "c"(ecx)); + return r; +}; + +int main() { + cpuid_t r; + uint32_t leafs = 1; + + for (uint32_t l = 0; l < leafs; ++l) { + r = cpuid(l); + if (l == 0) { + // leaf 0 returns the highest available cpuid leaf in eax. + leafs = r.eax; + + // ebx, edx, ecx contain the vendor string + // clang-format off + printf("vendor: %c%c%c%c%c%c%c%c%c%c%c%c\n", + (r.ebx & 0xFF), (r.ebx >> 8) & 0xFF, (r.ebx >> 16) & 0xFF, (r.ebx >> 24) & 0xFF, + (r.edx & 0xFF), (r.edx >> 8) & 0xFF, (r.edx >> 16) & 0xFF, (r.edx >> 24) & 0xFF, + (r.ecx & 0xFF), (r.ecx >> 8) & 0xFF, (r.ecx >> 16) & 0xFF, (r.ecx >> 24) & 0xFF); + // clang-format on + } + printf("[0x%08x] eax=%08x ebx=%08x ecx=%08x edx=%08x\n", l, r.eax, r.ebx, r.ecx, r.edx); + } +} diff --git a/arch/x86/seg/Makefile b/arch/x86/seg/Makefile new file mode 100644 index 0000000..290025e --- /dev/null +++ b/arch/x86/seg/Makefile @@ -0,0 +1,5 @@ +a.out: seg.c + gcc -g seg.c + +clean: + $(RM) a.out diff --git a/arch/x86/seg/seg.c b/arch/x86/seg/seg.c new file mode 100644 index 0000000..b06e0cb --- /dev/null +++ b/arch/x86/seg/seg.c @@ -0,0 +1,75 @@ +#include +#include + +// Reads GS segment base address (backed by IA32_GS_BASE msr). +// +// Instruction must be supported. Can be checked as +// cpuid(0x7).ebx & 1 == 1 +// +// In case the instruction is not available, the base address can be +// read with the following syscall. +// uint64_t addr; +// arch_prctl(ARCH_GET_GS, &addr) +static inline uint64_t rdgsbase() { + uint64_t gs; + asm volatile("rdgsbase %0" : "=r"(gs)); + return gs; +} + +// Write GS segment base address (backed by IA32_GS_BASE msr). +// +// Instruction must be supported. Can be checked as +// cpuid(0x7).ebx & 1 == 1 +// +// In case the instruction is not available, the base address can be +// set with the following syscall. +// arch_prctl(ARCH_GET_GS, addr) +static inline void wrgsbase(uint64_t* gs) { + asm volatile("wrgsbase %0" ::"r"(gs)); +} + +// Read u32 from off relative to GS segment. +static inline uint32_t rdgs32(int64_t off) { + uint32_t ret; + asm volatile("mov %%gs:%1, %0" : "=r"(ret) : "m"(*(uint64_t*)off)); + return ret; +} + +// Read u64 from off relative to GS segment. +static inline uint64_t rdgs64(int64_t off) { + uint64_t ret; + asm volatile("mov %%gs:%1, %0" : "=r"(ret) : "m"(*(uint64_t*)off)); + return ret; +} + +// Write u32 to off relative to GS segment. +static inline void wrgs32(int64_t off, uint32_t val) { + asm volatile("mov %1, %%gs:%0" ::"m"(*(uint64_t*)off), "r"(val)); +} + +int main() { + printf("gsbase=%016lx\n", rdgsbase()); + + uint64_t VALS[] = { + 0xa7a6a5a4a3a2a1a0, + 0xb7b6b5b4b3b2b1b0, + }; + + // Setup GS segment base address. + wrgsbase(VALS); + printf("gsbase=%016lx | &VALS=%p\n", rdgsbase(), VALS); + + // Read values relative to GS segment. + int64_t off[] = {0, 8, 4, 1}; + for (int64_t i = 0; i < 4; ++i) { + printf("64: gs:%ld=%016lx\n", off[i], rdgs64(off[i])); + printf("32: gs:%ld=%016lx\n", off[i], rdgs32(off[i])); + } + + // Write value relative to GS segment. + wrgs32(4, 0xddccbbaa); + printf("64: gs:%ld=%016lx\n", 0, rdgs64(0)); + + // Reset GS segment base address. + wrgsbase(0); +} diff --git a/arch/x86_64.html b/arch/x86_64.html index b738a36..6f0e435 100644 --- a/arch/x86_64.html +++ b/arch/x86_64.html @@ -24,9 +24,9 @@ - - - + + + @@ -213,6 +213,9 @@ popfd // pop flags (4byte) from stack
rdmsr     // Read MSR register, effectively does EDX:EAX <- MSR[ECX]
 wrmsr     // Write MSR register, effectively does MSR[ECX] <- EDX:EAX
 
+
+

See guest64-msr.S as an example.

+

Size directives

Explicitly specify size of the operation.

mov  byte ptr [rax], 0xff    // save 1 byte(s) at [rax]
@@ -298,6 +301,13 @@ core changes frequency. This is the architectural behavior moving forward.

implemented TSC ticks with a constant frequency.

grep constant_tsc /proc/cpuinfo
 
+

Cpu & hw features - cpuid

+
cpuid   // in:  eax leaf; ecx sub-leaf
+        // out: eax, ebx, ecx, edx (interpreting depends on leaf)
+
+

This instruction is used to query for availability of certain +instructions or hardware details like cache sizes and son on.

+

An example how to read cpuid leafs is show in cpuid.c.

SysV x86_64 ABI

Passing arguments to functions

    @@ -648,8 +658,8 @@ itself.

    # Segment Selector (cs, ds, es, ss, fs, gs).
     
     [15:3] I   Descriptor Index
    - [2:1] TI  Table Indicator (0=GTD | 1=LDT)
    -   [0] RPL Requested Privilege Level
    +   [2] TI  Table Indicator (0=GTD | 1=LDT)
    + [1:0] RPL Requested Privilege Level
     
     
     # Segment Descriptor (2 x 4 byte words).
    @@ -675,6 +685,15 @@ itself.

    [47:16] Base address of GDT table. [15:0] Length of GDT table.
    +
    +

    In 64-bit mode the {cs, ds, es, ss} segment register have no +effect, segmentation is effectively disabled. The {gs, fs} segment +register however can still be used for segmented memory access in +64-bit with paging enabled. Segmentation takes place before VA -> PA +address translation.

    +

    The example in seg.c shows how to set the gs base +address and to relative accesses.

    +

    References