Skip to content

Commit

Permalink
Tweak handling of guest machine execution mode (#109)
Browse files Browse the repository at this point in the history
- Split machine mode `m->mode` into two parts, to explicitly
  distinguish real mode & 16-bit protected mode
  - `m->mode.omode` now says how instructions should be decoded
  - `m->mode.genmode` says whether guest is in real mode or not
- Use `Mode(rde)` more often, so we can optimize away dead
  code on `--disable-metal`
- Setting `CR0_PE` in guest `%cr0` now immediately triggers
  machine mode change
  • Loading branch information
tkchia authored Apr 20, 2023
1 parent 8b17fed commit 83372fa
Show file tree
Hide file tree
Showing 18 changed files with 98 additions and 55 deletions.
2 changes: 1 addition & 1 deletion blink/address.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ i64 GetPc(struct Machine *m) {
}

i64 GetIp(struct Machine *m) {
return MaskAddress(m->mode, m->ip);
return MaskAddress(m->mode.omode, m->ip);
}

u64 MaskAddress(u32 mode, u64 x) {
Expand Down
2 changes: 1 addition & 1 deletion blink/blink.c
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ static int Exec(char *execfn, char *prog, char **argv, char **envp) {
sigset_t oldmask;
struct Machine *m, *old;
if ((old = g_machine)) KillOtherThreads(old->system);
unassert((g_machine = m = NewMachine(NewSystem(XED_MODE_LONG), 0)));
unassert((g_machine = m = NewMachine(NewSystem(XED_MACHINE_MODE_LONG), 0)));
#ifdef HAVE_JIT
if (FLAG_nojit) DisableJit(&m->system->jit);
#endif
Expand Down
23 changes: 12 additions & 11 deletions blink/blinkenlights.c
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ alt-t slowmo"
#define DISPWIDTH 80 // size of the embedded tty display
#define DUMPWIDTH 64 // columns of bytes in memory panel
#define ASMWIDTH 40 // seed the width of assembly panel
#define ASMRAWMIN (m->mode == XED_MODE_REAL ? 50 : 65)
#define ASMRAWMIN (m->mode.omode == XED_MODE_REAL ? 50 : 65)

#define RESTART 0x001
#define REDRAW 0x002
Expand Down Expand Up @@ -549,7 +549,7 @@ static u8 CycleXmmSize(u8 w) {
}

static int GetPointerWidth(void) {
return 2 << m->mode;
return 2 << m->mode.omode;
}

static i64 GetSp(void) {
Expand Down Expand Up @@ -1037,7 +1037,7 @@ static int PickNumberOfXmmRegistersToShow(void) {
}

static int GetRegHexWidth(void) {
switch (m->mode & 3) {
switch (m->mode.omode) {
case XED_MODE_LONG:
return 16;
case XED_MODE_LEGACY:
Expand All @@ -1057,7 +1057,7 @@ static int GetRegHexWidth(void) {
}

static int GetAddrHexWidth(void) {
switch (m->mode & 3) {
switch (m->mode.omode) {
case XED_MODE_LONG:
return 12;
case XED_MODE_LEGACY:
Expand Down Expand Up @@ -1403,7 +1403,7 @@ static void DrawRegister(struct Panel *p, i64 i, i64 r, bool first) {
value = Read64(m->weg[r]);
previous = Read64(laststate.weg[r]);
if (value != previous) AppendPanel(p, i, "\033[7m");
snprintf(buf, sizeof(buf), "%-3s", kRegisterNames[m->mode][r]);
snprintf(buf, sizeof(buf), "%-3s", kRegisterNames[m->mode.omode][r]);
AppendPanel(p, i, buf);
AppendPanel(p, i, " ");
snprintf(buf, sizeof(buf), "%0*" PRIx64, GetRegHexWidth(), value);
Expand Down Expand Up @@ -1457,8 +1457,8 @@ static void DrawCpu(struct Panel *p) {
DrawRegister(p, 5, 9, 1), DrawRegister(p, 5, 13, 0), DrawSt(p, 5, 5);
DrawRegister(p, 6, 10, 1), DrawRegister(p, 6, 14, 0), DrawSt(p, 6, 6);
DrawRegister(p, 7, 11, 1), DrawRegister(p, 7, 15, 0), DrawSt(p, 7, 7);
snprintf(buf, sizeof(buf), "%-3s %0*" PRIx64 " FLG", kRipName[m->mode],
GetRegHexWidth(), m->ip);
snprintf(buf, sizeof(buf), "%-3s %0*" PRIx64 " FLG",
kRipName[m->mode.omode], GetRegHexWidth(), m->ip);
AppendPanel(p, 8, buf);
DrawFlag(p, 8, 'C', GetFlag(m->flags, FLAGS_CF));
DrawFlag(p, 8, 'P', GetFlag(m->flags, FLAGS_PF));
Expand Down Expand Up @@ -1808,7 +1808,7 @@ static void DrawBreakpoints(struct Panel *p) {
}

static int GetPreferredStackAlignmentMask(void) {
switch (m->mode) {
switch (m->mode.omode) {
case XED_MODE_LONG:
return 15;
case XED_MODE_LEGACY:
Expand Down Expand Up @@ -1860,8 +1860,8 @@ static void DrawFrames(struct Panel *p) {
break;
}
sp = bp;
bp = ReadWordSafely(m->mode, r + 0);
rp = ReadWordSafely(m->mode, r + 8);
bp = ReadWordSafely(m->mode.omode, r + 0);
rp = ReadWordSafely(m->mode.omode, r + 8);
}
}

Expand Down Expand Up @@ -4063,7 +4063,8 @@ int main(int argc, char *argv[]) {
AddPath_StartOp_Hook = AddPath_StartOp_Tui;
#endif
unassert((pty = NewPty()));
unassert((s = NewSystem(wantmetal ? XED_MODE_REAL : XED_MODE_LONG)));
unassert((s = NewSystem(wantmetal ? XED_MACHINE_MODE_REAL :
XED_MACHINE_MODE_LONG)));
unassert((m = g_machine = NewMachine(s, 0)));
#ifdef HAVE_JIT
if (!FLAG_wantjit || wantmetal) {
Expand Down
15 changes: 8 additions & 7 deletions blink/debug.c
Original file line number Diff line number Diff line change
Expand Up @@ -137,20 +137,20 @@ int GetInstruction(struct Machine *m, i64 pc, struct XedDecodedInst *x) {
BEGIN_NO_PAGE_FAULTS;
if ((addr = LookupAddress(m, pc))) {
if ((i = 4096 - (pc & 4095)) >= 15) {
if (!DecodeInstruction(x, addr, 15, m->mode)) {
if (!DecodeInstruction(x, addr, 15, m->mode.omode)) {
rc = 0;
} else {
rc = kMachineDecodeError;
}
} else if ((toil = LookupAddress(m, pc + i))) {
memcpy(copy, addr, i);
memcpy(copy + i, toil, 15 - i);
if (!DecodeInstruction(x, copy, 15, m->mode)) {
if (!DecodeInstruction(x, copy, 15, m->mode.omode)) {
rc = 0;
} else {
rc = kMachineDecodeError;
}
} else if (!(err = DecodeInstruction(x, addr, i, m->mode))) {
} else if (!(err = DecodeInstruction(x, addr, i, m->mode.omode))) {
rc = 0;
} else if (err == XED_ERROR_BUFFER_TOO_SHORT) {
rc = kMachineSegmentationFault;
Expand Down Expand Up @@ -255,7 +255,8 @@ const char *GetBacktrace(struct Machine *m) {
"OPS %-16ld "
"FLG %s\n\t"
"%s\n\t",
m->cs.base + MaskAddress(m->mode, m->ip), DescribeOp(m, GetPc(m)),
m->cs.base + MaskAddress(m->mode.omode, m->ip),
DescribeOp(m, GetPc(m)),
Get64(m->ax), Get64(m->cx), Get64(m->dx), Get64(m->bx), Get64(m->sp),
Get64(m->bp), Get64(m->si), Get64(m->di), Get64(m->r8), Get64(m->r9),
Get64(m->r10), Get64(m->r11), Get64(m->r12), Get64(m->r13),
Expand All @@ -281,7 +282,7 @@ const char *GetBacktrace(struct Machine *m) {
} else if (bp - sp <= 0x1000) {
APPEND(" %" PRId64 " bytes", bp - sp);
}
if (bp & kAlignmentMask[m->mode] && i) {
if (bp & kAlignmentMask[m->mode.omode] && i) {
APPEND(" [MISALIGN]");
}
++i;
Expand All @@ -291,8 +292,8 @@ const char *GetBacktrace(struct Machine *m) {
break;
}
sp = bp;
bp = ReadWordSafely(m->mode, r + 0);
rp = ReadWordSafely(m->mode, r + 8);
bp = ReadWordSafely(m->mode.omode, r + 0);
rp = ReadWordSafely(m->mode.omode, r + 8);
}
if (m->system->dis == &dis) {
DisFree(&dis);
Expand Down
2 changes: 1 addition & 1 deletion blink/dis.c
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,7 @@ static long DisAppendOpLines(struct Dis *d, struct Machine *m, i64 addr) {
n = k;
}
}
DecodeInstruction(d->xedd, p, n, m->mode);
DecodeInstruction(d->xedd, p, n, m->mode.omode);
n = d->xedd->length;
op.addr = addr;
op.size = n;
Expand Down
2 changes: 1 addition & 1 deletion blink/fpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -1030,7 +1030,7 @@ void OpFpu(P) {
bool ismemory;
op = Opcode(rde) & 7;
ismemory = ModrmMod(rde) != 3;
m->fpu.ip = MaskAddress(m->mode, m->ip - Oplength(rde));
m->fpu.ip = MaskAddress(m->mode.omode, m->ip - Oplength(rde));
m->fpu.op = op << 8 | ModrmMod(rde) << 6 | ModrmReg(rde) << 3 | ModrmRm(rde);
m->fpu.dp = ismemory ? ComputeAddress(A) : 0;
switch (DISP(op, ismemory, ModrmReg(rde))) {
Expand Down
2 changes: 1 addition & 1 deletion blink/instruction.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ static bool IsOpcodeEqual(struct XedDecodedInst *xedd, u8 *a) {
static int ReadInstruction(struct Machine *m, u8 *p, unsigned n) {
struct XedDecodedInst xedd[1];
STATISTIC(++instructions_decoded);
if (!DecodeInstruction(xedd, p, n, m->mode)) {
if (!DecodeInstruction(xedd, p, n, m->mode.omode)) {
memcpy(m->xedd, xedd, kInstructionBytes);
return 0;
} else {
Expand Down
2 changes: 1 addition & 1 deletion blink/loader.c
Original file line number Diff line number Diff line change
Expand Up @@ -746,7 +746,7 @@ error: unsupported executable; we need:\n\
m->system->brk ^= Read64(elf->rng) & FLAG_aslrmask;
m->system->automap ^= (Read64(elf->rng) & FLAG_aslrmask);
}
if (m->mode == XED_MODE_REAL) {
if (m->mode.genmode == XED_GEN_MODE_REAL) {
LoadDefaultBios(m);
if (endswith(prog, ".com")) {
// cosmo convention (see also binbase)
Expand Down
10 changes: 5 additions & 5 deletions blink/machine.c
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ static relegated void OpLsl(P) {
}
}

void SetMachineMode(struct Machine *m, int mode) {
void SetMachineMode(struct Machine *m, struct XedMachineMode mode) {
m->mode = mode;
m->system->mode = mode;
}
Expand Down Expand Up @@ -810,11 +810,11 @@ static void GenInterrupt(P, u8 trapno) {
#else
u16 offset;
struct System *s;
switch (m->mode) {
switch (m->mode.genmode) {
default:
HaltMachine(m, trapno);
break;
case XED_MODE_REAL:
case XED_GEN_MODE_REAL:
offset = (u16)trapno * 4;
s = m->system;
if (offset + 3 > s->idt_limit) {
Expand Down Expand Up @@ -872,15 +872,15 @@ static void OpInterrupt3(P) {

#ifndef DISABLE_METAL
static void OpInto(P) {
if (m->mode != XED_MODE_LONG) {
if (Mode(rde) != XED_MODE_LONG) {
if (GetFlag(m->flags, FLAGS_OF)) HaltMachine(m, 4);
} else {
OpUdImpl(m);
}
}

static void OpIret(P) {
if (m->mode == XED_MODE_REAL) {
if (m->mode.genmode == XED_GEN_MODE_REAL) {
OpRetf(A);
if (!Osz(rde)) {
// Intel V2A § 3.2 says that iretl should only update some parts of
Expand Down
10 changes: 5 additions & 5 deletions blink/machine.h
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,7 @@ struct OpCache {
};

struct System {
u8 mode;
struct XedMachineMode mode;
bool dlab;
bool isfork;
bool exited;
Expand Down Expand Up @@ -326,7 +326,7 @@ struct MachineTlb {
struct Machine { //
u64 ip; // instruction pointer
u8 oplen; // length of operation
u8 mode; // [dup] XED_MODE_{REAL,LEGACY,LONG}
struct XedMachineMode mode; // [dup] XED_MACHINE_MODE_REAL etc.
bool threaded; // must use synchronization
_Atomic(bool) attention; // signals main interpreter loop
u32 flags; // x86 eflags register
Expand Down Expand Up @@ -441,10 +441,10 @@ extern _Thread_local struct Machine *g_machine;
extern const nexgen32e_f kConvert[3];
extern const nexgen32e_f kSax[3];

struct System *NewSystem(int);
struct System *NewSystem(struct XedMachineMode);
void FreeSystem(struct System *);
void SignalActor(struct Machine *);
void SetMachineMode(struct Machine *, int);
void SetMachineMode(struct Machine *, struct XedMachineMode);
struct Machine *NewMachine(struct System *, struct Machine *);
i64 AreAllPagesUnlocked(struct System *) nosideeffect;
bool IsOrphan(struct Machine *) nosideeffect;
Expand Down Expand Up @@ -802,7 +802,7 @@ void LogCodOp(struct Machine *, const char *);
#endif

MICRO_OP_SAFE u8 Cpl(struct Machine *m) {
return m->mode != XED_MODE_REAL ? (m->cs.sel & 3u) : 0u;
return m->mode.genmode != XED_GEN_MODE_REAL ? (m->cs.sel & 3u) : 0u;
}

#define BEGIN_NO_PAGE_FAULTS \
Expand Down
6 changes: 3 additions & 3 deletions blink/memory.c
Original file line number Diff line number Diff line change
Expand Up @@ -262,8 +262,8 @@ u64 FindPageTableEntry(struct Machine *m, u64 page) {
u8 *LookupAddress2(struct Machine *m, i64 virt, u64 mask, u64 need) {
u8 *host;
u64 entry;
if (m->mode == XED_MODE_LONG ||
(m->mode != XED_MODE_REAL && (m->system->cr0 & CR0_PG))) {
if (m->mode.omode == XED_MODE_LONG ||
(m->mode.genmode != XED_GEN_MODE_REAL && (m->system->cr0 & CR0_PG))) {
if (!(entry = FindPageTableEntry(m, virt & -4096))) {
return 0;
}
Expand Down Expand Up @@ -316,7 +316,7 @@ bool IsValidMemory(struct Machine *m, i64 virt, i64 size, int prot) {
u64 pte, mask, need;
size += virt & 4095;
virt &= -4096;
unassert(m->mode == XED_MODE_LONG);
unassert(m->mode.omode == XED_MODE_LONG);
unassert(prot && !(prot & ~(PROT_READ | PROT_WRITE | PROT_EXEC)));
need = mask = 0;
if (prot & PROT_READ) {
Expand Down
14 changes: 8 additions & 6 deletions blink/memorymalloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -189,19 +189,21 @@ long GetMaxRss(struct System *s) {
return MIN(kMaxResident, Read64(s->rlim[RLIMIT_AS_LINUX].cur)) / 4096;
}

struct System *NewSystem(int mode) {
struct System *NewSystem(struct XedMachineMode mode) {
long i;
struct System *s;
unassert(mode == XED_MODE_REAL || //
mode == XED_MODE_LEGACY || //
mode == XED_MODE_LONG);
unassert(mode.omode == XED_MODE_REAL || //
mode.omode == XED_MODE_LEGACY || //
mode.omode == XED_MODE_LONG);
unassert(mode.genmode == XED_GEN_MODE_REAL || //
mode.genmode == XED_GEN_MODE_PROTECTED);
if (posix_memalign((void **)&s, _Alignof(struct System), sizeof(*s))) {
enomem();
return 0;
}
memset(s, 0, sizeof(*s));
s->mode = mode;
if (s->mode == XED_MODE_REAL) {
if (s->mode.omode == XED_MODE_REAL) {
if (posix_memalign((void **)&s->real, 4096, kRealSize)) {
free(s);
enomem();
Expand Down Expand Up @@ -787,7 +789,7 @@ i64 ReserveVirtual(struct System *s, i64 virt, i64 size, u64 flags, int fd,
unassert(!(flags & PAGE_MAP));
unassert(!(flags & PAGE_HOST));
unassert(!(flags & PAGE_RSRV));
unassert(s->mode == XED_MODE_LONG);
unassert(s->mode.omode == XED_MODE_LONG);

// determine memory protection
prot = GetProtection(flags);
Expand Down
27 changes: 21 additions & 6 deletions blink/metal.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include <string.h>

#include "blink/bus.h"
#include "blink/endian.h"
#include "blink/machine.h"
Expand All @@ -38,8 +40,11 @@ static relegated u64 GetDescriptorBase(u64 d) {
return (d & 0xff00000000000000) >> 32 | (d & 0x000000ffffff0000) >> 16;
}

static relegated int GetDescriptorMode(u64 d) {
u8 kMode[] = {XED_MODE_REAL, XED_MODE_LONG, XED_MODE_LEGACY, XED_MODE_LONG};
static struct XedMachineMode GetDescriptorMode(u64 d) {
static const struct XedMachineMode kMode[] = {XED_MACHINE_MODE_LEGACY_16,
XED_MACHINE_MODE_LONG,
XED_MACHINE_MODE_LEGACY_32,
XED_MACHINE_MODE_LONG};
return kMode[(d & 0x0060000000000000) >> 53];
}

Expand All @@ -51,12 +56,13 @@ static relegated bool IsNullSelector(u16 sel) {
return (sel & -4u) == 0;
}

static relegated void ChangeMachineMode(struct Machine *m, int mode) {
if (mode == m->mode) return;
static relegated void ChangeMachineMode(struct Machine *m,
struct XedMachineMode mode) {
if (memcmp(&mode, &m->mode, sizeof(mode)) == 0) return;
ResetInstructionCache(m);
SetMachineMode(m, mode);
#ifdef HAVE_JIT
if (mode == XED_MODE_LONG && FLAG_wantjit) {
if (mode.omode == XED_MODE_LONG && FLAG_wantjit) {
EnableJit(&m->system->jit);
}
#endif
Expand Down Expand Up @@ -286,9 +292,18 @@ relegated void OpMovRqCq(P) {
}

relegated void OpMovCqRq(P) {
u64 cr0;
struct XedMachineMode mode;
switch (ModrmReg(rde)) {
case 0:
m->system->cr0 = Get64(RegRexbRm(m, rde));
m->system->cr0 = cr0 = Get64(RegRexbRm(m, rde));
mode = m->system->mode;
if ((cr0 & CR0_PE)) {
mode.genmode = XED_GEN_MODE_PROTECTED;
} else {
mode.genmode = XED_GEN_MODE_REAL;
}
ChangeMachineMode(m, mode);
break;
case 2:
m->system->cr2 = Get64(RegRexbRm(m, rde));
Expand Down
Loading

0 comments on commit 83372fa

Please sign in to comment.