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.
+
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
+
+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 .
@@ -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.
+