Add syscalls to Blinkenlights and fix bugs

This commit is contained in:
Justine Tunney 2022-05-13 13:31:21 -07:00
parent f6df29cc3d
commit 578cb21591
25 changed files with 187 additions and 108 deletions

View file

@ -25,26 +25,21 @@ int MachineFdAdd(struct MachineFds *mf) {
int fd;
struct MachineFdClosed *closed;
if ((closed = mf->closed)) {
DCHECK_LT(closed->fd, mf->i);
fd = closed->fd;
mf->closed = closed->next;
free(closed);
} else {
DCHECK_LE(mf->i, mf->n);
if (mf->i == mf->n) {
if (!__grow(&mf->p, &mf->n, sizeof(struct MachineFd), 0)) {
return -1;
}
fd = mf->i;
if (mf->i++ == mf->n) {
mf->n = mf->i + (mf->i >> 1);
mf->p = realloc(mf->p, mf->n * sizeof(*mf->p));
}
fd = mf->i++;
}
return fd;
}
void MachineFdRemove(struct MachineFds *mf, int fd) {
struct MachineFdClosed *closed;
DCHECK_GE(fd, 0);
DCHECK_LT(fd, mf->i);
mf->p[fd].cb = NULL;
if ((closed = malloc(sizeof(struct MachineFdClosed)))) {
closed->fd = fd;

View file

@ -25,6 +25,7 @@
#include "libc/log/log.h"
#include "libc/macros.internal.h"
#include "libc/nexgen32e/vendor.internal.h"
#include "libc/runtime/pc.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
#include "libc/sysv/consts/fileno.h"
@ -65,9 +66,12 @@ 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, 0x0207));
CHECK_NE(-1, ReserveVirtual(m, vstart, fend - fstart,
PAGE_V | PAGE_RW | PAGE_U | PAGE_RSRV));
VirtualRecv(m, vstart, (void *)fstart, fend - fstart);
if (bsssize) CHECK_NE(-1, ReserveVirtual(m, vbss, bsssize, 0x0207));
if (bsssize)
CHECK_NE(-1, ReserveVirtual(m, vbss, bsssize,
PAGE_V | PAGE_RW | PAGE_U | PAGE_RSRV));
if (phdr->p_memsz - phdr->p_filesz > bsssize) {
VirtualSet(m, phdr->p_vaddr + phdr->p_filesz, 0,
phdr->p_memsz - phdr->p_filesz - bsssize);
@ -158,7 +162,8 @@ void LoadProgram(struct Machine *m, const char *prog, char **args, char **vars,
sp = 0x800000000000;
Write64(m->sp, sp);
m->cr3 = AllocateLinearPage(m);
CHECK_NE(-1, ReserveVirtual(m, sp - STACKSIZE, STACKSIZE, 0x0207));
CHECK_NE(-1, ReserveVirtual(m, sp - STACKSIZE, STACKSIZE,
PAGE_V | PAGE_RW | PAGE_U | PAGE_RSRV));
LoadArgv(m, prog, args, vars);
if (memcmp(elf->map, "\177ELF", 4) == 0) {
elf->ehdr = (void *)elf->map;

View file

@ -46,13 +46,18 @@ void SetWriteAddr(struct Machine *m, int64_t addr, uint32_t size) {
}
}
uint64_t HandlePageFault(struct Machine *m, uint64_t entry, uint64_t table,
unsigned index) {
uint64_t HandlePageFault(struct Machine *m, int64_t virt, uint64_t entry,
uint64_t table, unsigned index) {
long page;
if ((page = AllocateLinearPage(m)) != -1) {
--m->memstat.reserved;
if (entry & PAGE_GROD) {
ReserveVirtual(m, virt - 4096, 4096,
PAGE_GROD | PAGE_RSRV |
(entry & (PAGE_XD | PAGE_U | PAGE_RW | PAGE_V)));
}
return (*(uint64_t *)(m->real.p + table + index * 8) =
page | entry & ~0x7ffffffffe00);
page | entry & ~(PAGE_TA | PAGE_IGN1));
} else {
return 0;
}
@ -61,7 +66,7 @@ uint64_t HandlePageFault(struct Machine *m, uint64_t entry, uint64_t table,
uint64_t FindPage(struct Machine *m, int64_t virt) {
uint64_t table, entry;
unsigned level, index, i;
virt &= -0x1000;
virt &= -4096;
for (i = 0; i < ARRAYLEN(m->tlb); ++i) {
if (m->tlb[i].virt == virt && (m->tlb[i].entry & 1)) {
return m->tlb[i].entry;
@ -76,8 +81,8 @@ uint64_t FindPage(struct Machine *m, int64_t virt) {
entry = *(uint64_t *)(m->real.p + table + index * 8);
if (!(entry & 1)) return 0;
} while ((level -= 9) >= 12);
if ((entry & 0x0e00) &&
(entry = HandlePageFault(m, entry, table, index)) == -1) {
if ((entry & PAGE_RSRV) &&
(entry = HandlePageFault(m, virt, entry, table, index)) == -1) {
return 0;
}
m->tlbindex = (m->tlbindex + 1) & (ARRAYLEN(m->tlb) - 1);
@ -113,21 +118,21 @@ void *ResolveAddress(struct Machine *m, int64_t v) {
void VirtualSet(struct Machine *m, int64_t v, char c, uint64_t n) {
char *p;
uint64_t k;
k = 0x1000 - (v & 0xfff);
k = 4096 - (v & 0xfff);
while (n) {
k = MIN(k, n);
p = ResolveAddress(m, v);
memset(p, c, k);
n -= k;
v += k;
k = 0x1000;
k = 4096;
}
}
void VirtualCopy(struct Machine *m, int64_t v, char *r, uint64_t n, bool d) {
char *p;
uint64_t k;
k = 0x1000 - (v & 0xfff);
k = 4096 - (v & 0xfff);
while (n) {
k = MIN(k, n);
p = ResolveAddress(m, v);
@ -139,7 +144,7 @@ void VirtualCopy(struct Machine *m, int64_t v, char *r, uint64_t n, bool d) {
n -= k;
r += k;
v += k;
k = 0x1000;
k = 4096;
}
}
@ -165,7 +170,7 @@ void VirtualRecvWrite(struct Machine *m, int64_t addr, void *src, uint64_t n) {
void *ReserveAddress(struct Machine *m, int64_t v, size_t n) {
void *r;
DCHECK_LE(n, sizeof(m->stash));
if ((v & 0xfff) + n <= 0x1000) return ResolveAddress(m, v);
if ((v & 0xfff) + n <= 4096) return ResolveAddress(m, v);
m->stashaddr = v;
m->stashsize = n;
r = m->stash;
@ -177,11 +182,11 @@ void *AccessRam(struct Machine *m, int64_t v, size_t n, void *p[2],
uint8_t *tmp, bool copy) {
unsigned k;
uint8_t *a, *b;
DCHECK_LE(n, 0x1000);
if ((v & 0xfff) + n <= 0x1000) return ResolveAddress(m, v);
k = 0x1000;
DCHECK_LE(n, 4096);
if ((v & 0xfff) + n <= 4096) return ResolveAddress(m, v);
k = 4096;
k -= v & 0xfff;
DCHECK_LE(k, 0x1000);
DCHECK_LE(k, 4096);
a = ResolveAddress(m, v);
b = ResolveAddress(m, v + k);
if (copy) {
@ -220,9 +225,9 @@ void *BeginLoadStore(struct Machine *m, int64_t v, size_t n, void *p[2],
void EndStore(struct Machine *m, int64_t v, size_t n, void *p[2], uint8_t *b) {
uint8_t *a;
unsigned k;
DCHECK_LE(n, 0x1000);
if ((v & 0xfff) + n <= 0x1000) return;
k = 0x1000;
DCHECK_LE(n, 4096);
if ((v & 0xfff) + n <= 4096) return;
k = 4096;
k -= v & 0xfff;
DCHECK_GT(k, n);
DCHECK_NOTNULL(p[0]);
@ -239,7 +244,7 @@ void EndStoreNp(struct Machine *m, int64_t v, size_t n, void *p[2],
void *LoadStr(struct Machine *m, int64_t addr) {
size_t have;
char *copy, *page, *p;
have = 0x1000 - (addr & 0xfff);
have = 4096 - (addr & 0xfff);
if (!addr) return NULL;
if (!(page = FindReal(m, addr))) return NULL;
if ((p = memchr(page, '\0', have))) {
@ -247,16 +252,16 @@ void *LoadStr(struct Machine *m, int64_t addr) {
return page;
}
CHECK_LT(m->freelist.i, ARRAYLEN(m->freelist.p));
if (!(copy = malloc(have + 0x1000))) return NULL;
if (!(copy = malloc(have + 4096))) return NULL;
memcpy(copy, page, have);
for (;;) {
if (!(page = FindReal(m, addr + have))) break;
if ((p = memccpy(copy + have, page, '\0', 0x1000))) {
if ((p = memccpy(copy + have, page, '\0', 4096))) {
SetReadAddr(m, addr, have + (p - (copy + have)) + 1);
return (m->freelist.p[m->freelist.i++] = copy);
}
have += 0x1000;
if (!(p = realloc(copy, have + 0x1000))) break;
have += 4096;
if (!(p = realloc(copy, have + 4096))) break;
copy = p;
}
free(copy);
@ -266,7 +271,7 @@ void *LoadStr(struct Machine *m, int64_t addr) {
void *LoadBuf(struct Machine *m, int64_t addr, size_t size) {
size_t have, need;
char *buf, *copy, *page;
have = 0x1000 - (addr & 0xfff);
have = 4096 - (addr & 0xfff);
if (!addr) return NULL;
if (!(buf = FindReal(m, addr))) return NULL;
if (size > have) {
@ -274,7 +279,7 @@ void *LoadBuf(struct Machine *m, int64_t addr, size_t size) {
if (!(copy = malloc(size))) return NULL;
buf = memcpy(copy, buf, have);
do {
need = MIN(0x1000, size - have);
need = MIN(4096, size - have);
if ((page = FindReal(m, addr + have))) {
memcpy(copy + have, page, need);
have += need;

View file

@ -21,6 +21,7 @@
#include "libc/log/check.h"
#include "libc/log/log.h"
#include "libc/mem/mem.h"
#include "libc/runtime/pc.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
#include "libc/sysv/errfuns.h"
@ -66,7 +67,7 @@ void ResetMem(struct Machine *m) {
long AllocateLinearPage(struct Machine *m) {
long page;
if ((page = AllocateLinearPageRaw(m)) != -1) {
bzero(m->real.p + page, 0x1000);
bzero(m->real.p + page, 4096);
}
return page;
}
@ -77,12 +78,12 @@ long AllocateLinearPageRaw(struct Machine *m) {
struct MachineRealFree *rf;
if ((rf = m->realfree)) {
DCHECK(rf->n);
DCHECK_EQ(0, rf->i & 0xfff);
DCHECK_EQ(0, rf->n & 0xfff);
DCHECK_EQ(0, rf->i & 4095);
DCHECK_EQ(0, rf->n & 4095);
DCHECK_LE(rf->i + rf->n, m->real.i);
i = rf->i;
rf->i += 0x1000;
if (!(rf->n -= 0x1000)) {
rf->i += 4096;
if (!(rf->n -= 4096)) {
m->realfree = rf->next;
free(rf);
}
@ -96,9 +97,9 @@ long AllocateLinearPageRaw(struct Machine *m) {
if (n) {
n += n >> 1;
} else {
n = 0x10000;
n = 65536;
}
n = ROUNDUP(n, 0x1000);
n = ROUNDUP(n, 4096);
if ((p = realloc(p, n))) {
m->real.p = p;
m->real.n = n;
@ -108,10 +109,10 @@ long AllocateLinearPageRaw(struct Machine *m) {
return -1;
}
}
DCHECK_EQ(0, i & 0xfff);
DCHECK_EQ(0, n & 0xfff);
DCHECK_LE(i + 0x1000, n);
m->real.i += 0x1000;
DCHECK_EQ(0, i & 4095);
DCHECK_EQ(0, n & 4095);
DCHECK_LE(i + 4096, n);
m->real.i += 4096;
++m->memstat.allocated;
}
++m->memstat.committed;
@ -130,7 +131,7 @@ static void MachineWrite64(struct Machine *m, unsigned long i, uint64_t x) {
int ReserveReal(struct Machine *m, size_t n) {
uint8_t *p;
DCHECK_EQ(0, n & 0xfff);
DCHECK_EQ(0, n & 4095);
if (m->real.n < n) {
if ((p = realloc(m->real.p, n))) {
m->real.p = p;
@ -148,9 +149,9 @@ 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;
pt = pt & PAGE_TA;
ti = (virt >> level) & 511;
mi = (pt & 0x7ffffffff000) + ti * 8;
mi = (pt & PAGE_TA) + ti * 8;
pt = MachineRead64(m, mi);
if (level > 12) {
if (!(pt & 1)) {
@ -165,7 +166,7 @@ int ReserveVirtual(struct Machine *m, int64_t virt, size_t size, uint64_t key) {
MachineWrite64(m, mi, key);
++m->memstat.reserved;
}
if ((virt += 0x1000) >= end) return 0;
if ((virt += 4096) >= end) return 0;
if (++ti == 512) break;
pt = MachineRead64(m, (mi += 8));
}
@ -179,13 +180,13 @@ int64_t FindVirtual(struct Machine *m, int64_t virt, size_t size) {
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);
pt = MachineRead64(m, (pt & PAGE_TA) + ((virt >> i) & 511) * 8);
if (!(pt & 1)) break;
}
if (i >= 12) {
got += 1ull << i;
} else {
virt += 0x1000;
virt += 4096;
got = 0;
}
} while (got < size);
@ -195,10 +196,10 @@ int64_t FindVirtual(struct Machine *m, int64_t virt, size_t size) {
static void AppendRealFree(struct Machine *m, uint64_t real) {
struct MachineRealFree *rf;
if (m->realfree && real == m->realfree->i + m->realfree->n) {
m->realfree->n += 0x1000;
m->realfree->n += 4096;
} else if ((rf = malloc(sizeof(struct MachineRealFree)))) {
rf->i = real;
rf->n = 0x1000;
rf->n = 4096;
rf->next = m->realfree;
m->realfree = rf;
}
@ -208,17 +209,17 @@ 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;
mi = (pt & PAGE_TA) + ((virt >> i) & 511) * 8;
pt = MachineRead64(m, mi);
if (!(pt & 1)) {
break;
} else if (i == 12) {
++m->memstat.freed;
if (pt & 0x0e00) {
if (pt & PAGE_RSRV) {
--m->memstat.reserved;
} else {
--m->memstat.committed;
AppendRealFree(m, pt & 0x7ffffffff000);
AppendRealFree(m, pt & PAGE_TA);
}
MachineWrite64(m, mi, 0);
break;

View file

@ -37,6 +37,7 @@
#include "libc/mem/mem.h"
#include "libc/nexgen32e/vendor.internal.h"
#include "libc/runtime/gc.internal.h"
#include "libc/runtime/pc.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/sock/select.h"
#include "libc/sock/sock.h"
@ -221,6 +222,7 @@ static int XlatMapFlags(int x) {
if (x & 2) res |= MAP_PRIVATE;
if (x & 16) res |= MAP_FIXED;
if (x & 32) res |= MAP_ANONYMOUS;
if (x & 256) res |= MAP_GROWSDOWN;
return res;
}
@ -522,7 +524,8 @@ 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, 0x0207) != -1) {
if (ReserveVirtual(m, m->brk, addr - m->brk,
PAGE_V | PAGE_RW | PAGE_U | PAGE_RSRV) != -1) {
m->brk = addr;
}
} else if (addr < m->brk) {
@ -545,9 +548,10 @@ static int64_t OpMmap(struct Machine *m, int64_t virt, size_t size, int prot,
VERBOSEF("MMAP%s %012lx %,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;
key = PAGE_RSRV | PAGE_U | PAGE_V;
if (prot & PROT_WRITE) key |= PAGE_RW;
if (!(prot & PROT_EXEC)) key |= PAGE_XD;
if (flags & 256 /* MAP_GROWSDOWN */) key |= PAGE_GROD;
flags = XlatMapFlags(flags);
if (fd != -1 && (fd = XlatFd(m, fd)) == -1) return -1;
if (!(flags & MAP_FIXED)) {
@ -1127,6 +1131,21 @@ static int OpGetrlimit(struct Machine *m, int resource, int64_t rlimitaddr) {
return enosys();
}
static ssize_t OpReadlinkat(struct Machine *m, int dirfd, int64_t pathaddr,
int64_t bufaddr, size_t size) {
char *buf;
ssize_t rc;
const char *path;
if ((dirfd = XlatAfd(m, dirfd)) == -1) return -1;
path = LoadStr(m, pathaddr);
if (!(buf = malloc(size))) return enomem();
if ((rc = readlinkat(dirfd, path, buf, size)) != -1) {
VirtualRecvWrite(m, bufaddr, buf, rc);
}
free(buf);
return rc;
}
static int64_t OpGetcwd(struct Machine *m, int64_t bufaddr, size_t size) {
size_t n;
char *buf;
@ -1437,6 +1456,7 @@ void OpSyscall(struct Machine *m, uint32_t rde) {
SYSCALL(0x106, OpFstatat(m, di, si, dx, r0));
SYSCALL(0x107, OpUnlinkat(m, di, si, dx));
SYSCALL(0x108, OpRenameat(m, di, si, dx, r0));
SYSCALL(0x10B, OpReadlinkat(m, di, si, dx, r0));
SYSCALL(0x10D, OpFaccessat(m, di, si, dx, r0));
SYSCALL(0x113, splice(di, P(si), dx, P(r0), r8, XlatAtf(r9)));
SYSCALL(0x115, sync_file_range(di, si, dx, XlatAtf(r0)));