Add minor improvements and cleanup

This commit is contained in:
Justine Tunney 2020-10-27 03:39:46 -07:00
parent 9e3e985ae5
commit feed0d2b0e
163 changed files with 2286 additions and 2245 deletions

View file

@ -37,15 +37,6 @@ const aluop_f kBsu[8][4] = {
{Shl8, Shl16, Shl32, Shl64}, {Sar8, Sar16, Sar32, Sar64},
};
int64_t AluFlags(uint64_t x, uint32_t af, uint32_t *f, uint32_t of, uint32_t cf,
uint32_t sf) {
*f &= ~(1u << FLAGS_CF | 1u << FLAGS_ZF | 1u << FLAGS_SF | 1u << FLAGS_OF |
1u << FLAGS_AF | 0xFF000000u);
*f |= sf << FLAGS_SF | cf << FLAGS_CF | !x << FLAGS_ZF | of << FLAGS_OF |
af << FLAGS_AF | (x & 0xFF) << 24;
return x;
}
int64_t AluFlags8(uint8_t z, uint32_t af, uint32_t *f, uint32_t of,
uint32_t cf) {
return AluFlags(z, af, f, of, cf, z >> 7);

View file

@ -108,7 +108,6 @@ int64_t Rcl64(uint64_t, uint64_t, uint32_t *);
uint64_t BsuDoubleShift(int, uint64_t, uint64_t, uint8_t, bool, uint32_t *);
int64_t AluFlags(uint64_t, uint32_t, uint32_t *, uint32_t, uint32_t, uint32_t);
int64_t AluFlags8(uint8_t, uint32_t, uint32_t *, uint32_t, uint32_t);
int64_t AluFlags16(uint16_t, uint32_t, uint32_t *, uint32_t, uint32_t);
int64_t AluFlags32(uint32_t, uint32_t, uint32_t *, uint32_t, uint32_t);

View file

@ -49,16 +49,17 @@ void AppendWide(struct Buffer *b, wint_t wc) {
} while (wb);
}
void AppendFmt(struct Buffer *b, const char *fmt, ...) {
int size;
int AppendFmt(struct Buffer *b, const char *fmt, ...) {
int bytes;
char *tmp;
va_list va;
tmp = NULL;
va_start(va, fmt);
size = vasprintf(&tmp, fmt, va);
bytes = vasprintf(&tmp, fmt, va);
va_end(va);
if (size != -1) AppendData(b, tmp, size);
if (bytes != -1) AppendData(b, tmp, bytes);
free(tmp);
return bytes;
}
/**

View file

@ -12,7 +12,7 @@ void AppendChar(struct Buffer *, char);
void AppendData(struct Buffer *, char *, size_t);
void AppendStr(struct Buffer *, const char *);
void AppendWide(struct Buffer *, wint_t);
void AppendFmt(struct Buffer *, const char *, ...);
int AppendFmt(struct Buffer *, const char *, ...);
ssize_t WriteBuffer(struct Buffer *, int);
COSMOPOLITAN_C_END_

View file

@ -68,6 +68,10 @@ $(TOOL_BUILD_LIB_A_OBJS): \
-fsanitize=address
endif
o/$(MODE)/tool/build/lib/memory-gcc.asm: \
OVERRIDE_CFLAGS += \
-fsanitize=address
o/$(MODE)/tool/build/lib/ssefloat.o: \
TARGET_ARCH += \
-msse3

View file

@ -31,8 +31,8 @@ void OpCpuid(struct Machine *m, uint32_t rde) {
case 0x80000000:
ax = 7;
bx = 'G' | 'e' << 8 | 'n' << 16 | 'u' << 24;
cx = 'i' | 'n' << 8 | 'e' << 16 | 'C' << 24;
dx = 'o' | 's' << 8 | 'm' << 16 | 'o' << 24;
dx = 'i' | 'n' << 8 | 'e' << 16 | 'C' << 24;
cx = 'o' | 's' << 8 | 'm' << 16 | 'o' << 24;
break;
case 1:
cx |= 1 << 0; // sse3

View file

@ -89,7 +89,7 @@ static char *DisError(struct Dis *d, char *p) {
p = HighStart(p, g_high.comment);
*p++ = '#';
*p++ = ' ';
p = stpcpy(p, indexdoublenulstring(kXedErrorNames, d->xedd->op.error));
p = stpcpy(p, IndexDoubleNulString(kXedErrorNames, d->xedd->op.error));
p = HighEnd(p);
*p = '\0';
return p;

View file

@ -30,10 +30,10 @@ struct Dis {
size_t i, n;
struct DisSym {
int64_t addr;
int rank;
int unique;
int size;
int name;
char rank;
bool iscode;
bool isabs;
} * p;

View file

@ -156,17 +156,12 @@ static char *DisSymImpl(struct Dis *d, char *p, int64_t x, long sym) {
return p;
}
static char *DisSym(struct Dis *d, char *p, int64_t x1, int64_t x2,
bool isrelative) {
static char *DisSym(struct Dis *d, char *p, int64_t value, int64_t addr) {
long sym;
if ((sym = DisFindSym(d, x2)) != -1 && d->syms.p[sym].name &&
(d->syms.p[sym].isabs ^ isrelative)) {
return DisSymImpl(d, p, x2, sym);
} else if ((sym = DisFindSym(d, x1)) != -1 && d->syms.p[sym].name &&
(d->syms.p[sym].isabs ^ isrelative)) {
return DisSymImpl(d, p, x1, sym);
if ((sym = DisFindSym(d, addr)) != -1 && d->syms.p[sym].name) {
return DisSymImpl(d, p, addr, sym);
} else {
return DisInt(p, x1);
return DisInt(p, value);
}
}
@ -174,7 +169,7 @@ static char *DisSymLiteral(struct Dis *d, uint32_t rde, char *p, uint64_t addr,
uint64_t ip) {
*p++ = '$';
p = HighStart(p, g_high.literal);
p = DisSym(d, p, addr, addr, false);
p = DisSym(d, p, addr, addr);
p = HighEnd(p);
return p;
}
@ -227,7 +222,7 @@ static char *DisDisp(struct Dis *d, uint32_t rde, char *p) {
} else {
rela = true;
}
p = DisSym(d, p, disp, disp, rela);
p = DisSym(d, p, disp, disp);
}
return p;
}
@ -477,11 +472,11 @@ static char *DisJb(struct Dis *d, uint32_t rde, char *p) {
static char *DisJvds(struct Dis *d, uint32_t rde, char *p) {
return DisSym(d, p, RipRelative(d, d->xedd->op.disp),
RipRelative(d, d->xedd->op.disp) - Read64(d->m->cs), true);
RipRelative(d, d->xedd->op.disp) - Read64(d->m->cs));
}
static char *DisAbs(struct Dis *d, uint32_t rde, char *p) {
return DisSym(d, p, d->xedd->op.disp, d->xedd->op.disp, false);
return DisSym(d, p, d->xedd->op.disp, d->xedd->op.disp);
}
static char *DisSw(struct Dis *d, uint32_t rde, char *p) {

View file

@ -18,12 +18,12 @@
02110-1301 USA
*/
#include "libc/alg/alg.h"
#include "libc/alg/arraylist2.h"
#include "libc/elf/elf.h"
#include "libc/elf/struct/sym.h"
#include "libc/log/check.h"
#include "libc/log/log.h"
#include "libc/macros.h"
#include "libc/mem/mem.h"
#include "libc/str/str.h"
#include "tool/build/lib/dis.h"
@ -46,38 +46,51 @@ static int DisSymCompare(const struct DisSym *a, const struct DisSym *b) {
}
static void DisLoadElfLoads(struct Dis *d, struct Elf *elf) {
long i;
long i, j, n;
int64_t addr;
uint64_t size;
Elf64_Phdr *phdr;
struct DisLoad l;
d->loads.i = 0;
for (i = 0; i < elf->ehdr->e_phnum; ++i) {
j = 0;
n = elf->ehdr->e_phnum;
if (d->loads.n < n) {
d->loads.n = n;
d->loads.p = realloc(d->loads.p, d->loads.n * sizeof(*d->loads.p));
CHECK_NOTNULL(d->loads.p);
}
for (i = 0; i < n; ++i) {
phdr = getelfsegmentheaderaddress(elf->ehdr, elf->size, i);
if (phdr->p_type != PT_LOAD) continue;
l.addr = phdr->p_vaddr;
l.size = phdr->p_memsz;
l.istext = (phdr->p_flags & PF_X) == PF_X;
APPEND(&d->loads.p, &d->loads.i, &d->loads.n, &l);
d->loads.p[j].addr = phdr->p_vaddr;
d->loads.p[j].size = phdr->p_memsz;
d->loads.p[j].istext = (phdr->p_flags & PF_X) == PF_X;
++j;
}
d->loads.i = j;
}
static void DisLoadElfSyms(struct Dis *d, struct Elf *elf) {
size_t i, n;
size_t i, j, n;
int64_t stablen;
struct DisSym t;
const Elf64_Sym *st, *sym;
bool isabs, iscode, isweak, islocal, ishidden, isprotected, isfunc, isobject;
d->syms.i = 0;
j = 0;
if ((d->syms.stab = getelfstringtable(elf->ehdr, elf->size)) &&
(st = getelfsymboltable(elf->ehdr, elf->size, &n))) {
stablen = (intptr_t)elf->ehdr + elf->size - (intptr_t)d->syms.stab;
if (d->syms.n < n) {
d->syms.n = n;
d->syms.p = realloc(d->syms.p, d->syms.n * sizeof(*d->syms.p));
CHECK_NOTNULL(d->syms.p);
}
for (i = 0; i < n; ++i) {
if (!st[i].st_name) continue;
if (!(0 <= st[i].st_name && st[i].st_name < stablen)) continue;
if (ELF64_ST_TYPE(st[i].st_info) == STT_SECTION) continue;
if (ELF64_ST_TYPE(st[i].st_info) == STT_FILE) continue;
if (startswith(d->syms.stab + st[i].st_name, "v_")) continue;
if (ELF64_ST_TYPE(st[i].st_info) == STT_SECTION ||
ELF64_ST_TYPE(st[i].st_info) == STT_FILE || !st[i].st_name ||
startswith(d->syms.stab + st[i].st_name, "v_") ||
!(0 <= st[i].st_name && st[i].st_name < stablen) || !st[i].st_value ||
!(-0x800000000000 <= (int64_t)st[i].st_value &&
(int64_t)st[i].st_value < 0x800000000000)) {
continue;
}
isabs = st[i].st_shndx == SHN_ABS;
isweak = ELF64_ST_BIND(st[i].st_info) == STB_WEAK;
islocal = ELF64_ST_BIND(st[i].st_info) == STB_LOCAL;
@ -85,19 +98,51 @@ static void DisLoadElfSyms(struct Dis *d, struct Elf *elf) {
isprotected = st[i].st_other == STV_PROTECTED;
isfunc = ELF64_ST_TYPE(st[i].st_info) == STT_FUNC;
isobject = ELF64_ST_TYPE(st[i].st_info) == STT_OBJECT;
t.unique = i;
t.size = st[i].st_size;
t.name = st[i].st_name;
t.addr = st[i].st_value;
t.rank = -islocal + -isweak + -isabs + isprotected + isobject + isfunc;
t.iscode = DisIsText(d, st[i].st_value) ? !isobject : isfunc;
t.isabs = isabs;
APPEND(&d->syms.p, &d->syms.i, &d->syms.n, &t);
d->syms.p[j].unique = i;
d->syms.p[j].size = st[i].st_size;
d->syms.p[j].name = st[i].st_name;
d->syms.p[j].addr = st[i].st_value;
d->syms.p[j].rank =
-islocal + -isweak + -isabs + isprotected + isobject + isfunc;
d->syms.p[j].iscode = DisIsText(d, st[i].st_value) ? !isobject : isfunc;
d->syms.p[j].isabs = isabs;
++j;
}
}
d->syms.i = j;
}
static void DisSortSyms(struct Dis *d) {
qsort(d->syms.p, d->syms.i, sizeof(struct DisSym), (void *)DisSymCompare);
}
static void DisCanonizeSyms(struct Dis *d) {
int64_t i, j, a;
if (d->syms.i) {
i = 1;
j = 1;
a = d->syms.p[0].addr;
do {
if (d->syms.p[j].addr > a) {
a = d->syms.p[j].addr;
if (j > i) {
d->syms.p[i] = d->syms.p[j];
}
++i;
}
++j;
} while (j < d->syms.i);
d->syms.p = realloc(d->syms.p, sizeof(*d->syms.p) * i);
d->syms.i = i;
d->syms.n = i;
}
for (i = 0; i < d->syms.i; ++i) {
DEBUGF("%p-%p %s", d->syms.p[i].addr,
d->syms.p[i].addr + (d->syms.p[i].size ? d->syms.p[i].size - 1 : 0),
d->syms.stab + d->syms.p[i].name);
}
}
bool DisIsProg(struct Dis *d, int64_t addr) {
long i;
if (g_disisprog_disable) return true;
@ -122,36 +167,24 @@ bool DisIsText(struct Dis *d, int64_t addr) {
}
long DisFindSym(struct Dis *d, int64_t addr) {
size_t i, l, r, m, n;
if (d->syms.p) {
if (DisIsProg(d, addr)) {
l = 0;
r = d->syms.i;
while (l < r) {
m = (l + r) >> 1;
if (d->syms.p[m].addr < addr) {
l = m + 1;
} else {
r = m;
}
}
if (d->syms.p[l].addr == addr) {
return l;
}
l = MAX(0, (long)l - 10);
for (n = 0, i = l; i < d->syms.i && n < 20; ++i, ++n) {
if (addr >= d->syms.p[i].addr &&
addr < d->syms.p[i].addr + d->syms.p[i].size) {
return i;
}
}
for (n = 0, i = l; i < d->syms.i && n < 20; ++i, ++n) {
if (addr >= d->syms.p[i].addr &&
(i + 1 == d->syms.i || addr < d->syms.p[i + 1].addr)) {
return i;
}
long l, r, m, n;
if (DisIsProg(d, addr)) {
l = 0;
r = d->syms.i;
while (l < r) {
m = (l + r) >> 1;
if (d->syms.p[m].addr > addr) {
r = m;
} else {
l = m + 1;
}
}
if (r && (addr == d->syms.p[r - 1].addr ||
(addr > d->syms.p[r - 1].addr &&
(addr <= d->syms.p[r - 1].addr + d->syms.p[r - 1].size ||
!d->syms.p[r - 1].size)))) {
return r - 1;
}
}
return -1;
}
@ -170,4 +203,6 @@ void DisLoadElf(struct Dis *d, struct Elf *elf) {
if (!elf || !elf->ehdr) return;
DisLoadElfLoads(d, elf);
DisLoadElfSyms(d, elf);
DisSortSyms(d);
DisCanonizeSyms(d);
}

View file

@ -53,3 +53,12 @@ uint64_t ExportFlags(uint64_t flags) {
flags |= GetLazyParityBool(flags) << FLAGS_PF;
return flags;
}
int64_t AluFlags(uint64_t x, uint32_t af, uint32_t *f, uint32_t of, uint32_t cf,
uint32_t sf) {
*f &= ~(1u << FLAGS_CF | 1u << FLAGS_ZF | 1u << FLAGS_SF | 1u << FLAGS_OF |
1u << FLAGS_AF | 0xFF000000u);
*f |= sf << FLAGS_SF | cf << FLAGS_CF | !x << FLAGS_ZF | of << FLAGS_OF |
af << FLAGS_AF | (x & 0xFF) << 24;
return x;
}

View file

@ -64,6 +64,7 @@ COSMOPOLITAN_C_START_
bool GetParity(uint8_t);
uint64_t ExportFlags(uint64_t);
void ImportFlags(struct Machine *, uint64_t);
int64_t AluFlags(uint64_t, uint32_t, uint32_t *, uint32_t, uint32_t, uint32_t);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */

View file

@ -46,9 +46,6 @@ static void LoadElfLoadSegment(struct Machine *m, void *code, size_t codesize,
align = MAX(phdr->p_align, PAGESIZE);
CHECK_EQ(1, popcnt(align));
CHECK_EQ(0, (phdr->p_vaddr - phdr->p_offset) % align);
/*-Type-Offset---VirtAddr-----------PhysAddr-----------FileSiz--MemSiz---Flg-Align----*/
/*-LOAD-0x000000-0x0000000000400000-0x0000000000400000-0x0008e4-0x0008e4-R-E-0x200000-*/
/*-LOAD-0x000fe0-0x0000000000600fe0-0x0000000000600fe0-0x000030-0x000310-RW--0x200000-*/
felf = (int64_t)(intptr_t)code;
vstart = ROUNDDOWN(phdr->p_vaddr, align);
vbss = ROUNDUP(phdr->p_vaddr + phdr->p_filesz, align);
@ -56,10 +53,10 @@ static void LoadElfLoadSegment(struct Machine *m, void *code, size_t codesize,
fstart = felf + ROUNDDOWN(phdr->p_offset, align);
fend = felf + phdr->p_offset + phdr->p_filesz;
bsssize = vend - vbss;
LOGF("LOADELFLOADSEGMENT"
" VSTART %#lx VBSS %#lx VEND %#lx"
" FSTART %#lx FEND %#lx BSSSIZE %#lx",
vstart, vbss, vend, fstart, fend, bsssize);
VERBOSEF("LOADELFLOADSEGMENT"
" VSTART %#lx VBSS %#lx VEND %#lx"
" FSTART %#lx FEND %#lx BSSSIZE %#lx",
vstart, vbss, vend, fstart, fend, bsssize);
m->brk = MAX(m->brk, vend);
CHECK_GE(vend, vstart);
CHECK_GE(fend, fstart);
@ -69,9 +66,9 @@ static void LoadElfLoadSegment(struct Machine *m, void *code, size_t codesize,
CHECK_GE(vend - vstart, fstart - fend);
CHECK_LE(phdr->p_filesz, phdr->p_memsz);
CHECK_EQ(felf + phdr->p_offset - fstart, phdr->p_vaddr - vstart);
CHECK_NE(-1, ReserveVirtual(m, vstart, fend - fstart));
CHECK_NE(-1, ReserveVirtual(m, vstart, fend - fstart, 0x0207));
VirtualRecv(m, vstart, (void *)fstart, fend - fstart);
if (bsssize) CHECK_NE(-1, ReserveVirtual(m, vbss, bsssize));
if (bsssize) CHECK_NE(-1, ReserveVirtual(m, vbss, bsssize, 0x0207));
if (phdr->p_memsz - phdr->p_filesz > bsssize) {
VirtualSet(m, phdr->p_vaddr + phdr->p_filesz, 0,
phdr->p_memsz - phdr->p_filesz - bsssize);
@ -82,7 +79,7 @@ static void LoadElf(struct Machine *m, struct Elf *elf) {
unsigned i;
Elf64_Phdr *phdr;
m->ip = elf->base = elf->ehdr->e_entry;
LOGF("LOADELF ENTRY %p", m->ip);
VERBOSEF("LOADELF ENTRY %p", m->ip);
for (i = 0; i < elf->ehdr->e_phnum; ++i) {
phdr = getelfsegmentheaderaddress(elf->ehdr, elf->size, i);
switch (phdr->p_type) {
@ -149,9 +146,9 @@ void LoadProgram(struct Machine *m, const char *prog, char **args, char **vars,
}
CHECK_NE(-1, close(fd));
ResetCpu(m);
if (m->mode == XED_MACHINE_MODE_REAL) {
if ((m->mode & 3) == XED_MODE_REAL) {
elf->base = 0x7c00;
CHECK_NE(-1, ReserveVirtual(m, 0, BIGPAGESIZE));
CHECK_NE(-1, ReserveReal(m, BIGPAGESIZE));
m->ip = 0x7c00;
Write64(m->cs, 0);
Write64(m->dx, 0);
@ -168,7 +165,8 @@ void LoadProgram(struct Machine *m, const char *prog, char **args, char **vars,
} else {
sp = 0x800000000000;
Write64(m->sp, sp);
CHECK_NE(-1, ReserveVirtual(m, sp - STACKSIZE, STACKSIZE));
m->cr3 = AllocateLinearPage(m);
CHECK_NE(-1, ReserveVirtual(m, sp - STACKSIZE, STACKSIZE, 0x0207));
LoadArgv(m, prog, args, vars);
if (memcmp(elf->map, "\177ELF", 4) == 0) {
elf->ehdr = (void *)elf->map;

View file

@ -35,6 +35,7 @@
#include "tool/build/lib/machine.h"
#include "tool/build/lib/memory.h"
#include "tool/build/lib/modrm.h"
#include "tool/build/lib/op101.h"
#include "tool/build/lib/sse.h"
#include "tool/build/lib/ssefloat.h"
#include "tool/build/lib/ssemov.h"
@ -883,9 +884,6 @@ static void OpBsubiImm(struct Machine *m, uint32_t rde) {
Bsubi(m, rde, m->xedd->op.uimm0);
}
static void OpLgdtMs(struct Machine *m, uint32_t rde) {
}
static void OpPushImm(struct Machine *m, uint32_t rde) {
Push(m, rde, m->xedd->op.uimm0);
}
@ -1328,21 +1326,6 @@ static void Op0ff(struct Machine *m, uint32_t rde) {
kOp0ff[ModrmReg(rde)](m, rde);
}
static void Op101(struct Machine *m, uint32_t rde) {
if (IsModrmRegister(rde)) {
if (ModrmReg(rde) == 0b111 && ModrmRm(rde) == 0b001) {
OpRdtscp(m, rde);
return;
}
} else {
if (ModrmReg(rde) == 2) {
OpLgdtMs(m, rde);
return;
}
}
OpUd(m, rde);
}
static void OpDoubleShift(struct Machine *m, uint32_t rde) {
uint8_t *p;
uint64_t x;
@ -1400,6 +1383,44 @@ static void OpNop(struct Machine *m, uint32_t rde) {
}
}
static void OpMovRqCq(struct Machine *m, uint32_t rde) {
switch (ModrmReg(rde)) {
case 0:
Write64(RegRexbRm(m, rde), m->cr0);
break;
case 2:
Write64(RegRexbRm(m, rde), m->cr2);
break;
case 3:
Write64(RegRexbRm(m, rde), m->cr3);
break;
case 4:
Write64(RegRexbRm(m, rde), m->cr4);
break;
default:
OpUd(m, rde);
}
}
static void OpMovCqRq(struct Machine *m, uint32_t rde) {
switch (ModrmReg(rde)) {
case 0:
m->cr0 = Read64(RegRexbRm(m, rde));
break;
case 2:
m->cr2 = Read64(RegRexbRm(m, rde));
break;
case 3:
m->cr3 = Read64(RegRexbRm(m, rde));
break;
case 4:
m->cr4 = Read64(RegRexbRm(m, rde));
break;
default:
OpUd(m, rde);
}
}
static const nexgen32e_f kNexgen32e[] = {
[0x000] = OpAlubAdd,
[0x001] = OpAluw,
@ -1689,9 +1710,9 @@ static const nexgen32e_f kNexgen32e[] = {
[0x11D] = OpHintNopEv,
[0x11E] = OpUd,
[0x11F] = OpNopEv,
[0x120] = OpUd,
[0x120] = OpMovRqCq,
[0x121] = OpUd,
[0x122] = OpUd,
[0x122] = OpMovCqRq,
[0x123] = OpUd,
[0x124] = OpUd,
[0x125] = OpUd,

View file

@ -131,6 +131,9 @@ struct Machine {
};
};
} sse;
uint64_t cr0;
uint64_t cr2;
uint64_t cr4;
struct MachineRealFree {
uint64_t i;
uint64_t n;
@ -140,6 +143,15 @@ struct Machine {
uint32_t i;
void *p[6];
} freelist;
struct MachineMemstat {
int freed;
int resizes;
int reserved;
int committed;
int allocated;
int reclaimed;
int pagetables;
} memstat;
int64_t brk;
int64_t bofram[2];
jmp_buf onhalt;
@ -157,7 +169,9 @@ void ResetTlb(struct Machine *);
void LoadInstruction(struct Machine *);
void ExecuteInstruction(struct Machine *);
long AllocateLinearPage(struct Machine *);
int ReserveVirtual(struct Machine *, int64_t, size_t);
long AllocateLinearPageRaw(struct Machine *);
int ReserveReal(struct Machine *, size_t);
int ReserveVirtual(struct Machine *, int64_t, size_t, uint64_t);
char *FormatPml4t(struct Machine *) nodiscard;
int64_t FindVirtual(struct Machine *, int64_t, size_t);
int FreeVirtual(struct Machine *, int64_t, size_t);

View file

@ -19,6 +19,7 @@
*/
#include "libc/assert.h"
#include "libc/log/check.h"
#include "libc/log/log.h"
#include "libc/macros.h"
#include "libc/mem/mem.h"
#include "libc/str/str.h"
@ -44,41 +45,58 @@ void SetWriteAddr(struct Machine *m, int64_t addr, uint32_t size) {
}
}
long HandlePageFault(struct Machine *m, uint64_t entry, uint64_t table,
unsigned index) {
long page;
if ((page = AllocateLinearPage(m)) != -1) {
--m->memstat.reserved;
*(uint64_t *)(m->real.p + table + index * 8) =
page | entry & ~0x7ffffffffe00;
}
return page;
}
void *FindReal(struct Machine *m, int64_t virt) {
uint8_t *host;
uint64_t real, pte, *pt;
unsigned skew, level, i;
if (!(-0x800000000000 <= virt && virt < 0x800000000000)) {
long page;
uint64_t table, entry;
unsigned skew, level, index, i;
if ((m->mode & 3) != XED_MODE_REAL) {
if (-0x800000000000 <= virt && virt < 0x800000000000) {
skew = virt & 0xfff;
virt &= -0x1000;
for (i = 0; i < ARRAYLEN(m->tlb); ++i) {
if (m->tlb[i].virt == virt && m->tlb[i].host) {
return m->tlb[i].host + skew;
}
}
level = 39;
entry = m->cr3;
do {
table = entry & 0x7ffffffff000;
CHECK_LT(table, m->real.n);
index = (virt >> level) & 511;
entry = *(uint64_t *)(m->real.p + table + index * 8);
if (!(entry & 1)) return NULL;
} while ((level -= 9) >= 12);
if (!(entry & 0x0e00)) {
page = entry & 0x7ffffffff000;
CHECK_LT(page, m->real.n);
} else if ((page = HandlePageFault(m, entry, table, index)) == -1) {
return NULL;
}
m->tlbindex = (m->tlbindex + 1) & (ARRAYLEN(m->tlb) - 1);
m->tlb[m->tlbindex] = m->tlb[0];
m->tlb[0].virt = virt;
m->tlb[0].host = m->real.p + page;
return m->real.p + page + skew;
} else {
return NULL;
}
} else if (0 <= virt && virt + 0xfff < m->real.n) {
return m->real.p + virt;
} else {
return NULL;
}
skew = virt & 0xfff;
virt &= -0x1000;
for (i = 0; i < ARRAYLEN(m->tlb); ++i) {
if (m->tlb[i].virt == virt && m->tlb[i].host) {
return m->tlb[i].host + skew;
}
}
level = 39;
real = m->cr3;
for (;;) {
if (real + 0x1000 > m->real.n) {
return NULL;
}
host = m->real.p + real;
if (level < 12) break;
pt = (uint64_t *)host;
pte = pt[(virt >> level) & 511];
if (!(pte & 1)) {
return NULL;
}
real = pte & 0x00007ffffffff000;
level -= 9;
}
m->tlbindex = (m->tlbindex + 1) & (ARRAYLEN(m->tlb) - 1);
m->tlb[m->tlbindex] = m->tlb[0];
m->tlb[0].host = host;
m->tlb[0].virt = virt;
return host + skew;
}
void *ResolveAddress(struct Machine *m, int64_t v) {

View file

@ -35,7 +35,6 @@
struct Machine *NewMachine(void) {
struct Machine *m;
m = xmemalignzero(alignof(struct Machine), sizeof(struct Machine));
m->mode = XED_MACHINE_MODE_LONG_64;
ResetCpu(m);
ResetMem(m);
return m;
@ -60,11 +59,20 @@ void FreeMachine(struct Machine *m) {
void ResetMem(struct Machine *m) {
FreeMachineRealFree(m);
ResetTlb(m);
memset(&m->memstat, 0, sizeof(m->memstat));
m->real.i = 0;
m->cr3 = AllocateLinearPage(m);
m->cr3 = 0;
}
long AllocateLinearPage(struct Machine *m) {
long page;
if ((page = AllocateLinearPageRaw(m)) != -1) {
memset(m->real.p + page, 0, 0x1000);
}
return page;
}
long AllocateLinearPageRaw(struct Machine *m) {
uint8_t *p;
size_t i, n;
struct MachineRealFree *rf;
@ -79,6 +87,8 @@ long AllocateLinearPage(struct Machine *m) {
m->realfree = rf->next;
free(rf);
}
--m->memstat.freed;
++m->memstat.reclaimed;
} else {
i = m->real.i;
n = m->real.n;
@ -94,6 +104,7 @@ long AllocateLinearPage(struct Machine *m) {
m->real.p = p;
m->real.n = n;
ResetTlb(m);
++m->memstat.resizes;
} else {
return -1;
}
@ -102,8 +113,9 @@ long AllocateLinearPage(struct Machine *m) {
DCHECK_EQ(0, n & 0xfff);
DCHECK_LE(i + 0x1000, n);
m->real.i += 0x1000;
++m->memstat.allocated;
}
memset(m->real.p + i, 0, 0x1000); /* TODO: lazy page clearing */
++m->memstat.committed;
return i;
}
@ -117,24 +129,51 @@ static void MachineWrite64(struct Machine *m, unsigned long i, uint64_t x) {
Write64(m->real.p + i, x);
}
int ReserveVirtual(struct Machine *m, int64_t virt, size_t size) {
int64_t level, pt, ti, mi, end;
for (end = virt + size; virt < end; virt += 0x1000) {
for (pt = m->cr3, level = 39; level >= 12; level -= 9) {
pt = pt & 0x00007ffffffff000;
ti = (virt >> level) & 511;
DEBUGF("reserve %p level %d table %p index %ld", virt, level, pt, ti);
mi = pt + ti * 8;
pt = MachineRead64(m, mi);
if (!(pt & 1)) {
if ((pt = AllocateLinearPage(m)) == -1) return -1;
MachineWrite64(m, mi, pt | 7);
}
int ReserveReal(struct Machine *m, size_t n) {
uint8_t *p;
DCHECK_EQ(0, n & 0xfff);
if (m->real.n < n) {
if ((p = realloc(m->real.p, n))) {
m->real.p = p;
m->real.n = n;
ResetTlb(m);
++m->memstat.resizes;
} else {
return -1;
}
}
return 0;
}
int ReserveVirtual(struct Machine *m, int64_t virt, size_t size, uint64_t key) {
int64_t ti, mi, pt, end, level;
for (end = virt + size;;) {
for (pt = m->cr3, level = 39; level >= 12; level -= 9) {
pt = pt & 0x7ffffffff000;
ti = (virt >> level) & 511;
mi = (pt & 0x7ffffffff000) + ti * 8;
pt = MachineRead64(m, mi);
if (level > 12) {
if (!(pt & 1)) {
if ((pt = AllocateLinearPage(m)) == -1) return -1;
MachineWrite64(m, mi, pt | 7);
++m->memstat.pagetables;
}
continue;
}
for (;;) {
if (!(pt & 1)) {
MachineWrite64(m, mi, key);
++m->memstat.reserved;
}
if ((virt += 0x1000) >= end) return 0;
if (++ti == 512) break;
pt = MachineRead64(m, (mi += 8));
}
}
}
}
int64_t FindVirtual(struct Machine *m, int64_t virt, size_t size) {
uint64_t i, pt, got;
got = 0;
@ -154,30 +193,39 @@ int64_t FindVirtual(struct Machine *m, int64_t virt, size_t size) {
return virt;
}
int FreeVirtual(struct Machine *m, int64_t base, size_t size) {
static void AppendRealFree(struct Machine *m, uint64_t real) {
struct MachineRealFree *rf;
uint64_t i, mi, pt, la, end, virt;
for (virt = base, end = virt + size; virt < end;) {
if (m->realfree && real == m->realfree->i + m->realfree->n) {
m->realfree->n += 0x1000;
} else if ((rf = malloc(sizeof(struct MachineRealFree)))) {
rf->i = real;
rf->n = 0x1000;
rf->next = m->realfree;
m->realfree = rf;
}
}
int FreeVirtual(struct Machine *m, int64_t base, size_t size) {
uint64_t i, mi, pt, end, virt;
for (virt = base, end = virt + size; virt < end; virt += 1ull << i) {
for (pt = m->cr3, i = 39;; i -= 9) {
mi = (pt & 0x7ffffffff000) + ((virt >> i) & 511) * 8;
pt = MachineRead64(m, mi);
if (!(pt & 1)) {
break;
} else if (i == 12) {
MachineWrite64(m, mi, 0);
la = pt & 0x7ffffffff000;
if (m->realfree && la == m->realfree->i + m->realfree->n) {
m->realfree->n += 0x1000;
} else if ((rf = malloc(sizeof(struct MachineRealFree)))) {
rf->i = la;
rf->n = 0x1000;
rf->next = m->realfree;
m->realfree = rf;
++m->memstat.freed;
if (pt & 0x0e00) {
--m->memstat.reserved;
} else {
--m->memstat.committed;
AppendRealFree(m, pt & 0x7ffffffff000);
}
MachineWrite64(m, mi, 0);
break;
}
}
virt += 1ull << i;
}
ResetTlb(m);
return 0;
}

View file

@ -236,6 +236,10 @@ uint8_t *GetModrmRegisterWordPointerWrite(struct Machine *m, uint32_t rde,
}
}
uint8_t *GetModrmRegisterWordPointerWrite2(struct Machine *m, uint32_t rde) {
return GetModrmRegisterWordPointerWrite(m, rde, 2);
}
uint8_t *GetModrmRegisterWordPointerWrite4(struct Machine *m, uint32_t rde) {
return GetModrmRegisterWordPointerWrite(m, rde, 4);
}

View file

@ -59,7 +59,6 @@ extern const uint8_t kByteReg[32];
int64_t ComputeAddress(const struct Machine *, uint32_t);
struct AddrSeg LoadEffectiveAddress(const struct Machine *, uint32_t);
void *ComputeReserveAddressRead(struct Machine *, uint32_t, size_t);
void *ComputeReserveAddressRead1(struct Machine *, uint32_t);
void *ComputeReserveAddressRead4(struct Machine *, uint32_t);
@ -68,7 +67,6 @@ void *ComputeReserveAddressWrite(struct Machine *, uint32_t, size_t);
void *ComputeReserveAddressWrite1(struct Machine *, uint32_t);
void *ComputeReserveAddressWrite4(struct Machine *, uint32_t);
void *ComputeReserveAddressWrite8(struct Machine *, uint32_t);
uint8_t *GetModrmRegisterBytePointerRead(struct Machine *, uint32_t);
uint8_t *GetModrmRegisterBytePointerWrite(struct Machine *, uint32_t);
uint8_t *GetModrmRegisterMmPointerRead(struct Machine *, uint32_t, size_t);
@ -82,6 +80,7 @@ uint8_t *GetModrmRegisterWordPointerRead8(struct Machine *, uint32_t);
uint8_t *GetModrmRegisterWordPointerReadOsz(struct Machine *, uint32_t);
uint8_t *GetModrmRegisterWordPointerReadOszRexw(struct Machine *, uint32_t);
uint8_t *GetModrmRegisterWordPointerWrite(struct Machine *, uint32_t, size_t);
uint8_t *GetModrmRegisterWordPointerWrite2(struct Machine *, uint32_t);
uint8_t *GetModrmRegisterWordPointerWrite4(struct Machine *, uint32_t);
uint8_t *GetModrmRegisterWordPointerWrite8(struct Machine *, uint32_t);
uint8_t *GetModrmRegisterWordPointerWriteOsz(struct Machine *, uint32_t);

160
tool/build/lib/op101.c Normal file
View file

@ -0,0 +1,160 @@
/*-*- 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
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "tool/build/lib/endian.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 SgdtMs(struct Machine *m, uint32_t rde) {
}
static void LgdtMs(struct Machine *m, uint32_t rde) {
}
static void SidtMs(struct Machine *m, uint32_t rde) {
}
static void LidtMs(struct Machine *m, uint32_t rde) {
}
static void Monitor(struct Machine *m, uint32_t rde) {
}
static void Mwait(struct Machine *m, uint32_t rde) {
}
static void Swapgs(struct Machine *m, uint32_t rde) {
}
static void Vmcall(struct Machine *m, uint32_t rde) {
}
static void Vmlaunch(struct Machine *m, uint32_t rde) {
}
static void Vmresume(struct Machine *m, uint32_t rde) {
}
static void Vmxoff(struct Machine *m, uint32_t rde) {
}
static void InvlpgM(struct Machine *m, uint32_t rde) {
ResetTlb(m);
}
static void Smsw(struct Machine *m, uint32_t rde, bool ismem) {
if (ismem) {
Write16(GetModrmRegisterWordPointerWrite2(m, rde), m->cr0);
} else if (Rexw(rde)) {
Write64(RegRexrReg(m, rde), m->cr0);
} else if (!Osz(rde)) {
Write64(RegRexrReg(m, rde), m->cr0 & 0xffffffff);
} else {
Write16(RegRexrReg(m, rde), m->cr0);
}
}
static void Lmsw(struct Machine *m, uint32_t rde) {
m->cr0 = Read16(GetModrmRegisterWordPointerRead2(m, rde));
}
void Op101(struct Machine *m, uint32_t rde) {
bool ismem;
ismem = !IsModrmRegister(rde);
switch (ModrmReg(rde)) {
case 0:
if (ismem) {
SgdtMs(m, rde);
} else {
switch (ModrmRm(rde)) {
case 1:
Vmcall(m, rde);
break;
case 2:
Vmlaunch(m, rde);
break;
case 3:
Vmresume(m, rde);
break;
case 4:
Vmxoff(m, rde);
break;
default:
OpUd(m, rde);
}
}
break;
case 1:
if (ismem) {
SidtMs(m, rde);
} else {
switch (ModrmRm(rde)) {
case 0:
Monitor(m, rde);
break;
case 1:
Mwait(m, rde);
break;
default:
OpUd(m, rde);
}
}
break;
case 2:
if (ismem) {
LgdtMs(m, rde);
} else {
OpUd(m, rde);
}
break;
case 3:
if (ismem) {
LidtMs(m, rde);
} else {
OpUd(m, rde);
}
break;
case 4:
Smsw(m, rde, ismem);
break;
case 6:
Lmsw(m, rde);
break;
case 7:
if (ismem) {
InvlpgM(m, rde);
} else {
switch (ModrmRm(rde)) {
case 0:
Swapgs(m, rde);
break;
case 1:
OpRdtscp(m, rde);
break;
default:
OpUd(m, rde);
}
}
break;
default:
OpUd(m, rde);
}
}

11
tool/build/lib/op101.h Normal file
View file

@ -0,0 +1,11 @@
#ifndef COSMOPOLITAN_TOOL_BUILD_LIB_OP101_H_
#define COSMOPOLITAN_TOOL_BUILD_LIB_OP101_H_
#include "tool/build/lib/machine.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
void Op101(struct Machine *, uint32_t);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_TOOL_BUILD_LIB_OP101_H_ */

View file

@ -5,10 +5,12 @@
COSMOPOLITAN_C_START_
struct Panel {
int i;
int top, bottom;
int left, right;
int top;
int bottom;
int left;
int right;
struct Buffer *lines;
size_t n;
};
ssize_t PrintPanels(int, long, struct Panel *, long, long);

View file

@ -70,6 +70,7 @@ char *FormatPml4t(struct Machine *m) {
unsigned short i, a[4];
struct Pml4tFormater pp = {0};
unsigned short range[][2] = {{256, 512}, {0, 256}};
if ((m->mode & 3) != XED_MODE_LONG) return strdup("");
pd[0] = GetPt(m, m->cr3);
for (i = 0; i < ARRAYLEN(range); ++i) {
a[0] = range[i][0];

File diff suppressed because it is too large Load diff

View file

@ -2,36 +2,36 @@
#define COSMOPOLITAN_TOOL_BUILD_LIB_PTY_H_
#include "tool/build/lib/buffer.h"
#define kMachinePtyFg 0x0001
#define kMachinePtyBg 0x0002
#define kMachinePtyBold 0x0004
#define kMachinePtyFlip 0x0008
#define kMachinePtyFaint 0x0010
#define kMachinePtyUnder 0x0020
#define kMachinePtyDunder 0x0040
#define kMachinePtyTrue 0x0080
#define kMachinePtyBlink 0x0100
#define kMachinePtyItalic 0x0200
#define kMachinePtyFraktur 0x0400
#define kMachinePtyStrike 0x0800
#define kMachinePtyConceal 0x1000
#define kPtyFg 0x0001
#define kPtyBg 0x0002
#define kPtyBold 0x0004
#define kPtyFlip 0x0008
#define kPtyFaint 0x0010
#define kPtyUnder 0x0020
#define kPtyDunder 0x0040
#define kPtyTrue 0x0080
#define kPtyBlink 0x0100
#define kPtyItalic 0x0200
#define kPtyFraktur 0x0400
#define kPtyStrike 0x0800
#define kPtyConceal 0x1000
#define kMachinePtyBell 0x001
#define kMachinePtyRedzone 0x002
#define kMachinePtyNocursor 0x004
#define kMachinePtyBlinkcursor 0x008
#define kMachinePtyNocanon 0x010
#define kMachinePtyNoecho 0x020
#define kMachinePtyNoopost 0x040
#define kMachinePtyLed1 0x080
#define kMachinePtyLed2 0x100
#define kMachinePtyLed3 0x200
#define kMachinePtyLed4 0x400
#define kPtyBell 0x001
#define kPtyRedzone 0x002
#define kPtyNocursor 0x004
#define kPtyBlinkcursor 0x008
#define kPtyNocanon 0x010
#define kPtyNoecho 0x020
#define kPtyNoopost 0x040
#define kPtyLed1 0x080
#define kPtyLed2 0x100
#define kPtyLed3 0x200
#define kPtyLed4 0x400
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
struct MachinePty {
struct Pty {
int y;
int x;
int yn;
@ -48,34 +48,34 @@ struct MachinePty {
uint32_t *fgs;
uint32_t *bgs;
wchar_t *xlat;
enum MachinePtyState {
kMachinePtyAscii,
kMachinePtyUtf8,
kMachinePtyEsc,
kMachinePtyCsi,
enum PtyState {
kPtyAscii,
kPtyUtf8,
kPtyEsc,
kPtyCsi,
} state;
struct MachinePtyEsc {
struct PtyEsc {
unsigned i;
char s[64];
} esc;
struct MachinePtyInput {
struct PtyInput {
size_t i, n;
char *p;
} input;
};
void MachinePtyFree(struct MachinePty *);
struct MachinePty *MachinePtyNew(void) nodiscard;
void MachinePtyResize(struct MachinePty *, int, int);
ssize_t MachinePtyRead(struct MachinePty *, void *, size_t);
ssize_t MachinePtyWrite(struct MachinePty *, const void *, size_t);
ssize_t MachinePtyWriteInput(struct MachinePty *, const void *, size_t);
void MachinePtyAppendLine(struct MachinePty *, struct Buffer *, unsigned);
void MachinePtyFullReset(struct MachinePty *);
void MachinePtyMemmove(struct MachinePty *, long, long, long);
void MachinePtyErase(struct MachinePty *, long, long);
void MachinePtySetY(struct MachinePty *, int);
void MachinePtySetX(struct MachinePty *, int);
void FreePty(struct Pty *);
struct Pty *NewPty(void) nodiscard;
void PtyResize(struct Pty *, int, int);
ssize_t PtyRead(struct Pty *, void *, size_t);
ssize_t PtyWrite(struct Pty *, const void *, size_t);
ssize_t PtyWriteInput(struct Pty *, const void *, size_t);
int PtyAppendLine(struct Pty *, struct Buffer *, unsigned);
void PtyFullReset(struct Pty *);
void PtyMemmove(struct Pty *, long, long, long);
void PtyErase(struct Pty *, long, long);
void PtySetY(struct Pty *, int);
void PtySetX(struct Pty *, int);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */

View file

@ -17,6 +17,7 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/intrin/pmovmskb.h"
#include "libc/str/str.h"
#include "tool/build/lib/address.h"
#include "tool/build/lib/endian.h"
@ -496,23 +497,9 @@ void OpMov0fD6(struct Machine *m, uint32_t rde) {
}
}
static uint8_t pmovmskb(uint64_t x) {
return (x & 0x0000000000000080) >> 007 | (x & 0x0000000000008000) >> 016 |
(x & 0x0000000000800000) >> 025 | (x & 0x0000000080000000) >> 034 |
(x & 0x0000008000000000) >> 043 | (x & 0x0000800000000000) >> 052 |
(x & 0x0080000000000000) >> 061 | (x & 0x8000000000000000) >> 070;
}
void OpPmovmskbGdqpNqUdq(struct Machine *m, uint32_t rde) {
uint64_t bitmask;
if (Osz(rde)) {
bitmask = pmovmskb(Read64(XmmRexbRm(m, rde) + 8)) << 8 |
pmovmskb(Read64(XmmRexbRm(m, rde)));
} else {
bitmask = pmovmskb(Read64(MmRm(m, rde) + 8)) << 8 |
pmovmskb(Read64(MmRm(m, rde)));
}
Write64(RegRexrReg(m, rde), bitmask);
Write64(RegRexrReg(m, rde),
pmovmskb(XmmRexbRm(m, rde)) & (Osz(rde) ? 0xffff : 0xff));
}
void OpMaskMovDiXmmRegXmmRm(struct Machine *m, uint32_t rde) {

View file

@ -19,6 +19,6 @@
*/
#include "tool/build/lib/stats.h"
unsigned long ops;
unsigned long taken;
unsigned long ntaken;
unsigned long opcount;

View file

@ -3,9 +3,9 @@
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
extern unsigned long ops;
extern unsigned long taken;
extern unsigned long ntaken;
extern unsigned long opcount;
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */

View file

@ -30,6 +30,7 @@
#include "libc/calls/struct/timeval.h"
#include "libc/calls/struct/winsize.h"
#include "libc/errno.h"
#include "libc/fmt/fmt.h"
#include "libc/log/check.h"
#include "libc/log/log.h"
#include "libc/macros.h"
@ -321,11 +322,22 @@ static int XlatMsyncFlags(int x) {
return res;
}
static unsigned XlatOpenMode(unsigned flags) {
switch (flags & 3) {
case 0:
return O_RDONLY;
case 1:
return O_WRONLY;
case 2:
return O_RDWR;
default:
unreachable;
}
}
static unsigned XlatOpenFlags(unsigned flags) {
unsigned res = 0;
if ((flags & 3) == 0) res = O_RDONLY;
if ((flags & 3) == 1) res = O_WRONLY;
if ((flags & 3) == 3) res = O_RDWR;
res = XlatOpenMode(flags);
if (flags & 0x80000) res |= O_CLOEXEC;
if (flags & 0x400) res |= O_APPEND;
if (flags & 0x40) res |= O_CREAT;
@ -355,6 +367,7 @@ static int XlatFcntlArg(int x) {
switch (x) {
XLAT(0, 0);
XLAT(1, FD_CLOEXEC);
XLAT(0x0800, O_NONBLOCK);
default:
return einval();
}
@ -401,6 +414,14 @@ static int XlatRusage(int x) {
}
}
static const char *GetSimulated(void) {
if (IsGenuineCosmo()) {
return " SIMULATED";
} else {
return "";
}
}
static void VirtualSendRead(struct Machine *m, void *dst, int64_t addr,
uint64_t n) {
VirtualSend(m, dst, addr, n);
@ -508,7 +529,7 @@ static int OpMadvise(struct Machine *m, int64_t addr, size_t length,
static int64_t OpBrk(struct Machine *m, int64_t addr) {
addr = ROUNDUP(addr, PAGESIZE);
if (addr > m->brk) {
if (ReserveVirtual(m, m->brk, addr - m->brk) != -1) {
if (ReserveVirtual(m, m->brk, addr - m->brk, 0x0207) != -1) {
m->brk = addr;
}
} else if (addr < m->brk) {
@ -519,34 +540,47 @@ static int64_t OpBrk(struct Machine *m, int64_t addr) {
return m->brk;
}
static int OpMunmap(struct Machine *m, int64_t virt, uint64_t size) {
VERBOSEF("MUNMAP%s %p %,ld", GetSimulated(), virt, size);
return FreeVirtual(m, virt, size);
}
static int64_t OpMmap(struct Machine *m, int64_t virt, size_t size, int prot,
int flags, int fd, int64_t offset) {
void *tmp;
LOGF("MMAP%s %p %,ld %#x %#x %d %#lx", IsGenuineCosmo() ? " SIMULATED" : "",
virt, size, prot, flags, fd, offset);
flags = XlatMapFlags(flags);
if (fd != -1 && (fd = XlatFd(m, fd)) == -1) return -1;
if (!(flags & MAP_FIXED)) {
if (!virt) {
if ((virt = FindVirtual(m, m->brk, size)) == -1) return -1;
m->brk = virt + size;
} else {
if ((virt = FindVirtual(m, virt, size)) == -1) return -1;
uint64_t key;
VERBOSEF("MMAP%s %p %,ld %#x %#x %d %#lx", GetSimulated(), virt, size, prot,
flags, fd, offset);
if (prot & PROT_READ) {
key = 0x0205;
if (prot & PROT_WRITE) key |= 2;
if (!(prot & PROT_EXEC)) key |= 0x8000000000000000;
flags = XlatMapFlags(flags);
if (fd != -1 && (fd = XlatFd(m, fd)) == -1) return -1;
if (!(flags & MAP_FIXED)) {
if (!virt) {
if ((virt = FindVirtual(m, m->brk, size)) == -1) return -1;
m->brk = virt + size;
} else {
if ((virt = FindVirtual(m, virt, size)) == -1) return -1;
}
}
if (ReserveVirtual(m, virt, size, key) != -1) {
if (fd != -1 && !(flags & MAP_ANONYMOUS)) {
/* TODO: lazy file mappings */
CHECK_NOTNULL((tmp = malloc(size)));
CHECK_EQ(size, pread(fd, tmp, size, offset));
VirtualRecvWrite(m, virt, tmp, size);
free(tmp);
}
} else {
FreeVirtual(m, virt, size);
return -1;
}
return virt;
} else {
return FreeVirtual(m, virt, size);
}
if (ReserveVirtual(m, virt, size) == -1) return -1;
if (fd != -1 && !(flags & MAP_ANONYMOUS)) {
/* TODO: lazy page loading */
CHECK_NOTNULL((tmp = malloc(size)));
CHECK_EQ(size, pread(fd, tmp, size, offset));
VirtualRecvWrite(m, virt, tmp, size);
free(tmp);
}
return virt;
}
static int OpMunmap(struct Machine *m, int64_t addr, uint64_t size) {
return FreeVirtual(m, addr, size);
}
static int OpMsync(struct Machine *m, int64_t virt, size_t size, int flags) {
@ -574,18 +608,23 @@ static int OpClose(struct Machine *m, int fd) {
return rc;
}
static int OpOpenat(struct Machine *m, int dirfd, int64_t path, int flags,
static int OpOpenat(struct Machine *m, int dirfd, int64_t pathaddr, int flags,
int mode) {
int fd, i;
const char *path;
flags = XlatOpenFlags(flags);
if ((dirfd = XlatAfd(m, dirfd)) == -1) return -1;
if ((i = MachineFdAdd(&m->fds)) == -1) return -1;
if ((fd = openat(dirfd, LoadStr(m, path), flags, mode)) != -1) {
path = LoadStr(m, pathaddr);
if ((fd = openat(dirfd, path, flags, mode)) != -1) {
m->fds.p[i].cb = &kMachineFdCbHost;
m->fds.p[i].fd = fd;
VERBOSEF("openat(%#x, %`'s, %#x, %#x) → %d [%d]", dirfd, path, flags, mode,
i, fd);
fd = i;
} else {
MachineFdRemove(&m->fds, i);
VERBOSEF("openat(%#x, %`'s, %#x, %#x) failed", dirfd, path, flags, mode);
}
return fd;
}
@ -768,9 +807,13 @@ static ssize_t OpWrite(struct Machine *m, int fd, int64_t addr, size_t size) {
if ((rc = AppendIovsReal(m, &iv, addr, size)) != -1) {
if ((rc = m->fds.p[fd].cb->writev(m->fds.p[fd].fd, iv.p, iv.i)) != -1) {
SetReadAddr(m, addr, rc);
} else {
VERBOSEF("write(%d [%d], %p, %zu) failed: %s", fd, m->fds.p[fd].fd,
addr, size, strerror(errno));
}
}
} else {
VERBOSEF("write(%d, %p, %zu) bad fd", fd, addr, size);
rc = ebadf();
}
FreeIovs(&iv);
@ -1363,7 +1406,7 @@ void OpSyscall(struct Machine *m, uint32_t rde) {
SYSCALL(0x177, vmsplice(di, P(si), dx, r0));
CASE(0xE7, HaltMachine(m, di | 0x100));
default:
LOGF("missing syscall 0x%03x", ax);
VERBOSEF("missing syscall 0x%03x", ax);
ax = enosys();
break;
}

View file

@ -20,6 +20,7 @@
#include "libc/log/check.h"
#include "libc/log/log.h"
#include "libc/nexgen32e/vendor.h"
#include "libc/runtime/gc.h"
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
#include "tool/build/lib/address.h"
@ -34,7 +35,7 @@ static bool IsHaltingInitialized(struct Machine *m) {
void HaltMachine(struct Machine *m, int code) {
CHECK(IsHaltingInitialized(m));
longjmp(m->onhalt, code);
gclongjmp(m->onhalt, code);
}
void ThrowDivideError(struct Machine *m) {