diff --git a/tool/build/lib/machine.h b/tool/build/lib/machine.h index e75e62f5..4e187415 100644 --- a/tool/build/lib/machine.h +++ b/tool/build/lib/machine.h @@ -56,7 +56,7 @@ struct Machine { }; struct MachineTlb { int64_t virt; - uint8_t *host; + uint64_t entry; } tlb[16]; struct MachineReal { size_t i, n; diff --git a/tool/build/lib/memory.c b/tool/build/lib/memory.c index e8a8cc68..4513356f 100644 --- a/tool/build/lib/memory.c +++ b/tool/build/lib/memory.c @@ -21,6 +21,7 @@ #include "libc/log/log.h" #include "libc/macros.internal.h" #include "libc/mem/mem.h" +#include "libc/runtime/pc.internal.h" #include "libc/str/str.h" #include "libc/x/x.h" #include "tool/build/lib/endian.h" @@ -44,50 +45,54 @@ void SetWriteAddr(struct Machine *m, int64_t addr, uint32_t size) { } } -long HandlePageFault(struct Machine *m, uint64_t entry, uint64_t table, - unsigned index) { +uint64_t 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 (*(uint64_t *)(m->real.p + table + index * 8) = + page | entry & ~0x7ffffffffe00); + } else { + return 0; } - return page; +} + +uint64_t FindPage(struct Machine *m, int64_t virt) { + uint64_t table, entry; + unsigned level, index, i; + virt &= -0x1000; + for (i = 0; i < ARRAYLEN(m->tlb); ++i) { + if (m->tlb[i].virt == virt && (m->tlb[i].entry & 1)) { + return m->tlb[i].entry; + } + } + level = 39; + entry = m->cr3; + do { + table = entry & PAGE_TA; + CHECK_LT(table, m->real.n); + index = (virt >> level) & 511; + 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) { + return 0; + } + m->tlbindex = (m->tlbindex + 1) & (ARRAYLEN(m->tlb) - 1); + m->tlb[m->tlbindex] = m->tlb[0]; + m->tlb[0].virt = virt; + m->tlb[0].entry = entry; + return entry; } void *FindReal(struct Machine *m, int64_t virt) { - long page; - uint64_t table, entry; + uint64_t table, entry, page; 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; + if (!(entry = FindPage(m, virt))) return NULL; + return m->real.p + (entry & PAGE_TA) + (virt & 0xfff); } else { return NULL; } diff --git a/tool/build/lib/memory.h b/tool/build/lib/memory.h index c0b21e45..a2d7c075 100644 --- a/tool/build/lib/memory.h +++ b/tool/build/lib/memory.h @@ -5,6 +5,7 @@ COSMOPOLITAN_C_START_ int RegisterMemory(struct Machine *, int64_t, void *, size_t); +uint64_t FindPage(struct Machine *, int64_t); void *AccessRam(struct Machine *, int64_t, size_t, void *[2], uint8_t *, bool); void *BeginLoadStore(struct Machine *, int64_t, size_t, void *[2], uint8_t *); void *BeginStore(struct Machine *, int64_t, size_t, void *[2], uint8_t *); @@ -14,19 +15,19 @@ void *Load(struct Machine *, int64_t, size_t, uint8_t *); void *LoadBuf(struct Machine *, int64_t, size_t); void *LoadStr(struct Machine *, int64_t); void *MallocPage(void); +void *RealAddress(struct Machine *, int64_t); void *ReserveAddress(struct Machine *, int64_t, size_t); void *ResolveAddress(struct Machine *, int64_t); +void *VirtualSend(struct Machine *, void *, int64_t, uint64_t); void EndStore(struct Machine *, int64_t, size_t, void *[2], uint8_t *); void EndStoreNp(struct Machine *, int64_t, size_t, void *[2], uint8_t *); void ResetRam(struct Machine *); void SetReadAddr(struct Machine *, int64_t, uint32_t); void SetWriteAddr(struct Machine *, int64_t, uint32_t); void VirtualRecv(struct Machine *, int64_t, void *, uint64_t); -void *VirtualSend(struct Machine *, void *, int64_t, uint64_t); -void VirtualSet(struct Machine *, int64_t, char, uint64_t); -void *RealAddress(struct Machine *, int64_t); -void VirtualSendRead(struct Machine *, void *, int64_t, uint64_t); void VirtualRecvWrite(struct Machine *, int64_t, void *, uint64_t); +void VirtualSendRead(struct Machine *, void *, int64_t, uint64_t); +void VirtualSet(struct Machine *, int64_t, char, uint64_t); COSMOPOLITAN_C_END_ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ diff --git a/tool/build/lib/reset.c b/tool/build/lib/reset.c index f5bd60c9..a567d0e2 100644 --- a/tool/build/lib/reset.c +++ b/tool/build/lib/reset.c @@ -92,5 +92,5 @@ void ResetTlb(struct Machine *m) { m->tlbindex = 0; memset(m->tlb, 0, sizeof(m->tlb)); m->codevirt = 0; - m->codehost = NULL; + m->codehost = 0; }