mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-07-16 07:39:56 +00:00
Make terminal ui binaries work well everywhere
Here's some screenshots of an emulator tui program that was compiled on Linux, then scp'd it to Windows, Mac, and FreeBSD. https://justine.storage.googleapis.com/blinkenlights-cmdexe.png https://justine.storage.googleapis.com/blinkenlights-imac.png https://justine.storage.googleapis.com/blinkenlights-freebsd.png https://justine.storage.googleapis.com/blinkenlights-lisp.png How is this even possible that we have a nontrivial ui binary that just works on Mac, Windows, Linux, and BSD? Surely a first ever achievement. Fixed many bugs. Bootstrapped John McCarthy's metacircular evaluator on bare metal in half the size of Altair BASIC (about 2.5kb) and ran it in emulator for fun and profit.
This commit is contained in:
parent
680daf1210
commit
9e3e985ae5
276 changed files with 7026 additions and 3790 deletions
11
tool/build/lib/argv.h
Normal file
11
tool/build/lib/argv.h
Normal file
|
@ -0,0 +1,11 @@
|
|||
#ifndef COSMOPOLITAN_TOOL_BUILD_LIB_ARGV_H_
|
||||
#define COSMOPOLITAN_TOOL_BUILD_LIB_ARGV_H_
|
||||
#include "tool/build/lib/machine.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
void LoadArgv(struct Machine *, const char *, char **, char **);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_TOOL_BUILD_LIB_ARGV_H_ */
|
|
@ -19,6 +19,7 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/alg/arraylist2.h"
|
||||
#include "libc/assert.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "tool/build/lib/breakpoint.h"
|
||||
|
||||
void PopBreakpoint(struct Breakpoints *bps) {
|
||||
|
|
|
@ -22,6 +22,8 @@
|
|||
#include "libc/errno.h"
|
||||
#include "libc/fmt/fmt.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"
|
||||
|
||||
|
@ -38,8 +40,13 @@ void AppendStr(struct Buffer *b, const char *s) {
|
|||
}
|
||||
|
||||
void AppendWide(struct Buffer *b, wint_t wc) {
|
||||
char cbuf[8];
|
||||
AppendData(b, cbuf, tpencode(cbuf, 8, wc, false));
|
||||
uint64_t wb;
|
||||
wb = wc;
|
||||
if (!isascii(wb)) wb = tpenc(wb);
|
||||
do {
|
||||
AppendChar(b, wb & 0xFF);
|
||||
wb >>= 8;
|
||||
} while (wb);
|
||||
}
|
||||
|
||||
void AppendFmt(struct Buffer *b, const char *fmt, ...) {
|
||||
|
|
|
@ -178,9 +178,9 @@ static long DisAppendOpLines(struct Dis *d, struct Machine *m, int64_t addr) {
|
|||
void *r;
|
||||
int64_t ip;
|
||||
unsigned k;
|
||||
uint8_t b[15];
|
||||
struct DisOp op;
|
||||
long i, n, symbol;
|
||||
uint8_t *p, b[15];
|
||||
n = 15;
|
||||
ip = addr - Read64(m->cs);
|
||||
if ((symbol = DisFindSym(d, ip)) != -1) {
|
||||
|
@ -202,8 +202,9 @@ static long DisAppendOpLines(struct Dis *d, struct Machine *m, int64_t addr) {
|
|||
if (!(r = FindReal(m, addr))) return -1;
|
||||
k = 0x1000 - (addr & 0xfff);
|
||||
if (n <= k) {
|
||||
memcpy(b, r, n);
|
||||
p = r;
|
||||
} else {
|
||||
p = b;
|
||||
memcpy(b, r, k);
|
||||
if ((r = FindReal(m, addr + k))) {
|
||||
memcpy(b + k, r, n - k);
|
||||
|
@ -212,7 +213,7 @@ static long DisAppendOpLines(struct Dis *d, struct Machine *m, int64_t addr) {
|
|||
}
|
||||
}
|
||||
xed_decoded_inst_zero_set_mode(d->xedd, m->mode);
|
||||
xed_instruction_length_decode(d->xedd, b, n);
|
||||
xed_instruction_length_decode(d->xedd, p, n);
|
||||
n = d->xedd->op.error ? 1 : d->xedd->length;
|
||||
op.addr = addr;
|
||||
op.size = n;
|
||||
|
@ -240,7 +241,6 @@ long Dis(struct Dis *d, struct Machine *m, uint64_t addr, uint64_t ip,
|
|||
}
|
||||
|
||||
const char *DisGetLine(struct Dis *d, struct Machine *m, size_t i) {
|
||||
char *p;
|
||||
void *r[2];
|
||||
uint8_t b[15];
|
||||
if (i >= d->ops.i) return "";
|
||||
|
@ -250,10 +250,9 @@ const char *DisGetLine(struct Dis *d, struct Machine *m, size_t i) {
|
|||
xed_instruction_length_decode(
|
||||
d->xedd, AccessRam(m, d->ops.p[i].addr, d->ops.p[i].size, r, b, true),
|
||||
d->ops.p[i].size);
|
||||
d->addr = d->ops.p[i].addr;
|
||||
d->m = m;
|
||||
p = DisLineCode(d, d->buf);
|
||||
CHECK_LT(p - d->buf, sizeof(d->buf));
|
||||
d->addr = d->ops.p[i].addr;
|
||||
CHECK_LT(DisLineCode(d, d->buf) - d->buf, sizeof(d->buf));
|
||||
return d->buf;
|
||||
}
|
||||
|
||||
|
|
|
@ -17,10 +17,8 @@
|
|||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/alg/arraylist.h"
|
||||
#include "libc/alg/arraylist2.h"
|
||||
#include "libc/assert.h"
|
||||
#include "libc/bits/safemacros.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/macros.h"
|
||||
|
@ -44,7 +42,8 @@ static const Elf64_Ehdr kObjHeader = {
|
|||
.e_machine = EM_NEXGEN32E,
|
||||
.e_version = 1,
|
||||
.e_ehsize = sizeof(Elf64_Ehdr),
|
||||
.e_shentsize = sizeof(Elf64_Shdr)};
|
||||
.e_shentsize = sizeof(Elf64_Shdr),
|
||||
};
|
||||
|
||||
static size_t AppendSection(struct ElfWriter *elf, const char *name,
|
||||
int sh_type, int sh_flags) {
|
||||
|
@ -193,7 +192,7 @@ void elfwriter_close(struct ElfWriter *elf) {
|
|||
void elfwriter_align(struct ElfWriter *elf, size_t addralign, size_t entsize) {
|
||||
elf->entsize = entsize;
|
||||
elf->addralign = addralign;
|
||||
elf->wrote = roundup(elf->wrote, addralign);
|
||||
elf->wrote = ROUNDUP(elf->wrote, addralign);
|
||||
}
|
||||
|
||||
size_t elfwriter_startsection(struct ElfWriter *elf, const char *name,
|
||||
|
@ -214,7 +213,7 @@ void *elfwriter_reserve(struct ElfWriter *elf, size_t size) {
|
|||
do {
|
||||
greed = greed + (greed >> 1);
|
||||
} while (need > greed);
|
||||
greed = roundup(greed, FRAMESIZE);
|
||||
greed = ROUNDUP(greed, FRAMESIZE);
|
||||
CHECK_NE(-1, ftruncate(elf->fd, greed));
|
||||
CHECK_NE(MAP_FAILED, mmap((char *)elf->map + elf->mapsize,
|
||||
greed - elf->mapsize, PROT_READ | PROT_WRITE,
|
||||
|
|
|
@ -23,11 +23,11 @@
|
|||
void elfwriter_yoink(struct ElfWriter *elf, const char *symbol) {
|
||||
unsigned char *p;
|
||||
struct ElfWriterSymRef sym;
|
||||
const unsigned char nopl[8] = "\x0f\x1f\x04\x25\x00\x00\x00\x00";
|
||||
const unsigned char kNopl[8] = "\017\037\004\045\000\000\000\000";
|
||||
p = elfwriter_reserve(elf, 8);
|
||||
memcpy(p, nopl, sizeof(nopl));
|
||||
memcpy(p, kNopl, sizeof(kNopl));
|
||||
sym = elfwriter_linksym(elf, symbol, ELF64_ST_INFO(STB_GLOBAL, STT_OBJECT),
|
||||
STV_HIDDEN);
|
||||
elfwriter_appendrela(elf, sizeof(nopl) - 4, sym, R_X86_64_32, 0);
|
||||
elfwriter_commit(elf, sizeof(nopl));
|
||||
elfwriter_appendrela(elf, sizeof(kNopl) - 4, sym, R_X86_64_32, 0);
|
||||
elfwriter_commit(elf, sizeof(kNopl));
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#ifndef COSMOPOLITAN_TOOL_BUILD_LIB_ENDIAN_H_
|
||||
#define COSMOPOLITAN_TOOL_BUILD_LIB_ENDIAN_H_
|
||||
#include "libc/dce.h"
|
||||
#include "libc/str/str.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
#if __BYTE_ORDER__ + 0 == 1234
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#ifndef COSMOPOLITAN_TOOL_BUILD_LIB_FDS_H_
|
||||
#define COSMOPOLITAN_TOOL_BUILD_LIB_FDS_H_
|
||||
#include "libc/calls/struct/iovec.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
|
@ -9,8 +10,8 @@ struct MachineFds {
|
|||
int fd;
|
||||
struct MachineFdCb {
|
||||
int (*close)(int);
|
||||
ssize_t (*read)(int, void *, size_t);
|
||||
ssize_t (*write)(int, const void *, size_t);
|
||||
ssize_t (*readv)(int, const struct iovec *, int);
|
||||
ssize_t (*writev)(int, const struct iovec *, int);
|
||||
int (*ioctl)(int, uint64_t, void *);
|
||||
} * cb;
|
||||
} * p;
|
||||
|
|
|
@ -75,12 +75,12 @@ void LoadInstruction(struct Machine *m) {
|
|||
key = ip & (ARRAYLEN(m->icache) - 1);
|
||||
m->xedd = (struct XedDecodedInst *)m->icache[key];
|
||||
if ((ip & 0xfff) < 0x1000 - 15) {
|
||||
if (ip - (ip & 0xfff) == m->codevirt && ip) {
|
||||
addr = m->codereal + (ip & 0xfff);
|
||||
if (ip - (ip & 0xfff) == m->codevirt && m->codehost) {
|
||||
addr = m->codehost + (ip & 0xfff);
|
||||
} else {
|
||||
m->codevirt = ip - (ip & 0xfff);
|
||||
m->codereal = ResolveAddress(m, m->codevirt);
|
||||
addr = m->codereal + (ip & 0xfff);
|
||||
m->codehost = ResolveAddress(m, m->codevirt);
|
||||
addr = m->codehost + (ip & 0xfff);
|
||||
}
|
||||
if (!IsOpcodeEqual(m->xedd, addr)) {
|
||||
DecodeInstruction(m, addr, 15);
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/struct/iovec.h"
|
||||
#include "libc/sysv/consts/fileno.h"
|
||||
#include "tool/build/lib/ioports.h"
|
||||
|
||||
|
@ -26,7 +27,7 @@ static int OpE9Read(struct Machine *m) {
|
|||
fd = STDIN_FILENO;
|
||||
if (fd >= m->fds.i) return -1;
|
||||
if (!m->fds.p[fd].cb) return -1;
|
||||
if (m->fds.p[fd].cb->read(m->fds.p[fd].fd, &b, 1) == 1) {
|
||||
if (m->fds.p[fd].cb->readv(m->fds.p[fd].fd, &(struct iovec){&b, 1}, 1) == 1) {
|
||||
return b;
|
||||
} else {
|
||||
return -1;
|
||||
|
@ -38,7 +39,7 @@ static void OpE9Write(struct Machine *m, uint8_t b) {
|
|||
fd = STDOUT_FILENO;
|
||||
if (fd >= m->fds.i) return;
|
||||
if (!m->fds.p[fd].cb) return;
|
||||
m->fds.p[fd].cb->write(m->fds.p[fd].fd, &b, 1);
|
||||
m->fds.p[fd].cb->writev(m->fds.p[fd].fd, &(struct iovec){&b, 1}, 1);
|
||||
}
|
||||
|
||||
uint64_t OpIn(struct Machine *m, uint16_t p) {
|
||||
|
|
|
@ -17,7 +17,37 @@
|
|||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "tool/build/lib/machine.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "tool/build/lib/iovs.h"
|
||||
|
||||
void InitMachine(struct Machine *m) {
|
||||
/**
|
||||
* Appends memory region to i/o vector builder.
|
||||
*/
|
||||
int AppendIovs(struct Iovs *ib, void *base, size_t len) {
|
||||
unsigned i, n;
|
||||
struct iovec *p;
|
||||
if (len) {
|
||||
p = ib->p;
|
||||
i = ib->i;
|
||||
n = ib->n;
|
||||
if (i && (intptr_t)base == (intptr_t)p[i - 1].iov_base + p[i - 1].iov_len) {
|
||||
p[i - 1].iov_len += len;
|
||||
} else {
|
||||
if (unlikely(i == n)) {
|
||||
n += n >> 1;
|
||||
if (p == ib->init) {
|
||||
if (!(p = malloc(sizeof(struct iovec) * n))) return -1;
|
||||
memcpy(p, ib->init, sizeof(ib->init));
|
||||
} else {
|
||||
if (!(p = realloc(p, sizeof(struct iovec) * n))) return -1;
|
||||
}
|
||||
ib->p = p;
|
||||
ib->n = n;
|
||||
}
|
||||
p[i].iov_base = base;
|
||||
p[i].iov_len = len;
|
||||
++ib->i;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
31
tool/build/lib/iovs.h
Normal file
31
tool/build/lib/iovs.h
Normal file
|
@ -0,0 +1,31 @@
|
|||
#ifndef COSMOPOLITAN_TOOL_BUILD_LIB_IOVS_H_
|
||||
#define COSMOPOLITAN_TOOL_BUILD_LIB_IOVS_H_
|
||||
#include "libc/calls/struct/iovec.h"
|
||||
#include "libc/macros.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
struct Iovs {
|
||||
struct iovec *p;
|
||||
unsigned i, n;
|
||||
struct iovec init[2];
|
||||
};
|
||||
|
||||
int AppendIovs(struct Iovs *, void *, size_t);
|
||||
|
||||
forceinline void InitIovs(struct Iovs *ib) {
|
||||
ib->p = ib->init;
|
||||
ib->i = 0;
|
||||
ib->n = ARRAYLEN(ib->init);
|
||||
}
|
||||
|
||||
forceinline void FreeIovs(struct Iovs *ib) {
|
||||
if (ib->p != ib->init) {
|
||||
free(ib->p);
|
||||
}
|
||||
}
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_TOOL_BUILD_LIB_IOVS_H_ */
|
|
@ -23,20 +23,21 @@
|
|||
#include "libc/elf/elf.h"
|
||||
#include "libc/elf/struct/phdr.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/macros.h"
|
||||
#include "libc/nexgen32e/vendor.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/sysv/consts/fileno.h"
|
||||
#include "libc/sysv/consts/map.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/consts/prot.h"
|
||||
#include "tool/build/lib/argv.h"
|
||||
#include "tool/build/lib/endian.h"
|
||||
#include "tool/build/lib/loader.h"
|
||||
#include "tool/build/lib/machine.h"
|
||||
#include "tool/build/lib/memory.h"
|
||||
|
||||
#define DSOLOL "ERROR: ELF not ET_EXEC try `gcc -static -o foo foo.c`\n"
|
||||
|
||||
static void LoadElfLoadSegment(struct Machine *m, void *code, size_t codesize,
|
||||
Elf64_Phdr *phdr) {
|
||||
void *rbss;
|
||||
|
@ -45,13 +46,20 @@ 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);
|
||||
vend = ROUNDUP(phdr->p_vaddr + phdr->p_memsz, align);
|
||||
fstart = felf + ROUNDDOWN(phdr->p_offset, align);
|
||||
fend = felf + ROUNDUP(phdr->p_offset + phdr->p_filesz, 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);
|
||||
m->brk = MAX(m->brk, vend);
|
||||
CHECK_GE(vend, vstart);
|
||||
CHECK_GE(fend, fstart);
|
||||
|
@ -61,12 +69,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, RegisterMemory(m, vstart, (void *)fstart, fend - fstart));
|
||||
if (bsssize) {
|
||||
CHECK_NE(MAP_FAILED, (rbss = mmap(NULL, bsssize, PROT_READ | PROT_WRITE,
|
||||
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0)));
|
||||
CHECK_NE(-1, RegisterMemory(m, vbss, rbss, bsssize));
|
||||
}
|
||||
CHECK_NE(-1, ReserveVirtual(m, vstart, fend - fstart));
|
||||
VirtualRecv(m, vstart, (void *)fstart, fend - fstart);
|
||||
if (bsssize) CHECK_NE(-1, ReserveVirtual(m, vbss, bsssize));
|
||||
if (phdr->p_memsz - phdr->p_filesz > bsssize) {
|
||||
VirtualSet(m, phdr->p_vaddr + phdr->p_filesz, 0,
|
||||
phdr->p_memsz - phdr->p_filesz - bsssize);
|
||||
|
@ -76,11 +81,8 @@ static void LoadElfLoadSegment(struct Machine *m, void *code, size_t codesize,
|
|||
static void LoadElf(struct Machine *m, struct Elf *elf) {
|
||||
unsigned i;
|
||||
Elf64_Phdr *phdr;
|
||||
if (elf->ehdr->e_type != ET_EXEC) {
|
||||
write(STDERR_FILENO, DSOLOL, strlen(DSOLOL));
|
||||
exit(1);
|
||||
}
|
||||
m->ip = elf->base = elf->ehdr->e_entry;
|
||||
LOGF("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) {
|
||||
|
@ -114,10 +116,11 @@ void LoadProgram(struct Machine *m, const char *prog, char **args, char **vars,
|
|||
struct Elf *elf) {
|
||||
int fd;
|
||||
ssize_t rc;
|
||||
int64_t sp;
|
||||
char *real;
|
||||
void *stack;
|
||||
struct stat st;
|
||||
char *real, *memory;
|
||||
size_t i, codesize, mappedsize, extrasize, stacksize;
|
||||
size_t i, codesize, mappedsize, extrasize;
|
||||
DCHECK_NOTNULL(prog);
|
||||
elf->prog = prog;
|
||||
if ((fd = open(prog, O_RDONLY)) == -1 ||
|
||||
|
@ -148,14 +151,11 @@ void LoadProgram(struct Machine *m, const char *prog, char **args, char **vars,
|
|||
ResetCpu(m);
|
||||
if (m->mode == XED_MACHINE_MODE_REAL) {
|
||||
elf->base = 0x7c00;
|
||||
CHECK_NE(MAP_FAILED,
|
||||
(memory = mmap(NULL, BIGPAGESIZE, PROT_READ | PROT_WRITE,
|
||||
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0)));
|
||||
RegisterMemory(m, 0, memory, BIGPAGESIZE);
|
||||
CHECK_NE(-1, ReserveVirtual(m, 0, BIGPAGESIZE));
|
||||
m->ip = 0x7c00;
|
||||
Write64(m->cs, 0);
|
||||
Write64(m->dx, 0);
|
||||
memcpy(memory + 0x7c00, elf->map, 512);
|
||||
VirtualRecv(m, m->ip, elf->map, 512);
|
||||
if (memcmp(elf->map, "\177ELF", 4) == 0) {
|
||||
elf->ehdr = (void *)elf->map;
|
||||
elf->size = codesize;
|
||||
|
@ -166,11 +166,9 @@ void LoadProgram(struct Machine *m, const char *prog, char **args, char **vars,
|
|||
elf->size = 0;
|
||||
}
|
||||
} else {
|
||||
stacksize = STACKSIZE;
|
||||
CHECK_NE(MAP_FAILED, (stack = mmap(NULL, stacksize, PROT_READ | PROT_WRITE,
|
||||
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0)));
|
||||
Write64(m->sp, 0x0000800000000000);
|
||||
RegisterMemory(m, 0x0000800000000000 - stacksize, stack, stacksize);
|
||||
sp = 0x800000000000;
|
||||
Write64(m->sp, sp);
|
||||
CHECK_NE(-1, ReserveVirtual(m, sp - STACKSIZE, STACKSIZE));
|
||||
LoadArgv(m, prog, args, vars);
|
||||
if (memcmp(elf->map, "\177ELF", 4) == 0) {
|
||||
elf->ehdr = (void *)elf->map;
|
||||
|
|
|
@ -17,11 +17,6 @@
|
|||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/conv/conv.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/macros.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "tool/build/lib/abp.h"
|
||||
|
@ -558,7 +553,7 @@ static void OpMovZvqpIvqp(struct Machine *m, uint32_t rde) {
|
|||
WriteRegister(rde, RegRexbSrm(m, rde), m->xedd->op.uimm0);
|
||||
}
|
||||
|
||||
static void OpIncZv(struct Machine *m, uint32_t rde) {
|
||||
static relegated void OpIncZv(struct Machine *m, uint32_t rde) {
|
||||
if (!Osz(rde)) {
|
||||
Write32(RegSrm(m, rde), Inc32(Read32(RegSrm(m, rde)), 0, &m->flags));
|
||||
} else {
|
||||
|
@ -566,7 +561,7 @@ static void OpIncZv(struct Machine *m, uint32_t rde) {
|
|||
}
|
||||
}
|
||||
|
||||
static void OpDecZv(struct Machine *m, uint32_t rde) {
|
||||
static relegated void OpDecZv(struct Machine *m, uint32_t rde) {
|
||||
if (!Osz(rde)) {
|
||||
Write32(RegSrm(m, rde), Dec32(Read32(RegSrm(m, rde)), 0, &m->flags));
|
||||
} else {
|
||||
|
@ -888,22 +883,6 @@ static void OpBsubiImm(struct Machine *m, uint32_t rde) {
|
|||
Bsubi(m, rde, m->xedd->op.uimm0);
|
||||
}
|
||||
|
||||
static relegated void LoadFarPointer(struct Machine *m, uint32_t rde,
|
||||
uint8_t seg[8]) {
|
||||
uint32_t fp;
|
||||
fp = Read32(ComputeReserveAddressRead4(m, rde));
|
||||
Write64(seg, (fp & 0x0000ffff) << 4);
|
||||
Write16(RegRexrReg(m, rde), fp >> 16);
|
||||
}
|
||||
|
||||
static relegated void OpLes(struct Machine *m, uint32_t rde) {
|
||||
LoadFarPointer(m, rde, m->es);
|
||||
}
|
||||
|
||||
static relegated void OpLds(struct Machine *m, uint32_t rde) {
|
||||
LoadFarPointer(m, rde, m->ds);
|
||||
}
|
||||
|
||||
static void OpLgdtMs(struct Machine *m, uint32_t rde) {
|
||||
}
|
||||
|
||||
|
@ -1234,6 +1213,22 @@ static void OpNegEb(struct Machine *m, uint32_t rde) {
|
|||
AluEb(m, rde, Neg8);
|
||||
}
|
||||
|
||||
static relegated void LoadFarPointer(struct Machine *m, uint32_t rde,
|
||||
uint8_t seg[8]) {
|
||||
uint32_t fp;
|
||||
fp = Read32(ComputeReserveAddressRead4(m, rde));
|
||||
Write64(seg, (fp & 0x0000ffff) << 4);
|
||||
Write16(RegRexrReg(m, rde), fp >> 16);
|
||||
}
|
||||
|
||||
static relegated void OpLes(struct Machine *m, uint32_t rde) {
|
||||
LoadFarPointer(m, rde, m->es);
|
||||
}
|
||||
|
||||
static relegated void OpLds(struct Machine *m, uint32_t rde) {
|
||||
LoadFarPointer(m, rde, m->ds);
|
||||
}
|
||||
|
||||
static relegated void Loop(struct Machine *m, uint32_t rde, bool cond) {
|
||||
uint64_t cx;
|
||||
cx = Read64(m->cx) - 1;
|
||||
|
@ -1386,10 +1381,12 @@ static void OpSalc(struct Machine *m, uint32_t rde) {
|
|||
}
|
||||
|
||||
static void OpNopEv(struct Machine *m, uint32_t rde) {
|
||||
if (ModrmMod(rde) == 0b01 && ModrmReg(rde) == 0 && ModrmRm(rde) == 0b101) {
|
||||
OpBofram(m, rde);
|
||||
} else {
|
||||
OpNoop(m, rde);
|
||||
switch (ModrmMod(rde) << 6 | ModrmReg(rde) << 3 | ModrmRm(rde)) {
|
||||
case 0x45:
|
||||
OpBofram(m, rde);
|
||||
break;
|
||||
default:
|
||||
OpNoop(m, rde);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,10 +5,6 @@
|
|||
#include "tool/build/lib/fds.h"
|
||||
#include "tool/build/lib/pml4t.h"
|
||||
|
||||
#define kXmmIntegral 0
|
||||
#define kXmmDouble 1
|
||||
#define kXmmFloat 2
|
||||
|
||||
#define kMachineHalt -1
|
||||
#define kMachineDecodeError -2
|
||||
#define kMachineUndefinedInstruction -3
|
||||
|
@ -28,7 +24,7 @@ struct Machine {
|
|||
uint8_t cs[8];
|
||||
uint8_t ss[8];
|
||||
uint64_t codevirt;
|
||||
uint8_t *codereal;
|
||||
uint8_t *codehost;
|
||||
uint32_t mode;
|
||||
uint32_t flags;
|
||||
uint32_t tlbindex;
|
||||
|
@ -59,13 +55,15 @@ struct Machine {
|
|||
uint8_t r15[8];
|
||||
};
|
||||
};
|
||||
uint8_t *real;
|
||||
uint64_t realsize;
|
||||
uint64_t *cr3;
|
||||
struct TlbEntry {
|
||||
int64_t v;
|
||||
void *r;
|
||||
struct MachineTlb {
|
||||
int64_t virt;
|
||||
uint8_t *host;
|
||||
} tlb[16];
|
||||
struct MachineReal {
|
||||
size_t i, n;
|
||||
uint8_t *p;
|
||||
} real;
|
||||
uint64_t cr3;
|
||||
uint8_t xmm[16][16] aligned(16);
|
||||
uint8_t es[8];
|
||||
uint8_t ds[8];
|
||||
|
@ -76,34 +74,34 @@ struct Machine {
|
|||
union {
|
||||
uint32_t cw;
|
||||
struct {
|
||||
unsigned im : 1; /* invalid operation mask */
|
||||
unsigned dm : 1; /* denormal operand mask */
|
||||
unsigned zm : 1; /* zero divide mask */
|
||||
unsigned om : 1; /* overflow mask */
|
||||
unsigned um : 1; /* underflow mask */
|
||||
unsigned pm : 1; /* precision mask */
|
||||
unsigned _p1 : 2; /* reserved */
|
||||
unsigned pc : 2; /* precision: 32,∅,64,80 */
|
||||
unsigned rc : 2; /* rounding: even,→-∞,→+∞,→0 */
|
||||
unsigned im : 1; // invalid operation mask
|
||||
unsigned dm : 1; // denormal operand mask
|
||||
unsigned zm : 1; // zero divide mask
|
||||
unsigned om : 1; // overflow mask
|
||||
unsigned um : 1; // underflow mask
|
||||
unsigned pm : 1; // precision mask
|
||||
unsigned _p1 : 2; // reserved
|
||||
unsigned pc : 2; // precision: 32,∅,64,80
|
||||
unsigned rc : 2; // rounding: even,→-∞,→+∞,→0
|
||||
};
|
||||
};
|
||||
union {
|
||||
uint32_t sw;
|
||||
struct {
|
||||
unsigned ie : 1; /* invalid operation */
|
||||
unsigned de : 1; /* denormalized operand */
|
||||
unsigned ze : 1; /* zero divide */
|
||||
unsigned oe : 1; /* overflow */
|
||||
unsigned ue : 1; /* underflow */
|
||||
unsigned pe : 1; /* precision */
|
||||
unsigned sf : 1; /* stack fault */
|
||||
unsigned es : 1; /* exception summary status */
|
||||
unsigned c0 : 1; /* condition 0 */
|
||||
unsigned c1 : 1; /* condition 1 */
|
||||
unsigned c2 : 1; /* condition 2 */
|
||||
unsigned sp : 3; /* top stack */
|
||||
unsigned c3 : 1; /* condition 3 */
|
||||
unsigned bf : 1; /* busy flag */
|
||||
unsigned ie : 1; // invalid operation
|
||||
unsigned de : 1; // denormalized operand
|
||||
unsigned ze : 1; // zero divide
|
||||
unsigned oe : 1; // overflow
|
||||
unsigned ue : 1; // underflow
|
||||
unsigned pe : 1; // precision
|
||||
unsigned sf : 1; // stack fault
|
||||
unsigned es : 1; // exception summary status
|
||||
unsigned c0 : 1; // condition 0
|
||||
unsigned c1 : 1; // condition 1
|
||||
unsigned c2 : 1; // condition 2
|
||||
unsigned sp : 3; // top stack
|
||||
unsigned c3 : 1; // condition 3
|
||||
unsigned bf : 1; // busy flag
|
||||
};
|
||||
};
|
||||
int tw;
|
||||
|
@ -111,28 +109,33 @@ struct Machine {
|
|||
int64_t ip;
|
||||
int64_t dp;
|
||||
} fpu;
|
||||
struct {
|
||||
struct MachineSse {
|
||||
union {
|
||||
uint32_t mxcsr;
|
||||
struct {
|
||||
unsigned ie : 1; /* invalid operation flag */
|
||||
unsigned de : 1; /* denormal flag */
|
||||
unsigned ze : 1; /* divide by zero flag */
|
||||
unsigned oe : 1; /* overflow flag */
|
||||
unsigned ue : 1; /* underflow flag */
|
||||
unsigned pe : 1; /* precision flag */
|
||||
unsigned daz : 1; /* denormals are zeros */
|
||||
unsigned im : 1; /* invalid operation mask */
|
||||
unsigned dm : 1; /* denormal mask */
|
||||
unsigned zm : 1; /* divide by zero mask */
|
||||
unsigned om : 1; /* overflow mask */
|
||||
unsigned um : 1; /* underflow mask */
|
||||
unsigned pm : 1; /* precision mask */
|
||||
unsigned rc : 2; /* rounding control */
|
||||
unsigned ftz : 1; /* flush to zero */
|
||||
unsigned ie : 1; // invalid operation flag
|
||||
unsigned de : 1; // denormal flag
|
||||
unsigned ze : 1; // divide by zero flag
|
||||
unsigned oe : 1; // overflow flag
|
||||
unsigned ue : 1; // underflow flag
|
||||
unsigned pe : 1; // precision flag
|
||||
unsigned daz : 1; // denormals are zeros
|
||||
unsigned im : 1; // invalid operation mask
|
||||
unsigned dm : 1; // denormal mask
|
||||
unsigned zm : 1; // divide by zero mask
|
||||
unsigned om : 1; // overflow mask
|
||||
unsigned um : 1; // underflow mask
|
||||
unsigned pm : 1; // precision mask
|
||||
unsigned rc : 2; // rounding control
|
||||
unsigned ftz : 1; // flush to zero
|
||||
};
|
||||
};
|
||||
} sse;
|
||||
struct MachineRealFree {
|
||||
uint64_t i;
|
||||
uint64_t n;
|
||||
struct MachineRealFree *next;
|
||||
} * realfree;
|
||||
struct FreeList {
|
||||
uint32_t i;
|
||||
void *p[6];
|
||||
|
@ -141,18 +144,23 @@ struct Machine {
|
|||
int64_t bofram[2];
|
||||
jmp_buf onhalt;
|
||||
int64_t faultaddr;
|
||||
uint8_t stash[4096];
|
||||
uint8_t xmmtype[2][8];
|
||||
uint8_t icache[4096 / 4][40] aligned(16);
|
||||
struct MachineFds fds;
|
||||
uint8_t stash[4096];
|
||||
uint8_t icache[1024][40];
|
||||
} aligned(64);
|
||||
|
||||
struct Machine *NewMachine(void) nodiscard;
|
||||
void FreeMachine(struct Machine *);
|
||||
void ResetMem(struct Machine *);
|
||||
void ResetCpu(struct Machine *);
|
||||
void ResetTlb(struct Machine *);
|
||||
void LoadInstruction(struct Machine *);
|
||||
void ExecuteInstruction(struct Machine *);
|
||||
struct Machine *NewMachine(void) nodiscard;
|
||||
void LoadArgv(struct Machine *, const char *, char **, char **);
|
||||
void InitMachine(struct Machine *);
|
||||
long AllocateLinearPage(struct Machine *);
|
||||
int ReserveVirtual(struct Machine *, int64_t, size_t);
|
||||
char *FormatPml4t(struct Machine *) nodiscard;
|
||||
int64_t FindVirtual(struct Machine *, int64_t, size_t);
|
||||
int FreeVirtual(struct Machine *, int64_t, size_t);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
|
|
|
@ -31,39 +31,54 @@
|
|||
#include "tool/build/lib/throw.h"
|
||||
|
||||
void SetReadAddr(struct Machine *m, int64_t addr, uint32_t size) {
|
||||
m->readaddr = addr;
|
||||
m->readsize = size;
|
||||
if (size) {
|
||||
m->readaddr = addr;
|
||||
m->readsize = size;
|
||||
}
|
||||
}
|
||||
|
||||
void SetWriteAddr(struct Machine *m, int64_t addr, uint32_t size) {
|
||||
m->writeaddr = addr;
|
||||
m->writesize = size;
|
||||
if (size) {
|
||||
m->writeaddr = addr;
|
||||
m->writesize = size;
|
||||
}
|
||||
}
|
||||
|
||||
void *FindReal(struct Machine *m, int64_t v) {
|
||||
uint64_t *p;
|
||||
unsigned skew;
|
||||
unsigned char i;
|
||||
skew = v & 0xfff;
|
||||
v &= -0x1000;
|
||||
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)) {
|
||||
return NULL;
|
||||
}
|
||||
skew = virt & 0xfff;
|
||||
virt &= -0x1000;
|
||||
for (i = 0; i < ARRAYLEN(m->tlb); ++i) {
|
||||
if (m->tlb[i].v == v && m->tlb[i].r) {
|
||||
return (char *)m->tlb[i].r + skew;
|
||||
if (m->tlb[i].virt == virt && m->tlb[i].host) {
|
||||
return m->tlb[i].host + skew;
|
||||
}
|
||||
}
|
||||
for (p = m->cr3, i = 39; i >= 12; i -= 9) {
|
||||
if (IsValidPage(p[(v >> i) & 511])) {
|
||||
p = UnmaskPageAddr(p[(v >> i) & 511]);
|
||||
} else {
|
||||
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].r = p;
|
||||
m->tlb[0].v = ROUNDDOWN(v, 0x1000);
|
||||
DCHECK_NOTNULL(p);
|
||||
return (char *)p + skew;
|
||||
m->tlb[0].host = host;
|
||||
m->tlb[0].virt = virt;
|
||||
return host + skew;
|
||||
}
|
||||
|
||||
void *ResolveAddress(struct Machine *m, int64_t v) {
|
||||
|
@ -196,7 +211,7 @@ void *LoadStr(struct Machine *m, int64_t addr) {
|
|||
if (!addr) return NULL;
|
||||
if (!(page = FindReal(m, addr))) return NULL;
|
||||
if ((p = memchr(page, '\0', have))) {
|
||||
SetReadAddr(m, addr, p - page);
|
||||
SetReadAddr(m, addr, p - page + 1);
|
||||
return page;
|
||||
}
|
||||
CHECK_LT(m->freelist.i, ARRAYLEN(m->freelist.p));
|
||||
|
@ -205,7 +220,7 @@ void *LoadStr(struct Machine *m, int64_t addr) {
|
|||
for (;;) {
|
||||
if (!(page = FindReal(m, addr + have))) break;
|
||||
if ((p = memccpy(copy + have, page, '\0', 0x1000))) {
|
||||
SetReadAddr(m, addr, have + (p - (copy + have)));
|
||||
SetReadAddr(m, addr, have + (p - (copy + have)) + 1);
|
||||
return (m->freelist.p[m->freelist.i++] = copy);
|
||||
}
|
||||
have += 0x1000;
|
||||
|
@ -217,19 +232,19 @@ void *LoadStr(struct Machine *m, int64_t addr) {
|
|||
}
|
||||
|
||||
void *LoadBuf(struct Machine *m, int64_t addr, size_t size) {
|
||||
char *buf, *copy;
|
||||
size_t have, need;
|
||||
char *buf, *copy, *page;
|
||||
have = 0x1000 - (addr & 0xfff);
|
||||
if (!addr) return NULL;
|
||||
if (!(buf = FindReal(m, addr))) return NULL;
|
||||
if (size > have) {
|
||||
CHECK_LT(m->freelist.i, ARRAYLEN(m->freelist.p));
|
||||
if (!(copy = malloc(size))) return NULL;
|
||||
memcpy(copy, buf, have);
|
||||
buf = memcpy(copy, buf, have);
|
||||
do {
|
||||
need = MIN(0x1000, size - have);
|
||||
if ((buf = FindReal(m, addr + have))) {
|
||||
memcpy(copy + have, buf, need);
|
||||
if ((page = FindReal(m, addr + have))) {
|
||||
memcpy(copy + have, page, need);
|
||||
have += need;
|
||||
} else {
|
||||
free(copy);
|
||||
|
|
|
@ -17,35 +17,167 @@
|
|||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/x/x.h"
|
||||
#include "tool/build/lib/buffer.h"
|
||||
#include "tool/build/lib/endian.h"
|
||||
#include "tool/build/lib/machine.h"
|
||||
#include "tool/build/lib/memory.h"
|
||||
#include "tool/build/lib/pml4t.h"
|
||||
|
||||
void *MallocPage(void) {
|
||||
void *p;
|
||||
size_t n;
|
||||
if ((p = memalign(4096, 4096))) {
|
||||
memset(p, 0, 4096);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
int RegisterMemory(struct Machine *m, int64_t v, void *r, size_t n) {
|
||||
return RegisterPml4t(m->cr3, v, (int64_t)(intptr_t)r, n, MallocPage);
|
||||
}
|
||||
|
||||
void ResetRam(struct Machine *m) {
|
||||
FreePml4t(m->cr3, -0x800000000000, 0x800000000000, free, munmap);
|
||||
}
|
||||
|
||||
struct Machine *NewMachine(void) {
|
||||
struct Machine *m;
|
||||
m = memalign(alignof(struct Machine), sizeof(struct Machine));
|
||||
memset(m, 0, sizeof(struct Machine));
|
||||
m = xmemalignzero(alignof(struct Machine), sizeof(struct Machine));
|
||||
m->mode = XED_MACHINE_MODE_LONG_64;
|
||||
InitMachine(m);
|
||||
ResetCpu(m);
|
||||
ResetMem(m);
|
||||
return m;
|
||||
}
|
||||
|
||||
static void FreeMachineRealFree(struct Machine *m) {
|
||||
struct MachineRealFree *rf;
|
||||
while ((rf = m->realfree)) {
|
||||
m->realfree = rf->next;
|
||||
free(rf);
|
||||
}
|
||||
}
|
||||
|
||||
void FreeMachine(struct Machine *m) {
|
||||
if (m) {
|
||||
FreeMachineRealFree(m);
|
||||
free(m->real.p);
|
||||
free(m);
|
||||
}
|
||||
}
|
||||
|
||||
void ResetMem(struct Machine *m) {
|
||||
FreeMachineRealFree(m);
|
||||
ResetTlb(m);
|
||||
m->real.i = 0;
|
||||
m->cr3 = AllocateLinearPage(m);
|
||||
}
|
||||
|
||||
long AllocateLinearPage(struct Machine *m) {
|
||||
uint8_t *p;
|
||||
size_t i, n;
|
||||
struct MachineRealFree *rf;
|
||||
if ((rf = m->realfree)) {
|
||||
DCHECK(rf->n);
|
||||
DCHECK_EQ(0, rf->i & 0xfff);
|
||||
DCHECK_EQ(0, rf->n & 0xfff);
|
||||
DCHECK_LE(rf->i + rf->n, m->real.i);
|
||||
i = rf->i;
|
||||
rf->i += 0x1000;
|
||||
if (!(rf->n -= 0x1000)) {
|
||||
m->realfree = rf->next;
|
||||
free(rf);
|
||||
}
|
||||
} else {
|
||||
i = m->real.i;
|
||||
n = m->real.n;
|
||||
p = m->real.p;
|
||||
if (i == n) {
|
||||
if (n) {
|
||||
n += n >> 1;
|
||||
} else {
|
||||
n = 0x10000;
|
||||
}
|
||||
n = ROUNDUP(n, 0x1000);
|
||||
if ((p = realloc(p, n))) {
|
||||
m->real.p = p;
|
||||
m->real.n = n;
|
||||
ResetTlb(m);
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
DCHECK_EQ(0, i & 0xfff);
|
||||
DCHECK_EQ(0, n & 0xfff);
|
||||
DCHECK_LE(i + 0x1000, n);
|
||||
m->real.i += 0x1000;
|
||||
}
|
||||
memset(m->real.p + i, 0, 0x1000); /* TODO: lazy page clearing */
|
||||
return i;
|
||||
}
|
||||
|
||||
static uint64_t MachineRead64(struct Machine *m, unsigned long i) {
|
||||
CHECK_LE(i + 8, m->real.n);
|
||||
return Read64(m->real.p + i);
|
||||
}
|
||||
|
||||
static void MachineWrite64(struct Machine *m, unsigned long i, uint64_t x) {
|
||||
CHECK_LE(i + 8, m->real.n);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int64_t FindVirtual(struct Machine *m, int64_t virt, size_t size) {
|
||||
uint64_t i, pt, got;
|
||||
got = 0;
|
||||
do {
|
||||
if (virt >= 0x800000000000) return enomem();
|
||||
for (pt = m->cr3, i = 39; i >= 12; i -= 9) {
|
||||
pt = MachineRead64(m, (pt & 0x7ffffffff000) + ((virt >> i) & 511) * 8);
|
||||
if (!(pt & 1)) break;
|
||||
}
|
||||
if (i >= 12) {
|
||||
got += 1ull << i;
|
||||
} else {
|
||||
virt += 0x1000;
|
||||
got = 0;
|
||||
}
|
||||
} while (got < size);
|
||||
return virt;
|
||||
}
|
||||
|
||||
int FreeVirtual(struct Machine *m, int64_t base, size_t size) {
|
||||
struct MachineRealFree *rf;
|
||||
uint64_t i, mi, pt, la, end, virt;
|
||||
for (virt = base, end = virt + size; virt < end;) {
|
||||
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;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
virt += 1ull << i;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1,192 +0,0 @@
|
|||
/*-*- 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 "libc/log/check.h"
|
||||
#include "libc/macros.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "tool/build/lib/memory.h"
|
||||
#include "tool/build/lib/pml4t.h"
|
||||
|
||||
static int64_t MakeAddress(unsigned short a[4]) {
|
||||
uint64_t x;
|
||||
x = 0;
|
||||
x |= a[0];
|
||||
x <<= 9;
|
||||
x |= a[1];
|
||||
x <<= 9;
|
||||
x |= a[2];
|
||||
x <<= 9;
|
||||
x |= a[3];
|
||||
x <<= 12;
|
||||
return SignExtendAddr(x);
|
||||
}
|
||||
|
||||
static uint64_t *GetPageTable(pml4t_t p, long i, void *NewPhysicalPage(void)) {
|
||||
uint64_t *res;
|
||||
DCHECK_ALIGNED(4096, p);
|
||||
DCHECK(0 <= i && i < 512);
|
||||
if (IsValidPage(p[i])) {
|
||||
res = UnmaskPageAddr(p[i]);
|
||||
} else if ((res = NewPhysicalPage())) {
|
||||
DCHECK_ALIGNED(4096, res);
|
||||
p[i] = MaskPageAddr(res) | 0b11;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static void PtFinder(uint64_t *a, uint64_t *b, uint64_t n, pml4t_t pd, int k) {
|
||||
unsigned i;
|
||||
uint64_t e, c;
|
||||
while (*b - *a < n) {
|
||||
i = (*b >> k) & 511;
|
||||
e = pd[i];
|
||||
c = ROUNDUP(*b + 1, 1 << k);
|
||||
if (!IsValidPage(e)) {
|
||||
*b = c;
|
||||
} else if (k && *b - *a + (c - *b) > n) {
|
||||
PtFinder(a, b, n, UnmaskPageAddr(e), k - 9);
|
||||
} else {
|
||||
*a = *b = c;
|
||||
}
|
||||
if (((*b >> k) & 511) < i) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Locates free memory range.
|
||||
*
|
||||
* @param h specifies signedness and around where to start searching
|
||||
* @return virtual page address with size bytes free, or -1 w/ errno
|
||||
*/
|
||||
int64_t FindPml4t(pml4t_t pml4t, uint64_t h, uint64_t n) {
|
||||
uint64_t a, b;
|
||||
n = ROUNDUP(n, 4096) >> 12;
|
||||
a = b = (h & 0x0000fffffffff000) >> 12;
|
||||
if (!n || n > 0x10000000) return einval();
|
||||
PtFinder(&a, &b, n, pml4t, 9 * 3);
|
||||
if (b > 0x0000001000000000) return eoverflow();
|
||||
if (h < 0x0000800000000000 && b > 0x0000000800000000) return eoverflow();
|
||||
if (b - a < n) return enomem();
|
||||
return a << 12;
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps virtual page region to system memory region.
|
||||
*
|
||||
* @param pml4t is root of 48-bit page tables
|
||||
* @param v is fixed page-aligned virtual address, rounded down
|
||||
* @param r is real memory address, rounded down
|
||||
* @param n is number of bytes needed, rounded up
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
* @note existing pages are overwritten
|
||||
*/
|
||||
int RegisterPml4t(pml4t_t pml4t, int64_t v, int64_t r, size_t n,
|
||||
void *NewPhysicalPage(void)) {
|
||||
unsigned i, j, k, l;
|
||||
uint64_t *pdpt, *pdt, *pd, u;
|
||||
if (!n) return 0;
|
||||
u = ROUNDDOWN(r, 4096);
|
||||
n = ROUNDUP(n, 4096) >> 12;
|
||||
i = (v >> 39) & 511;
|
||||
j = (v >> 30) & 511;
|
||||
k = (v >> 21) & 511;
|
||||
l = (v >> 12) & 511;
|
||||
if (u + n > 0x800000000000) return eoverflow();
|
||||
if (r + n > 0x800000000000) return eoverflow();
|
||||
for (; i < 512; ++i) {
|
||||
if (!(pdpt = GetPageTable(pml4t, i, NewPhysicalPage))) return -1;
|
||||
for (; j < 512; ++j) {
|
||||
if (!(pdt = GetPageTable(pdpt, j, NewPhysicalPage))) return -1;
|
||||
for (; k < 512; ++k) {
|
||||
if (!(pd = GetPageTable(pdt, k, NewPhysicalPage))) return -1;
|
||||
for (; l < 512; ++l) {
|
||||
pd[l] = MaskPageAddr(u) | 0b11;
|
||||
if (!--n) return 0;
|
||||
u += 4096;
|
||||
}
|
||||
l = 0;
|
||||
}
|
||||
k = 0;
|
||||
}
|
||||
j = 0;
|
||||
}
|
||||
return enomem();
|
||||
}
|
||||
|
||||
/**
|
||||
* Unmaps pages and frees page tables.
|
||||
*/
|
||||
int FreePml4t(pml4t_t pml4t, int64_t addr, uint64_t size,
|
||||
void FreePhysicalPageTable(void *),
|
||||
int FreePhysicalPages(void *, size_t)) {
|
||||
int rc;
|
||||
char *pages;
|
||||
uint64_t i, *pdpt, *pdt, *pd;
|
||||
unsigned short r, s[4], a[4], R[2][2] = {{256, 512}, {0, 256}};
|
||||
a[0] = addr >> 39;
|
||||
a[1] = addr >> 30;
|
||||
a[2] = addr >> 21;
|
||||
a[3] = addr >> 12;
|
||||
size = ROUNDUP(size, 4096) >> 12;
|
||||
for (rc = r = 0; r < ARRAYLEN(R); ++r) {
|
||||
for (a[0] &= 511; size && R[r][0] <= a[0] && a[0] < R[r][1]; ++a[0]) {
|
||||
if (!IsValidPage(pml4t[a[0]])) continue;
|
||||
pdpt = UnmaskPageAddr(pml4t[a[0]]);
|
||||
for (s[1] = (a[1] &= 511); size && a[1] < 512; ++a[1]) {
|
||||
if (!IsValidPage(pdpt[a[1]])) continue;
|
||||
pdt = UnmaskPageAddr(pdpt[a[1]]);
|
||||
for (s[2] = (a[2] &= 511); size && a[2] < 512; ++a[2]) {
|
||||
if (!IsValidPage(pdt[a[2]])) continue;
|
||||
pd = UnmaskPageAddr(pdt[a[2]]);
|
||||
for (s[3] = (a[3] &= 511); size && a[3] < 512; ++a[3]) {
|
||||
if (IsValidPage(pd[a[3]])) {
|
||||
pages = UnmaskPageAddr(pd[a[3]]);
|
||||
pd[a[3]] = 0;
|
||||
for (i = 1; i + 1 < size && a[3] + i < 512; ++i) {
|
||||
if (!IsValidPage(pd[a[3] + i])) break;
|
||||
if (UnmaskPageAddr(pd[a[3] + i]) != pages + i * 4096) break;
|
||||
pd[a[3] + i] = 0;
|
||||
}
|
||||
FreePhysicalPages(pages, i * 4096);
|
||||
a[3] += i - 1;
|
||||
size -= i;
|
||||
}
|
||||
}
|
||||
if (s[3] == 0 && a[3] == 512) {
|
||||
FreePhysicalPageTable(pd);
|
||||
pdt[a[2]] = 0;
|
||||
}
|
||||
}
|
||||
if (s[2] == 0 && a[2] == 512) {
|
||||
FreePhysicalPageTable(pdt);
|
||||
pdpt[a[1]] = 0;
|
||||
}
|
||||
}
|
||||
if (s[1] == 0 && a[1] == 512) {
|
||||
FreePhysicalPageTable(pdpt);
|
||||
pml4t[a[0]] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
|
@ -4,17 +4,9 @@
|
|||
COSMOPOLITAN_C_START_
|
||||
|
||||
#define IsValidPage(x) ((x)&1)
|
||||
#define UnmaskPageAddr(x) ((void *)SignExtendAddr(MaskPageAddr(x)))
|
||||
#define MaskPageAddr(x) ((int64_t)(intptr_t)(x)&0x00007ffffffff000)
|
||||
#define SignExtendAddr(x) (!((x)&0x800000000000) ? (x) : (x) | -0x800000000000)
|
||||
|
||||
typedef uint64_t pml4t_t[512] aligned(4096);
|
||||
|
||||
int FreePml4t(pml4t_t, int64_t, uint64_t, void (*)(void *),
|
||||
int (*)(void *, size_t));
|
||||
int RegisterPml4t(pml4t_t, int64_t, int64_t, size_t, void *(*)(void));
|
||||
int64_t FindPml4t(pml4t_t, uint64_t, uint64_t);
|
||||
char *FormatPml4t(pml4t_t) nodiscard;
|
||||
#define MaskPageAddr(x) ((x)&0x00007ffffffff000)
|
||||
#define UnmaskPageAddr(x) SignExtendAddr(MaskPageAddr(x))
|
||||
#define SignExtendAddr(x) ((int64_t)((uint64_t)(x) << 16) >> 16)
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/macros.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/x/x.h"
|
||||
|
@ -59,12 +60,17 @@ static void FormatEndPage(struct Pml4tFormater *pp, int64_t end) {
|
|||
AppendFmt(&pp->b, "%p %p %,ld bytes", end - 1, size, size);
|
||||
}
|
||||
|
||||
char *FormatPml4t(uint64_t pml4t[512]) {
|
||||
static void *GetPt(struct Machine *m, uint64_t r) {
|
||||
CHECK_LE(r + 0x1000, m->real.n);
|
||||
return m->real.p + r;
|
||||
}
|
||||
|
||||
char *FormatPml4t(struct Machine *m) {
|
||||
uint64_t *pd[4];
|
||||
unsigned short i, a[4];
|
||||
struct Pml4tFormater pp = {0};
|
||||
unsigned short range[][2] = {{256, 512}, {0, 256}};
|
||||
pd[0] = pml4t;
|
||||
pd[0] = GetPt(m, m->cr3);
|
||||
for (i = 0; i < ARRAYLEN(range); ++i) {
|
||||
a[0] = range[i][0];
|
||||
do {
|
||||
|
@ -72,19 +78,19 @@ char *FormatPml4t(uint64_t pml4t[512]) {
|
|||
if (!IsValidPage(pd[0][a[0]])) {
|
||||
if (pp.t) FormatEndPage(&pp, MakeAddress(a));
|
||||
} else {
|
||||
pd[1] = UnmaskPageAddr(pd[0][a[0]]);
|
||||
pd[1] = GetPt(m, UnmaskPageAddr(pd[0][a[0]]));
|
||||
do {
|
||||
a[2] = a[3] = 0;
|
||||
if (!IsValidPage(pd[1][a[1]])) {
|
||||
if (pp.t) FormatEndPage(&pp, MakeAddress(a));
|
||||
} else {
|
||||
pd[2] = UnmaskPageAddr(pd[1][a[1]]);
|
||||
pd[2] = GetPt(m, UnmaskPageAddr(pd[1][a[1]]));
|
||||
do {
|
||||
a[3] = 0;
|
||||
if (!IsValidPage(pd[2][a[2]])) {
|
||||
if (pp.t) FormatEndPage(&pp, MakeAddress(a));
|
||||
} else {
|
||||
pd[3] = UnmaskPageAddr(pd[2][a[2]]);
|
||||
pd[3] = GetPt(m, UnmaskPageAddr(pd[2][a[2]]));
|
||||
do {
|
||||
if (!IsValidPage(pd[3][a[3]])) {
|
||||
if (pp.t) FormatEndPage(&pp, MakeAddress(a));
|
||||
|
|
1252
tool/build/lib/pty.c
1252
tool/build/lib/pty.c
File diff suppressed because it is too large
Load diff
|
@ -2,19 +2,31 @@
|
|||
#define COSMOPOLITAN_TOOL_BUILD_LIB_PTY_H_
|
||||
#include "tool/build/lib/buffer.h"
|
||||
|
||||
#define kMachinePtyFg 0x01
|
||||
#define kMachinePtyBg 0x02
|
||||
#define kMachinePtyTrue 0x04
|
||||
#define kMachinePtyBold 0x08
|
||||
#define kMachinePtyFaint 0x10
|
||||
#define kMachinePtyFlip 0x20
|
||||
#define kMachinePtyBlink 0x40
|
||||
#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 kMachinePtyNocursor 0x01
|
||||
#define kMachinePtyBlinkcursor 0x02
|
||||
#define kMachinePtyNocanon 0x04
|
||||
#define kMachinePtyNoecho 0x08
|
||||
#define kMachinePtyNoopost 0x10
|
||||
#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
|
||||
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
@ -24,16 +36,18 @@ struct MachinePty {
|
|||
int x;
|
||||
int yn;
|
||||
int xn;
|
||||
uint32_t u8;
|
||||
uint32_t n8;
|
||||
uint32_t pr;
|
||||
uint32_t fg;
|
||||
uint32_t bg;
|
||||
uint32_t u8;
|
||||
uint32_t n8;
|
||||
uint32_t conf;
|
||||
uint32_t save;
|
||||
uint32_t *wcs;
|
||||
uint32_t *prs;
|
||||
uint32_t *fgs;
|
||||
uint32_t *bgs;
|
||||
uint32_t *prs;
|
||||
uint32_t conf;
|
||||
wchar_t *xlat;
|
||||
enum MachinePtyState {
|
||||
kMachinePtyAscii,
|
||||
kMachinePtyUtf8,
|
||||
|
@ -57,6 +71,11 @@ 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);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
|
|
|
@ -60,17 +60,9 @@ static void ResetSse(struct Machine *m) {
|
|||
m->sse.rc = RINT;
|
||||
m->sse.ftz = false;
|
||||
memset(m->xmm, 0, sizeof(m->xmm));
|
||||
memset(m->xmmtype, 0, sizeof(m->xmmtype));
|
||||
}
|
||||
|
||||
static void ResetTlb(struct Machine *m) {
|
||||
m->tlbindex = 0;
|
||||
memset(m->tlb, 0, sizeof(m->tlb));
|
||||
}
|
||||
|
||||
void ResetCpu(struct Machine *m) {
|
||||
m->codevirt = 0;
|
||||
m->codereal = NULL;
|
||||
m->faultaddr = 0;
|
||||
m->stashsize = 0;
|
||||
m->stashaddr = 0;
|
||||
|
@ -89,7 +81,13 @@ void ResetCpu(struct Machine *m) {
|
|||
memset(m->reg, 0, sizeof(m->reg));
|
||||
memset(m->bofram, 0, sizeof(m->bofram));
|
||||
memset(&m->freelist, 0, sizeof(m->freelist));
|
||||
ResetTlb(m);
|
||||
ResetSse(m);
|
||||
ResetFpu(m);
|
||||
}
|
||||
|
||||
void ResetTlb(struct Machine *m) {
|
||||
m->tlbindex = 0;
|
||||
memset(m->tlb, 0, sizeof(m->tlb));
|
||||
m->codevirt = 0;
|
||||
m->codehost = NULL;
|
||||
}
|
||||
|
|
|
@ -94,7 +94,6 @@
|
|||
#include "libc/intrin/punpcklwd.h"
|
||||
#include "libc/intrin/pxor.h"
|
||||
#include "libc/macros.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "tool/build/lib/case.h"
|
||||
#include "tool/build/lib/machine.h"
|
||||
#include "tool/build/lib/memory.h"
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include "libc/intrin/pshufw.h"
|
||||
#include "libc/intrin/shufpd.h"
|
||||
#include "libc/intrin/shufps.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/macros.h"
|
||||
#include "libc/math.h"
|
||||
#include "libc/str/str.h"
|
||||
|
@ -387,33 +388,26 @@ static void VspsdWspsd(struct Machine *m, uint32_t rde,
|
|||
double_v opd(struct Machine *, double_v, double_v)) {
|
||||
float_v xf, yf;
|
||||
double_v xd, yd;
|
||||
switch (Rep(rde) | Osz(rde)) {
|
||||
case 0:
|
||||
memcpy(&yf, GetModrmRegisterXmmPointerRead16(m, rde), 16);
|
||||
memcpy(&xf, XmmRexrReg(m, rde), 16);
|
||||
xf = opf(m, xf, yf);
|
||||
memcpy(XmmRexrReg(m, rde), &xf, 16);
|
||||
break;
|
||||
case 1:
|
||||
memcpy(&yd, GetModrmRegisterXmmPointerRead16(m, rde), 16);
|
||||
memcpy(&xd, XmmRexrReg(m, rde), 16);
|
||||
xd = opd(m, xd, yd);
|
||||
memcpy(XmmRexrReg(m, rde), &xd, 16);
|
||||
break;
|
||||
case 2:
|
||||
memcpy(&yd, GetModrmRegisterXmmPointerRead8(m, rde), 8);
|
||||
memcpy(&xd, XmmRexrReg(m, rde), 8);
|
||||
xd = opd(m, xd, yd);
|
||||
memcpy(XmmRexrReg(m, rde), &xd, 8);
|
||||
break;
|
||||
case 3:
|
||||
memcpy(&yf, GetModrmRegisterXmmPointerRead4(m, rde), 4);
|
||||
memcpy(&xf, XmmRexrReg(m, rde), 4);
|
||||
xf = opf(m, xf, yf);
|
||||
memcpy(XmmRexrReg(m, rde), &xf, 4);
|
||||
break;
|
||||
default:
|
||||
unreachable;
|
||||
if (Rep(rde) == 2) {
|
||||
memcpy(&yd, GetModrmRegisterXmmPointerRead8(m, rde), 8);
|
||||
memcpy(&xd, XmmRexrReg(m, rde), 8);
|
||||
xd = opd(m, xd, yd);
|
||||
memcpy(XmmRexrReg(m, rde), &xd, 8);
|
||||
} else if (Rep(rde) == 3) {
|
||||
memcpy(&yf, GetModrmRegisterXmmPointerRead4(m, rde), 4);
|
||||
memcpy(&xf, XmmRexrReg(m, rde), 4);
|
||||
xf = opf(m, xf, yf);
|
||||
memcpy(XmmRexrReg(m, rde), &xf, 4);
|
||||
} else if (Osz(rde)) {
|
||||
memcpy(&yd, GetModrmRegisterXmmPointerRead16(m, rde), 16);
|
||||
memcpy(&xd, XmmRexrReg(m, rde), 16);
|
||||
xd = opd(m, xd, yd);
|
||||
memcpy(XmmRexrReg(m, rde), &xd, 16);
|
||||
} else {
|
||||
memcpy(&yf, GetModrmRegisterXmmPointerRead16(m, rde), 16);
|
||||
memcpy(&xf, XmmRexrReg(m, rde), 16);
|
||||
xf = opf(m, xf, yf);
|
||||
memcpy(XmmRexrReg(m, rde), &xf, 16);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -172,7 +172,12 @@ static void MovqVqWq(struct Machine *m, uint32_t rde) {
|
|||
}
|
||||
|
||||
static void MovssVpsWps(struct Machine *m, uint32_t rde) {
|
||||
memcpy(XmmRexrReg(m, rde), GetModrmRegisterXmmPointerRead4(m, rde), 4);
|
||||
if (IsModrmRegister(rde)) {
|
||||
memcpy(XmmRexrReg(m, rde), XmmRexbRm(m, rde), 4);
|
||||
} else {
|
||||
memcpy(XmmRexrReg(m, rde), ComputeReserveAddressRead4(m, rde), 4);
|
||||
memset(XmmRexrReg(m, rde) + 4, 0, 12);
|
||||
}
|
||||
}
|
||||
|
||||
static void MovssWpsVps(struct Machine *m, uint32_t rde) {
|
||||
|
@ -180,11 +185,16 @@ static void MovssWpsVps(struct Machine *m, uint32_t rde) {
|
|||
}
|
||||
|
||||
static void MovsdVpsWps(struct Machine *m, uint32_t rde) {
|
||||
memcpy(XmmRexrReg(m, rde), GetModrmRegisterXmmPointerRead16(m, rde), 8);
|
||||
if (IsModrmRegister(rde)) {
|
||||
memcpy(XmmRexrReg(m, rde), XmmRexbRm(m, rde), 8);
|
||||
} else {
|
||||
memcpy(XmmRexrReg(m, rde), ComputeReserveAddressRead8(m, rde), 8);
|
||||
memset(XmmRexrReg(m, rde) + 8, 0, 8);
|
||||
}
|
||||
}
|
||||
|
||||
static void MovsdWpsVps(struct Machine *m, uint32_t rde) {
|
||||
memcpy(GetModrmRegisterXmmPointerWrite16(m, rde), XmmRexrReg(m, rde), 8);
|
||||
memcpy(GetModrmRegisterXmmPointerWrite8(m, rde), XmmRexrReg(m, rde), 8);
|
||||
}
|
||||
|
||||
static void MovhlpsVqUq(struct Machine *m, uint32_t rde) {
|
||||
|
|
|
@ -34,6 +34,8 @@
|
|||
#include "libc/log/log.h"
|
||||
#include "libc/macros.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/nexgen32e/vendor.h"
|
||||
#include "libc/runtime/gc.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sock/sock.h"
|
||||
#include "libc/str/str.h"
|
||||
|
@ -65,6 +67,7 @@
|
|||
#include "libc/x/x.h"
|
||||
#include "tool/build/lib/case.h"
|
||||
#include "tool/build/lib/endian.h"
|
||||
#include "tool/build/lib/iovs.h"
|
||||
#include "tool/build/lib/machine.h"
|
||||
#include "tool/build/lib/memory.h"
|
||||
#include "tool/build/lib/pml4t.h"
|
||||
|
@ -93,8 +96,8 @@
|
|||
|
||||
const struct MachineFdCb kMachineFdCbHost = {
|
||||
.close = close,
|
||||
.read = read,
|
||||
.write = write,
|
||||
.readv = readv,
|
||||
.writev = writev,
|
||||
.ioctl = ioctl,
|
||||
};
|
||||
|
||||
|
@ -281,10 +284,10 @@ static int XlatTcp(int x) {
|
|||
switch (x) {
|
||||
XLAT(1, TCP_NODELAY);
|
||||
XLAT(2, TCP_MAXSEG);
|
||||
XLAT(23, TCP_FASTOPEN);
|
||||
XLAT(4, TCP_KEEPIDLE);
|
||||
XLAT(5, TCP_KEEPINTVL);
|
||||
XLAT(6, TCP_KEEPCNT);
|
||||
XLAT(23, TCP_FASTOPEN);
|
||||
default:
|
||||
return x;
|
||||
}
|
||||
|
@ -398,18 +401,58 @@ static int XlatRusage(int x) {
|
|||
}
|
||||
}
|
||||
|
||||
static void *VirtualSendRead(struct Machine *m, void *dst, int64_t addr,
|
||||
uint64_t n) {
|
||||
static void VirtualSendRead(struct Machine *m, void *dst, int64_t addr,
|
||||
uint64_t n) {
|
||||
VirtualSend(m, dst, addr, n);
|
||||
SetReadAddr(m, addr, n);
|
||||
return dst;
|
||||
}
|
||||
|
||||
static void *VirtualRecvWrite(struct Machine *m, int64_t addr, void *dst,
|
||||
uint64_t n) {
|
||||
VirtualRecv(m, addr, dst, n);
|
||||
static void VirtualRecvWrite(struct Machine *m, int64_t addr, void *src,
|
||||
uint64_t n) {
|
||||
VirtualRecv(m, addr, src, n);
|
||||
SetWriteAddr(m, addr, n);
|
||||
return dst;
|
||||
}
|
||||
|
||||
static int AppendIovsReal(struct Machine *m, struct Iovs *ib, int64_t addr,
|
||||
size_t size) {
|
||||
void *real;
|
||||
size_t have;
|
||||
unsigned got;
|
||||
while (size) {
|
||||
if (!(real = FindReal(m, addr))) return efault();
|
||||
have = 0x1000 - (addr & 0xfff);
|
||||
got = MIN(size, have);
|
||||
if (AppendIovs(ib, real, got) == -1) return -1;
|
||||
addr += got;
|
||||
size -= got;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int AppendIovsGuest(struct Machine *m, struct Iovs *iv, int64_t iovaddr,
|
||||
long iovlen) {
|
||||
int rc;
|
||||
long i, iovsize;
|
||||
struct iovec *guestiovs;
|
||||
if (!__builtin_mul_overflow(iovlen, sizeof(struct iovec), &iovsize) &&
|
||||
(0 <= iovsize && iovsize <= 0x7ffff000)) {
|
||||
if ((guestiovs = malloc(iovsize))) {
|
||||
VirtualSendRead(m, guestiovs, iovaddr, iovsize);
|
||||
for (rc = i = 0; i < iovlen; ++i) {
|
||||
if (AppendIovsReal(m, iv, (intptr_t)guestiovs[i].iov_base,
|
||||
guestiovs[i].iov_len) == -1) {
|
||||
rc = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
free(guestiovs);
|
||||
} else {
|
||||
rc = enomem();
|
||||
}
|
||||
} else {
|
||||
rc = eoverflow();
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
static struct sigaction *CoerceSigactionToCosmo(
|
||||
|
@ -463,44 +506,52 @@ static int OpMadvise(struct Machine *m, int64_t addr, size_t length,
|
|||
}
|
||||
|
||||
static int64_t OpBrk(struct Machine *m, int64_t addr) {
|
||||
void *real;
|
||||
if (addr && addr != m->brk) {
|
||||
if (addr < m->brk) {
|
||||
addr = ROUNDUP(addr, FRAMESIZE);
|
||||
FreePml4t(m->cr3, addr, m->brk - addr, free, munmap);
|
||||
addr = ROUNDUP(addr, PAGESIZE);
|
||||
if (addr > m->brk) {
|
||||
if (ReserveVirtual(m, m->brk, addr - m->brk) != -1) {
|
||||
m->brk = addr;
|
||||
}
|
||||
} else if (addr < m->brk) {
|
||||
if (FreeVirtual(m, addr, m->brk - addr) != -1) {
|
||||
m->brk = addr;
|
||||
} else {
|
||||
addr = ROUNDUP(addr, FRAMESIZE);
|
||||
if ((real = mmap(NULL, addr - m->brk, PROT_READ | PROT_WRITE,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0)) != MAP_FAILED) {
|
||||
CHECK_NE(-1, RegisterMemory(m, m->brk, real, addr - m->brk));
|
||||
m->brk = addr;
|
||||
}
|
||||
}
|
||||
}
|
||||
return m->brk;
|
||||
}
|
||||
|
||||
static int64_t OpMmap(struct Machine *m, int64_t virt, size_t size, int prot,
|
||||
int flags, int fd, int64_t off) {
|
||||
void *real;
|
||||
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;
|
||||
real = mmap(NULL, size, prot, flags & ~MAP_FIXED, fd, off);
|
||||
if (real == MAP_FAILED) return -1;
|
||||
if (!(flags & MAP_FIXED)) {
|
||||
if (0 <= virt && virt < 0x400000) virt = 0x400000;
|
||||
if ((virt = FindPml4t(m->cr3, virt, size)) == -1) return -1;
|
||||
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) == -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);
|
||||
}
|
||||
CHECK_NE(-1, RegisterMemory(m, virt, real, size));
|
||||
return virt;
|
||||
}
|
||||
|
||||
static int OpMunmap(struct Machine *m, int64_t addr, uint64_t size) {
|
||||
return FreePml4t(m->cr3, addr, size, free, munmap);
|
||||
return FreeVirtual(m, addr, size);
|
||||
}
|
||||
|
||||
static int OpMsync(struct Machine *m, int64_t virt, size_t size, int flags) {
|
||||
return enosys();
|
||||
#if 0
|
||||
size_t i;
|
||||
void *page;
|
||||
virt = ROUNDDOWN(virt, 4096);
|
||||
|
@ -510,42 +561,7 @@ static int OpMsync(struct Machine *m, int64_t virt, size_t size, int flags) {
|
|||
if (msync(page, 4096, flags) == -1) return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void *GetDirectBuf(struct Machine *m, int64_t addr, size_t *size) {
|
||||
void *page;
|
||||
*size = MIN(*size, 0x1000 - (addr & 0xfff));
|
||||
if (!(page = FindReal(m, addr))) return MAP_FAILED;
|
||||
return page;
|
||||
}
|
||||
|
||||
static struct iovec *GetDirectIov(struct Machine *m, int64_t addr, int *len) {
|
||||
int i;
|
||||
size_t n, size;
|
||||
struct iovec *iov;
|
||||
if (!__builtin_mul_overflow(sizeof(*iov), *len, &n) && n <= 0x7ffff000) {
|
||||
if ((iov = malloc(n))) {
|
||||
VirtualSendRead(m, iov, addr, n);
|
||||
for (i = 0; i < *len; ++i) {
|
||||
size = iov[i].iov_len;
|
||||
if ((iov[i].iov_base = GetDirectBuf(
|
||||
m, (int64_t)(intptr_t)iov[i].iov_base, &size)) == MAP_FAILED) {
|
||||
free(iov);
|
||||
return (struct iovec *)efault();
|
||||
}
|
||||
if (size < iov[i].iov_len) {
|
||||
iov[i].iov_len = size;
|
||||
*len = i + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return iov;
|
||||
} else {
|
||||
return (struct iovec *)-1;
|
||||
}
|
||||
} else {
|
||||
return (struct iovec *)eoverflow();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static int OpClose(struct Machine *m, int fd) {
|
||||
|
@ -575,36 +591,39 @@ static int OpOpenat(struct Machine *m, int dirfd, int64_t path, int flags,
|
|||
}
|
||||
|
||||
static int OpPipe(struct Machine *m, int64_t pipefds_addr) {
|
||||
void *p[2];
|
||||
uint8_t b[8];
|
||||
int rc, i, j, *pipefds;
|
||||
if ((i = MachineFdAdd(&m->fds)) == -1) return -1;
|
||||
if ((j = MachineFdAdd(&m->fds)) == -1) return -1;
|
||||
if ((rc = pipe((pipefds = BeginStoreNp(m, pipefds_addr, 8, p, b)))) != -1) {
|
||||
EndStoreNp(m, pipefds_addr, 8, p, b);
|
||||
m->fds.p[i].cb = &kMachineFdCbHost;
|
||||
m->fds.p[i].fd = pipefds[0];
|
||||
m->fds.p[j].cb = &kMachineFdCbHost;
|
||||
m->fds.p[j].fd = pipefds[1];
|
||||
} else {
|
||||
int i, j, pipefds[2];
|
||||
if ((i = MachineFdAdd(&m->fds)) != -1) {
|
||||
if ((j = MachineFdAdd(&m->fds)) != -1) {
|
||||
if (pipe(pipefds) != -1) {
|
||||
m->fds.p[i].cb = &kMachineFdCbHost;
|
||||
m->fds.p[i].fd = pipefds[0];
|
||||
m->fds.p[j].cb = &kMachineFdCbHost;
|
||||
m->fds.p[j].fd = pipefds[1];
|
||||
pipefds[0] = i;
|
||||
pipefds[1] = j;
|
||||
VirtualRecvWrite(m, pipefds_addr, pipefds, sizeof(pipefds));
|
||||
return 0;
|
||||
}
|
||||
MachineFdRemove(&m->fds, j);
|
||||
}
|
||||
MachineFdRemove(&m->fds, i);
|
||||
MachineFdRemove(&m->fds, j);
|
||||
}
|
||||
return rc;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int OpDup(struct Machine *m, int fd) {
|
||||
int i, rc;
|
||||
if ((fd = XlatFd(m, fd)) == -1) return -1;
|
||||
if ((i = MachineFdAdd(&m->fds)) == -1) return -1;
|
||||
if ((rc = dup(fd)) != -1) {
|
||||
m->fds.p[i].cb = &kMachineFdCbHost;
|
||||
m->fds.p[i].fd = rc;
|
||||
rc = i;
|
||||
} else {
|
||||
MachineFdRemove(&m->fds, i);
|
||||
int i;
|
||||
if ((fd = XlatFd(m, fd)) != -1) {
|
||||
if ((i = MachineFdAdd(&m->fds)) != -1) {
|
||||
if ((fd = dup(fd)) != -1) {
|
||||
m->fds.p[i].cb = &kMachineFdCbHost;
|
||||
m->fds.p[i].fd = fd;
|
||||
return i;
|
||||
}
|
||||
MachineFdRemove(&m->fds, i);
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int OpDup2(struct Machine *m, int fd, int newfd) {
|
||||
|
@ -708,24 +727,70 @@ static int OpSetsockopt(struct Machine *m, int fd, int level, int optname,
|
|||
}
|
||||
|
||||
static ssize_t OpRead(struct Machine *m, int fd, int64_t addr, size_t size) {
|
||||
void *data;
|
||||
ssize_t rc;
|
||||
if (!(0 <= fd && fd < m->fds.i) || !m->fds.p[fd].cb) return ebadf();
|
||||
if ((data = GetDirectBuf(m, addr, &size)) == MAP_FAILED) return efault();
|
||||
if ((rc = m->fds.p[fd].cb->read(m->fds.p[fd].fd, data, size)) != -1) {
|
||||
SetWriteAddr(m, addr, rc);
|
||||
struct Iovs iv;
|
||||
InitIovs(&iv);
|
||||
if ((0 <= fd && fd < m->fds.i) && m->fds.p[fd].cb) {
|
||||
if ((rc = AppendIovsReal(m, &iv, addr, size)) != -1) {
|
||||
if ((rc = m->fds.p[fd].cb->readv(m->fds.p[fd].fd, iv.p, iv.i)) != -1) {
|
||||
SetWriteAddr(m, addr, rc);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
rc = ebadf();
|
||||
}
|
||||
FreeIovs(&iv);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static ssize_t OpPread(struct Machine *m, int fd, int64_t addr, size_t size,
|
||||
int64_t offset) {
|
||||
ssize_t rc;
|
||||
struct Iovs iv;
|
||||
InitIovs(&iv);
|
||||
if ((rc = XlatFd(m, fd)) != -1) {
|
||||
fd = rc;
|
||||
if ((rc = AppendIovsReal(m, &iv, addr, size)) != -1) {
|
||||
if ((rc = preadv(fd, iv.p, iv.i, offset)) != -1) {
|
||||
SetWriteAddr(m, addr, rc);
|
||||
}
|
||||
}
|
||||
}
|
||||
FreeIovs(&iv);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static ssize_t OpWrite(struct Machine *m, int fd, int64_t addr, size_t size) {
|
||||
void *data;
|
||||
ssize_t rc;
|
||||
if (!(0 <= fd && fd < m->fds.i) || !m->fds.p[fd].cb) return ebadf();
|
||||
if ((data = GetDirectBuf(m, addr, &size)) == MAP_FAILED) return efault();
|
||||
if ((rc = m->fds.p[fd].cb->write(m->fds.p[fd].fd, data, size)) != -1) {
|
||||
SetReadAddr(m, addr, size);
|
||||
struct Iovs iv;
|
||||
InitIovs(&iv);
|
||||
if ((0 <= fd && fd < m->fds.i) && m->fds.p[fd].cb) {
|
||||
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 {
|
||||
rc = ebadf();
|
||||
}
|
||||
FreeIovs(&iv);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static ssize_t OpPwrite(struct Machine *m, int fd, int64_t addr, size_t size,
|
||||
int64_t offset) {
|
||||
ssize_t rc;
|
||||
struct Iovs iv;
|
||||
InitIovs(&iv);
|
||||
if ((rc = XlatFd(m, fd)) != -1) {
|
||||
fd = rc;
|
||||
if ((rc = AppendIovsReal(m, &iv, addr, size)) != -1) {
|
||||
if ((rc = pwritev(fd, iv.p, iv.i, offset)) != -1) {
|
||||
SetReadAddr(m, addr, rc);
|
||||
}
|
||||
}
|
||||
}
|
||||
FreeIovs(&iv);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -746,9 +811,9 @@ static int IoctlTcgets(struct Machine *m, int fd, int64_t addr,
|
|||
if ((rc = fn(fd, TCGETS, &tio)) != -1) {
|
||||
memcpy(&tio2, &tio, sizeof(tio));
|
||||
tio2.c_iflag = 0;
|
||||
if (tio.c_iflag & ISIG) tio2.c_iflag |= ISIG_LINUX;
|
||||
if (tio.c_iflag & ICANON) tio2.c_iflag |= ICANON_LINUX;
|
||||
if (tio.c_iflag & ECHO) tio2.c_iflag |= ECHO_LINUX;
|
||||
if (tio.c_lflag & ISIG) tio2.c_lflag |= ISIG_LINUX;
|
||||
if (tio.c_lflag & ICANON) tio2.c_lflag |= ICANON_LINUX;
|
||||
if (tio.c_lflag & ECHO) tio2.c_lflag |= ECHO_LINUX;
|
||||
tio2.c_oflag = 0;
|
||||
if (tio.c_oflag & OPOST) tio2.c_oflag |= OPOST_LINUX;
|
||||
VirtualRecvWrite(m, addr, &tio2, sizeof(tio2));
|
||||
|
@ -762,9 +827,9 @@ static int IoctlTcsets(struct Machine *m, int fd, int64_t request, int64_t addr,
|
|||
VirtualSendRead(m, &tio, addr, sizeof(tio));
|
||||
memcpy(&tio2, &tio, sizeof(tio));
|
||||
tio2.c_iflag = 0;
|
||||
if (tio.c_iflag & ISIG_LINUX) tio2.c_iflag |= ISIG;
|
||||
if (tio.c_iflag & ICANON_LINUX) tio2.c_iflag |= ICANON;
|
||||
if (tio.c_iflag & ECHO_LINUX) tio2.c_iflag |= ECHO;
|
||||
if (tio.c_lflag & ISIG_LINUX) tio2.c_lflag |= ISIG;
|
||||
if (tio.c_lflag & ICANON_LINUX) tio2.c_lflag |= ICANON;
|
||||
if (tio.c_lflag & ECHO_LINUX) tio2.c_lflag |= ECHO;
|
||||
tio2.c_oflag = 0;
|
||||
if (tio.c_oflag & OPOST_LINUX) tio2.c_oflag |= OPOST;
|
||||
return fn(fd, request, &tio2);
|
||||
|
@ -791,44 +856,34 @@ static int OpIoctl(struct Machine *m, int fd, uint64_t request, int64_t addr) {
|
|||
}
|
||||
}
|
||||
|
||||
static ssize_t OpPread(struct Machine *m, int fd, int64_t addr, size_t size,
|
||||
int64_t offset) {
|
||||
void *data;
|
||||
ssize_t rc;
|
||||
if ((fd = XlatFd(m, fd)) == -1) return -1;
|
||||
if ((data = GetDirectBuf(m, addr, &size)) == MAP_FAILED) return efault();
|
||||
if ((rc = pread(fd, data, size, offset)) != -1) SetWriteAddr(m, addr, rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static ssize_t OpPwrite(struct Machine *m, int fd, int64_t addr, size_t size,
|
||||
int64_t offset) {
|
||||
void *data;
|
||||
ssize_t rc;
|
||||
if ((fd = XlatFd(m, fd)) == -1) return -1;
|
||||
if ((data = GetDirectBuf(m, addr, &size)) == MAP_FAILED) return efault();
|
||||
if ((rc = pwrite(fd, data, size, offset)) != -1) SetReadAddr(m, addr, size);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static ssize_t OpReadv(struct Machine *m, int fd, int64_t iovaddr, int iovlen) {
|
||||
ssize_t rc;
|
||||
struct iovec *iov;
|
||||
if ((fd = XlatFd(m, fd)) == -1) return -1;
|
||||
if ((iov = GetDirectIov(m, iovaddr, &iovlen)) == MAP_FAILED) return -1;
|
||||
rc = readv(fd, iov, iovlen);
|
||||
free(iov);
|
||||
struct Iovs iv;
|
||||
InitIovs(&iv);
|
||||
if ((0 <= fd && fd < m->fds.i) && m->fds.p[fd].cb) {
|
||||
if ((rc = AppendIovsGuest(m, &iv, iovaddr, iovlen)) != -1) {
|
||||
rc = m->fds.p[fd].cb->readv(m->fds.p[fd].fd, iv.p, iv.i);
|
||||
}
|
||||
} else {
|
||||
rc = ebadf();
|
||||
}
|
||||
FreeIovs(&iv);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static ssize_t OpWritev(struct Machine *m, int fd, int64_t iovaddr,
|
||||
int iovlen) {
|
||||
ssize_t rc;
|
||||
struct iovec *iov;
|
||||
if ((fd = XlatFd(m, fd)) == -1) return -1;
|
||||
if ((iov = GetDirectIov(m, iovaddr, &iovlen)) == MAP_FAILED) return -1;
|
||||
rc = writev(fd, iov, iovlen);
|
||||
free(iov);
|
||||
struct Iovs iv;
|
||||
InitIovs(&iv);
|
||||
if ((0 <= fd && fd < m->fds.i) && m->fds.p[fd].cb) {
|
||||
if ((rc = AppendIovsGuest(m, &iv, iovaddr, iovlen)) != -1) {
|
||||
rc = m->fds.p[fd].cb->writev(m->fds.p[fd].fd, iv.p, iv.i);
|
||||
}
|
||||
} else {
|
||||
rc = ebadf();
|
||||
}
|
||||
FreeIovs(&iv);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -850,33 +905,25 @@ static int OpFaccessat(struct Machine *m, int dirfd, int64_t path, int mode,
|
|||
return faccessat(dirfd, LoadStr(m, path), mode, flags);
|
||||
}
|
||||
|
||||
static int OpFstatat(struct Machine *m, int dirfd, int64_t path, int64_t st,
|
||||
static int OpFstatat(struct Machine *m, int dirfd, int64_t path, int64_t staddr,
|
||||
int flags) {
|
||||
int rc;
|
||||
void *stp[2];
|
||||
uint8_t *stbuf;
|
||||
struct stat st;
|
||||
flags = XlatAtf(flags);
|
||||
if ((dirfd = XlatAfd(m, dirfd)) == -1) return -1;
|
||||
if (!(stbuf = malloc(sizeof(struct stat)))) return enomem();
|
||||
if ((rc = fstatat(dirfd, LoadStr(m, path),
|
||||
BeginStoreNp(m, st, sizeof(stbuf), stp, stbuf), flags)) !=
|
||||
-1) {
|
||||
EndStoreNp(m, st, sizeof(stbuf), stp, stbuf);
|
||||
if ((rc = fstatat(dirfd, LoadStr(m, path), &st, flags)) != -1) {
|
||||
VirtualRecvWrite(m, staddr, &st, sizeof(struct stat));
|
||||
}
|
||||
free(stbuf);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int OpFstat(struct Machine *m, int fd, int64_t st) {
|
||||
static int OpFstat(struct Machine *m, int fd, int64_t staddr) {
|
||||
int rc;
|
||||
void *stp[2];
|
||||
uint8_t *stbuf;
|
||||
struct stat st;
|
||||
if ((fd = XlatFd(m, fd)) == -1) return -1;
|
||||
if (!(stbuf = malloc(sizeof(struct stat)))) return enomem();
|
||||
if ((rc = fstat(fd, BeginStoreNp(m, st, sizeof(stbuf), stp, stbuf))) != -1) {
|
||||
EndStoreNp(m, st, sizeof(stbuf), stp, stbuf);
|
||||
if ((rc = fstat(fd, &st)) != -1) {
|
||||
VirtualRecvWrite(m, staddr, &st, sizeof(struct stat));
|
||||
}
|
||||
free(stbuf);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -1091,21 +1138,34 @@ static int OpGettimeofday(struct Machine *m, int64_t tv, int64_t tz) {
|
|||
|
||||
static int OpPoll(struct Machine *m, int64_t fdsaddr, uint64_t nfds,
|
||||
int32_t timeout_ms) {
|
||||
int rc;
|
||||
size_t n;
|
||||
struct pollfd *fds;
|
||||
if (!__builtin_mul_overflow(sizeof(*fds), nfds, &n) && n <= 0x7ffff000) {
|
||||
if ((fds = malloc(n))) {
|
||||
VirtualSendRead(m, fds, fdsaddr, n);
|
||||
rc = poll(fds, nfds, timeout_ms);
|
||||
free(fds);
|
||||
return rc;
|
||||
int count, i;
|
||||
uint64_t fdssize;
|
||||
struct pollfd *hostfds, *guestfds;
|
||||
if (!__builtin_mul_overflow(nfds, sizeof(struct pollfd), &fdssize) &&
|
||||
fdssize <= 0x7ffff000) {
|
||||
hostfds = malloc(fdssize);
|
||||
guestfds = malloc(fdssize);
|
||||
if (hostfds && guestfds) {
|
||||
VirtualSendRead(m, guestfds, fdsaddr, fdssize);
|
||||
memcpy(hostfds, guestfds, fdssize);
|
||||
for (i = 0; i < nfds; ++i) {
|
||||
hostfds[i].fd = XlatFd(m, hostfds[i].fd);
|
||||
}
|
||||
if ((count = poll(hostfds, nfds, timeout_ms)) != -1) {
|
||||
for (i = 0; i < count; ++i) {
|
||||
hostfds[i].fd = guestfds[i].fd;
|
||||
}
|
||||
VirtualRecvWrite(m, fdsaddr, hostfds, count * sizeof(struct pollfd));
|
||||
}
|
||||
} else {
|
||||
return enomem();
|
||||
count = enomem();
|
||||
}
|
||||
free(guestfds);
|
||||
free(hostfds);
|
||||
} else {
|
||||
return einval();
|
||||
count = einval();
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
static int OpSigprocmask(struct Machine *m, int how, int64_t setaddr,
|
||||
|
@ -1303,7 +1363,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); */
|
||||
LOGF("missing syscall 0x%03x", ax);
|
||||
ax = enosys();
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -18,9 +18,12 @@
|
|||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/nexgen32e/vendor.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "tool/build/lib/address.h"
|
||||
#include "tool/build/lib/endian.h"
|
||||
#include "tool/build/lib/throw.h"
|
||||
|
||||
static bool IsHaltingInitialized(struct Machine *m) {
|
||||
|
@ -40,7 +43,15 @@ void ThrowDivideError(struct Machine *m) {
|
|||
|
||||
void ThrowSegmentationFault(struct Machine *m, int64_t va) {
|
||||
m->faultaddr = va;
|
||||
m->ip -= m->xedd->length;
|
||||
if (m->xedd) m->ip -= m->xedd->length;
|
||||
WARNF("%s%s ADDR %p IP %p AX %lx CX %lx DX %lx BX %lx SP %lx "
|
||||
"BP %lx SI %lx DI %lx R8 %lx R9 %lx R10 %lx R11 %lx R12 %lx R13 %lx "
|
||||
"R14 %lx R15 %lx",
|
||||
"SEGMENTATION FAULT", IsGenuineCosmo() ? " SIMULATED" : "", va, m->ip,
|
||||
Read64(m->ax), Read64(m->cx), Read64(m->dx), Read64(m->bx),
|
||||
Read64(m->sp), Read64(m->bp), Read64(m->si), Read64(m->di),
|
||||
Read64(m->r8), Read64(m->r9), Read64(m->r10), Read64(m->r11),
|
||||
Read64(m->r12), Read64(m->r13), Read64(m->r14), Read64(m->r15));
|
||||
HaltMachine(m, kMachineSegmentationFault);
|
||||
}
|
||||
|
||||
|
@ -49,7 +60,7 @@ void ThrowProtectionFault(struct Machine *m) {
|
|||
}
|
||||
|
||||
void OpUd(struct Machine *m, uint32_t rde) {
|
||||
m->ip -= m->xedd->length;
|
||||
if (m->xedd) m->ip -= m->xedd->length;
|
||||
HaltMachine(m, kMachineUndefinedInstruction);
|
||||
}
|
||||
|
||||
|
|
|
@ -24,13 +24,14 @@
|
|||
#include "tool/build/lib/endian.h"
|
||||
#include "tool/build/lib/time.h"
|
||||
|
||||
/**
|
||||
* @fileoverview i am the timelorde
|
||||
*/
|
||||
|
||||
void OpPause(struct Machine *m, uint32_t rde) {
|
||||
sched_yield();
|
||||
}
|
||||
|
||||
/**
|
||||
* I am the timelorde.
|
||||
*/
|
||||
void OpRdtsc(struct Machine *m, uint32_t rde) {
|
||||
uint64_t c;
|
||||
struct timespec ts;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue