mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-07-02 09:18:31 +00:00
Get binaries closer to running without an o/s
blinkenlights now does a pretty good job emulating what happens when binaries boot from BIOS into long mode. So it's been much easier to debug the bare metal process and wrinkle out many issues.
This commit is contained in:
parent
feed0d2b0e
commit
2d80bbc802
50 changed files with 974 additions and 1062 deletions
|
@ -17,16 +17,10 @@
|
|||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/alg/arraylist2.h"
|
||||
#include "libc/assert.h"
|
||||
#include "libc/bits/popcnt.h"
|
||||
#include "libc/bits/safemacros.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/runtime/gc.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/auxv.h"
|
||||
#include "tool/build/lib/endian.h"
|
||||
#include "tool/build/lib/machine.h"
|
||||
#include "tool/build/lib/memory.h"
|
||||
|
|
|
@ -21,18 +21,27 @@
|
|||
#include "libc/calls/calls.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/macros.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/str/tpenc.h"
|
||||
#include "libc/str/tpencode.h"
|
||||
#include "tool/build/lib/buffer.h"
|
||||
|
||||
void AppendChar(struct Buffer *b, char c) {
|
||||
APPEND(&b->p, &b->i, &b->n, &c);
|
||||
void AppendData(struct Buffer *b, char *data, unsigned len) {
|
||||
char *p;
|
||||
unsigned n;
|
||||
if (b->i + len + 1 > b->n) {
|
||||
n = MAX(b->i + len + 1, MAX(16, b->n + (b->n >> 1)));
|
||||
if (!(p = realloc(b->p, n))) return;
|
||||
b->p = p;
|
||||
b->n = n;
|
||||
}
|
||||
memcpy(b->p + b->i, data, len);
|
||||
b->p[b->i += len] = 0;
|
||||
}
|
||||
|
||||
void AppendData(struct Buffer *b, char *data, size_t len) {
|
||||
CONCAT(&b->p, &b->i, &b->n, data, len);
|
||||
void AppendChar(struct Buffer *b, char c) {
|
||||
AppendData(b, &c, 1);
|
||||
}
|
||||
|
||||
void AppendStr(struct Buffer *b, const char *s) {
|
||||
|
|
|
@ -4,12 +4,12 @@
|
|||
COSMOPOLITAN_C_START_
|
||||
|
||||
struct Buffer {
|
||||
size_t i, n;
|
||||
unsigned i, n;
|
||||
char *p;
|
||||
};
|
||||
|
||||
void AppendChar(struct Buffer *, char);
|
||||
void AppendData(struct Buffer *, char *, size_t);
|
||||
void AppendData(struct Buffer *, char *, unsigned);
|
||||
void AppendStr(struct Buffer *, const char *);
|
||||
void AppendWide(struct Buffer *, wint_t);
|
||||
int AppendFmt(struct Buffer *, const char *, ...);
|
||||
|
|
|
@ -41,6 +41,7 @@ TOOL_BUILD_LIB_A_DIRECTDEPS = \
|
|||
LIBC_SYSV_CALLS \
|
||||
LIBC_TIME \
|
||||
LIBC_LOG \
|
||||
LIBC_RAND \
|
||||
LIBC_STR \
|
||||
LIBC_SOCK \
|
||||
LIBC_UNICODE \
|
||||
|
@ -68,7 +69,7 @@ $(TOOL_BUILD_LIB_A_OBJS): \
|
|||
-fsanitize=address
|
||||
endif
|
||||
|
||||
o/$(MODE)/tool/build/lib/memory-gcc.asm: \
|
||||
o/$(MODE)/tool/build/lib/buffer-gcc.asm: \
|
||||
OVERRIDE_CFLAGS += \
|
||||
-fsanitize=address
|
||||
|
||||
|
|
|
@ -39,8 +39,9 @@ void OpCpuid(struct Machine *m, uint32_t rde) {
|
|||
cx |= 0 << 1; // pclmulqdq
|
||||
cx |= 1 << 9; // ssse3
|
||||
cx |= 1 << 23; // popcnt
|
||||
cx |= 0 << 30; // rdrnd
|
||||
cx |= 1 << 30; // rdrnd
|
||||
cx |= 0 << 25; // aes
|
||||
cx |= 1 << 13; // cmpxchg16b
|
||||
dx |= 1 << 0; // fpu
|
||||
dx |= 1 << 4; // tsc
|
||||
dx |= 1 << 6; // pae
|
||||
|
@ -48,15 +49,31 @@ void OpCpuid(struct Machine *m, uint32_t rde) {
|
|||
dx |= 1 << 15; // cmov
|
||||
dx |= 1 << 19; // clflush
|
||||
dx |= 1 << 23; // mmx
|
||||
dx |= 1 << 24; // fxsave
|
||||
dx |= 1 << 25; // sse
|
||||
dx |= 1 << 26; // sse2
|
||||
break;
|
||||
case 7:
|
||||
bx |= 1 << 9; // erms
|
||||
switch (Read32(m->cx)) {
|
||||
case 0:
|
||||
bx |= 1 << 0; // fsgsbase
|
||||
bx |= 1 << 9; // erms
|
||||
bx |= 0 << 18; // rdseed
|
||||
cx |= 1 << 22; // rdpid
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0x80000001:
|
||||
cx |= 1 << 0; // lahf
|
||||
dx |= 1 << 0; // fpu
|
||||
dx |= 1 << 8; // cmpxchg8b
|
||||
dx |= 1 << 11; // syscall
|
||||
dx |= 1 << 15; // cmov
|
||||
dx |= 1 << 23; // mmx
|
||||
dx |= 1 << 24; // fxsave
|
||||
dx |= 1 << 27; // rdtscp
|
||||
dx |= 1 << 29; // long
|
||||
break;
|
||||
case 0x80000007:
|
||||
|
|
|
@ -23,7 +23,6 @@
|
|||
#include "libc/conv/itoa.h"
|
||||
#include "libc/fmt/bing.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/macros.h"
|
||||
|
@ -96,7 +95,7 @@ static char *DisError(struct Dis *d, char *p) {
|
|||
}
|
||||
|
||||
static char *DisAddr(struct Dis *d, char *p) {
|
||||
if (INT32_MIN <= d->addr && d->addr <= INT32_MAX) {
|
||||
if (-0x80000000 <= d->addr && d->addr <= 0x7fffffff) {
|
||||
return p + uint64toarray_fixed16(d->addr, p, 32);
|
||||
} else {
|
||||
return p + uint64toarray_fixed16(d->addr, p, 48);
|
||||
|
|
|
@ -336,20 +336,24 @@ static char *DisEvqp(struct Dis *d, uint32_t rde, char *p) {
|
|||
return DisE(d, rde, p, DisRegisterWord);
|
||||
}
|
||||
|
||||
static char *DisEdqpReg(struct Dis *d, uint32_t rde, char *p) {
|
||||
static char *DisRv(struct Dis *d, uint32_t rde, char *p) {
|
||||
return DisRegister(p, kGreg[Osz(rde)][0][Rexb(rde)][ModrmRm(rde)]);
|
||||
}
|
||||
|
||||
static char *DisRvqp(struct Dis *d, uint32_t rde, char *p) {
|
||||
return DisRegister(p, kGreg[Osz(rde)][Rexw(rde)][Rexb(rde)][ModrmRm(rde)]);
|
||||
}
|
||||
|
||||
static char *DisRdqp(struct Dis *d, uint32_t rde, char *p) {
|
||||
return DisRegister(p, kGreg[0][Rexw(rde)][Rexb(rde)][ModrmRm(rde)]);
|
||||
}
|
||||
|
||||
static char *DisEdqp(struct Dis *d, uint32_t rde, char *p) {
|
||||
return DisRegMem(d, rde, p, DisEdqpReg);
|
||||
}
|
||||
|
||||
static char *DisEvReg(struct Dis *d, uint32_t rde, char *p) {
|
||||
return DisRegister(p, kGreg[Osz(rde)][0][Rexb(rde)][ModrmRm(rde)]);
|
||||
return DisRegMem(d, rde, p, DisRdqp);
|
||||
}
|
||||
|
||||
static char *DisEv(struct Dis *d, uint32_t rde, char *p) {
|
||||
return DisRegMem(d, rde, p, DisEvReg);
|
||||
return DisRegMem(d, rde, p, DisRv);
|
||||
}
|
||||
|
||||
static char *DisGvq(struct Dis *d, uint32_t rde, char *p, int r) {
|
||||
|
@ -597,8 +601,6 @@ static char *DisWps(struct Dis *d, uint32_t rde, char *p) {
|
|||
#define DisOvqp DisAbs
|
||||
#define DisPpi DisPq
|
||||
#define DisQpi DisQq
|
||||
#define DisRdqp DisGdqp
|
||||
#define DisRvqp DisGvqp
|
||||
#define DisVpd DisVdq
|
||||
#define DisVps DisVdq
|
||||
#define DisVq DisVdq
|
||||
|
|
|
@ -200,6 +200,7 @@ long DisFindSymByName(struct Dis *d, const char *s) {
|
|||
}
|
||||
|
||||
void DisLoadElf(struct Dis *d, struct Elf *elf) {
|
||||
LOGF("DisLoadElf");
|
||||
if (!elf || !elf->ehdr) return;
|
||||
DisLoadElfLoads(d, elf);
|
||||
DisLoadElfSyms(d, elf);
|
||||
|
|
|
@ -447,7 +447,11 @@ const char *DisSpecMap0(struct XedDecodedInst *x, char *p) {
|
|||
}
|
||||
|
||||
const char *DisSpecMap1(struct XedDecodedInst *x, char *p) {
|
||||
bool isreg;
|
||||
isreg = IsModrmRegister(x->op.rde);
|
||||
switch (x->op.opcode & 0xff) {
|
||||
RCASE(0x02, "lar %Gvqp Ev");
|
||||
RCASE(0x03, "lsl %Gvqp Ev");
|
||||
RCASE(0x05, "syscall");
|
||||
RCASE(0x0B, "ud2");
|
||||
RCASE(0x0D, "nop Ev");
|
||||
|
@ -464,7 +468,12 @@ const char *DisSpecMap1(struct XedDecodedInst *x, char *p) {
|
|||
RCASE(0x2B, "movntpSD Mps %Vps");
|
||||
RCASE(0x2E, Osz(x->op.rde) ? "ucomisd %Vsd Wsd" : "ucomiss %Vss Wss");
|
||||
RCASE(0x2F, Osz(x->op.rde) ? "comisd %Vsd Wsd" : "comiss %Vss Wss");
|
||||
RCASE(0x30, "wrmsr");
|
||||
RCASE(0x31, "rdtsc");
|
||||
RCASE(0x32, "rdmsr");
|
||||
RCASE(0x33, "rdpmc");
|
||||
RCASE(0x34, "sysenter");
|
||||
RCASE(0x35, "sysexit");
|
||||
RCASE(0x40 ... 0x4f, "cmovCC %Gvqp Evqp");
|
||||
RCASE(0x52, DisOpVpsWpsVssWss(x, p, "rsqrt"));
|
||||
RCASE(0x53, DisOpVpsWpsVssWss(x, p, "rcp"));
|
||||
|
@ -570,17 +579,76 @@ const char *DisSpecMap1(struct XedDecodedInst *x, char *p) {
|
|||
RCASE(0xFE, DisOpPqQqVdqWdq(x, p, "paddd"));
|
||||
RCASE(0xFF, "ud0 %Gvqp Evqp");
|
||||
case 0x01:
|
||||
if (ModrmMod(x->op.rde) == 0b11 && ModrmReg(x->op.rde) == 0b111 &&
|
||||
ModrmRm(x->op.rde) == 0b001) {
|
||||
return "rdtscp";
|
||||
} else if (!IsModrmRegister(x->op.rde) && ModrmReg(x->op.rde) == 0) {
|
||||
return "sgdt Ms";
|
||||
} else if (!IsModrmRegister(x->op.rde) && ModrmReg(x->op.rde) == 2) {
|
||||
return "lgdt Ms";
|
||||
} else {
|
||||
return UNKNOWN;
|
||||
switch (ModrmReg(x->op.rde)) {
|
||||
case 0:
|
||||
if (!isreg) {
|
||||
return "sgdt Ms";
|
||||
} else {
|
||||
switch (ModrmRm(x->op.rde)) {
|
||||
case 1:
|
||||
return "vmcall";
|
||||
case 2:
|
||||
return "vmlaunch";
|
||||
case 3:
|
||||
return "vmresume";
|
||||
case 4:
|
||||
return "vmxoff";
|
||||
default:
|
||||
return UNKNOWN;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
if (!isreg) {
|
||||
return "sidt Ms";
|
||||
} else {
|
||||
switch (ModrmRm(x->op.rde)) {
|
||||
case 0:
|
||||
return "monitor";
|
||||
case 1:
|
||||
return "mwait";
|
||||
default:
|
||||
return UNKNOWN;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
if (!isreg) {
|
||||
return "lgdt Ms";
|
||||
} else if (ModrmRm(x->op.rde) == 0) {
|
||||
return "xgetbv";
|
||||
} else if (ModrmRm(x->op.rde) == 1) {
|
||||
return "xsetbv";
|
||||
} else {
|
||||
return UNKNOWN;
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
if (!isreg) {
|
||||
return "lidt Ms";
|
||||
} else {
|
||||
return UNKNOWN;
|
||||
}
|
||||
case 4:
|
||||
return "smsw Ew";
|
||||
case 6:
|
||||
return "lmsw Ew";
|
||||
case 7:
|
||||
if (!isreg) {
|
||||
return "invlpg M";
|
||||
} else {
|
||||
switch (ModrmRm(x->op.rde)) {
|
||||
case 0:
|
||||
return "swapgs";
|
||||
case 1:
|
||||
return "rdtscp";
|
||||
default:
|
||||
return UNKNOWN;
|
||||
}
|
||||
}
|
||||
default:
|
||||
return UNKNOWN;
|
||||
}
|
||||
break;
|
||||
case 0x1F:
|
||||
if (ModrmMod(x->op.rde) == 1 && ModrmReg(x->op.rde) == 0 &&
|
||||
ModrmRm(x->op.rde) == 0b101) {
|
||||
|
@ -621,15 +689,42 @@ const char *DisSpecMap1(struct XedDecodedInst *x, char *p) {
|
|||
break;
|
||||
case 0xAE:
|
||||
switch (ModrmReg(x->op.rde)) {
|
||||
RCASE(0, "fxsave Mstx %st %st(1)");
|
||||
RCASE(1, "fxrstor Mstx %st %st(1)");
|
||||
RCASE(2, "ldmxcsr Md");
|
||||
RCASE(3, "stmxcsr Md");
|
||||
RCASE(4, "xsave M %edx %eax");
|
||||
RCASE(5, "lfence");
|
||||
RCASE(6, "mfence");
|
||||
case 0:
|
||||
if (isreg) {
|
||||
return "rdfsbase %Rdqp";
|
||||
} else {
|
||||
return "fxsave M";
|
||||
}
|
||||
case 1:
|
||||
if (isreg) {
|
||||
return "rdgsbase %Rdqp";
|
||||
} else {
|
||||
return "fxrstor M";
|
||||
}
|
||||
case 2:
|
||||
if (isreg) {
|
||||
return "wrfsbase %Rdqp";
|
||||
} else {
|
||||
return "ldmxcsr Md";
|
||||
}
|
||||
case 3:
|
||||
if (isreg) {
|
||||
return "wrgsbase %Rdqp";
|
||||
} else {
|
||||
return "stmxcsr Md";
|
||||
}
|
||||
case 4:
|
||||
if (isreg) {
|
||||
return UNKNOWN;
|
||||
} else {
|
||||
return "xsave M %edx %eax";
|
||||
}
|
||||
case 5:
|
||||
return "lfence";
|
||||
case 6:
|
||||
return "mfence";
|
||||
case 7:
|
||||
if (ModrmMod(x->op.rde) == 0b11 && ModrmReg(x->op.rde) == 0b111) {
|
||||
if (isreg && ModrmReg(x->op.rde) == 0b111) {
|
||||
return "sfence";
|
||||
} else {
|
||||
return "clflush";
|
||||
|
@ -668,13 +763,13 @@ const char *DisSpecMap1(struct XedDecodedInst *x, char *p) {
|
|||
break;
|
||||
case 0xC4:
|
||||
if (!Osz(x->op.rde)) {
|
||||
if (IsModrmRegister(x->op.rde)) {
|
||||
if (isreg) {
|
||||
return "pinsrw %Pq %Rdqp Ib";
|
||||
} else {
|
||||
return "pinsrw %Pq Mw Ib";
|
||||
}
|
||||
} else {
|
||||
if (IsModrmRegister(x->op.rde)) {
|
||||
if (isreg) {
|
||||
return "pinsrw %Vdq %Rdqp Ib";
|
||||
} else {
|
||||
return "pinsrw %Vdq Mw Ib";
|
||||
|
@ -696,10 +791,38 @@ const char *DisSpecMap1(struct XedDecodedInst *x, char *p) {
|
|||
}
|
||||
break;
|
||||
case 0xC7:
|
||||
if (Rexw(x->op.rde)) {
|
||||
return "cmpxchg16b Mdq";
|
||||
} else {
|
||||
return "cmpxchg8b Mq";
|
||||
switch (ModrmReg(x->op.rde)) {
|
||||
case 1:
|
||||
if (!isreg) {
|
||||
if (Rexw(x->op.rde)) {
|
||||
return "cmpxchg16b Mdq";
|
||||
} else {
|
||||
return "cmpxchg8b Mq";
|
||||
}
|
||||
} else {
|
||||
return UNKNOWN;
|
||||
}
|
||||
break;
|
||||
case 6:
|
||||
if (isreg) {
|
||||
return "rdrand %Rdqp";
|
||||
} else {
|
||||
return UNKNOWN;
|
||||
}
|
||||
break;
|
||||
case 7:
|
||||
if (isreg) {
|
||||
if (Rep(x->op.rde) == 3) {
|
||||
return "rdpid %Rdqp";
|
||||
} else {
|
||||
return "rdseed %Rdqp";
|
||||
}
|
||||
} else {
|
||||
return UNKNOWN;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return UNKNOWN;
|
||||
}
|
||||
break;
|
||||
case 0xD6:
|
||||
|
@ -714,7 +837,7 @@ const char *DisSpecMap1(struct XedDecodedInst *x, char *p) {
|
|||
case 0x12:
|
||||
switch (Rep(x->op.rde) | Osz(x->op.rde)) {
|
||||
case 0:
|
||||
if (IsModrmRegister(x->op.rde)) {
|
||||
if (isreg) {
|
||||
return "movhlps %Vq %Uq";
|
||||
} else {
|
||||
return "movlps %Vq Mq";
|
||||
|
@ -740,7 +863,7 @@ const char *DisSpecMap1(struct XedDecodedInst *x, char *p) {
|
|||
case 0x16:
|
||||
switch (Rep(x->op.rde) | Osz(x->op.rde)) {
|
||||
case 0:
|
||||
if (IsModrmRegister(x->op.rde)) {
|
||||
if (isreg) {
|
||||
return "movlhps %Vq %Uq";
|
||||
} else {
|
||||
return "movhps %Vq Mq";
|
||||
|
@ -938,6 +1061,20 @@ const char *DisSpecMap2(struct XedDecodedInst *x, char *p) {
|
|||
RCASE(0x41, "phminposuw %Vdq Wdq");
|
||||
RCASE(0x80, "invept %Gq Mdq");
|
||||
RCASE(0x81, "invvpid %Gq Mdq");
|
||||
case 0xF0:
|
||||
if (Rep(x->op.rde) == 2) {
|
||||
return "crc32 %Gvqp Eb";
|
||||
} else {
|
||||
return "movbe %Gvqp M";
|
||||
}
|
||||
break;
|
||||
case 0xF1:
|
||||
if (Rep(x->op.rde) == 2) {
|
||||
return "crc32 %Gvqp Evqp";
|
||||
} else {
|
||||
return "movbe M %Gvqp";
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return UNKNOWN;
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/struct/iovec.h"
|
||||
#include "libc/nexgen32e/uart.h"
|
||||
#include "libc/sysv/consts/fileno.h"
|
||||
#include "tool/build/lib/ioports.h"
|
||||
|
||||
|
@ -42,10 +43,42 @@ static void OpE9Write(struct Machine *m, uint8_t b) {
|
|||
m->fds.p[fd].cb->writev(m->fds.p[fd].fd, &(struct iovec){&b, 1}, 1);
|
||||
}
|
||||
|
||||
static int OpSerialIn(struct Machine *m, int r) {
|
||||
switch (r) {
|
||||
case UART_DLL:
|
||||
if (!m->dlab) {
|
||||
return OpE9Read(m);
|
||||
} else {
|
||||
return 0x01;
|
||||
}
|
||||
case UART_LSR:
|
||||
return UART_TTYDA | UART_TTYTXR | UART_TTYIDL;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void OpSerialOut(struct Machine *m, int r, uint32_t x) {
|
||||
switch (r) {
|
||||
case UART_DLL:
|
||||
if (!m->dlab) {
|
||||
return OpE9Write(m, x);
|
||||
}
|
||||
break;
|
||||
case UART_LCR:
|
||||
m->dlab = !!(x & UART_DLAB);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t OpIn(struct Machine *m, uint16_t p) {
|
||||
switch (p) {
|
||||
case 0xE9:
|
||||
return OpE9Read(m);
|
||||
case 0x3F8 ... 0x3FF:
|
||||
return OpSerialIn(m, p - 0x3F8);
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
@ -56,6 +89,9 @@ void OpOut(struct Machine *m, uint16_t p, uint32_t x) {
|
|||
case 0xE9:
|
||||
OpE9Write(m, x);
|
||||
break;
|
||||
case 0x3F8 ... 0x3FF:
|
||||
OpSerialOut(m, p - 0x3F8, x);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -109,6 +109,29 @@ static void LoadBin(struct Machine *m, intptr_t base, const char *prog,
|
|||
m->ip = base;
|
||||
}
|
||||
|
||||
static void BootProgram(struct Machine *m, struct Elf *elf, size_t codesize) {
|
||||
m->ip = 0x7c00;
|
||||
elf->base = 0x7c00;
|
||||
CHECK_NE(-1, ReserveReal(m, 0x00f00000));
|
||||
memset(m->real.p, 0, 0x00f00000);
|
||||
Write16(m->real.p + 0x400, 0x3F8);
|
||||
Write16(m->real.p + 0x40E, 0xb0000 >> 4);
|
||||
Write16(m->real.p + 0x413, 0xb0000 / 1024);
|
||||
Write16(m->real.p + 0x44A, 80);
|
||||
Write64(m->cs, 0);
|
||||
Write64(m->dx, 0);
|
||||
memcpy(m->real.p + 0x7c00, elf->map, 512);
|
||||
if (memcmp(elf->map, "\177ELF", 4) == 0) {
|
||||
elf->ehdr = (void *)elf->map;
|
||||
elf->size = codesize;
|
||||
elf->base = elf->ehdr->e_entry;
|
||||
} else {
|
||||
elf->base = 0x7c00;
|
||||
elf->ehdr = NULL;
|
||||
elf->size = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void LoadProgram(struct Machine *m, const char *prog, char **args, char **vars,
|
||||
struct Elf *elf) {
|
||||
int fd;
|
||||
|
@ -147,21 +170,7 @@ void LoadProgram(struct Machine *m, const char *prog, char **args, char **vars,
|
|||
CHECK_NE(-1, close(fd));
|
||||
ResetCpu(m);
|
||||
if ((m->mode & 3) == XED_MODE_REAL) {
|
||||
elf->base = 0x7c00;
|
||||
CHECK_NE(-1, ReserveReal(m, BIGPAGESIZE));
|
||||
m->ip = 0x7c00;
|
||||
Write64(m->cs, 0);
|
||||
Write64(m->dx, 0);
|
||||
VirtualRecv(m, m->ip, elf->map, 512);
|
||||
if (memcmp(elf->map, "\177ELF", 4) == 0) {
|
||||
elf->ehdr = (void *)elf->map;
|
||||
elf->size = codesize;
|
||||
elf->base = elf->ehdr->e_entry;
|
||||
} else {
|
||||
elf->base = 0x7c00;
|
||||
elf->ehdr = NULL;
|
||||
elf->size = 0;
|
||||
}
|
||||
BootProgram(m, elf, codesize);
|
||||
} else {
|
||||
sp = 0x800000000000;
|
||||
Write64(m->sp, sp);
|
||||
|
|
|
@ -17,7 +17,9 @@
|
|||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/macros.h"
|
||||
#include "libc/rand/rand.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "tool/build/lib/abp.h"
|
||||
#include "tool/build/lib/address.h"
|
||||
|
@ -202,14 +204,87 @@ static relegated void OpMovEvqpSw(struct Machine *m, uint32_t rde) {
|
|||
Read64(GetSegment(m, rde, ModrmReg(rde))) >> 4);
|
||||
}
|
||||
|
||||
static relegated void OpMovSwEvqp(struct Machine *m, uint32_t rde) {
|
||||
Write64(GetSegment(m, rde, ModrmReg(rde)),
|
||||
ReadMemory(rde, GetModrmRegisterWordPointerReadOszRexw(m, rde)) << 4);
|
||||
static relegated int GetDescriptor(struct Machine *m, int selector,
|
||||
uint64_t *out_descriptor) {
|
||||
uint8_t buf[8];
|
||||
DCHECK(m->gdt_base + m->gdt_limit <= m->real.n);
|
||||
selector &= -8;
|
||||
if (8 <= selector && selector + 8 <= m->gdt_limit) {
|
||||
SetReadAddr(m, m->gdt_base + selector, 8);
|
||||
*out_descriptor = Read64(m->real.p + m->gdt_base + selector);
|
||||
return 0;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static relegated void OpJmpf(struct Machine *m, uint32_t rde) {
|
||||
Write64(m->cs, m->xedd->op.uimm0 << 4);
|
||||
m->ip = m->xedd->op.disp;
|
||||
static uint64_t GetDescriptorBase(uint64_t d) {
|
||||
return (d & 0xff00000000000000) >> 32 | (d & 0x000000ffffff0000) >> 16;
|
||||
}
|
||||
|
||||
static uint64_t GetDescriptorLimit(uint64_t d) {
|
||||
return (d & 0x000f000000000000) >> 32 | d & 0xffff;
|
||||
}
|
||||
|
||||
static int GetDescriptorMode(uint64_t d) {
|
||||
uint8_t kMode[] = {
|
||||
XED_MACHINE_MODE_REAL,
|
||||
XED_MACHINE_MODE_LONG_64,
|
||||
XED_MACHINE_MODE_LEGACY_32,
|
||||
XED_MACHINE_MODE_LONG_64,
|
||||
};
|
||||
return kMode[(d & 0x0060000000000000) >> 53];
|
||||
}
|
||||
|
||||
static bool IsProtectedMode(struct Machine *m) {
|
||||
return m->cr0 & 1;
|
||||
}
|
||||
|
||||
static relegated void OpMovSwEvqp(struct Machine *m, uint32_t rde) {
|
||||
uint64_t x, d;
|
||||
x = ReadMemory(rde, GetModrmRegisterWordPointerReadOszRexw(m, rde));
|
||||
if (!IsProtectedMode(m)) {
|
||||
x <<= 4;
|
||||
} else if (GetDescriptor(m, x, &d) != -1) {
|
||||
x = GetDescriptorBase(d);
|
||||
} else {
|
||||
ThrowProtectionFault(m);
|
||||
}
|
||||
Write64(GetSegment(m, rde, ModrmReg(rde)), x);
|
||||
}
|
||||
|
||||
static void OpLsl(struct Machine *m, uint32_t rde) {
|
||||
uint64_t descriptor;
|
||||
if (GetDescriptor(m, Read16(GetModrmRegisterWordPointerRead2(m, rde)),
|
||||
&descriptor) != -1) {
|
||||
WriteRegister(rde, RegRexrReg(m, rde), GetDescriptorLimit(descriptor));
|
||||
SetFlag(m->flags, FLAGS_ZF, true);
|
||||
} else {
|
||||
SetFlag(m->flags, FLAGS_ZF, false);
|
||||
}
|
||||
}
|
||||
|
||||
static void ChangeMachineMode(struct Machine *m, int mode) {
|
||||
if (mode == m->mode) return;
|
||||
ResetInstructionCache(m);
|
||||
m->mode = mode;
|
||||
}
|
||||
|
||||
static void OpJmpf(struct Machine *m, uint32_t rde) {
|
||||
uint64_t descriptor;
|
||||
if (!IsProtectedMode(m)) {
|
||||
Write64(m->cs, m->xedd->op.uimm0 << 4);
|
||||
m->ip = m->xedd->op.disp;
|
||||
} else if (GetDescriptor(m, m->xedd->op.uimm0, &descriptor) != -1) {
|
||||
Write64(m->cs, GetDescriptorBase(descriptor));
|
||||
m->ip = m->xedd->op.disp;
|
||||
ChangeMachineMode(m, GetDescriptorMode(descriptor));
|
||||
} else {
|
||||
ThrowProtectionFault(m);
|
||||
}
|
||||
if (m->onlongbranch) {
|
||||
m->onlongbranch(m);
|
||||
}
|
||||
}
|
||||
|
||||
static relegated void OpXlatAlBbb(struct Machine *m, uint32_t rde) {
|
||||
|
@ -373,11 +448,49 @@ static void OpCmpxchg16b(struct Machine *m, uint32_t rde) {
|
|||
}
|
||||
}
|
||||
|
||||
static void OpCmpxchgDxAx(struct Machine *m, uint32_t rde) {
|
||||
if (Rexw(rde)) {
|
||||
OpCmpxchg16b(m, rde);
|
||||
} else {
|
||||
OpCmpxchg8b(m, rde);
|
||||
static void OpRdrand(struct Machine *m, uint32_t rde) {
|
||||
WriteRegister(rde, RegRexbRm(m, rde), rand64());
|
||||
}
|
||||
|
||||
static void OpRdseed(struct Machine *m, uint32_t rde) {
|
||||
OpRdrand(m, rde);
|
||||
}
|
||||
|
||||
static void Op1c7(struct Machine *m, uint32_t rde) {
|
||||
bool ismem;
|
||||
ismem = !IsModrmRegister(rde);
|
||||
switch (ModrmReg(rde)) {
|
||||
case 1:
|
||||
if (ismem) {
|
||||
if (Rexw(rde)) {
|
||||
OpCmpxchg16b(m, rde);
|
||||
} else {
|
||||
OpCmpxchg8b(m, rde);
|
||||
}
|
||||
} else {
|
||||
OpUd(m, rde);
|
||||
}
|
||||
break;
|
||||
case 6:
|
||||
if (!ismem) {
|
||||
OpRdrand(m, rde);
|
||||
} else {
|
||||
OpUd(m, rde);
|
||||
}
|
||||
break;
|
||||
case 7:
|
||||
if (!ismem) {
|
||||
if (Rep(rde) == 3) {
|
||||
OpRdpid(m, rde);
|
||||
} else {
|
||||
OpRdseed(m, rde);
|
||||
}
|
||||
} else {
|
||||
OpUd(m, rde);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
OpUd(m, rde);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -699,8 +812,7 @@ static void OpAlubFlipTest(struct Machine *m, uint32_t rde) {
|
|||
}
|
||||
|
||||
static void Alubi(struct Machine *m, uint32_t rde, aluop_f op) {
|
||||
uint8_t *a, x;
|
||||
a = GetModrmRegisterBytePointerWrite(m, rde);
|
||||
uint8_t *a = GetModrmRegisterBytePointerWrite(m, rde);
|
||||
Write8(a, op(Read8(a), m->xedd->op.uimm0, &m->flags));
|
||||
}
|
||||
|
||||
|
@ -770,7 +882,6 @@ static void OpAluwFlipTest(struct Machine *m, uint32_t rde) {
|
|||
|
||||
static void Aluwi(struct Machine *m, uint32_t rde, aluop_f ops[4]) {
|
||||
uint8_t *a;
|
||||
uint64_t x;
|
||||
a = GetModrmRegisterWordPointerWriteOszRexw(m, rde);
|
||||
WriteRegisterOrMemory(
|
||||
rde, a,
|
||||
|
@ -1339,8 +1450,105 @@ static void OpDoubleShift(struct Machine *m, uint32_t rde) {
|
|||
m->xedd->op.opcode & 8, &m->flags));
|
||||
}
|
||||
|
||||
static void OpFxsave(struct Machine *m, uint32_t rde) {
|
||||
int64_t v;
|
||||
uint8_t buf[32];
|
||||
memset(buf, 0, 32);
|
||||
Write16(buf + 0, m->fpu.cw);
|
||||
Write16(buf + 2, m->fpu.sw);
|
||||
Write8(buf + 4, m->fpu.tw);
|
||||
Write16(buf + 6, m->fpu.op);
|
||||
Write32(buf + 8, m->fpu.ip);
|
||||
Write32(buf + 24, m->sse.mxcsr);
|
||||
v = ComputeAddress(m, rde);
|
||||
VirtualRecv(m, v + 0, buf, 32);
|
||||
VirtualRecv(m, v + 32, m->fpu.st, 128);
|
||||
VirtualRecv(m, v + 160, m->xmm, 256);
|
||||
SetWriteAddr(m, v, 416);
|
||||
}
|
||||
|
||||
static void OpFxrstor(struct Machine *m, uint32_t rde) {
|
||||
int64_t v;
|
||||
uint8_t buf[32];
|
||||
v = ComputeAddress(m, rde);
|
||||
SetReadAddr(m, v, 416);
|
||||
VirtualSend(m, buf, v + 0, 32);
|
||||
VirtualSend(m, m->fpu.st, v + 32, 128);
|
||||
VirtualSend(m, m->xmm, v + 160, 256);
|
||||
m->fpu.cw = Read16(buf + 0);
|
||||
m->fpu.sw = Read16(buf + 2);
|
||||
m->fpu.tw = Read8(buf + 4);
|
||||
m->fpu.op = Read16(buf + 6);
|
||||
m->fpu.ip = Read32(buf + 8);
|
||||
m->sse.mxcsr = Read32(buf + 24);
|
||||
}
|
||||
|
||||
static void OpXsave(struct Machine *m, uint32_t rde) {
|
||||
}
|
||||
|
||||
static void OpLdmxcsr(struct Machine *m, uint32_t rde) {
|
||||
m->sse.mxcsr = Read32(ComputeReserveAddressRead4(m, rde));
|
||||
}
|
||||
|
||||
static void OpStmxcsr(struct Machine *m, uint32_t rde) {
|
||||
Write32(ComputeReserveAddressWrite4(m, rde), m->sse.mxcsr);
|
||||
}
|
||||
|
||||
static void OpRdfsbase(struct Machine *m, uint32_t rde) {
|
||||
WriteRegister(rde, RegRexbRm(m, rde), Read64(m->fs));
|
||||
}
|
||||
|
||||
static void OpRdgsbase(struct Machine *m, uint32_t rde) {
|
||||
WriteRegister(rde, RegRexbRm(m, rde), Read64(m->gs));
|
||||
}
|
||||
|
||||
static void OpWrfsbase(struct Machine *m, uint32_t rde) {
|
||||
Write64(m->fs, ReadMemory(rde, RegRexbRm(m, rde)));
|
||||
}
|
||||
|
||||
static void OpWrgsbase(struct Machine *m, uint32_t rde) {
|
||||
Write64(m->gs, ReadMemory(rde, RegRexbRm(m, rde)));
|
||||
}
|
||||
|
||||
static void Op1ae(struct Machine *m, uint32_t rde) {
|
||||
bool ismem;
|
||||
ismem = !IsModrmRegister(rde);
|
||||
switch (ModrmReg(rde)) {
|
||||
case 0:
|
||||
if (ismem) {
|
||||
OpFxsave(m, rde);
|
||||
} else {
|
||||
OpRdfsbase(m, rde);
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
if (ismem) {
|
||||
OpFxrstor(m, rde);
|
||||
} else {
|
||||
OpRdgsbase(m, rde);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
if (ismem) {
|
||||
OpLdmxcsr(m, rde);
|
||||
} else {
|
||||
OpWrfsbase(m, rde);
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
if (ismem) {
|
||||
OpStmxcsr(m, rde);
|
||||
} else {
|
||||
OpWrgsbase(m, rde);
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
if (ismem) {
|
||||
OpXsave(m, rde);
|
||||
} else {
|
||||
OpUd(m, rde);
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
OpLfence(m, rde);
|
||||
break;
|
||||
|
@ -1348,10 +1556,10 @@ static void Op1ae(struct Machine *m, uint32_t rde) {
|
|||
OpMfence(m, rde);
|
||||
break;
|
||||
case 7:
|
||||
if (ModrmMod(rde) == 0b11 && ModrmReg(rde) == 0b111) {
|
||||
OpSfence(m, rde);
|
||||
} else {
|
||||
if (ismem) {
|
||||
OpClflush(m, rde);
|
||||
} else {
|
||||
OpSfence(m, rde);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
@ -1363,11 +1571,32 @@ static void OpSalc(struct Machine *m, uint32_t rde) {
|
|||
Write8(m->ax, GetFlag(m->flags, FLAGS_CF));
|
||||
}
|
||||
|
||||
static void OpBofram(struct Machine *m, uint32_t rde) {
|
||||
if (m->xedd->op.disp) {
|
||||
m->bofram[0] = m->ip;
|
||||
m->bofram[1] = m->ip + (m->xedd->op.disp & 0xff);
|
||||
} else {
|
||||
m->bofram[0] = 0;
|
||||
m->bofram[1] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void OpBinbase(struct Machine *m, uint32_t rde) {
|
||||
if (m->onbinbase) {
|
||||
m->onbinbase(m);
|
||||
}
|
||||
}
|
||||
|
||||
static void OpNopEv(struct Machine *m, uint32_t rde) {
|
||||
switch (ModrmMod(rde) << 6 | ModrmReg(rde) << 3 | ModrmRm(rde)) {
|
||||
case 0x45:
|
||||
case 0105:
|
||||
OpBofram(m, rde);
|
||||
break;
|
||||
case 0007:
|
||||
case 0107:
|
||||
case 0207:
|
||||
OpBinbase(m, rde);
|
||||
break;
|
||||
default:
|
||||
OpNoop(m, rde);
|
||||
}
|
||||
|
@ -1421,6 +1650,14 @@ static void OpMovCqRq(struct Machine *m, uint32_t rde) {
|
|||
}
|
||||
}
|
||||
|
||||
static void OpWrmsr(struct Machine *m, uint32_t rde) {
|
||||
}
|
||||
|
||||
static void OpRdmsr(struct Machine *m, uint32_t rde) {
|
||||
Write32(m->dx, 0);
|
||||
Write32(m->ax, 0);
|
||||
}
|
||||
|
||||
static const nexgen32e_f kNexgen32e[] = {
|
||||
[0x000] = OpAlubAdd,
|
||||
[0x001] = OpAluw,
|
||||
|
@ -1681,7 +1918,7 @@ static const nexgen32e_f kNexgen32e[] = {
|
|||
[0x100] = OpUd,
|
||||
[0x101] = Op101,
|
||||
[0x102] = OpUd,
|
||||
[0x103] = OpUd,
|
||||
[0x103] = OpLsl,
|
||||
[0x104] = OpUd,
|
||||
[0x105] = OpSyscall,
|
||||
[0x106] = OpUd,
|
||||
|
@ -1708,7 +1945,7 @@ static const nexgen32e_f kNexgen32e[] = {
|
|||
[0x11B] = OpHintNopEv,
|
||||
[0x11C] = OpHintNopEv,
|
||||
[0x11D] = OpHintNopEv,
|
||||
[0x11E] = OpUd,
|
||||
[0x11E] = OpHintNopEv,
|
||||
[0x11F] = OpNopEv,
|
||||
[0x120] = OpMovRqCq,
|
||||
[0x121] = OpUd,
|
||||
|
@ -1726,9 +1963,9 @@ static const nexgen32e_f kNexgen32e[] = {
|
|||
[0x12D] = OpCvt0f2d,
|
||||
[0x12E] = OpComissVsWs,
|
||||
[0x12F] = OpComissVsWs,
|
||||
[0x130] = OpUd,
|
||||
[0x130] = OpWrmsr,
|
||||
[0x131] = OpRdtsc,
|
||||
[0x132] = OpUd,
|
||||
[0x132] = OpRdmsr,
|
||||
[0x133] = OpUd,
|
||||
[0x134] = OpUd,
|
||||
[0x135] = OpUd,
|
||||
|
@ -1877,7 +2114,7 @@ static const nexgen32e_f kNexgen32e[] = {
|
|||
[0x1C4] = OpPinsrwVdqEwIb,
|
||||
[0x1C5] = OpPextrwGdqpUdqIb,
|
||||
[0x1C6] = OpShufpsd,
|
||||
[0x1C7] = OpCmpxchgDxAx,
|
||||
[0x1C7] = Op1c7,
|
||||
[0x1C8] = OpBswapZvqp,
|
||||
[0x1C9] = OpBswapZvqp,
|
||||
[0x1CA] = OpBswapZvqp,
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
#include "libc/runtime/runtime.h"
|
||||
#include "third_party/xed/x86.h"
|
||||
#include "tool/build/lib/fds.h"
|
||||
#include "tool/build/lib/pml4t.h"
|
||||
|
||||
#define kMachineHalt -1
|
||||
#define kMachineDecodeError -2
|
||||
|
@ -134,6 +133,10 @@ struct Machine {
|
|||
uint64_t cr0;
|
||||
uint64_t cr2;
|
||||
uint64_t cr4;
|
||||
uint64_t gdt_base;
|
||||
uint64_t idt_base;
|
||||
uint16_t gdt_limit;
|
||||
uint16_t idt_limit;
|
||||
struct MachineRealFree {
|
||||
uint64_t i;
|
||||
uint64_t n;
|
||||
|
@ -156,9 +159,12 @@ struct Machine {
|
|||
int64_t bofram[2];
|
||||
jmp_buf onhalt;
|
||||
int64_t faultaddr;
|
||||
bool dlab;
|
||||
struct MachineFds fds;
|
||||
uint8_t stash[4096];
|
||||
uint8_t icache[1024][40];
|
||||
void (*onbinbase)(struct Machine *);
|
||||
void (*onlongbranch)(struct Machine *);
|
||||
} aligned(64);
|
||||
|
||||
struct Machine *NewMachine(void) nodiscard;
|
||||
|
@ -166,6 +172,7 @@ void FreeMachine(struct Machine *);
|
|||
void ResetMem(struct Machine *);
|
||||
void ResetCpu(struct Machine *);
|
||||
void ResetTlb(struct Machine *);
|
||||
void ResetInstructionCache(struct Machine *);
|
||||
void LoadInstruction(struct Machine *);
|
||||
void ExecuteInstruction(struct Machine *);
|
||||
long AllocateLinearPage(struct Machine *);
|
||||
|
|
|
@ -143,10 +143,20 @@ void *VirtualSend(struct Machine *m, void *dst, int64_t src, uint64_t n) {
|
|||
return dst;
|
||||
}
|
||||
|
||||
void VirtualSendRead(struct Machine *m, void *dst, int64_t addr, uint64_t n) {
|
||||
VirtualSend(m, dst, addr, n);
|
||||
SetReadAddr(m, addr, n);
|
||||
}
|
||||
|
||||
void VirtualRecv(struct Machine *m, int64_t dst, void *src, uint64_t n) {
|
||||
VirtualCopy(m, dst, src, n, false);
|
||||
}
|
||||
|
||||
void VirtualRecvWrite(struct Machine *m, int64_t addr, void *src, uint64_t n) {
|
||||
VirtualRecv(m, addr, src, n);
|
||||
SetWriteAddr(m, addr, n);
|
||||
}
|
||||
|
||||
void *ReserveAddress(struct Machine *m, int64_t v, size_t n) {
|
||||
void *r;
|
||||
DCHECK_LE(n, sizeof(m->stash));
|
||||
|
|
|
@ -25,6 +25,8 @@ void VirtualRecv(struct Machine *, int64_t, void *, uint64_t);
|
|||
void *VirtualSend(struct Machine *, void *, int64_t, uint64_t);
|
||||
void VirtualSet(struct Machine *, int64_t, char, uint64_t);
|
||||
void *RealAddress(struct Machine *, int64_t);
|
||||
void VirtualSendRead(struct Machine *, void *, int64_t, uint64_t);
|
||||
void VirtualRecvWrite(struct Machine *, int64_t, void *, uint64_t);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
|
|
|
@ -17,22 +17,79 @@
|
|||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/log/log.h"
|
||||
#include "tool/build/lib/endian.h"
|
||||
#include "tool/build/lib/memory.h"
|
||||
#include "tool/build/lib/modrm.h"
|
||||
#include "tool/build/lib/op101.h"
|
||||
#include "tool/build/lib/throw.h"
|
||||
#include "tool/build/lib/time.h"
|
||||
|
||||
static void StoreDescriptorTable(struct Machine *m, uint32_t rde,
|
||||
uint16_t limit, uint64_t base) {
|
||||
uint64_t l;
|
||||
l = ComputeAddress(m, rde);
|
||||
if (l + 10 <= m->real.n) {
|
||||
Write16(m->real.p + l, limit);
|
||||
if (Rexw(rde)) {
|
||||
Write64(m->real.p + l + 2, base);
|
||||
SetWriteAddr(m, l, 10);
|
||||
} else if (!Osz(rde)) {
|
||||
Write32(m->real.p + l + 2, base);
|
||||
SetWriteAddr(m, l, 6);
|
||||
} else {
|
||||
Write16(m->real.p + l + 2, base);
|
||||
SetWriteAddr(m, l, 4);
|
||||
}
|
||||
} else {
|
||||
ThrowSegmentationFault(m, l);
|
||||
}
|
||||
}
|
||||
|
||||
static void LoadDescriptorTable(struct Machine *m, uint32_t rde,
|
||||
uint16_t *out_limit, uint64_t *out_base) {
|
||||
uint16_t limit;
|
||||
uint64_t l, base;
|
||||
l = ComputeAddress(m, rde);
|
||||
if (l + 10 <= m->real.n) {
|
||||
limit = Read16(m->real.p + l);
|
||||
if (Rexw(rde)) {
|
||||
base = Read64(m->real.p + l + 2) & 0x00ffffff;
|
||||
SetReadAddr(m, l, 10);
|
||||
} else if (!Osz(rde)) {
|
||||
base = Read32(m->real.p + l + 2);
|
||||
SetReadAddr(m, l, 6);
|
||||
} else {
|
||||
base = Read16(m->real.p + l + 2);
|
||||
SetReadAddr(m, l, 4);
|
||||
}
|
||||
if (base + limit <= m->real.n) {
|
||||
*out_limit = limit;
|
||||
*out_base = base;
|
||||
} else {
|
||||
ThrowProtectionFault(m);
|
||||
}
|
||||
} else {
|
||||
ThrowSegmentationFault(m, l);
|
||||
}
|
||||
}
|
||||
|
||||
static void SgdtMs(struct Machine *m, uint32_t rde) {
|
||||
StoreDescriptorTable(m, rde, m->gdt_limit, m->gdt_base);
|
||||
}
|
||||
|
||||
static void LgdtMs(struct Machine *m, uint32_t rde) {
|
||||
LoadDescriptorTable(m, rde, &m->gdt_limit, &m->gdt_base);
|
||||
LOGF("set gdt %p lim %,d", m->gdt_base, m->gdt_limit);
|
||||
}
|
||||
|
||||
static void SidtMs(struct Machine *m, uint32_t rde) {
|
||||
StoreDescriptorTable(m, rde, m->idt_limit, m->idt_base);
|
||||
}
|
||||
|
||||
static void LidtMs(struct Machine *m, uint32_t rde) {
|
||||
LoadDescriptorTable(m, rde, &m->idt_limit, &m->idt_base);
|
||||
LOGF("set idt %p lim %,d", m->idt_base, m->idt_limit);
|
||||
}
|
||||
|
||||
static void Monitor(struct Machine *m, uint32_t rde) {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-bansic-offset:2;tab-width:8;coding:utf-8
|
||||
-*-│ │vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
|
|
|
@ -62,6 +62,10 @@ static void ResetSse(struct Machine *m) {
|
|||
memset(m->xmm, 0, sizeof(m->xmm));
|
||||
}
|
||||
|
||||
void ResetInstructionCache(struct Machine *m) {
|
||||
memset(m->icache, -1, sizeof(m->icache));
|
||||
}
|
||||
|
||||
void ResetCpu(struct Machine *m) {
|
||||
m->faultaddr = 0;
|
||||
m->stashsize = 0;
|
||||
|
|
|
@ -186,16 +186,6 @@ void OpRet(struct Machine *m, uint32_t rde) {
|
|||
m->ip = Pop(m, rde, m->xedd->op.uimm0);
|
||||
}
|
||||
|
||||
void OpBofram(struct Machine *m, uint32_t rde) {
|
||||
if (m->xedd->op.disp) {
|
||||
m->bofram[0] = m->ip;
|
||||
m->bofram[1] = m->ip + (m->xedd->op.disp & 0xff);
|
||||
} else {
|
||||
m->bofram[0] = 0;
|
||||
m->bofram[1] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void OpPushEvq(struct Machine *m, uint32_t rde) {
|
||||
unsigned osz;
|
||||
osz = kStackOsz[m->xedd->op.osz][Mode(rde)];
|
||||
|
@ -303,9 +293,15 @@ relegated void OpCallf(struct Machine *m, uint32_t rde) {
|
|||
Push(m, rde, m->ip);
|
||||
Write64(m->cs, m->xedd->op.uimm0 << 4);
|
||||
m->ip = m->xedd->op.disp & (Osz(rde) ? 0xffff : 0xffffffff);
|
||||
if (m->onlongbranch) {
|
||||
m->onlongbranch(m);
|
||||
}
|
||||
}
|
||||
|
||||
relegated void OpRetf(struct Machine *m, uint32_t rde) {
|
||||
m->ip = Pop(m, rde, 0);
|
||||
Write64(m->cs, Pop(m, rde, m->xedd->op.uimm0) << 4);
|
||||
if (m->onlongbranch) {
|
||||
m->onlongbranch(m);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,7 +11,6 @@ void OpRet(struct Machine *, uint32_t);
|
|||
void OpRetf(struct Machine *, uint32_t);
|
||||
void OpLeave(struct Machine *, uint32_t);
|
||||
void OpCallEq(struct Machine *, uint32_t);
|
||||
void OpBofram(struct Machine *, uint32_t);
|
||||
void OpPopEvq(struct Machine *, uint32_t);
|
||||
void OpPopZvq(struct Machine *, uint32_t);
|
||||
void OpPushZvq(struct Machine *, uint32_t);
|
||||
|
|
|
@ -422,18 +422,6 @@ static const char *GetSimulated(void) {
|
|||
}
|
||||
}
|
||||
|
||||
static void VirtualSendRead(struct Machine *m, void *dst, int64_t addr,
|
||||
uint64_t n) {
|
||||
VirtualSend(m, dst, addr, n);
|
||||
SetReadAddr(m, addr, n);
|
||||
}
|
||||
|
||||
static void VirtualRecvWrite(struct Machine *m, int64_t addr, void *src,
|
||||
uint64_t n) {
|
||||
VirtualRecv(m, addr, src, n);
|
||||
SetWriteAddr(m, addr, n);
|
||||
}
|
||||
|
||||
static int AppendIovsReal(struct Machine *m, struct Iovs *ib, int64_t addr,
|
||||
size_t size) {
|
||||
void *real;
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "libc/sysv/consts/clock.h"
|
||||
#include "libc/time/time.h"
|
||||
#include "tool/build/lib/endian.h"
|
||||
#include "tool/build/lib/modrm.h"
|
||||
#include "tool/build/lib/time.h"
|
||||
|
||||
/**
|
||||
|
@ -41,11 +42,18 @@ void OpRdtsc(struct Machine *m, uint32_t rde) {
|
|||
Write64(m->dx, (c >> 040) & 0xffffffff);
|
||||
}
|
||||
|
||||
void OpRdtscp(struct Machine *m, uint32_t rde) {
|
||||
uint32_t core, node, tscaux;
|
||||
OpRdtsc(m, rde);
|
||||
static int64_t GetTscAux(struct Machine *m) {
|
||||
uint32_t core, node;
|
||||
core = 0;
|
||||
node = 0;
|
||||
tscaux = (node & 0xfff) << 12 | (core & 0xfff);
|
||||
Write64(m->cx, tscaux & 0xffffffff);
|
||||
return (node & 0xfff) << 12 | (core & 0xfff);
|
||||
}
|
||||
|
||||
void OpRdtscp(struct Machine *m, uint32_t rde) {
|
||||
OpRdtsc(m, rde);
|
||||
Write64(m->cx, GetTscAux(m));
|
||||
}
|
||||
|
||||
void OpRdpid(struct Machine *m, uint32_t rde) {
|
||||
Write64(RegRexbRm(m, rde), GetTscAux(m));
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ COSMOPOLITAN_C_START_
|
|||
void OpPause(struct Machine *, uint32_t);
|
||||
void OpRdtsc(struct Machine *, uint32_t);
|
||||
void OpRdtscp(struct Machine *, uint32_t);
|
||||
void OpRdpid(struct Machine *, uint32_t);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue