From 2d80bbc802a25102ca66a628daa9e8f986cffea4 Mon Sep 17 00:00:00 2001 From: Justine Tunney Date: Thu, 29 Oct 2020 04:53:20 -0700 Subject: [PATCH] Get binaries closer to running without an o/s blinkenlights now does a pretty good job emulating what happens when binaries boot from BIOS into long mode. So it's been much easier to debug the bare metal process and wrinkle out many issues. --- ape/ape.S | 341 +++++---------- ape/config.h | 2 +- ape/lib/getpagetableentry.c | 12 +- ape/lib/kbiosdataarea.S | 2 +- ape/lib/mapimage.c | 38 ++ ape/lib/pageunmap.c | 5 +- ape/lib/pc.h | 5 +- examples/hidecursor.c | 26 -- examples/package/build.mk | 2 +- libc/calls/hefty/spawnve-sysv.c | 2 +- libc/calls/kntwindowsdirectory.S | 1 + libc/crt/crt.S | 3 +- libc/log/asan.c | 1 + libc/macros.inc | 10 +- libc/nexgen32e/rdtscp.h | 16 +- libc/nexgen32e/uart.h | 68 +-- libc/stdio/serialstdio.c | 7 +- libc/stdio/system.c | 92 ++-- libc/sysv/systemfive.S | 7 + test/dsp/core/getintegercoefficients_test.c | 6 +- third_party/duktape/duktape.mk | 1 + tool/build/blinkenlights.c | 136 +++--- tool/build/build.mk | 1 + tool/build/emubin/emubin.mk | 30 -- tool/build/emubin/lisp.c | 460 -------------------- tool/build/emubin/spiral.c | 2 +- tool/build/lib/argv.c | 6 - tool/build/lib/buffer.c | 19 +- tool/build/lib/buffer.h | 4 +- tool/build/lib/buildlib.mk | 3 +- tool/build/lib/cpuid.c | 21 +- tool/build/lib/dis.c | 3 +- tool/build/lib/disarg.c | 20 +- tool/build/lib/diself.c | 1 + tool/build/lib/disspec.c | 189 ++++++-- tool/build/lib/ioports.c | 36 ++ tool/build/lib/loader.c | 39 +- tool/build/lib/machine.c | 283 +++++++++++- tool/build/lib/machine.h | 9 +- tool/build/lib/memory.c | 10 + tool/build/lib/memory.h | 2 + tool/build/lib/op101.c | 57 +++ tool/build/lib/pml4tfmt.c | 4 +- tool/build/lib/reset.c | 4 + tool/build/lib/stack.c | 16 +- tool/build/lib/stack.h | 1 - tool/build/lib/syscall.c | 12 - tool/build/lib/time.c | 18 +- tool/build/lib/time.h | 1 + tool/emacs/cosmo-c-constants.el | 2 + 50 files changed, 974 insertions(+), 1062 deletions(-) create mode 100644 ape/lib/mapimage.c delete mode 100644 examples/hidecursor.c delete mode 100644 tool/build/emubin/lisp.c diff --git a/ape/ape.S b/ape/ape.S index 73c7b3c4..acc1d2f3 100644 --- a/ape/ape.S +++ b/ape/ape.S @@ -45,8 +45,11 @@ #include "libc/nexgen32e/vidya.h" #include "libc/nt/pedef.h" #include "libc/nexgen32e/vidya.h" +#include "libc/dce.h" #include "libc/sysv/consts/prot.h" +#define USE_SYMBOL_HACK 0 + .source "NOTICE" .source "ape/ape.S" .source "ape/ape.lds" @@ -179,6 +182,10 @@ stub: mov $0x40,%dl # *literally* dos / @noreturn .code16 pc: cld +#if USE_SYMBOL_HACK + .byte 0x0f,0x1f,0207 # nop rdi binbase + .short (0x7c00-IMAGE_BASE_VIRTUAL)/512 +#endif mov $REAL_STACK_FRAME>>4,%di # we need a stack xor %cx,%cx rlstack %di,%cx @@ -197,6 +204,10 @@ pc: cld xor %di,%di rep movsb %ds:(%si),%es:(%di) +#if USE_SYMBOL_HACK + .byte 0x0f,0x1f,0207 # nop rdi binbase + .short (IMAGE_BASE_REAL-0x7c00)/512 +#endif ljmp $0,$REAL(1f) # longjmp() 1: mov $-512,%cx # memcpy() [relocate this frame] rep @@ -932,9 +943,6 @@ ape.str: .Lstr.long: .asciz "nolong" .endobj .Lstr.long -.Lstr.hello: - .asciz "hello\n" - .endobj .Lstr.hello .endobj ape.str / Serial Line Configuration (8250 UART 16550) @@ -964,7 +972,7 @@ sconf: .short 1843200/*hz*/ / 16/*wut*/ / 9600/*baud*/ .align 8 gdt: .short 2f-1f # table byte length .long REAL(1f),0 # table address - .align 8 + .zero 2 1: / ┌G:granularity (1 → limit *= 0x1000) / │┌D/B:default operation size (0 = 16|64bit, 1 = 32-bit) @@ -1047,13 +1055,8 @@ ape.grub.entry: nop nop realmodeloader: - push %bp - mov %sp,%bp call rlinit call sinit4 - call vinit - mov %es,XLM(VIDEO_POSITION_FAR_POINTER) - mov %ax,XLM(VIDEO_POSITION_FAR_POINTER)+2 mov $REAL(.Lstr.ape),%di call rvputs .optfn _start16 @@ -1062,38 +1065,29 @@ realmodeloader: .endfn realmodeloader,globl,hidden .section .sort.text.real.init.1,"ax",@progbits - .type rrinit,@function -rlinit: push %bp - mov %sp,%bp - .previous/* + .type rlinit,@function +rlinit: .previous/* ... decentralized function ... */.section .sort.text.real.init.3,"ax",@progbits - pop %bp ret .previous / Initializes present PC serial lines. -sinit4: push %bp - mov %sp,%bp - movw $4,%cx - movw $kBiosDataAreaXlm+COM1,%si -0: lodsb - mov %al,%dl - lodsb - mov %al,%dh - test %dx,%dx +sinit4: mov $4,%cx + mov $kBiosDataAreaXlm+COM1,%si +0: lodsw + test %ax,%ax jz 1f push %cx push %si - mov %dx,%di - movw $REAL(sconf),%si + xchg %ax,%di + mov $REAL(sconf),%si call sinit pop %si pop %cx 1: loop 0b - pop %bp ret .endfn sinit4,global,hidden @@ -1103,9 +1097,7 @@ sinit4: push %bp / @param char (*{es:,e,r}si)[4] register initial values / @mode long,legacy,real / @see www.lammertbies.nl/comm/info/serial-uart.html -sinit: push %bp - mov %sp,%bp - mov %di,%dx +sinit: mov %di,%dx test %dx,%dx jz 2f push %dx @@ -1123,8 +1115,7 @@ sinit: push %bp add $1,%dx sub $1,%cx jns 1b -2: pop %bp - ret +2: ret .endfn sinit,global,hidden / Abnormally exits program. @@ -1132,9 +1123,7 @@ sinit: push %bp / @param di message / @mode real / @noreturn -rldie: push %bp - mov %sp,%bp - call rlpute +rldie: call rlpute call rloff .endfn rldie,globl,hidden @@ -1142,9 +1131,7 @@ rldie: push %bp / / @mode real / @noreturn -rloff: push %bp - mov %sp,%bp - mov $kBiosDataAreaXlm+COM1,%di +rloff: mov $kBiosDataAreaXlm+COM1,%di mov $4,%si call sflush call apmoff @@ -1154,9 +1141,7 @@ rloff: push %bp / / @param di message / @mode real -rlpute: push %bp - mov %sp,%bp - mov kBiosDataAreaXlm+METAL_STDERR(%bx),%si +rlpute: mov kBiosDataAreaXlm+METAL_STDERR(%bx),%si test %si,%si jnz 1f mov kBiosDataAreaXlm+METAL_STDOUT,%si @@ -1176,8 +1161,7 @@ rlpute: push %bp pop %si call rlput2 jmp 1b -2: pop %bp - ret +2: ret .endfn rlpute,globl,hidden / Prints string to both video and serial. @@ -1185,9 +1169,7 @@ rlpute: push %bp / @param di NUL-terminated string / @param si serial port / @mode real -rlput2: push %bp - mov %sp,%bp - push %di +rlput2: push %di push %si call rvputs pop %si @@ -1195,33 +1177,42 @@ rlput2: push %bp test %si,%si jz 1f call sputs -1: pop %bp - ret +1: ret .endfn rlput2,globl,hidden / Video put string. / / @param di is the string / @mode real -rvputs: push %bp - mov %sp,%bp - mov %di,%si - les XLM(VIDEO_POSITION_FAR_POINTER),%di - call vputs - mov %es,XLM(VIDEO_POSITION_FAR_POINTER) - mov %ax,XLM(VIDEO_POSITION_FAR_POINTER)+2 - pop %bp - ret +rvputs: mov %di,%si +0: lodsb + test %al,%al + je 1f + call rvputc + jmp 0b +1: ret .endfn rvputs,globl,hidden +/ Video put char. +/ +/ @param al is the char +/ @mode real +rvputc: push %bx # don't clobber bp,bx,di,si,cx + push %bp # original ibm pc scroll up bug + mov $7,%bx # normal mda/cga style page zero + mov $0x0e,%ah # teletype output al cp437 + int $0x10 # vidya service + pop %bp # preserves al + pop %bx + ret + .endfn rvputc + / Writes string to serial line. / / @param di NUL-terminated string / @param si serial port / @mode long,legacy,real -sputs: push %bp - mov %sp,%bp - push %bx +sputs: push %bx mov %di,%bx 1: xchg %bx,%si lodsb @@ -1234,7 +1225,6 @@ sputs: push %bp pop %si jmp 1b 2: pop %bx - pop %bp ret .endfn sputs,globl @@ -1290,137 +1280,11 @@ sputc: push %ax ret .endfn sputc,globl -/ Asks BIOS to initialize Monochrome Display Adapter. -/ -/ @return es:ax start of video page -/ @mode real -vinit: push $7 - pop %ax - int $VIDYA_SERVICE - bbmov VIDYA_ADDR_MDA>>4,%ax,%ah,%al - mov %ax,%es - xor %ax,%ax - ret - .endfn vinit,globl - -/ Prints byte to display w/ teletype emulation. -/ -/ @param es:di screen position -/ @param sil byte -/ @return es:ax new screen position -/ @mode long,legacy,real -vputc: push %bp - mov %sp,%bp - sub $16,%sp # goal is to turn sil into a buffer - xchg %si,%ax # modrm sooo different in real mode - mov %di,%cx - mov %sp,%si - mov %sp,%di - stosb - mov %cx,%di - pushpop 1,%dx - jmp 23f - -/ Prints string to display w/ teletype emulation. -/ -/ @param es:di screen position -/ @param si NUL-terminated string -/ @return es:ax new screen position -/ @mode long,legacy,real -vputs: push %si # inlined strlen -1: lodsb - test %al,%al - jnz 1b - mov %si,%dx - pop %si - sub %si,%dx -/ fallthrough - -/ Prints data to display w/ teletype emulation. -/ -/ @param es:di screen position -/ @param si data address -/ @param dx data size in bytes -/ @return es:ax new screen position -/ @mode long,legacy,real -vtput: push %bp - mov %sp,%bp -23: push %bx - mov %dx,%cx - mov %di,%dx - bband VIDYA_REWIND,%dh,%dl - bbadd VIDYA_SIZE,%dh,%dl - bbmov VIDYA_COLUMNS*2-2,%bx,%bh,%bl -0: cmp %dx,%di - je 6f - ja 3f - lodsb # todo: utf8 → cp437 - cmp $'\n,%al - je 4f - cmp $'\r,%al - je 5f -1: stosb - mov $VIDYA_ATTR_NORMAL,%al # todo: ansi color - stosb -2: loop 0b -3: mov %di,%ax - pop %bx - pop %bp - ret -4: add %bx,%di # line feed - jmp 2b -5: mov %di,%ax # carriage return - push %dx - xor %dx,%dx - idiv %bx # todo: division is deprecated - sub %dx,%di - pop %dx - jmp 2b -6: push %ax - push %cx - push %dx - push %si - mov %bx,%si - rlcall vscroll - mov %ax,%di - pop %si - pop %dx - pop %cx - pop %ax - jmp 2b - .endfn vtput,globl - .endfn vputs,globl - .endfn vputc,globl - -/ Scrolls up content in display page. -/ -/ @param es:di cursor address (bytes after aren't moved) -/ @param si byte difference, e.g. VIDYA_COLUMNS*2 -/ @return es:ax new cursor address (which is es:di-si) -/ @mode long,legacy,real -vscroll:not %dx - mov %di,%cx - bband VIDYA_REWIND,%ch,%cl - xchg %cx,%di # di is now page addr, i.e. top-left - sub %si,%cx # cx is now future cursor address - push %cx - sub %di,%cx # cx is now memcpy size - mov %di,%si - add %cx,%si - mov $0,%ax - movpp %ds,%es - rep movsb - pop %ax - ret - .endfn vscroll,globl - / Shuts down personal computer. / / @mode real / @noreturn -apmoff: push %bp - mov %sp,%bp - mov $0x5300,%ax # apm installation check +apmoff: mov $0x5300,%ax # apm installation check xor %bx,%bx # for the apm bios itself int $APM_SERVICE jc 1f @@ -1485,8 +1349,6 @@ apmoff: push %bp long mode is long */ longmodeloader: - push %bp - mov %sp,%bp call lcheck call a20 mov $XLM(E820),%di @@ -1495,15 +1357,13 @@ longmodeloader: jc 9f call unreal call hiload - call golong + jmp golong 9: mov $REAL(.Lstr.e820),%ax call rldie .endfn longmodeloader,globl,hidden / Long Mode Hardware Check -lcheck: push %bp - mov %sp,%bp - pushf # check for i8086 / i8088 / i80186 +lcheck: pushf # check for i8086 / i8088 / i80186 pop %ax test $0x80,%ah # see intel manual volume 1 20.1.2 jnz 9f # we now assume 32bit is supported @@ -1534,8 +1394,7 @@ lcheck: push %bp cmp %edi,%edx jne 10f xor %ax,%ax -1: pop %bp - ret +1: ret 9: mov $REAL(.Lstr.oldskool),%ax jmp 20f 10: mov $REAL(.Lstr.long),%ax @@ -1587,9 +1446,7 @@ e820: push %bp / Unreal Mode. / Makes 4gb of real memory accessible via %fs segment. -unreal: push %bp - mov %sp,%bp - cli +unreal: cli lgdt REAL(gdt) mov %cr0,%eax or $CR0_PE,%al @@ -1599,16 +1456,13 @@ unreal: push %bp mov %cx,%fs and $~CR0_PE,%al mov %eax,%cr0 - ljmpl $0,$REAL(1f) + ljmp $0,$REAL(1f) 1: sti - pop %bp ret .endfn unreal / Loads remainder of executable off disk. -hiload: push %bp - mov %sp,%bp - push %bx +hiload: push %bx mov $IMAGE_BASE_REAL,%esi # relocate, again mov $IMAGE_BASE_PHYSICAL,%ebx mov $v_ape_realsectors,%ecx @@ -1647,7 +1501,6 @@ hiload: push %bp pop %cx jmp 0b 9: pop %bx - pop %bp ret .endfn hiload @@ -1724,18 +1577,16 @@ a20: cli / stack segment base. This function only defines enough tables / to get us started. #define TIP REAL_STACK_FRAME -pinit: push %bp - mov %sp,%bp - push %ds +pinit: push %ds mov $(TIP-0x4000)>>4,%ax mov %ax,%ds - movl $TIP-0x2000+PAGE_V+PAGE_RW,%ds:0x3000 # PML4T→PDPT - movl $TIP-0x3000+PAGE_V+PAGE_RW,%ds:0x2000 # PDPT→PDT - movl $TIP-0x4000+PAGE_V+PAGE_RW,%ds:0x1000 # PDT→PD + movl $TIP-0x2000+PAGE_V+PAGE_RW,0x3000 # PML4T→PDPT + movl $TIP-0x3000+PAGE_V+PAGE_RW,0x2000 # PDPT→PDT + movl $TIP-0x4000+PAGE_V+PAGE_RW,0x1000 # PDT→PD mov $0x100000/0x1000,%cx # PD→512kb mov $PAGE_V+PAGE_RW,%eax xor %si,%si -0: mov %eax,%ds:(%si) +0: mov %eax,(%si) add $0x1000,%eax add $8,%si loop 0b @@ -1743,7 +1594,6 @@ pinit: push %bp movl $TIP-0x4000,XLM(PAGE_TABLE_STACK_POINTER) # STACK→XLM mov $TIP-0x1000,%eax # PML4T→CR3 mov %eax,%cr3 - pop %bp ret .endfn pinit,globl,hidden @@ -1765,44 +1615,47 @@ golong: cli or $CR0_PE|CR0_PG|CR0_MP,%eax and $~CR0_EM,%eax mov %eax,%cr0 - ljmp $GDT_LONG_CODE,$REAL(1f) - .code64 -1: mov $GDT_LONG_DATA,%eax - mov %ax,%ds - mov %ax,%fs - mov %ax,%gs - xor %edx,%edx - jmp long + ljmp $GDT_LONG_CODE,$REAL(long) .endfn golong / Long mode is long. -/ / @noreturn -long: .frame0 - xor %edi,%edi - call pageunmap - - mov $e820map_xlm,%edi - call smapsort - - mov $e820map_xlm,%edi - mov $g_pml4t,%esi - mov $g_ptsp_xlm,%edx - call flattenhighmemory - - mov $REAL(.Lstr.hello),%edi - mov kBiosDataAreaXlm+METAL_STDOUT,%esi - call sputs - mov $kBiosDataAreaXlm+METAL_STDOUT,%edi - mov $4,%esi - call sflush - - jmp triplf - lea triplf(%rip),%rdx - call _start - jmp triplf + .code64 +long: push $GDT_LONG_DATA + pop %rax + mov %eax,%ds + mov %eax,%ss + mov %eax,%es + mov %eax,%fs + mov %eax,%gs + xor %ebp,%ebp + mov $REAL_STACK_FRAME+FRAMESIZE,%esp + call __map_image + mov $_metal,%eax + jmp *%rax .endfn long +/ Long mode in virtual address space. +/ @noreturn +_metal: +#if USE_SYMBOL_HACK + .byte 0x0f,0x1f,0207 # nop rdi binbase + .long (IMAGE_BASE_VIRTUAL-IMAGE_BASE_REAL)/512 +#endif + xor %eax,%eax # clear bss + mov $.Lape.bss.vaddr,%edi + mov $.Lape.bss.memsz,%ecx + rep stosb + movb $METAL,hostos(%rip) + push $0 # auxv + push $0 + push $0 # envp + push $0 # auxv + push $0 # argc + xor %edi,%edi + jmp _start + .endfn _metal + / Avoid linker script variables appearing as code in objdump. .macro .ldsvar name:req .type \name,@object diff --git a/ape/config.h b/ape/config.h index bdf0a307..8c4b35f1 100644 --- a/ape/config.h +++ b/ape/config.h @@ -32,7 +32,7 @@ #define METAL_STDOUT COM1 #endif #ifndef METAL_STDERR -#define METAL_STDERR COM2 /* will fallback to stdout if COM2 not present */ +#define METAL_STDERR COM1 #endif /** diff --git a/ape/lib/getpagetableentry.c b/ape/lib/getpagetableentry.c index 1e3b6438..c5a4f06a 100644 --- a/ape/lib/getpagetableentry.c +++ b/ape/lib/getpagetableentry.c @@ -24,14 +24,16 @@ textreal static uint64_t pushpagetable(uint64_t *ptsp) { return (*ptsp -= PAGESIZE) | PAGE_V | PAGE_RW; } -textreal uint64_t *getpagetableentry(uint64_t vaddr, unsigned depth, +textreal uint64_t *getpagetableentry(int64_t vaddr, unsigned depth, struct PageTable *pml4t, uint64_t *ptsp) { + uint64_t *entry; + unsigned char shift; assert(depth <= 3); - assert(*ptsp % PAGESIZE == 0); - assert((intptr_t)pml4t % PAGESIZE == 0); - unsigned char shift = 39; + assert(!(*ptsp & 0xfff)); + assert(!((uintptr_t)pml4t & 0xfff)); + shift = 39; for (;;) { - uint64_t *entry = &pml4t->p[(vaddr >> shift) & 511]; + entry = &pml4t->p[(vaddr >> shift) & 511]; if (!depth--) return entry; shift -= 9; if (!*entry) *entry = pushpagetable(ptsp); diff --git a/ape/lib/kbiosdataarea.S b/ape/lib/kbiosdataarea.S index 61c8b3a0..c2048b0d 100644 --- a/ape/lib/kbiosdataarea.S +++ b/ape/lib/kbiosdataarea.S @@ -37,7 +37,7 @@ .size kBiosDataAreaXlm,XLM_BIOS_DATA_AREA_SIZE kBiosDataAreaXlm = XLM(BIOS_DATA_AREA) - .section .sort.real.init.2.kBiosDataArea,"ax",@progbits + .section .sort.text.real.init.2.kBiosDataArea,"ax",@progbits movpp %ds,%es # copy bios data to valid page mov $PC_BIOS_DATA_AREA,%si mov $XLM(BIOS_DATA_AREA),%di diff --git a/ape/lib/mapimage.c b/ape/lib/mapimage.c new file mode 100644 index 00000000..bc3d0629 --- /dev/null +++ b/ape/lib/mapimage.c @@ -0,0 +1,38 @@ +/*-*- 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 "ape/lib/pc.h" +#include "ape/relocations.h" +#include "libc/runtime/runtime.h" + +textreal static void __map_segment(uint64_t k, uint64_t a, uint64_t b) { + uint64_t *e; + for (; a < b; a += 0x1000) { + e = getpagetableentry(IMAGE_BASE_VIRTUAL + a, 3, &g_pml4t, &g_ptsp_xlm); + *e = (IMAGE_BASE_PHYSICAL + a) | k; + } +} + +textreal void __map_image(void) { + pageunmap(0); + __map_segment(PAGE_V | PAGE_U, 0, (uintptr_t)_etext - IMAGE_BASE_VIRTUAL); + __map_segment(PAGE_V | PAGE_U | PAGE_RW | PAGE_XD, + (uintptr_t)_etext - IMAGE_BASE_VIRTUAL, + (uintptr_t)_end - IMAGE_BASE_VIRTUAL); +} diff --git a/ape/lib/pageunmap.c b/ape/lib/pageunmap.c index d09bf2c8..2e9980d9 100644 --- a/ape/lib/pageunmap.c +++ b/ape/lib/pageunmap.c @@ -20,8 +20,9 @@ #include "ape/lib/pc.h" #include "libc/bits/bits.h" -textreal void pageunmap(uint64_t vaddr) { - uint64_t *entry = getpagetableentry(vaddr, 3, &g_pml4t, &g_ptsp_xlm); +textreal void pageunmap(int64_t vaddr) { + uint64_t *entry; + entry = getpagetableentry(vaddr, 3, &g_pml4t, &g_ptsp_xlm); *entry &= ~PAGE_V; invlpg(vaddr); } diff --git a/ape/lib/pc.h b/ape/lib/pc.h index 5b04a341..e0d6cac9 100644 --- a/ape/lib/pc.h +++ b/ape/lib/pc.h @@ -157,6 +157,7 @@ #define PAGE_1GB /* */ 0b110000000 #define PAGE_TA 0b11111111111111111111111111111111111111000000000000 #define PAGE_PA2 0b11111111111111111111111111111000000000000000000000 +#define PAGE_XD 0x8000000000000000 #if !(__ASSEMBLER__ + __LINKER__ + 0) #include "ape/config.h" @@ -213,9 +214,9 @@ extern uint64_t g_ptsp_xlm; void bootdr(char drive) noreturn; void smapsort(struct SmapEntry *); -uint64_t *getpagetableentry(uint64_t, unsigned, struct PageTable *, uint64_t *); +uint64_t *getpagetableentry(int64_t, unsigned, struct PageTable *, uint64_t *); void flattenhighmemory(struct SmapEntry *, struct PageTable *, uint64_t *); -void pageunmap(uint64_t); +void pageunmap(int64_t); forceinline unsigned long eflags(void) { unsigned long res; diff --git a/examples/hidecursor.c b/examples/hidecursor.c deleted file mode 100644 index 05bf4c3d..00000000 --- a/examples/hidecursor.c +++ /dev/null @@ -1,26 +0,0 @@ -#if 0 -/*─────────────────────────────────────────────────────────────────╗ -│ To the extent possible under law, Justine Tunney has waived │ -│ all copyright and related or neighboring rights to this file, │ -│ as it is written in the following disclaimers: │ -│ • http://unlicense.org/ │ -│ • http://creativecommons.org/publicdomain/zero/1.0/ │ -╚─────────────────────────────────────────────────────────────────*/ -#endif -#include "libc/nt/console.h" -#include "libc/nt/runtime.h" -#include "libc/nt/struct/consolecursorinfo.h" -#include "libc/nt/synchronization.h" - -int main(int argc, char *argv[]) { - struct NtConsoleCursorInfo ntcursor; - SleepEx(1000, false); - GetConsoleCursorInfo(GetStdHandle(kNtStdOutputHandle), &ntcursor); - ntcursor.bVisible = false; - SetConsoleCursorInfo(GetStdHandle(kNtStdOutputHandle), &ntcursor); - SleepEx(1000, false); - ntcursor.bVisible = true; - SetConsoleCursorInfo(GetStdHandle(kNtStdOutputHandle), &ntcursor); - SleepEx(1000, false); - return 0; -} diff --git a/examples/package/build.mk b/examples/package/build.mk index 183067f6..32a810cb 100644 --- a/examples/package/build.mk +++ b/examples/package/build.mk @@ -27,7 +27,7 @@ EXAMPLES_PACKAGE_FILES := $(wildcard examples/package/*) # Defines sets of files without needing further iops. EXAMPLES_PACKAGE_SRCS = $(filter %.c,$(EXAMPLES_PACKAGE_FILES)) EXAMPLES_PACKAGE_HDRS = $(filter %.h,$(EXAMPLES_PACKAGE_FILES)) -EXAMPLES_PACKAGE_COMS = $(EXAMPLES_PACKAGE_OBJS:%.o=%.com) +EXAMPLES_PACKAGE_COMS = $(EXAMPLES_PACKAGE_SRCS:%.c=o/$(MODE)/%.com) EXAMPLES_PACKAGE_BINS = \ $(EXAMPLES_PACKAGE_COMS) \ $(EXAMPLES_PACKAGE_COMS:%=%.dbg) diff --git a/libc/calls/hefty/spawnve-sysv.c b/libc/calls/hefty/spawnve-sysv.c index ce273a66..cdeaa362 100644 --- a/libc/calls/hefty/spawnve-sysv.c +++ b/libc/calls/hefty/spawnve-sysv.c @@ -84,7 +84,7 @@ int spawnve$sysv(unsigned flags, int stdiofds[3], const char *program, } if (pid != -1) { - if ((pid = fork$sysv()) == 0) { + if ((pid = vfork()) == 0) { if (flags & SPAWN_DETACH) { if (setsid() == -1) abort(); if ((rc = fork$sysv()) == -1) abort(); diff --git a/libc/calls/kntwindowsdirectory.S b/libc/calls/kntwindowsdirectory.S index a03faca7..01eb39df 100644 --- a/libc/calls/kntwindowsdirectory.S +++ b/libc/calls/kntwindowsdirectory.S @@ -17,6 +17,7 @@ │ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │ │ 02110-1301 USA │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/dce.h" #include "libc/macros.h" .source __FILE__ diff --git a/libc/crt/crt.S b/libc/crt/crt.S index 050669d1..1f796f8c 100644 --- a/libc/crt/crt.S +++ b/libc/crt/crt.S @@ -40,7 +40,8 @@ _start: test %rdi,%rdi lea 24(%rsp,%rbx,8),%rdx # envp .frame0 / bofram 9f - .weak idata.iat,idata.iatend + .weak idata.iat + .weak idata.iatend ezlea missingno,ax # make win32 imps noop ezlea idata.iat,di ezlea idata.iatend,cx diff --git a/libc/log/asan.c b/libc/log/asan.c index 6b0cbe8d..66e11526 100644 --- a/libc/log/asan.c +++ b/libc/log/asan.c @@ -140,6 +140,7 @@ static const char *__asan_describe_access_poison(int c) { case kAsanUnscoped: return "unscoped"; default: + DebugBreak(); return "poisoned"; } } diff --git a/libc/macros.inc b/libc/macros.inc index 513e9baa..06525302 100644 --- a/libc/macros.inc +++ b/libc/macros.inc @@ -186,11 +186,6 @@ .endif .endm -/ Custom emulator instruction for bottom stack frame. -.macro bofram endfunc:req - .byte 0x0f,0x1f,0x45,\endfunc-. # nopl disp8(%rbp) -.endm - / Overrides LOOP instruction. / With its mop-Fusion Mexican equivalent. / Thus avoiding 3x legacy pipeline slowdown. @@ -330,3 +325,8 @@ _init_\name: call *\symbol(%rip) add $32,%rsp .endm + +/ Custom emulator instruction for bottom stack frame. +.macro bofram endfunc:req + .byte 0x0f,0x1f,0105,\endfunc-. # nopl disp8(%rbp) +.endm diff --git a/libc/nexgen32e/rdtscp.h b/libc/nexgen32e/rdtscp.h index 21daa6c2..45367301 100644 --- a/libc/nexgen32e/rdtscp.h +++ b/libc/nexgen32e/rdtscp.h @@ -1,5 +1,6 @@ #ifndef COSMOPOLITAN_LIBC_NEXGEN32E_RDTSCP_H_ #define COSMOPOLITAN_LIBC_NEXGEN32E_RDTSCP_H_ +#include "libc/bits/bits.h" #if !(__ASSEMBLER__ + __LINKER__ + 0) COSMOPOLITAN_C_START_ @@ -32,17 +33,26 @@ COSMOPOLITAN_C_START_ */ #define rdpid() \ ({ \ + bool Ok; \ long Msr; \ + Ok = false; \ if (X86_HAVE(RDPID)) { \ asm volatile("rdpid\t%0" : "=r"(Msr) : /* no inputs */ : "memory"); \ + Ok = true; \ } else if (IsLinux()) { \ - asm volatile("lsl\t%1,%0" : "=r"(Msr) : "r"(0x7b) : "memory"); \ - } else if (X86_HAVE(RDTSCP)) { \ + asm volatile(ZFLAG_ASM("lsl\t%2,%1") \ + : ZFLAG_CONSTRAINT(Ok), "=r"(Msr) \ + : "r"(0x7b) \ + : "memory"); \ + } \ + if (!Ok && X86_HAVE(RDTSCP)) { \ asm volatile("rdtscp" \ : "=c"(Msr) \ : /* no inputs */ \ : "eax", "edx", "memory"); \ - } else { \ + Ok = true; \ + } \ + if (!Ok) { \ Msr = -1; \ } \ Msr; \ diff --git a/libc/nexgen32e/uart.h b/libc/nexgen32e/uart.h index 21c62451..d8a214c4 100644 --- a/libc/nexgen32e/uart.h +++ b/libc/nexgen32e/uart.h @@ -1,38 +1,3 @@ -/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ -│vi: set net ft=c ts=8 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 │ -╠──────────────────────────────────────────────────────────────────────────────╣ -│░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░│ -│░░░░░░░█▀█░█▀█░▀█▀░█░█░█▀█░█░░░█░░░█░█░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░│ -│░░░░░░░█▀█░█░▄░░█░░█░█░█▀█░█░░░█░░░▀█▀░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░│ -│░░░░░░░▀░▀░▀▀▀░░▀░░▀▀▀░▀░▀░▀▀▀░▀▀▀░░▀░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░│ -│░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░│ -│░░░░░░░█▀█░█▀█░█▀█░▀█▀░█▀█░█▀█░█░░░█▀▀░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░│ -│░░░░░░░█▀▀░█ █░██▀░░█░░█▀█░█▀█░█░░░█▀▀░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░│ -│░░░░░░░▀░░░▀▀▀░▀░▀░░▀░░▀░▀░▀▀▀░▀▀▀░▀▀▀░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░│ -│░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░│ -│░░░░░░░█▀▀░█░█░█▀▀░█▀█░█░█░▀█▀░█▀█░█▀█░█░░█▀▀░░░░░░░░░░░░░░░░░░░░░░░░▄▄░░░▐█░░│ -│░░░░░░░█▀▀░▄▀▄░█▀▀░█░▄░█░█░░█░░█▀█░█▀█░█░░█▀▀░░░░░░░░░░░░▄▄▄░░░▄██▄░░█▀░░░█░▄░│ -│░░░░░░░▀▀▀░▀░▀░▀▀▀░▀▀▀░▀▀▀░░▀░░▀░▀░▀▀▀░▀▀░▀▀▀░░░░░░░░░░▄██▀█▌░██▄▄░░▐█▀▄░▐█▀░░│ -│░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▐█▀▀▌░░░▄▀▌░▌░█░▌░░▌░▌░░│ -╠──────────────────────────────────────────────────────▌▀▄─▐──▀▄─▐▄─▐▄▐▄─▐▄─▐▄─│ -│ αcτµαlly pδrταblε εxεcµταblε § telecommunications │ -╚─────────────────────────────────────────────────────────────────────────────*/ #ifndef COSMOPOLITAN_LIBC_NEXGEN32E_UART_H_ #define COSMOPOLITAN_LIBC_NEXGEN32E_UART_H_ @@ -53,22 +18,23 @@ * @see www.lammertbies.nl/comm/info/serial-uart.html */ -#define COM1 0x0 /* offset in pc bios data area with port number (0x400) */ -#define COM2 0x2 -#define COM3 0x4 -#define COM4 0x6 -#define IRQ3 0x0b /* com2 interrupt number (irq3) */ -#define IRQ4 0x0c /* com1 interrupt number (irq4) */ -#define UART_DLAB (1 << 7) /* serial line conf mode bit */ -#define UART_DLL 0 /* divisor latch register */ -#define UART_DLM 1 /* divisor latch register */ -#define UART_IIR 2 /* interrupt identification register */ -#define UART_LCR 3 /* line control register */ -#define UART_LSR 5 /* line status register */ -#define UART_TTYDA (1 << 0) /* data available (rx ready) */ -#define UART_TTYOE (1 << 1) /* overrun error */ -#define UART_TTYPE (1 << 2) /* parity error */ -#define UART_TTYFE (1 << 3) /* framing error */ +#define COM1 0x0 /* offset in pc bios data area with port number (0x400) */ +#define COM2 0x2 +#define COM3 0x4 +#define COM4 0x6 +#define IRQ3 0x0b /* com2 interrupt number (irq3) */ +#define IRQ4 0x0c /* com1 interrupt number (irq4) */ +#define UART_DLAB (1 << 7) /* serial line conf mode bit */ +#define UART_DLL 0 /* divisor latch register */ +#define UART_DLM 1 /* divisor latch register */ +#define UART_IIR 2 /* interrupt identification register */ +#define UART_LCR 3 /* line control register */ +#define UART_MCR 4 /* modem control register */ +#define UART_LSR 5 /* line status register */ +#define UART_TTYDA (1 << 0) /* data available (rx ready) */ +#define UART_TTYOE (1 << 1) /* overrun error */ +#define UART_TTYPE (1 << 2) /* parity error */ +#define UART_TTYFE (1 << 3) /* framing error */ #define UART_TTYBSR (1 << 4) /* break signal received */ #define UART_TTYTXR (1 << 5) /* serial thr empty (tx ready) */ #define UART_TTYIDL (1 << 6) /* serial thr empty and line idle */ diff --git a/libc/stdio/serialstdio.c b/libc/stdio/serialstdio.c index 013f9922..a2da9f84 100644 --- a/libc/stdio/serialstdio.c +++ b/libc/stdio/serialstdio.c @@ -23,12 +23,12 @@ #include "libc/stdio/stdio.h" static void fin(FILE *f) { - f->buf[f->end] = inb(f->fd); + f->buf[f->end] = inb(0x3F8); f->end = (f->end + 1) & (f->size - 1); } static void fout(FILE *f) { - outb(f->fd, f->buf[f->beg]); + outb(0x3F8, f->buf[f->beg]); f->beg = (f->beg + 1) & (f->size - 1); } @@ -36,7 +36,7 @@ static int serialstdio(FILE *f, unsigned char status, void action(FILE *)) { int block = 1; unsigned tally = 0; while (f->end != f->beg) { - if (!(inb(f->fd + UART_LSR) & status)) { + if (!(inb(0x3F8 + UART_LSR) & status)) { if (!block) break; asm("pause"); } else { @@ -50,6 +50,7 @@ static int serialstdio(FILE *f, unsigned char status, void action(FILE *)) { int fsreadbuf(FILE *f) { return serialstdio(f, UART_TTYDA, fin); } + int fswritebuf(FILE *f) { return serialstdio(f, UART_TTYTXR, fout); } diff --git a/libc/stdio/system.c b/libc/stdio/system.c index c119de13..cadd81da 100644 --- a/libc/stdio/system.c +++ b/libc/stdio/system.c @@ -19,54 +19,52 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/bits/weaken.h" #include "libc/calls/calls.h" -#include "libc/calls/hefty/ntspawn.h" #include "libc/calls/internal.h" -#include "libc/dce.h" #include "libc/mem/mem.h" #include "libc/nt/accounting.h" #include "libc/nt/enum/startf.h" #include "libc/nt/enum/status.h" -#include "libc/nt/files.h" #include "libc/nt/process.h" #include "libc/nt/runtime.h" -#include "libc/nt/startupinfo.h" #include "libc/nt/struct/processinformation.h" #include "libc/nt/synchronization.h" -#include "libc/runtime/runtime.h" #include "libc/stdio/stdio.h" #include "libc/str/str.h" #include "libc/sysv/consts/fileno.h" #include "libc/sysv/errfuns.h" -#include "libc/x/x.h" #define SHELL_BIN "/bin/sh" #define SHELL_ARG "-c" #define CMD_C "CMD /C " static int system$sysv(const char *cmdline) { + int rc, n, wstatus; + struct mem { + char shell[sizeof(SHELL_BIN)]; + char arg[sizeof(SHELL_ARG)]; + char *args[4]; + char cmdline[]; + } * mem; if (cmdline != NULL) { - int pid = fork$sysv(); - if (pid == 0) { - struct mem { - char shell[sizeof(SHELL_BIN)]; - char arg[sizeof(SHELL_ARG)]; - char *args[4]; - char cmdline[]; - } *mem = malloc(sizeof(struct mem) + (strlen(cmdline) + 1)); - if (!mem) return enomem(); - strcpy(mem->shell, SHELL_BIN); - strcpy(mem->arg, SHELL_ARG); - mem->args[0] = mem->shell; - mem->args[1] = mem->arg; - mem->args[2] = mem->cmdline; - mem->args[3] = NULL; - strcpy(mem->cmdline, cmdline); - execve$sysv(mem->shell, mem->args, environ); - abort(); + mem = malloc(sizeof(struct mem) + (strlen(cmdline) + 1)); + if (!mem) return enomem(); + strcpy(mem->shell, SHELL_BIN); + strcpy(mem->arg, SHELL_ARG); + mem->args[0] = mem->shell; + mem->args[1] = mem->arg; + mem->args[2] = mem->cmdline; + mem->args[3] = NULL; + strcpy(mem->cmdline, cmdline); + if ((rc = vfork()) != -1) { + if (rc == 0) { + execve$sysv(mem->shell, mem->args, environ); + abort(); + } + if ((rc = wait4$sysv(rc, &wstatus, 0, NULL)) != -1) { + rc = wstatus; + } } - int rc; - int wstatus; - if ((rc = wait4$sysv(pid, &wstatus, 0, NULL)) != -1) rc = wstatus; + free(mem); return rc; } else { return fileexists(SHELL_BIN); @@ -74,27 +72,32 @@ static int system$sysv(const char *cmdline) { } static textwindows noinline int system$nt(const char *cmdline) { + char *mem; + int rc, status; + uint32_t dwExitCode; + struct NtStartupInfo startinfo; + struct NtProcessInformation *info; + uint16_t *cmdline16, *quotedcmdline16; + unsigned len, dosquotemultiplier, cmdline16bytes, quotedcmdline16bytes; if (cmdline != NULL) { - int rc = -1; - unsigned dosquotemultiplier = 2; - unsigned len = strlen(cmdline); - unsigned cmdline16bytes = (len + 1) * sizeof(uint16_t); - unsigned quotedcmdline16bytes = + rc = -1; + dosquotemultiplier = 2; + len = strlen(cmdline); + cmdline16bytes = (len + 1) * sizeof(uint16_t); + quotedcmdline16bytes = strlen(CMD_C) * sizeof(uint16_t) + cmdline16bytes * dosquotemultiplier; - void *mem = malloc(sizeof(struct NtProcessInformation) + cmdline16bytes + - quotedcmdline16bytes); - if (mem == NULL) return enomem(); - struct NtProcessInformation *info = mem; - uint16_t *cmdline16 = - (uint16_t *)((char *)mem + sizeof(struct NtProcessInformation)); - uint16_t *quotedcmdline16 = - (uint16_t *)((char *)mem + sizeof(struct NtProcessInformation) + - cmdline16bytes); + if (!(mem = malloc(sizeof(struct NtProcessInformation) + cmdline16bytes + + quotedcmdline16bytes))) { + return enomem(); + } + info = (struct NtProcessInformation *)mem; + cmdline16 = (uint16_t *)(mem + sizeof(struct NtProcessInformation)); + quotedcmdline16 = (uint16_t *)(mem + sizeof(struct NtProcessInformation) + + cmdline16bytes); strcpyzbw(cmdline16, cmdline); strcpyzbw(quotedcmdline16, CMD_C); if (escapedos(quotedcmdline16 + strlen(CMD_C), len * dosquotemultiplier, cmdline16, len)) { - struct NtStartupInfo startinfo; memset(&startinfo, 0, sizeof(startinfo)); startinfo.cb = sizeof(struct NtStartupInfo); startinfo.dwFlags = kNtStartfUsestdhandles; @@ -112,8 +115,7 @@ static textwindows noinline int system$nt(const char *cmdline) { /* lpCurrentDirectory */ NULL, /* lpStartupInfo */ &startinfo, /* lpProcessInformation */ info)) { - uint32_t dwExitCode = kNtStillActive; - int status; + dwExitCode = kNtStillActive; do { WaitForSingleObject(info->hProcess, 0xffffffff); } while ((status = GetExitCodeProcess(info->hProcess, &dwExitCode)) && @@ -130,7 +132,7 @@ static textwindows noinline int system$nt(const char *cmdline) { } else { rc = einval(); } - free(mem), mem = NULL; + free(mem); return rc; } else { /* how could cmd.exe not exist? */ diff --git a/libc/sysv/systemfive.S b/libc/sysv/systemfive.S index 43b399ce..e7a28a8f 100644 --- a/libc/sysv/systemfive.S +++ b/libc/sysv/systemfive.S @@ -166,6 +166,8 @@ systemfive.xnu: .init.start 300,_init_systemfive push %rbx push %rsi + testb $METAL,(%rdi) # @see ape/ape.S + jnz systemfive.init.metal testb $XNU,(%rdi) # @see libc/crt/crt.S jnz systemfive.init.xnu testb $FREEBSD,(%rdi) # @see libc/crt/crt.S @@ -181,6 +183,11 @@ systemfive.init.linux: push $LINUX ezlea syscon.linux,si jmp systemfive.init.os +systemfive.init.metal: + pushb systemfive.linux-.Lanchorpoint + push $METAL + ezlea syscon.linux,si + jmp systemfive.init.os systemfive.init.windows: pushb systemfive.enosys-.Lanchorpoint push $WINDOWS diff --git a/test/dsp/core/getintegercoefficients_test.c b/test/dsp/core/getintegercoefficients_test.c index 58393efc..1320b563 100644 --- a/test/dsp/core/getintegercoefficients_test.c +++ b/test/dsp/core/getintegercoefficients_test.c @@ -41,11 +41,11 @@ TEST(GetIntegerCoefficients, testBt601Vectors) { 16, 235, {.299, .587, .114, 1, 1, 1}, - {612, 1202, IsTiny() ? 233 : 234, 2048, 2048, 2048}}, + {612, 1202, NoDebug() ? 233 : 234, 2048, 2048, 2048}}, {12, 16, 235, {.299, .587, .114}, {1225, 2404, 467}}, {13, 16, 235, {.299, .587, .114}, {2449, 4809, 934}}, {14, 16, 235, {.299, .587, .114}, {4899, 9617, 1868}}, - {15, 16, 235, {.299, .587, .114}, {9798, 19235, IsTiny() ? 3736 : 3735}}, + {15, 16, 235, {.299, .587, .114}, {9798, 19235, NoDebug() ? 3736 : 3735}}, {16, 16, 235, {.299, .587, .114}, {19595, 38470, 7471}}, }; long i, got[6]; @@ -63,7 +63,7 @@ TEST(GetIntegerCoefficients, testForYCbCr2Rgb) { GetIntegerCoefficients(I, C, 11, 16, 232); EXPECT_EQ(612, I[0]); EXPECT_EQ(1202, I[1]); - EXPECT_EQ(IsTiny() ? 233 : 234, I[2]); + EXPECT_EQ(NoDebug() ? 233 : 234, I[2]); } TEST(GetIntegerCoefficients, testForGaussian) { diff --git a/third_party/duktape/duktape.mk b/third_party/duktape/duktape.mk index 70487a70..dbd6e73c 100644 --- a/third_party/duktape/duktape.mk +++ b/third_party/duktape/duktape.mk @@ -32,6 +32,7 @@ THIRD_PARTY_DUKTAPE_A_DIRECTDEPS = \ LIBC_FMT \ LIBC_TIME \ LIBC_MEM \ + LIBC_STR \ LIBC_TINYMATH \ LIBC_UNICODE \ LIBC_NEXGEN32E diff --git a/tool/build/blinkenlights.c b/tool/build/blinkenlights.c index 325ded7e..ea47f0c3 100644 --- a/tool/build/blinkenlights.c +++ b/tool/build/blinkenlights.c @@ -290,13 +290,6 @@ static bool IsCall(void) { (m->xedd->op.dispatch == 0x0FF && m->xedd->op.reg == 2)); } -static bool IsLongBranch(void) { - return m->mode != XED_MODE_LONG && - (m->xedd->op.dispatch == 0x0EA || m->xedd->op.dispatch == 0x09A || - (m->xedd->op.opcode == 0x0FF && m->xedd->op.reg == 3) || - (m->xedd->op.opcode == 0x0FF && m->xedd->op.reg == 5)); -} - static bool IsDebugBreak(void) { return m->xedd->op.map == XED_ILD_MAP0 && m->xedd->op.opcode == 0xCC; } @@ -791,6 +784,17 @@ static int GetTerminalDimensions(int *out_y, int *out_x) { return ReadCursorPosition(out_y, out_x); } +void CommonSetup(void) { + static bool once; + if (!once) { + if (tuimode || breakpoints.i) { + LoadSyms(); + ResolveBreakpoints(); + } + once = true; + } +} + void TuiSetup(void) { int y, x; bool report; @@ -798,8 +802,7 @@ void TuiSetup(void) { report = false; if (!once) { LOGF("loaded program %s\n%s", codepath, gc(FormatPml4t(m))); - LoadSyms(); - ResolveBreakpoints(); + CommonSetup(); ioctl(ttyout, TCGETS, &oldterm); xsigaction(SIGINT, OnSigInt, 0, 0, oldsig + 3); atexit(TtyRestore2); @@ -820,14 +823,7 @@ void TuiSetup(void) { } static void ExecSetup(void) { - static bool once; - if (!once) { - if (breakpoints.i) { - LoadSyms(); - ResolveBreakpoints(); - } - once = true; - } + CommonSetup(); setitimer(ITIMER_REAL, &((struct itimerval){{0, 1. / 60 * 1e6}, {0, 1. / 60 * 1e6}}), NULL); @@ -1089,44 +1085,49 @@ static void DrawHr(struct Panel *p, const char *s) { AppendStr(&p->lines[0], "\e[0m"); } -void DrawTerminal(struct Panel *p) { - long i, y, yn; +static void DrawTerminalHr(struct Panel *p) { + long i; + if (p->bottom == p->top) return; if (pty->conf & kPtyBell) { if (!alarmed) { alarmed = true; setitimer(ITIMER_REAL, &((struct itimerval){{0, 0}, {0, 800000}}), NULL); } - AppendStr(&pan.displayhr.lines[0], "\e[1m"); + AppendStr(&p->lines[0], "\e[1m"); } - AppendStr(&pan.displayhr.lines[0], - gc(xasprintf("──────────TELETYPEWRITER──%s──%s──%s──%s", - (pty->conf & kPtyLed1) ? "\e[1;31m◎\e[0m" : "○", - (pty->conf & kPtyLed2) ? "\e[1;32m◎\e[0m" : "○", - (pty->conf & kPtyLed3) ? "\e[1;33m◎\e[0m" : "○", - (pty->conf & kPtyLed4) ? "\e[1;34m◎\e[0m" : "○"))); - for (i = 36; i < pan.displayhr.right - pan.displayhr.left; ++i) { - AppendWide(&pan.displayhr.lines[0], u'─'); + AppendFmt(&p->lines[0], "──────────TELETYPEWRITER──%s──%s──%s──%s", + (pty->conf & kPtyLed1) ? "\e[1;31m◎\e[0m" : "○", + (pty->conf & kPtyLed2) ? "\e[1;32m◎\e[0m" : "○", + (pty->conf & kPtyLed3) ? "\e[1;33m◎\e[0m" : "○", + (pty->conf & kPtyLed4) ? "\e[1;34m◎\e[0m" : "○"); + for (i = 36; i < p->right - p->left; ++i) { + AppendWide(&p->lines[0], u'─'); } +} + +static void DrawTerminal(struct Panel *p) { + long y, yn; + if (p->top == p->bottom) return; for (yn = MIN(pty->yn, p->bottom - p->top), y = 0; y < yn; ++y) { PtyAppendLine(pty, p->lines + y, y); AppendStr(p->lines + y, "\e[0m"); } } -void DrawDisplay(struct Panel *p) { - if (p->top == p->bottom) return; +static void DrawDisplay(struct Panel *p) { switch (vidya) { case 7: DrawHr(&pan.displayhr, "MONOCHROME DISPLAY ADAPTER"); - DrawMda(p, - VirtualSend(m, gc(xmalloc(25 * 80 * 2)), 0xb0000, 25 * 80 * 2)); + if (0xb0000 + 25 * 80 * 2 > m->real.n) return; + DrawMda(p, (void *)(m->real.p + 0xb0000)); break; case 3: DrawHr(&pan.displayhr, "COLOR GRAPHICS ADAPTER"); - DrawCga(p, - VirtualSend(m, gc(xmalloc(25 * 80 * 2)), 0xb8000, 25 * 80 * 2)); + if (0xb8000 + 25 * 80 * 2 > m->real.n) return; + DrawCga(p, (void *)(m->real.p + 0xb8000)); break; default: + DrawTerminalHr(&pan.displayhr); DrawTerminal(p); break; } @@ -1530,9 +1531,9 @@ static int AppendStat(struct Buffer *b, const char *name, int64_t value, return 1 + width; } -void DrawStatus(struct Panel *p) { +static void DrawStatus(struct Panel *p) { int yn, xn, rw; - struct Buffer s; + struct Buffer *s; struct MachineMemstat *a, *b; yn = p->top - p->bottom; xn = p->right - p->left; @@ -1540,19 +1541,21 @@ void DrawStatus(struct Panel *p) { rw = 0; a = &m->memstat; b = &lastmemstat; - memset(&s, 0, sizeof(s)); - if (ips > 0) rw += AppendStat(&s, "ips", ips, false); - rw += AppendStat(&s, "kb", m->real.n / 1024, false); - rw += AppendStat(&s, "reserve", a->reserved, a->reserved != b->reserved); - rw += AppendStat(&s, "commit", a->committed, a->committed != b->committed); - rw += AppendStat(&s, "freed", a->freed, a->freed != b->freed); - rw += AppendStat(&s, "tables", a->pagetables, a->pagetables != b->pagetables); - rw += AppendStat(&s, "fds", m->fds.i, false); + s = xmalloc(sizeof(struct Buffer)); + memset(s, 0, sizeof(*s)); + if (ips > 0) rw += AppendStat(s, "ips", ips, false); + rw += AppendStat(s, "kb", m->real.n / 1024, false); + rw += AppendStat(s, "reserve", a->reserved, a->reserved != b->reserved); + rw += AppendStat(s, "commit", a->committed, a->committed != b->committed); + rw += AppendStat(s, "freed", a->freed, a->freed != b->freed); + rw += AppendStat(s, "tables", a->pagetables, a->pagetables != b->pagetables); + rw += AppendStat(s, "fds", m->fds.i, false); AppendFmt(&p->lines[0], "\e[7m%-*s%s\e[0m", xn - rw, statusmessage && nowl() < statusexpires ? statusmessage : "das blinkenlights", - s.p); - free(s.p); + s->p); + free(s->p); + free(s); memcpy(b, a, sizeof(*a)); } @@ -1900,7 +1903,9 @@ static void OnDiskServiceGetParams(void) { } static void OnDiskServiceReadSectors(void) { - int64_t drive, head, track, sector, offset, size, addr; + static int x; + uint64_t addr, size; + int64_t drive, head, track, sector, offset; drive = m->dx[0]; head = m->dx[1]; track = (m->cx[0] & 0b11000000) << 2 | m->cx[1]; @@ -1910,9 +1915,9 @@ static void OnDiskServiceReadSectors(void) { offset = sector * 512 + track * 512 * 63 + head * 512 * 63 * 1024; if (0 <= sector && offset + size <= elf->mapsize) { addr = Read64(m->es) + Read16(m->bx); - if (addr + size <= 0xffff0 + 0xffff + 1) { + if (addr + size <= m->real.n) { SetWriteAddr(m, addr, size); - VirtualRecv(m, addr, elf->map + offset, size); + memcpy(m->real.p + addr, elf->map + offset, size); m->ax[1] = 0x00; SetCarry(false); } else { @@ -2080,12 +2085,16 @@ static void OnApmService(void) { static void OnE820(void) { uint8_t p[20]; - if (Read32(m->dx) == 0x534D4150 && Read32(m->cx) == 24) { + uint64_t addr; + addr = Read64(m->es) + Read16(m->di); + if (Read32(m->dx) == 0x534D4150 && Read32(m->cx) == 24 && + addr + sizeof(p) <= m->real.n) { if (!Read32(m->bx)) { Write64(p + 000, 0); - Write64(p + 010, BIGPAGESIZE); + Write64(p + 010, m->real.n); Write32(p + 014, 1); - VirtualRecv(m, Read64(m->es) + Read16(m->di), p, sizeof(p)); + memcpy(m->real.p + addr, p, sizeof(p)); + SetWriteAddr(m, addr, sizeof(p)); Write32(m->cx, sizeof(p)); Write32(m->bx, 1); } else { @@ -2157,6 +2166,24 @@ static bool OnHalt(int interrupt) { } } +static void OnBinbase(struct Machine *m) { + unsigned i; + int64_t skew; + skew = m->xedd->op.disp * 512; + LOGF("skew binbase %,ld @ %p", skew, GetIp()); + for (i = 0; i < dis->syms.i; ++i) { + dis->syms.p[i].addr += skew; + } + for (i = 0; i < dis->loads.i; ++i) { + dis->loads.p[i].addr += skew; + } + Disassemble(); +} + +static void OnLongBranch(struct Machine *m) { + Disassemble(); +} + static void OnPageUp(void) { opstart -= tyn / 2; } @@ -2647,9 +2674,6 @@ static void Tui(void) { ScrollReadData(&pan.readdata); ScrollWriteData(&pan.writedata); } - if (IsLongBranch()) { - Disassemble(); - } } else { m->ip += m->xedd->length; action &= ~NEXT; @@ -2787,6 +2811,8 @@ int main(int argc, char *argv[]) { pty = NewPty(); m = NewMachine(); m->mode = XED_MACHINE_MODE_LONG_64; + m->onbinbase = OnBinbase; + m->onlongbranch = OnLongBranch; speed = 16; SetXmmSize(2); SetXmmDisp(kXmmHex); diff --git a/tool/build/build.mk b/tool/build/build.mk index 13bbb41c..2537f787 100644 --- a/tool/build/build.mk +++ b/tool/build/build.mk @@ -34,6 +34,7 @@ TOOL_BUILD_DIRECTDEPS = \ LIBC_DNS \ LIBC_ELF \ LIBC_FMT \ + LIBC_INTRIN \ LIBC_LOG \ LIBC_LOG_ASAN \ LIBC_TINYMATH \ diff --git a/tool/build/emubin/emubin.mk b/tool/build/emubin/emubin.mk index bb71fd98..1939429d 100644 --- a/tool/build/emubin/emubin.mk +++ b/tool/build/emubin/emubin.mk @@ -58,36 +58,6 @@ o/$(MODE)/tool/build/emubin/%.elf: \ $(ELF) @$(ELFLINK) -o/$(MODE)/tool/build/emubin/lisp.elf: \ - $(TOOL_BUILD_EMUBIN_DEPS) \ - $(TOOL_BUILD_EMUBIN_A) \ - o/$(MODE)/tool/build/emubin/lisp.o \ - o/$(MODE)/tool/build/emubin/lispelf.o \ - $(ELF) - @$(ELFLINK) - -o/dbg/tool/build/emubin/lisp.real.com.dbg: \ - $(TOOL_BUILD_EMUBIN_DEPS) \ - $(TOOL_BUILD_EMUBIN_A) \ - o/dbg/tool/build/emubin/lisp.real.o \ - $(CRT) \ - $(APE) - -@$(APELINK) - -o/$(MODE)/tool/build/emubin/lisp.bin.dbg: \ - $(TOOL_BUILD_EMUBIN_DEPS) \ - o/$(MODE)/tool/build/emubin/lisp.real.o \ - o/$(MODE)/tool/build/emubin/lispstart.o \ - tool/build/emubin/lisp.lds - @$(ELFLINK) -z max-page-size=0x10 - -o/$(MODE)/tool/build/emubin/love.bin.dbg: \ - $(TOOL_BUILD_EMUBIN_DEPS) \ - o/$(MODE)/tool/build/emubin/love.o \ - o/$(MODE)/tool/build/emubin/lispstart.o \ - tool/build/emubin/lisp.lds - @$(ELFLINK) -z max-page-size=0x10 - o/tiny/tool/build/emubin/spiral.bin.dbg: \ $(TOOL_BUILD_EMUBIN_DEPS) \ o/tiny/tool/build/emubin/spiral.real.o diff --git a/tool/build/emubin/lisp.c b/tool/build/emubin/lisp.c deleted file mode 100644 index e83c1bb9..00000000 --- a/tool/build/emubin/lisp.c +++ /dev/null @@ -1,460 +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 │ -│ │ -│ Permission to use, copy, modify, and/or distribute this software for │ -│ any purpose with or without fee is hereby granted, provided that the │ -│ above copyright notice and this permission notice appear in all copies. │ -│ │ -│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ -│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ -│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ -│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ -│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ -│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ -│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ -│ PERFORMANCE OF THIS SOFTWARE. │ -╚─────────────────────────────────────────────────────────────────────────────*/ -#include "tool/build/emubin/lisp.h" - -#define TRACE 0 // print eval input output -#define RETRO 0 // auto capitalize input -#define DELETE 0 // allow backspace to rub out symbol -#define QUOTES 0 // allow 'X shorthand (QUOTE X) -#define PROMPT 0 // show repl prompt -#define WORD short -#define WORDS 8192 - -/*───────────────────────────────────────────────────────────────────────────│─╗ -│ The LISP Challenge § LISP Machine ─╬─│┼ -╚────────────────────────────────────────────────────────────────────────────│*/ - -#define ATOM 0 -#define CONS 1 - -#define NIL 0 -#define UNDEFINED 8 -#define ATOM_T 30 -#define ATOM_QUOTE 34 -#define ATOM_ATOM 46 -#define ATOM_EQ 56 -#define ATOM_COND 62 -#define ATOM_CAR 72 -#define ATOM_CDR 80 -#define ATOM_CONS 88 -#define ATOM_LAMBDA 98 - -#define BOOL(x) ((x) ? ATOM_T : NIL) -#define VALUE(x) ((x) >> 1) -#define PTR(i) ((i) << 1 | CONS) - -struct Lisp { - WORD mem[WORDS]; - unsigned char syntax[256]; - WORD look; - WORD globals; - WORD index; - char token[128]; - char str[WORDS]; -}; - -_Static_assert(sizeof(struct Lisp) <= 0x7c00 - 0x600, - "LISP Machine too large for real mode"); - -_Alignas(char) const char kSymbols[] = "NIL\0" - "*UNDEFINED\0" - "T\0" - "QUOTE\0" - "ATOM\0" - "EQ\0" - "COND\0" - "CAR\0" - "CDR\0" - "CONS\0" - "LAMBDA\0"; - -#ifdef __REAL_MODE__ -static struct Lisp *const q; -#else -static struct Lisp q[1]; -#endif - -static void Print(long); -static WORD GetList(void); -static WORD GetObject(void); -static void PrintObject(long); -static WORD Eval(long, long); - -static void SetupSyntax(void) { - unsigned char *syntax = q->syntax; - asm("" : "+bSD"(syntax)); - syntax[' '] = ' '; - syntax['\r'] = ' '; - syntax['\n'] = ' '; - syntax['('] = '('; - syntax[')'] = ')'; - syntax['.'] = '.'; -#if QUOTES - syntax['\''] = '\''; -#endif -} - -static void SetupBuiltins(void) { - CopyMemory(q->str, kSymbols, sizeof(kSymbols)); -} - -static inline WORD Car(long x) { - return PEEK_ARRAY(q, mem, VALUE(x), 0); -} - -static inline WORD Cdr(long x) { - return PEEK_ARRAY(q, mem, VALUE(x), 1); -} - -static WORD Set(long i, long k, long v) { - POKE_ARRAY(q, mem, VALUE(i), 0, k); - POKE_ARRAY(q, mem, VALUE(i), 1, v); - return i; -} - -static WORD Cons(WORD car, WORD cdr) { - int i, cell; - i = q->index; - POKE_ARRAY(q, mem, i, 0, car); - POKE_ARRAY(q, mem, i, 1, cdr); - q->index = i + 2; - cell = OBJECT(CONS, i); - return cell; -} - -static char *StpCpy(char *d, char *s) { - char c; - do { - c = LODS(s); // a.k.a. c = *s++ - STOS(d, c); // a.k.a. *d++ = c - } while (c); - return d; -} - -static WORD Intern(char *s) { - int j, cx; - char c, *z, *t; - z = q->str; - c = LODS(z); - while (c) { - for (j = 0;; ++j) { - if (c != PEEK(s, j, 0)) { - break; - } - if (!c) { - return OBJECT(ATOM, z - q->str - j - 1); - } - c = LODS(z); - } - while (c) c = LODS(z); - c = LODS(z); - } - --z; - StpCpy(z, s); - return OBJECT(ATOM, SUB((long)z, q->str)); -} - -static unsigned char XlatSyntax(unsigned char b) { - return PEEK_ARRAY(q, syntax, b, 0); -} - -static void PrintString(char *s) { - char c; - for (;;) { - if (!(c = PEEK(s, 0, 0))) break; - PrintChar(c); - ++s; - } -} - -static int GetChar(void) { - int c; - c = ReadChar(); -#if RETRO - if (c >= 'a') { - CompilerBarrier(); - if (c <= 'z') c -= 'a' - 'A'; - } -#endif -#if DELETE - if (c == '\b') return c; -#endif - PrintChar(c); - if (c == '\r') PrintChar('\n'); - return c; -} - -static void GetToken(void) { - char *t; - unsigned char b, x; - b = q->look; - t = q->token; - for (;;) { - x = XlatSyntax(b); - if (x != ' ') break; - b = GetChar(); - } - if (x) { - STOS(t, b); - b = GetChar(); - } else { - while (b && !x) { - if (!DELETE || b != '\b') { - STOS(t, b); - } else if (t > q->token) { - PrintString("\b \b"); - if (t > q->token) --t; - } - b = GetChar(); - x = XlatSyntax(b); - } - } - STOS(t, 0); - q->look = b; -} - -static WORD ConsumeObject(void) { - GetToken(); - return GetObject(); -} - -static WORD Cadr(long x) { - return Car(Cdr(x)); // ((A B C D) (E F G) H I) → (E F G) -} - -static WORD List(long x, long y) { - return Cons(x, Cons(y, NIL)); -} - -static WORD Quote(long x) { - return List(ATOM_QUOTE, x); -} - -static WORD GetQuote(void) { - return Quote(ConsumeObject()); -} - -static WORD AddList(WORD x) { - return Cons(x, GetList()); -} - -static WORD GetList(void) { - GetToken(); - switch (*q->token & 0xFF) { - default: - return AddList(GetObject()); - case ')': - return NIL; - case '.': - return ConsumeObject(); -#if QUOTES - case '\'': - return AddList(GetQuote()); -#endif - } -} - -static WORD GetObject(void) { - switch (*q->token & 0xFF) { - default: - return Intern(q->token); - case '(': - return GetList(); -#if QUOTES - case '\'': - return GetQuote(); -#endif - } -} - -static WORD ReadObject(void) { - q->look = GetChar(); - GetToken(); - return GetObject(); -} - -static WORD Read(void) { - return ReadObject(); -} - -static void PrintAtom(long x) { - PrintString(q->str + VALUE(x)); -} - -static void PrintList(long x) { -#if QUOTES - if (Car(x) == ATOM_QUOTE) { - PrintChar('\''); - PrintObject(Cadr(x)); - return; - } -#endif - PrintChar('('); - PrintObject(Car(x)); - while ((x = Cdr(x))) { - if (!ISATOM(x)) { - PrintChar(' '); - PrintObject(Car(x)); - } else { - PrintString(" . "); - PrintObject(x); - break; - } - } - PrintChar(')'); -} - -static void PrintObject(long x) { - if (ISATOM(x)) { - PrintAtom(x); - } else { - PrintList(x); - } -} - -static void Print(long i) { - PrintObject(i); - PrintString("\r\n"); -} - -/*───────────────────────────────────────────────────────────────────────────│─╗ -│ The LISP Challenge § Bootstrap John McCarthy's Metacircular Evaluator ─╬─│┼ -╚────────────────────────────────────────────────────────────────────────────│*/ - -static WORD Atom(long x) { - return BOOL(ISATOM(x)); -} - -WORD Eq(long x, long y) { - return BOOL(x == y); -} - -static WORD Caar(long x) { - return Car(Car(x)); // ((A B C D) (E F G) H I) → A -} - -static WORD Cdar(long x) { - return Cdr(Car(x)); // ((A B C D) (E F G) H I) → (B C D) -} - -static WORD Cadar(long x) { - return Cadr(Car(x)); // ((A B C D) (E F G) H I) → B -} - -static WORD Caddr(long x) { - return Cadr(Cdr(x)); // ((A B C D) (E F G) H I) → H -} - -static WORD Caddar(long x) { - return Caddr(Car(x)); // ((A B C D) (E F G) H I) → C -} - -static WORD Arg1(long e, long a) { - return Eval(Cadr(e), a); -} - -static WORD Arg2(long e, long a) { - return Eval(Caddr(e), a); -} - -static WORD Append(long x, long y) { - return x ? Cons(Car(x), Append(Cdr(x), y)) : y; -} - -static WORD Evcon(long c, long a) { - return Eval(Caar(c), a) ? Eval(Cadar(c), a) : Evcon(Cdr(c), a); -} - -static WORD Bind(long v, long a, long e) { - return v ? Cons(Cons(Car(v), Eval(Car(a), e)), Bind(Cdr(v), Cdr(a), e)) : e; -} - -static WORD Assoc(long x, long y) { - return y ? Eq(Caar(y), x) ? Cdar(y) : Assoc(x, Cdr(y)) : NIL; -} - -static WORD Pair(long x, long y) { - if (Atom(x) || Atom(y)) { - return NIL; - } else { - return Cons(Cons(Car(x), Car(y)), Pair(Cdr(x), Cdr(y))); - } -} - -__attribute__((__noinline__)) static WORD Evaluate(long e, long a) { - if (Atom(e)) { - return Assoc(e, a); - } else if (Atom(Car(e))) { - switch (Car(e)) { - case NIL: - return UNDEFINED; - case ATOM_QUOTE: - return Cadr(e); - case ATOM_ATOM: - return Atom(Arg1(e, a)); - case ATOM_EQ: - return Eq(Arg1(e, a), Arg2(e, a)); - case ATOM_COND: - return Evcon(Cdr(e), a); - case ATOM_CAR: - return Car(Arg1(e, a)); - case ATOM_CDR: - return Cdr(Arg1(e, a)); - case ATOM_CONS: - return Cons(Arg1(e, a), Arg2(e, a)); - default: - return Eval(Cons(Assoc(Car(e), a), Cdr(e)), a); - } - } else if (Eq(Caar(e), ATOM_LAMBDA)) { - return Eval(Caddar(e), Bind(Cadar(e), Cdr(e), a)); - } else { - return UNDEFINED; - } -} - -static WORD Eval(long e, long a) { - WORD r; -#if TRACE - PrintString("->"); - Print(e); - PrintString(" "); - Print(a); -#endif - e = Evaluate(e, a); -#if TRACE - PrintString("<-"); - Print(e); -#endif - return e; -} - -/*───────────────────────────────────────────────────────────────────────────│─╗ -│ The LISP Challenge § User Interface ─╬─│┼ -╚────────────────────────────────────────────────────────────────────────────│*/ - -void Repl(void) { - for (;;) { -#if PROMPT - PrintString("* "); -#endif - Print(Eval(Read(), q->globals)); - } -} - -int main(int argc, char *argv[]) { - RawMode(); - SetupSyntax(); - SetupBuiltins(); -#if PROMPT - PrintString("THE LISP CHALLENGE V1\r\n" - "VISIT GITHUB.COM/JART\r\n"); -#endif - Repl(); - return 0; -} diff --git a/tool/build/emubin/spiral.c b/tool/build/emubin/spiral.c index 8f64db2a..6e2e4aba 100644 --- a/tool/build/emubin/spiral.c +++ b/tool/build/emubin/spiral.c @@ -133,7 +133,7 @@ int main() { SetEs(0); memset((void *)(0x7c00 + 512), 0, 25 * 80); SetEs(0xb8000 >> 4); - memset((void *)0, 0, 25 * 80 * 2); + /* memset((void *)0, 0, 25 * 80 * 2); */ spiral((void *)0, (void *)(0x7c00 + 512), g); } } diff --git a/tool/build/lib/argv.c b/tool/build/lib/argv.c index 1d46771e..735ee4a9 100644 --- a/tool/build/lib/argv.c +++ b/tool/build/lib/argv.c @@ -17,16 +17,10 @@ │ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │ │ 02110-1301 USA │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/alg/arraylist2.h" -#include "libc/assert.h" -#include "libc/bits/popcnt.h" -#include "libc/bits/safemacros.h" #include "libc/log/check.h" #include "libc/mem/mem.h" #include "libc/runtime/gc.h" -#include "libc/runtime/runtime.h" #include "libc/str/str.h" -#include "libc/sysv/consts/auxv.h" #include "tool/build/lib/endian.h" #include "tool/build/lib/machine.h" #include "tool/build/lib/memory.h" diff --git a/tool/build/lib/buffer.c b/tool/build/lib/buffer.c index 7e8d4d86..3f58e9a9 100644 --- a/tool/build/lib/buffer.c +++ b/tool/build/lib/buffer.c @@ -21,18 +21,27 @@ #include "libc/calls/calls.h" #include "libc/errno.h" #include "libc/fmt/fmt.h" +#include "libc/macros.h" #include "libc/mem/mem.h" #include "libc/str/str.h" #include "libc/str/tpenc.h" -#include "libc/str/tpencode.h" #include "tool/build/lib/buffer.h" -void AppendChar(struct Buffer *b, char c) { - APPEND(&b->p, &b->i, &b->n, &c); +void AppendData(struct Buffer *b, char *data, unsigned len) { + char *p; + unsigned n; + if (b->i + len + 1 > b->n) { + n = MAX(b->i + len + 1, MAX(16, b->n + (b->n >> 1))); + if (!(p = realloc(b->p, n))) return; + b->p = p; + b->n = n; + } + memcpy(b->p + b->i, data, len); + b->p[b->i += len] = 0; } -void AppendData(struct Buffer *b, char *data, size_t len) { - CONCAT(&b->p, &b->i, &b->n, data, len); +void AppendChar(struct Buffer *b, char c) { + AppendData(b, &c, 1); } void AppendStr(struct Buffer *b, const char *s) { diff --git a/tool/build/lib/buffer.h b/tool/build/lib/buffer.h index 795ee836..a4f616f7 100644 --- a/tool/build/lib/buffer.h +++ b/tool/build/lib/buffer.h @@ -4,12 +4,12 @@ COSMOPOLITAN_C_START_ struct Buffer { - size_t i, n; + unsigned i, n; char *p; }; void AppendChar(struct Buffer *, char); -void AppendData(struct Buffer *, char *, size_t); +void AppendData(struct Buffer *, char *, unsigned); void AppendStr(struct Buffer *, const char *); void AppendWide(struct Buffer *, wint_t); int AppendFmt(struct Buffer *, const char *, ...); diff --git a/tool/build/lib/buildlib.mk b/tool/build/lib/buildlib.mk index 9c30029b..4685d3ed 100644 --- a/tool/build/lib/buildlib.mk +++ b/tool/build/lib/buildlib.mk @@ -41,6 +41,7 @@ TOOL_BUILD_LIB_A_DIRECTDEPS = \ LIBC_SYSV_CALLS \ LIBC_TIME \ LIBC_LOG \ + LIBC_RAND \ LIBC_STR \ LIBC_SOCK \ LIBC_UNICODE \ @@ -68,7 +69,7 @@ $(TOOL_BUILD_LIB_A_OBJS): \ -fsanitize=address endif -o/$(MODE)/tool/build/lib/memory-gcc.asm: \ +o/$(MODE)/tool/build/lib/buffer-gcc.asm: \ OVERRIDE_CFLAGS += \ -fsanitize=address diff --git a/tool/build/lib/cpuid.c b/tool/build/lib/cpuid.c index 489e04bf..0fd80e03 100644 --- a/tool/build/lib/cpuid.c +++ b/tool/build/lib/cpuid.c @@ -39,8 +39,9 @@ void OpCpuid(struct Machine *m, uint32_t rde) { cx |= 0 << 1; // pclmulqdq cx |= 1 << 9; // ssse3 cx |= 1 << 23; // popcnt - cx |= 0 << 30; // rdrnd + cx |= 1 << 30; // rdrnd cx |= 0 << 25; // aes + cx |= 1 << 13; // cmpxchg16b dx |= 1 << 0; // fpu dx |= 1 << 4; // tsc dx |= 1 << 6; // pae @@ -48,15 +49,31 @@ void OpCpuid(struct Machine *m, uint32_t rde) { dx |= 1 << 15; // cmov dx |= 1 << 19; // clflush dx |= 1 << 23; // mmx + dx |= 1 << 24; // fxsave dx |= 1 << 25; // sse dx |= 1 << 26; // sse2 break; case 7: - bx |= 1 << 9; // erms + switch (Read32(m->cx)) { + case 0: + bx |= 1 << 0; // fsgsbase + bx |= 1 << 9; // erms + bx |= 0 << 18; // rdseed + cx |= 1 << 22; // rdpid + break; + default: + break; + } break; case 0x80000001: cx |= 1 << 0; // lahf + dx |= 1 << 0; // fpu + dx |= 1 << 8; // cmpxchg8b dx |= 1 << 11; // syscall + dx |= 1 << 15; // cmov + dx |= 1 << 23; // mmx + dx |= 1 << 24; // fxsave + dx |= 1 << 27; // rdtscp dx |= 1 << 29; // long break; case 0x80000007: diff --git a/tool/build/lib/dis.c b/tool/build/lib/dis.c index 41cd842f..1da54f6c 100644 --- a/tool/build/lib/dis.c +++ b/tool/build/lib/dis.c @@ -23,7 +23,6 @@ #include "libc/conv/itoa.h" #include "libc/fmt/bing.h" #include "libc/fmt/fmt.h" -#include "libc/limits.h" #include "libc/log/check.h" #include "libc/log/log.h" #include "libc/macros.h" @@ -96,7 +95,7 @@ static char *DisError(struct Dis *d, char *p) { } static char *DisAddr(struct Dis *d, char *p) { - if (INT32_MIN <= d->addr && d->addr <= INT32_MAX) { + if (-0x80000000 <= d->addr && d->addr <= 0x7fffffff) { return p + uint64toarray_fixed16(d->addr, p, 32); } else { return p + uint64toarray_fixed16(d->addr, p, 48); diff --git a/tool/build/lib/disarg.c b/tool/build/lib/disarg.c index 75f4e98e..41ccae7d 100644 --- a/tool/build/lib/disarg.c +++ b/tool/build/lib/disarg.c @@ -336,20 +336,24 @@ static char *DisEvqp(struct Dis *d, uint32_t rde, char *p) { return DisE(d, rde, p, DisRegisterWord); } -static char *DisEdqpReg(struct Dis *d, uint32_t rde, char *p) { +static char *DisRv(struct Dis *d, uint32_t rde, char *p) { + return DisRegister(p, kGreg[Osz(rde)][0][Rexb(rde)][ModrmRm(rde)]); +} + +static char *DisRvqp(struct Dis *d, uint32_t rde, char *p) { + return DisRegister(p, kGreg[Osz(rde)][Rexw(rde)][Rexb(rde)][ModrmRm(rde)]); +} + +static char *DisRdqp(struct Dis *d, uint32_t rde, char *p) { return DisRegister(p, kGreg[0][Rexw(rde)][Rexb(rde)][ModrmRm(rde)]); } static char *DisEdqp(struct Dis *d, uint32_t rde, char *p) { - return DisRegMem(d, rde, p, DisEdqpReg); -} - -static char *DisEvReg(struct Dis *d, uint32_t rde, char *p) { - return DisRegister(p, kGreg[Osz(rde)][0][Rexb(rde)][ModrmRm(rde)]); + return DisRegMem(d, rde, p, DisRdqp); } static char *DisEv(struct Dis *d, uint32_t rde, char *p) { - return DisRegMem(d, rde, p, DisEvReg); + return DisRegMem(d, rde, p, DisRv); } static char *DisGvq(struct Dis *d, uint32_t rde, char *p, int r) { @@ -597,8 +601,6 @@ static char *DisWps(struct Dis *d, uint32_t rde, char *p) { #define DisOvqp DisAbs #define DisPpi DisPq #define DisQpi DisQq -#define DisRdqp DisGdqp -#define DisRvqp DisGvqp #define DisVpd DisVdq #define DisVps DisVdq #define DisVq DisVdq diff --git a/tool/build/lib/diself.c b/tool/build/lib/diself.c index e35ab929..a5222162 100644 --- a/tool/build/lib/diself.c +++ b/tool/build/lib/diself.c @@ -200,6 +200,7 @@ long DisFindSymByName(struct Dis *d, const char *s) { } void DisLoadElf(struct Dis *d, struct Elf *elf) { + LOGF("DisLoadElf"); if (!elf || !elf->ehdr) return; DisLoadElfLoads(d, elf); DisLoadElfSyms(d, elf); diff --git a/tool/build/lib/disspec.c b/tool/build/lib/disspec.c index 85eb957e..1e3d3e2e 100644 --- a/tool/build/lib/disspec.c +++ b/tool/build/lib/disspec.c @@ -447,7 +447,11 @@ const char *DisSpecMap0(struct XedDecodedInst *x, char *p) { } const char *DisSpecMap1(struct XedDecodedInst *x, char *p) { + bool isreg; + isreg = IsModrmRegister(x->op.rde); switch (x->op.opcode & 0xff) { + RCASE(0x02, "lar %Gvqp Ev"); + RCASE(0x03, "lsl %Gvqp Ev"); RCASE(0x05, "syscall"); RCASE(0x0B, "ud2"); RCASE(0x0D, "nop Ev"); @@ -464,7 +468,12 @@ const char *DisSpecMap1(struct XedDecodedInst *x, char *p) { RCASE(0x2B, "movntpSD Mps %Vps"); RCASE(0x2E, Osz(x->op.rde) ? "ucomisd %Vsd Wsd" : "ucomiss %Vss Wss"); RCASE(0x2F, Osz(x->op.rde) ? "comisd %Vsd Wsd" : "comiss %Vss Wss"); + RCASE(0x30, "wrmsr"); RCASE(0x31, "rdtsc"); + RCASE(0x32, "rdmsr"); + RCASE(0x33, "rdpmc"); + RCASE(0x34, "sysenter"); + RCASE(0x35, "sysexit"); RCASE(0x40 ... 0x4f, "cmovCC %Gvqp Evqp"); RCASE(0x52, DisOpVpsWpsVssWss(x, p, "rsqrt")); RCASE(0x53, DisOpVpsWpsVssWss(x, p, "rcp")); @@ -570,17 +579,76 @@ const char *DisSpecMap1(struct XedDecodedInst *x, char *p) { RCASE(0xFE, DisOpPqQqVdqWdq(x, p, "paddd")); RCASE(0xFF, "ud0 %Gvqp Evqp"); case 0x01: - if (ModrmMod(x->op.rde) == 0b11 && ModrmReg(x->op.rde) == 0b111 && - ModrmRm(x->op.rde) == 0b001) { - return "rdtscp"; - } else if (!IsModrmRegister(x->op.rde) && ModrmReg(x->op.rde) == 0) { - return "sgdt Ms"; - } else if (!IsModrmRegister(x->op.rde) && ModrmReg(x->op.rde) == 2) { - return "lgdt Ms"; - } else { - return UNKNOWN; + switch (ModrmReg(x->op.rde)) { + case 0: + if (!isreg) { + return "sgdt Ms"; + } else { + switch (ModrmRm(x->op.rde)) { + case 1: + return "vmcall"; + case 2: + return "vmlaunch"; + case 3: + return "vmresume"; + case 4: + return "vmxoff"; + default: + return UNKNOWN; + } + } + break; + case 1: + if (!isreg) { + return "sidt Ms"; + } else { + switch (ModrmRm(x->op.rde)) { + case 0: + return "monitor"; + case 1: + return "mwait"; + default: + return UNKNOWN; + } + } + break; + case 2: + if (!isreg) { + return "lgdt Ms"; + } else if (ModrmRm(x->op.rde) == 0) { + return "xgetbv"; + } else if (ModrmRm(x->op.rde) == 1) { + return "xsetbv"; + } else { + return UNKNOWN; + } + break; + case 3: + if (!isreg) { + return "lidt Ms"; + } else { + return UNKNOWN; + } + case 4: + return "smsw Ew"; + case 6: + return "lmsw Ew"; + case 7: + if (!isreg) { + return "invlpg M"; + } else { + switch (ModrmRm(x->op.rde)) { + case 0: + return "swapgs"; + case 1: + return "rdtscp"; + default: + return UNKNOWN; + } + } + default: + return UNKNOWN; } - break; case 0x1F: if (ModrmMod(x->op.rde) == 1 && ModrmReg(x->op.rde) == 0 && ModrmRm(x->op.rde) == 0b101) { @@ -621,15 +689,42 @@ const char *DisSpecMap1(struct XedDecodedInst *x, char *p) { break; case 0xAE: switch (ModrmReg(x->op.rde)) { - RCASE(0, "fxsave Mstx %st %st(1)"); - RCASE(1, "fxrstor Mstx %st %st(1)"); - RCASE(2, "ldmxcsr Md"); - RCASE(3, "stmxcsr Md"); - RCASE(4, "xsave M %edx %eax"); - RCASE(5, "lfence"); - RCASE(6, "mfence"); + case 0: + if (isreg) { + return "rdfsbase %Rdqp"; + } else { + return "fxsave M"; + } + case 1: + if (isreg) { + return "rdgsbase %Rdqp"; + } else { + return "fxrstor M"; + } + case 2: + if (isreg) { + return "wrfsbase %Rdqp"; + } else { + return "ldmxcsr Md"; + } + case 3: + if (isreg) { + return "wrgsbase %Rdqp"; + } else { + return "stmxcsr Md"; + } + case 4: + if (isreg) { + return UNKNOWN; + } else { + return "xsave M %edx %eax"; + } + case 5: + return "lfence"; + case 6: + return "mfence"; case 7: - if (ModrmMod(x->op.rde) == 0b11 && ModrmReg(x->op.rde) == 0b111) { + if (isreg && ModrmReg(x->op.rde) == 0b111) { return "sfence"; } else { return "clflush"; @@ -668,13 +763,13 @@ const char *DisSpecMap1(struct XedDecodedInst *x, char *p) { break; case 0xC4: if (!Osz(x->op.rde)) { - if (IsModrmRegister(x->op.rde)) { + if (isreg) { return "pinsrw %Pq %Rdqp Ib"; } else { return "pinsrw %Pq Mw Ib"; } } else { - if (IsModrmRegister(x->op.rde)) { + if (isreg) { return "pinsrw %Vdq %Rdqp Ib"; } else { return "pinsrw %Vdq Mw Ib"; @@ -696,10 +791,38 @@ const char *DisSpecMap1(struct XedDecodedInst *x, char *p) { } break; case 0xC7: - if (Rexw(x->op.rde)) { - return "cmpxchg16b Mdq"; - } else { - return "cmpxchg8b Mq"; + switch (ModrmReg(x->op.rde)) { + case 1: + if (!isreg) { + if (Rexw(x->op.rde)) { + return "cmpxchg16b Mdq"; + } else { + return "cmpxchg8b Mq"; + } + } else { + return UNKNOWN; + } + break; + case 6: + if (isreg) { + return "rdrand %Rdqp"; + } else { + return UNKNOWN; + } + break; + case 7: + if (isreg) { + if (Rep(x->op.rde) == 3) { + return "rdpid %Rdqp"; + } else { + return "rdseed %Rdqp"; + } + } else { + return UNKNOWN; + } + break; + default: + return UNKNOWN; } break; case 0xD6: @@ -714,7 +837,7 @@ const char *DisSpecMap1(struct XedDecodedInst *x, char *p) { case 0x12: switch (Rep(x->op.rde) | Osz(x->op.rde)) { case 0: - if (IsModrmRegister(x->op.rde)) { + if (isreg) { return "movhlps %Vq %Uq"; } else { return "movlps %Vq Mq"; @@ -740,7 +863,7 @@ const char *DisSpecMap1(struct XedDecodedInst *x, char *p) { case 0x16: switch (Rep(x->op.rde) | Osz(x->op.rde)) { case 0: - if (IsModrmRegister(x->op.rde)) { + if (isreg) { return "movlhps %Vq %Uq"; } else { return "movhps %Vq Mq"; @@ -938,6 +1061,20 @@ const char *DisSpecMap2(struct XedDecodedInst *x, char *p) { RCASE(0x41, "phminposuw %Vdq Wdq"); RCASE(0x80, "invept %Gq Mdq"); RCASE(0x81, "invvpid %Gq Mdq"); + case 0xF0: + if (Rep(x->op.rde) == 2) { + return "crc32 %Gvqp Eb"; + } else { + return "movbe %Gvqp M"; + } + break; + case 0xF1: + if (Rep(x->op.rde) == 2) { + return "crc32 %Gvqp Evqp"; + } else { + return "movbe M %Gvqp"; + } + break; default: return UNKNOWN; } diff --git a/tool/build/lib/ioports.c b/tool/build/lib/ioports.c index 02861ac6..b8b2a263 100644 --- a/tool/build/lib/ioports.c +++ b/tool/build/lib/ioports.c @@ -18,6 +18,7 @@ │ 02110-1301 USA │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/struct/iovec.h" +#include "libc/nexgen32e/uart.h" #include "libc/sysv/consts/fileno.h" #include "tool/build/lib/ioports.h" @@ -42,10 +43,42 @@ static void OpE9Write(struct Machine *m, uint8_t b) { m->fds.p[fd].cb->writev(m->fds.p[fd].fd, &(struct iovec){&b, 1}, 1); } +static int OpSerialIn(struct Machine *m, int r) { + switch (r) { + case UART_DLL: + if (!m->dlab) { + return OpE9Read(m); + } else { + return 0x01; + } + case UART_LSR: + return UART_TTYDA | UART_TTYTXR | UART_TTYIDL; + default: + return 0; + } +} + +static void OpSerialOut(struct Machine *m, int r, uint32_t x) { + switch (r) { + case UART_DLL: + if (!m->dlab) { + return OpE9Write(m, x); + } + break; + case UART_LCR: + m->dlab = !!(x & UART_DLAB); + break; + default: + break; + } +} + uint64_t OpIn(struct Machine *m, uint16_t p) { switch (p) { case 0xE9: return OpE9Read(m); + case 0x3F8 ... 0x3FF: + return OpSerialIn(m, p - 0x3F8); default: return -1; } @@ -56,6 +89,9 @@ void OpOut(struct Machine *m, uint16_t p, uint32_t x) { case 0xE9: OpE9Write(m, x); break; + case 0x3F8 ... 0x3FF: + OpSerialOut(m, p - 0x3F8, x); + break; default: break; } diff --git a/tool/build/lib/loader.c b/tool/build/lib/loader.c index bd8ddca8..df450c5f 100644 --- a/tool/build/lib/loader.c +++ b/tool/build/lib/loader.c @@ -109,6 +109,29 @@ static void LoadBin(struct Machine *m, intptr_t base, const char *prog, m->ip = base; } +static void BootProgram(struct Machine *m, struct Elf *elf, size_t codesize) { + m->ip = 0x7c00; + elf->base = 0x7c00; + CHECK_NE(-1, ReserveReal(m, 0x00f00000)); + memset(m->real.p, 0, 0x00f00000); + Write16(m->real.p + 0x400, 0x3F8); + Write16(m->real.p + 0x40E, 0xb0000 >> 4); + Write16(m->real.p + 0x413, 0xb0000 / 1024); + Write16(m->real.p + 0x44A, 80); + Write64(m->cs, 0); + Write64(m->dx, 0); + memcpy(m->real.p + 0x7c00, elf->map, 512); + if (memcmp(elf->map, "\177ELF", 4) == 0) { + elf->ehdr = (void *)elf->map; + elf->size = codesize; + elf->base = elf->ehdr->e_entry; + } else { + elf->base = 0x7c00; + elf->ehdr = NULL; + elf->size = 0; + } +} + void LoadProgram(struct Machine *m, const char *prog, char **args, char **vars, struct Elf *elf) { int fd; @@ -147,21 +170,7 @@ void LoadProgram(struct Machine *m, const char *prog, char **args, char **vars, CHECK_NE(-1, close(fd)); ResetCpu(m); if ((m->mode & 3) == XED_MODE_REAL) { - elf->base = 0x7c00; - CHECK_NE(-1, ReserveReal(m, BIGPAGESIZE)); - m->ip = 0x7c00; - Write64(m->cs, 0); - Write64(m->dx, 0); - VirtualRecv(m, m->ip, elf->map, 512); - if (memcmp(elf->map, "\177ELF", 4) == 0) { - elf->ehdr = (void *)elf->map; - elf->size = codesize; - elf->base = elf->ehdr->e_entry; - } else { - elf->base = 0x7c00; - elf->ehdr = NULL; - elf->size = 0; - } + BootProgram(m, elf, codesize); } else { sp = 0x800000000000; Write64(m->sp, sp); diff --git a/tool/build/lib/machine.c b/tool/build/lib/machine.c index 1ac10a55..24e79036 100644 --- a/tool/build/lib/machine.c +++ b/tool/build/lib/machine.c @@ -17,7 +17,9 @@ │ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │ │ 02110-1301 USA │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/log/check.h" #include "libc/macros.h" +#include "libc/rand/rand.h" #include "libc/runtime/runtime.h" #include "tool/build/lib/abp.h" #include "tool/build/lib/address.h" @@ -202,14 +204,87 @@ static relegated void OpMovEvqpSw(struct Machine *m, uint32_t rde) { Read64(GetSegment(m, rde, ModrmReg(rde))) >> 4); } -static relegated void OpMovSwEvqp(struct Machine *m, uint32_t rde) { - Write64(GetSegment(m, rde, ModrmReg(rde)), - ReadMemory(rde, GetModrmRegisterWordPointerReadOszRexw(m, rde)) << 4); +static relegated int GetDescriptor(struct Machine *m, int selector, + uint64_t *out_descriptor) { + uint8_t buf[8]; + DCHECK(m->gdt_base + m->gdt_limit <= m->real.n); + selector &= -8; + if (8 <= selector && selector + 8 <= m->gdt_limit) { + SetReadAddr(m, m->gdt_base + selector, 8); + *out_descriptor = Read64(m->real.p + m->gdt_base + selector); + return 0; + } else { + return -1; + } } -static relegated void OpJmpf(struct Machine *m, uint32_t rde) { - Write64(m->cs, m->xedd->op.uimm0 << 4); - m->ip = m->xedd->op.disp; +static uint64_t GetDescriptorBase(uint64_t d) { + return (d & 0xff00000000000000) >> 32 | (d & 0x000000ffffff0000) >> 16; +} + +static uint64_t GetDescriptorLimit(uint64_t d) { + return (d & 0x000f000000000000) >> 32 | d & 0xffff; +} + +static int GetDescriptorMode(uint64_t d) { + uint8_t kMode[] = { + XED_MACHINE_MODE_REAL, + XED_MACHINE_MODE_LONG_64, + XED_MACHINE_MODE_LEGACY_32, + XED_MACHINE_MODE_LONG_64, + }; + return kMode[(d & 0x0060000000000000) >> 53]; +} + +static bool IsProtectedMode(struct Machine *m) { + return m->cr0 & 1; +} + +static relegated void OpMovSwEvqp(struct Machine *m, uint32_t rde) { + uint64_t x, d; + x = ReadMemory(rde, GetModrmRegisterWordPointerReadOszRexw(m, rde)); + if (!IsProtectedMode(m)) { + x <<= 4; + } else if (GetDescriptor(m, x, &d) != -1) { + x = GetDescriptorBase(d); + } else { + ThrowProtectionFault(m); + } + Write64(GetSegment(m, rde, ModrmReg(rde)), x); +} + +static void OpLsl(struct Machine *m, uint32_t rde) { + uint64_t descriptor; + if (GetDescriptor(m, Read16(GetModrmRegisterWordPointerRead2(m, rde)), + &descriptor) != -1) { + WriteRegister(rde, RegRexrReg(m, rde), GetDescriptorLimit(descriptor)); + SetFlag(m->flags, FLAGS_ZF, true); + } else { + SetFlag(m->flags, FLAGS_ZF, false); + } +} + +static void ChangeMachineMode(struct Machine *m, int mode) { + if (mode == m->mode) return; + ResetInstructionCache(m); + m->mode = mode; +} + +static void OpJmpf(struct Machine *m, uint32_t rde) { + uint64_t descriptor; + if (!IsProtectedMode(m)) { + Write64(m->cs, m->xedd->op.uimm0 << 4); + m->ip = m->xedd->op.disp; + } else if (GetDescriptor(m, m->xedd->op.uimm0, &descriptor) != -1) { + Write64(m->cs, GetDescriptorBase(descriptor)); + m->ip = m->xedd->op.disp; + ChangeMachineMode(m, GetDescriptorMode(descriptor)); + } else { + ThrowProtectionFault(m); + } + if (m->onlongbranch) { + m->onlongbranch(m); + } } static relegated void OpXlatAlBbb(struct Machine *m, uint32_t rde) { @@ -373,11 +448,49 @@ static void OpCmpxchg16b(struct Machine *m, uint32_t rde) { } } -static void OpCmpxchgDxAx(struct Machine *m, uint32_t rde) { - if (Rexw(rde)) { - OpCmpxchg16b(m, rde); - } else { - OpCmpxchg8b(m, rde); +static void OpRdrand(struct Machine *m, uint32_t rde) { + WriteRegister(rde, RegRexbRm(m, rde), rand64()); +} + +static void OpRdseed(struct Machine *m, uint32_t rde) { + OpRdrand(m, rde); +} + +static void Op1c7(struct Machine *m, uint32_t rde) { + bool ismem; + ismem = !IsModrmRegister(rde); + switch (ModrmReg(rde)) { + case 1: + if (ismem) { + if (Rexw(rde)) { + OpCmpxchg16b(m, rde); + } else { + OpCmpxchg8b(m, rde); + } + } else { + OpUd(m, rde); + } + break; + case 6: + if (!ismem) { + OpRdrand(m, rde); + } else { + OpUd(m, rde); + } + break; + case 7: + if (!ismem) { + if (Rep(rde) == 3) { + OpRdpid(m, rde); + } else { + OpRdseed(m, rde); + } + } else { + OpUd(m, rde); + } + break; + default: + OpUd(m, rde); } } @@ -699,8 +812,7 @@ static void OpAlubFlipTest(struct Machine *m, uint32_t rde) { } static void Alubi(struct Machine *m, uint32_t rde, aluop_f op) { - uint8_t *a, x; - a = GetModrmRegisterBytePointerWrite(m, rde); + uint8_t *a = GetModrmRegisterBytePointerWrite(m, rde); Write8(a, op(Read8(a), m->xedd->op.uimm0, &m->flags)); } @@ -770,7 +882,6 @@ static void OpAluwFlipTest(struct Machine *m, uint32_t rde) { static void Aluwi(struct Machine *m, uint32_t rde, aluop_f ops[4]) { uint8_t *a; - uint64_t x; a = GetModrmRegisterWordPointerWriteOszRexw(m, rde); WriteRegisterOrMemory( rde, a, @@ -1339,8 +1450,105 @@ static void OpDoubleShift(struct Machine *m, uint32_t rde) { m->xedd->op.opcode & 8, &m->flags)); } +static void OpFxsave(struct Machine *m, uint32_t rde) { + int64_t v; + uint8_t buf[32]; + memset(buf, 0, 32); + Write16(buf + 0, m->fpu.cw); + Write16(buf + 2, m->fpu.sw); + Write8(buf + 4, m->fpu.tw); + Write16(buf + 6, m->fpu.op); + Write32(buf + 8, m->fpu.ip); + Write32(buf + 24, m->sse.mxcsr); + v = ComputeAddress(m, rde); + VirtualRecv(m, v + 0, buf, 32); + VirtualRecv(m, v + 32, m->fpu.st, 128); + VirtualRecv(m, v + 160, m->xmm, 256); + SetWriteAddr(m, v, 416); +} + +static void OpFxrstor(struct Machine *m, uint32_t rde) { + int64_t v; + uint8_t buf[32]; + v = ComputeAddress(m, rde); + SetReadAddr(m, v, 416); + VirtualSend(m, buf, v + 0, 32); + VirtualSend(m, m->fpu.st, v + 32, 128); + VirtualSend(m, m->xmm, v + 160, 256); + m->fpu.cw = Read16(buf + 0); + m->fpu.sw = Read16(buf + 2); + m->fpu.tw = Read8(buf + 4); + m->fpu.op = Read16(buf + 6); + m->fpu.ip = Read32(buf + 8); + m->sse.mxcsr = Read32(buf + 24); +} + +static void OpXsave(struct Machine *m, uint32_t rde) { +} + +static void OpLdmxcsr(struct Machine *m, uint32_t rde) { + m->sse.mxcsr = Read32(ComputeReserveAddressRead4(m, rde)); +} + +static void OpStmxcsr(struct Machine *m, uint32_t rde) { + Write32(ComputeReserveAddressWrite4(m, rde), m->sse.mxcsr); +} + +static void OpRdfsbase(struct Machine *m, uint32_t rde) { + WriteRegister(rde, RegRexbRm(m, rde), Read64(m->fs)); +} + +static void OpRdgsbase(struct Machine *m, uint32_t rde) { + WriteRegister(rde, RegRexbRm(m, rde), Read64(m->gs)); +} + +static void OpWrfsbase(struct Machine *m, uint32_t rde) { + Write64(m->fs, ReadMemory(rde, RegRexbRm(m, rde))); +} + +static void OpWrgsbase(struct Machine *m, uint32_t rde) { + Write64(m->gs, ReadMemory(rde, RegRexbRm(m, rde))); +} + static void Op1ae(struct Machine *m, uint32_t rde) { + bool ismem; + ismem = !IsModrmRegister(rde); switch (ModrmReg(rde)) { + case 0: + if (ismem) { + OpFxsave(m, rde); + } else { + OpRdfsbase(m, rde); + } + break; + case 1: + if (ismem) { + OpFxrstor(m, rde); + } else { + OpRdgsbase(m, rde); + } + break; + case 2: + if (ismem) { + OpLdmxcsr(m, rde); + } else { + OpWrfsbase(m, rde); + } + break; + case 3: + if (ismem) { + OpStmxcsr(m, rde); + } else { + OpWrgsbase(m, rde); + } + break; + case 4: + if (ismem) { + OpXsave(m, rde); + } else { + OpUd(m, rde); + } + break; case 5: OpLfence(m, rde); break; @@ -1348,10 +1556,10 @@ static void Op1ae(struct Machine *m, uint32_t rde) { OpMfence(m, rde); break; case 7: - if (ModrmMod(rde) == 0b11 && ModrmReg(rde) == 0b111) { - OpSfence(m, rde); - } else { + if (ismem) { OpClflush(m, rde); + } else { + OpSfence(m, rde); } break; default: @@ -1363,11 +1571,32 @@ static void OpSalc(struct Machine *m, uint32_t rde) { Write8(m->ax, GetFlag(m->flags, FLAGS_CF)); } +static void OpBofram(struct Machine *m, uint32_t rde) { + if (m->xedd->op.disp) { + m->bofram[0] = m->ip; + m->bofram[1] = m->ip + (m->xedd->op.disp & 0xff); + } else { + m->bofram[0] = 0; + m->bofram[1] = 0; + } +} + +static void OpBinbase(struct Machine *m, uint32_t rde) { + if (m->onbinbase) { + m->onbinbase(m); + } +} + static void OpNopEv(struct Machine *m, uint32_t rde) { switch (ModrmMod(rde) << 6 | ModrmReg(rde) << 3 | ModrmRm(rde)) { - case 0x45: + case 0105: OpBofram(m, rde); break; + case 0007: + case 0107: + case 0207: + OpBinbase(m, rde); + break; default: OpNoop(m, rde); } @@ -1421,6 +1650,14 @@ static void OpMovCqRq(struct Machine *m, uint32_t rde) { } } +static void OpWrmsr(struct Machine *m, uint32_t rde) { +} + +static void OpRdmsr(struct Machine *m, uint32_t rde) { + Write32(m->dx, 0); + Write32(m->ax, 0); +} + static const nexgen32e_f kNexgen32e[] = { [0x000] = OpAlubAdd, [0x001] = OpAluw, @@ -1681,7 +1918,7 @@ static const nexgen32e_f kNexgen32e[] = { [0x100] = OpUd, [0x101] = Op101, [0x102] = OpUd, - [0x103] = OpUd, + [0x103] = OpLsl, [0x104] = OpUd, [0x105] = OpSyscall, [0x106] = OpUd, @@ -1708,7 +1945,7 @@ static const nexgen32e_f kNexgen32e[] = { [0x11B] = OpHintNopEv, [0x11C] = OpHintNopEv, [0x11D] = OpHintNopEv, - [0x11E] = OpUd, + [0x11E] = OpHintNopEv, [0x11F] = OpNopEv, [0x120] = OpMovRqCq, [0x121] = OpUd, @@ -1726,9 +1963,9 @@ static const nexgen32e_f kNexgen32e[] = { [0x12D] = OpCvt0f2d, [0x12E] = OpComissVsWs, [0x12F] = OpComissVsWs, - [0x130] = OpUd, + [0x130] = OpWrmsr, [0x131] = OpRdtsc, - [0x132] = OpUd, + [0x132] = OpRdmsr, [0x133] = OpUd, [0x134] = OpUd, [0x135] = OpUd, @@ -1877,7 +2114,7 @@ static const nexgen32e_f kNexgen32e[] = { [0x1C4] = OpPinsrwVdqEwIb, [0x1C5] = OpPextrwGdqpUdqIb, [0x1C6] = OpShufpsd, - [0x1C7] = OpCmpxchgDxAx, + [0x1C7] = Op1c7, [0x1C8] = OpBswapZvqp, [0x1C9] = OpBswapZvqp, [0x1CA] = OpBswapZvqp, diff --git a/tool/build/lib/machine.h b/tool/build/lib/machine.h index 0d43c4a2..8a6e9e54 100644 --- a/tool/build/lib/machine.h +++ b/tool/build/lib/machine.h @@ -3,7 +3,6 @@ #include "libc/runtime/runtime.h" #include "third_party/xed/x86.h" #include "tool/build/lib/fds.h" -#include "tool/build/lib/pml4t.h" #define kMachineHalt -1 #define kMachineDecodeError -2 @@ -134,6 +133,10 @@ struct Machine { uint64_t cr0; uint64_t cr2; uint64_t cr4; + uint64_t gdt_base; + uint64_t idt_base; + uint16_t gdt_limit; + uint16_t idt_limit; struct MachineRealFree { uint64_t i; uint64_t n; @@ -156,9 +159,12 @@ struct Machine { int64_t bofram[2]; jmp_buf onhalt; int64_t faultaddr; + bool dlab; struct MachineFds fds; uint8_t stash[4096]; uint8_t icache[1024][40]; + void (*onbinbase)(struct Machine *); + void (*onlongbranch)(struct Machine *); } aligned(64); struct Machine *NewMachine(void) nodiscard; @@ -166,6 +172,7 @@ void FreeMachine(struct Machine *); void ResetMem(struct Machine *); void ResetCpu(struct Machine *); void ResetTlb(struct Machine *); +void ResetInstructionCache(struct Machine *); void LoadInstruction(struct Machine *); void ExecuteInstruction(struct Machine *); long AllocateLinearPage(struct Machine *); diff --git a/tool/build/lib/memory.c b/tool/build/lib/memory.c index 409a09c6..5d13086d 100644 --- a/tool/build/lib/memory.c +++ b/tool/build/lib/memory.c @@ -143,10 +143,20 @@ void *VirtualSend(struct Machine *m, void *dst, int64_t src, uint64_t n) { return dst; } +void VirtualSendRead(struct Machine *m, void *dst, int64_t addr, uint64_t n) { + VirtualSend(m, dst, addr, n); + SetReadAddr(m, addr, n); +} + void VirtualRecv(struct Machine *m, int64_t dst, void *src, uint64_t n) { VirtualCopy(m, dst, src, n, false); } +void VirtualRecvWrite(struct Machine *m, int64_t addr, void *src, uint64_t n) { + VirtualRecv(m, addr, src, n); + SetWriteAddr(m, addr, n); +} + void *ReserveAddress(struct Machine *m, int64_t v, size_t n) { void *r; DCHECK_LE(n, sizeof(m->stash)); diff --git a/tool/build/lib/memory.h b/tool/build/lib/memory.h index c563095c..c0b21e45 100644 --- a/tool/build/lib/memory.h +++ b/tool/build/lib/memory.h @@ -25,6 +25,8 @@ void VirtualRecv(struct Machine *, int64_t, void *, uint64_t); void *VirtualSend(struct Machine *, void *, int64_t, uint64_t); void VirtualSet(struct Machine *, int64_t, char, uint64_t); void *RealAddress(struct Machine *, int64_t); +void VirtualSendRead(struct Machine *, void *, int64_t, uint64_t); +void VirtualRecvWrite(struct Machine *, int64_t, void *, uint64_t); COSMOPOLITAN_C_END_ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ diff --git a/tool/build/lib/op101.c b/tool/build/lib/op101.c index 30c13040..48732378 100644 --- a/tool/build/lib/op101.c +++ b/tool/build/lib/op101.c @@ -17,22 +17,79 @@ │ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │ │ 02110-1301 USA │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/log/log.h" #include "tool/build/lib/endian.h" +#include "tool/build/lib/memory.h" #include "tool/build/lib/modrm.h" #include "tool/build/lib/op101.h" #include "tool/build/lib/throw.h" #include "tool/build/lib/time.h" +static void StoreDescriptorTable(struct Machine *m, uint32_t rde, + uint16_t limit, uint64_t base) { + uint64_t l; + l = ComputeAddress(m, rde); + if (l + 10 <= m->real.n) { + Write16(m->real.p + l, limit); + if (Rexw(rde)) { + Write64(m->real.p + l + 2, base); + SetWriteAddr(m, l, 10); + } else if (!Osz(rde)) { + Write32(m->real.p + l + 2, base); + SetWriteAddr(m, l, 6); + } else { + Write16(m->real.p + l + 2, base); + SetWriteAddr(m, l, 4); + } + } else { + ThrowSegmentationFault(m, l); + } +} + +static void LoadDescriptorTable(struct Machine *m, uint32_t rde, + uint16_t *out_limit, uint64_t *out_base) { + uint16_t limit; + uint64_t l, base; + l = ComputeAddress(m, rde); + if (l + 10 <= m->real.n) { + limit = Read16(m->real.p + l); + if (Rexw(rde)) { + base = Read64(m->real.p + l + 2) & 0x00ffffff; + SetReadAddr(m, l, 10); + } else if (!Osz(rde)) { + base = Read32(m->real.p + l + 2); + SetReadAddr(m, l, 6); + } else { + base = Read16(m->real.p + l + 2); + SetReadAddr(m, l, 4); + } + if (base + limit <= m->real.n) { + *out_limit = limit; + *out_base = base; + } else { + ThrowProtectionFault(m); + } + } else { + ThrowSegmentationFault(m, l); + } +} + static void SgdtMs(struct Machine *m, uint32_t rde) { + StoreDescriptorTable(m, rde, m->gdt_limit, m->gdt_base); } static void LgdtMs(struct Machine *m, uint32_t rde) { + LoadDescriptorTable(m, rde, &m->gdt_limit, &m->gdt_base); + LOGF("set gdt %p lim %,d", m->gdt_base, m->gdt_limit); } static void SidtMs(struct Machine *m, uint32_t rde) { + StoreDescriptorTable(m, rde, m->idt_limit, m->idt_base); } static void LidtMs(struct Machine *m, uint32_t rde) { + LoadDescriptorTable(m, rde, &m->idt_limit, &m->idt_base); + LOGF("set idt %p lim %,d", m->idt_base, m->idt_limit); } static void Monitor(struct Machine *m, uint32_t rde) { diff --git a/tool/build/lib/pml4tfmt.c b/tool/build/lib/pml4tfmt.c index 3ea5dcf8..6c0a16f9 100644 --- a/tool/build/lib/pml4tfmt.c +++ b/tool/build/lib/pml4tfmt.c @@ -1,5 +1,5 @@ -/*-*- mode:c;indent-tabs-mode:nil;c-bansic-offset:2;tab-width:8;coding:utf-8 --*-│ │vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2020 Justine Alexandra Roberts Tunney │ │ │ diff --git a/tool/build/lib/reset.c b/tool/build/lib/reset.c index 65376a06..c0182284 100644 --- a/tool/build/lib/reset.c +++ b/tool/build/lib/reset.c @@ -62,6 +62,10 @@ static void ResetSse(struct Machine *m) { memset(m->xmm, 0, sizeof(m->xmm)); } +void ResetInstructionCache(struct Machine *m) { + memset(m->icache, -1, sizeof(m->icache)); +} + void ResetCpu(struct Machine *m) { m->faultaddr = 0; m->stashsize = 0; diff --git a/tool/build/lib/stack.c b/tool/build/lib/stack.c index db1a8e27..f36de347 100644 --- a/tool/build/lib/stack.c +++ b/tool/build/lib/stack.c @@ -186,16 +186,6 @@ void OpRet(struct Machine *m, uint32_t rde) { m->ip = Pop(m, rde, m->xedd->op.uimm0); } -void OpBofram(struct Machine *m, uint32_t rde) { - if (m->xedd->op.disp) { - m->bofram[0] = m->ip; - m->bofram[1] = m->ip + (m->xedd->op.disp & 0xff); - } else { - m->bofram[0] = 0; - m->bofram[1] = 0; - } -} - void OpPushEvq(struct Machine *m, uint32_t rde) { unsigned osz; osz = kStackOsz[m->xedd->op.osz][Mode(rde)]; @@ -303,9 +293,15 @@ relegated void OpCallf(struct Machine *m, uint32_t rde) { Push(m, rde, m->ip); Write64(m->cs, m->xedd->op.uimm0 << 4); m->ip = m->xedd->op.disp & (Osz(rde) ? 0xffff : 0xffffffff); + if (m->onlongbranch) { + m->onlongbranch(m); + } } relegated void OpRetf(struct Machine *m, uint32_t rde) { m->ip = Pop(m, rde, 0); Write64(m->cs, Pop(m, rde, m->xedd->op.uimm0) << 4); + if (m->onlongbranch) { + m->onlongbranch(m); + } } diff --git a/tool/build/lib/stack.h b/tool/build/lib/stack.h index b78d0907..76d94df4 100644 --- a/tool/build/lib/stack.h +++ b/tool/build/lib/stack.h @@ -11,7 +11,6 @@ void OpRet(struct Machine *, uint32_t); void OpRetf(struct Machine *, uint32_t); void OpLeave(struct Machine *, uint32_t); void OpCallEq(struct Machine *, uint32_t); -void OpBofram(struct Machine *, uint32_t); void OpPopEvq(struct Machine *, uint32_t); void OpPopZvq(struct Machine *, uint32_t); void OpPushZvq(struct Machine *, uint32_t); diff --git a/tool/build/lib/syscall.c b/tool/build/lib/syscall.c index 0d3624ec..7d7ea1c1 100644 --- a/tool/build/lib/syscall.c +++ b/tool/build/lib/syscall.c @@ -422,18 +422,6 @@ static const char *GetSimulated(void) { } } -static void VirtualSendRead(struct Machine *m, void *dst, int64_t addr, - uint64_t n) { - VirtualSend(m, dst, addr, n); - SetReadAddr(m, addr, n); -} - -static void VirtualRecvWrite(struct Machine *m, int64_t addr, void *src, - uint64_t n) { - VirtualRecv(m, addr, src, n); - SetWriteAddr(m, addr, n); -} - static int AppendIovsReal(struct Machine *m, struct Iovs *ib, int64_t addr, size_t size) { void *real; diff --git a/tool/build/lib/time.c b/tool/build/lib/time.c index 86e81cba..c0d7bd45 100644 --- a/tool/build/lib/time.c +++ b/tool/build/lib/time.c @@ -22,6 +22,7 @@ #include "libc/sysv/consts/clock.h" #include "libc/time/time.h" #include "tool/build/lib/endian.h" +#include "tool/build/lib/modrm.h" #include "tool/build/lib/time.h" /** @@ -41,11 +42,18 @@ void OpRdtsc(struct Machine *m, uint32_t rde) { Write64(m->dx, (c >> 040) & 0xffffffff); } -void OpRdtscp(struct Machine *m, uint32_t rde) { - uint32_t core, node, tscaux; - OpRdtsc(m, rde); +static int64_t GetTscAux(struct Machine *m) { + uint32_t core, node; core = 0; node = 0; - tscaux = (node & 0xfff) << 12 | (core & 0xfff); - Write64(m->cx, tscaux & 0xffffffff); + return (node & 0xfff) << 12 | (core & 0xfff); +} + +void OpRdtscp(struct Machine *m, uint32_t rde) { + OpRdtsc(m, rde); + Write64(m->cx, GetTscAux(m)); +} + +void OpRdpid(struct Machine *m, uint32_t rde) { + Write64(RegRexbRm(m, rde), GetTscAux(m)); } diff --git a/tool/build/lib/time.h b/tool/build/lib/time.h index 04662194..b745496f 100644 --- a/tool/build/lib/time.h +++ b/tool/build/lib/time.h @@ -7,6 +7,7 @@ COSMOPOLITAN_C_START_ void OpPause(struct Machine *, uint32_t); void OpRdtsc(struct Machine *, uint32_t); void OpRdtscp(struct Machine *, uint32_t); +void OpRdpid(struct Machine *, uint32_t); COSMOPOLITAN_C_END_ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ diff --git a/tool/emacs/cosmo-c-constants.el b/tool/emacs/cosmo-c-constants.el index 2da56d10..a31c0b3c 100644 --- a/tool/emacs/cosmo-c-constants.el +++ b/tool/emacs/cosmo-c-constants.el @@ -20,6 +20,8 @@ (defconst cosmo-c-constants-limits '("IMAGE_BASE_VIRTUAL" + "IMAGE_BASE_REAL" + "IMAGE_BASE_PHYSICAL" "SIZEOF_SHORT" "SIZEOF_INT" "SIZEOF_LONG"