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.main
parent
feed0d2b0e
commit
2d80bbc802
341
ape/ape.S
341
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
|
||||
|
|
|
@ -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
|
||||
|
||||
/**
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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)
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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__
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -140,6 +140,7 @@ static const char *__asan_describe_access_poison(int c) {
|
|||
case kAsanUnscoped:
|
||||
return "unscoped";
|
||||
default:
|
||||
DebugBreak();
|
||||
return "poisoned";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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; \
|
||||
|
|
|
@ -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_
|
||||
|
||||
|
@ -64,6 +29,7 @@
|
|||
#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 */
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -19,40 +19,34 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#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) {
|
||||
if (cmdline != NULL) {
|
||||
int pid = fork$sysv();
|
||||
if (pid == 0) {
|
||||
int rc, n, wstatus;
|
||||
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));
|
||||
} * mem;
|
||||
if (cmdline != NULL) {
|
||||
mem = malloc(sizeof(struct mem) + (strlen(cmdline) + 1));
|
||||
if (!mem) return enomem();
|
||||
strcpy(mem->shell, SHELL_BIN);
|
||||
strcpy(mem->arg, SHELL_ARG);
|
||||
|
@ -61,12 +55,16 @@ static int system$sysv(const char *cmdline) {
|
|||
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();
|
||||
}
|
||||
int rc;
|
||||
int wstatus;
|
||||
if ((rc = wait4$sysv(pid, &wstatus, 0, NULL)) != -1) rc = wstatus;
|
||||
if ((rc = wait4$sysv(rc, &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) +
|
||||
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? */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -32,6 +32,7 @@ THIRD_PARTY_DUKTAPE_A_DIRECTDEPS = \
|
|||
LIBC_FMT \
|
||||
LIBC_TIME \
|
||||
LIBC_MEM \
|
||||
LIBC_STR \
|
||||
LIBC_TINYMATH \
|
||||
LIBC_UNICODE \
|
||||
LIBC_NEXGEN32E
|
||||
|
|
|
@ -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",
|
||||
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 < pan.displayhr.right - pan.displayhr.left; ++i) {
|
||||
AppendWide(&pan.displayhr.lines[0], u'─');
|
||||
(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);
|
||||
|
|
|
@ -34,6 +34,7 @@ TOOL_BUILD_DIRECTDEPS = \
|
|||
LIBC_DNS \
|
||||
LIBC_ELF \
|
||||
LIBC_FMT \
|
||||
LIBC_INTRIN \
|
||||
LIBC_LOG \
|
||||
LIBC_LOG_ASAN \
|
||||
LIBC_TINYMATH \
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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 *, ...);
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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:
|
||||
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:
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) {
|
||||
switch (ModrmReg(x->op.rde)) {
|
||||
case 0:
|
||||
if (!isreg) {
|
||||
return "sgdt Ms";
|
||||
} else if (!IsModrmRegister(x->op.rde) && ModrmReg(x->op.rde) == 2) {
|
||||
} 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;
|
||||
}
|
||||
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,11 +791,39 @@ const char *DisSpecMap1(struct XedDecodedInst *x, char *p) {
|
|||
}
|
||||
break;
|
||||
case 0xC7:
|
||||
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:
|
||||
if (Osz(x->op.rde)) {
|
||||
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) {
|
||||
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,12 +448,50 @@ static void OpCmpxchg16b(struct Machine *m, uint32_t rde) {
|
|||
}
|
||||
}
|
||||
|
||||
static void OpCmpxchgDxAx(struct Machine *m, uint32_t 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);
|
||||
}
|
||||
}
|
||||
|
||||
static void OpXaddEbGb(struct Machine *m, uint32_t 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,
|
||||
|
|
|
@ -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 *);
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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) */
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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 │
|
||||
│ │
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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) */
|
||||
|
|
|
@ -20,6 +20,8 @@
|
|||
|
||||
(defconst cosmo-c-constants-limits
|
||||
'("IMAGE_BASE_VIRTUAL"
|
||||
"IMAGE_BASE_REAL"
|
||||
"IMAGE_BASE_PHYSICAL"
|
||||
"SIZEOF_SHORT"
|
||||
"SIZEOF_INT"
|
||||
"SIZEOF_LONG"
|
||||
|
|
Loading…
Reference in New Issue