Support malloc() on bare metal

Your Actually Portable Executables now contains a simple virtual memory
that works similarly to the Linux Kernel in the sense that it maps your
physical memory to negative addresses. This is needed to support mmap()
and malloc(). This functionality has zero code size impact. For example
the MODE=tiny LIFE.COM executable is still only 12KB in size.

The APE bootloader code has also been simplified to improve readibility
and further elevate the elegance by which we're able to support so many
platforms thereby enhancing verifiability so that we may engender trust
in this bootloading process.
This commit is contained in:
Justine Tunney 2021-02-23 20:23:19 -08:00
parent ac3b1dfb21
commit edd9297eba
89 changed files with 900 additions and 1417 deletions

View file

@ -101,7 +101,6 @@ include libc/str/str.mk # │
include third_party/xed/xed.mk # │
include third_party/zlib/zlib.mk # │
include libc/elf/elf.mk # │
include ape/lib/apelib.mk # │
include ape/ape.mk # │
include libc/fmt/fmt.mk #─┘
include libc/calls/calls.mk #─┐
@ -173,8 +172,6 @@ include test/libc/time/test.mk
include test/libc/stdio/test.mk
include test/libc/release/test.mk
include test/libc/test.mk
include test/ape/lib/test.mk
include test/ape/test.mk
include test/net/http/test.mk
include test/net/test.mk
include test/tool/build/lib/test.mk
@ -244,7 +241,6 @@ COSMOPOLITAN_OBJECTS = \
LIBC_TIME \
LIBC_ZIPOS \
THIRD_PARTY_ZLIB \
APE_LIB \
THIRD_PARTY_MUSL \
LIBC_STDIO \
THIRD_PARTY_REGEX \

535
ape/ape.S
View file

@ -32,17 +32,16 @@
αcτµαlly pδrταblε εxεcµταblε § program header
*/
#include "ape/config.h"
#include "ape/lib/pc.h"
#include "ape/macros.internal.h"
#include "ape/notice.inc"
#include "ape/relocations.h"
#include "libc/dce.h"
#include "libc/elf/def.h"
#include "libc/macho.internal.h"
#include "libc/nexgen32e/uart.internal.h"
#include "libc/nexgen32e/vidya.internal.h"
#include "libc/nt/pedef.internal.h"
#include "libc/dce.h"
#include "libc/runtime/pc.internal.h"
#include "libc/sysv/consts/prot.h"
#define USE_SYMBOL_HACK 0
@ -62,9 +61,6 @@ __ro: .endobj __ro,globl,hidden # ←for gdb readibility
.previous
.section .rodata.str1.1,"a",@progbits
cstr: .endobj cstr,globl,hidden # for gdb readibility
.previous
.section .sort.rodata.real.str1.1,"a",@progbits
rlstr: .endobj rlstr,globl,hidden # for gdb readibility
.previous
.section .head,"ax",@progbits
@ -105,7 +101,7 @@ rlstr: .endobj rlstr,globl,hidden # ←for gdb readibility
αcτµαlly pδrταblε εxεcµταblε § the old technology
*/
#if SupportsWindows() || SupportsUefi() || SupportsXnu()
#if SupportsWindows() || SupportsMetal() || SupportsXnu()
// MZ Literally Executable Header
//
@ -131,14 +127,14 @@ ape_mz: .asciz "MZqFpD='\n" # Mark 'Zibo' Joseph Zbikowski
.ascii "JT" # MZ: OEM identifier
.short 0 # MZ: OEM information
.org 0x40-4 # MZ: bytes reserved for you
#if SupportsWindows() || SupportsUefi()
#if SupportsWindows() || SupportsMetal()
.long RVA(ape_pe) # PE: the new technology
#else
.long 0
#endif
.endfn ape_mz,globl,hidden
#else /* !(SupportsWindows() || SupportsUefi() || SupportsXnu()) */
#else /* !(SupportsWindows() || SupportsMetal() || SupportsXnu()) */
// ELF Literally Executable Header
//
@ -168,7 +164,7 @@ ape_mz: .asciz "MZqFpD='\n" # Mark 'Zibo' Joseph Zbikowski
.short ape_elf_shnum # 3c: e_shnum
.short ape_elf_shstrndx # 3e: e_shstrndx
#endif /* SupportsWindows() || SupportsUefi() || SupportsXnu() */
#endif /* SupportsWindows() || SupportsMetal() || SupportsXnu() */
#if SupportsMetal()
@ -218,17 +214,17 @@ pc: cld
.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
mov $0x70000>>4,%di # we need a stack
xor %cx,%cx # 0x7f000-0x80000
mov %cx,%es
rlstack %di,%cx
push %cs # memcpy() [relocate this page]
pop %ds
call 1f
1: pop %si
push %cs # determine load address
pop %ds # and relocate this code
call 1f # to a way lower address
1: pop %si # and we'll make cs zero
sub $RVA(1b),%si
mov $IMAGE_BASE_REAL>>4,%ax
push %ax # save real base
push %ax # save IMAGE_BASE_REAL>>4
push %ax
pop %es
xor %di,%di
@ -238,18 +234,18 @@ pc: cld
.byte 0x0f,0x1f,0207 # nop rdi binbase
.short (IMAGE_BASE_REAL-0x7c00)/512
#endif
ljmp $0,$REAL(1f) # longjmp()
1: mov %cx,%ds # %ds and %cs are now zero
mov $XLM_SIZE,%cx # memset to clear real bss
mov $XLM_BASE_REAL>>4,%ax
ljmp $0,$REAL(1f)
1: mov %cx,%ds
mov $IMAGE_BASE_REAL-0x0500,%cx # clears bss
mov $0x0500>>4,%ax # struct mman
mov %ax,%es
xor %ax,%ax
xor %di,%di
rep stosb
cmp $0x40,%dl # statfs() [disk geometry]
cmp $0x40,%dl
je 6f
call dsknfo
pop %es # restore real base
pop %es # restore IMAGE_BASE_REAL>>4
mov $1,%al # current sector
xor %cx,%cx # current cylinder
xor %dh,%dh # current head
@ -257,15 +253,7 @@ pc: cld
3: call pcread
dec %di
jnz 3b
6: mov $XLM(LOADSTATE),%di # ax,cx,dx,es
stosw
xchg %cx,%ax
stosw
xchg %dx,%ax
stosw
mov %es,%ax
stosw
ljmp $0,$REAL(realmodeloader)
6: ljmp $0,$REAL(realmodeloader)
.endfn pc
// Determines disk geometry.
@ -326,7 +314,7 @@ dsknfo: push %bx
movpp %es,%ds
xor %si,%si
mov %si,%es
mov $XLM(DRIVE_BASE_TABLE),%si
mov $0x1510,%si # mman::pc_drive_base_table
xchg %si,%di
movsw # headunloadtime, headloadtime
movsw # shutofftime, bytespersector
@ -379,11 +367,11 @@ pcread: push %ax
add $512>>4,%si
mov %si,%es
inc %al # ++sector
cmp XLM(DRIVE_LAST_SECTOR),%al
cmp 0x151c,%al # mman::pc_drive_last_sector
jbe 2f
mov $1,%al
inc %dh # ++head
cmp XLM(DRIVE_LAST_HEAD),%dh
cmp 0x1520,%dh # mman::pc_drive_last_head
jbe 2f
xor %dh,%dh
inc %cx # ++cylinder
@ -395,6 +383,82 @@ pcread: push %ax
jmp pcread
.endfn pcread
// Video put string.
//
// @param di is the string
// @clob bp,bx
// @mode real
rvputs: mov %di,%si
0: lodsb
test %al,%al
je 1f
mov $7,%bx # normal mda/cga style page zero
mov $0x0e,%ah # teletype output al cp437
int $0x10 # vidya service
jmp 0b
1: ret
.endfn rvputs
// Abnormally halts startup.
//
// @param di message
// @mode real
// @noreturn
rldie: push %di
mov $REAL(str.error),%di
call rvputs
pop %di
call rvputs
mov $REAL(str.crlf),%di
call rvputs
0: rep nop
jmp 0b
.endfn rldie
// Initializes present PC serial lines.
sinit4: mov $4,%cx
mov $0x400,%si # BDA.COM1
0: lodsw
test %ax,%ax
jz 1f
push %cx
push %si
xchg %ax,%di
mov $REAL(sconf),%si
call sinit
pop %si
pop %cx
1: loop 0b
ret
.endfn sinit4,global,hidden
// Initializes Serial Line Communications 8250 UART 16550A
//
// @param word di tty port
// @param char (*{es:,e,r}si)[4] register initial values
// @mode long,legacy,real
// @see www.lammertbies.nl/comm/info/serial-uart.html
sinit: mov %di,%dx
test %dx,%dx
jz 2f
push %dx
push %si
xor %cx,%cx
mov $UART_LCR,%cl
add %cx,%dx
lodsb %ds:(%si),%al
pop %si
or $UART_DLAB,%al
out %al,%dx
pop %dx
1: lodsb %ds:(%si),%al
out %al,%dx
inc %dx
dec %cx
jns 1b
2: ret
.endfn sinit,global,hidden
/*
αcτµαlly pδrταblε εxεcµταblε § partition table
*/
@ -469,9 +533,7 @@ ape_disk:
the bourne executable & linkable format */
#if SupportsSystemv()
#if SupportsWindows() || SupportsUefi() || SupportsXnu()
#if SupportsWindows() || SupportsMetal() || SupportsXnu()
apesh: .ascii "'\n#'\"\n" # sixth edition shebang
.ascii "o=\"$(command -v \"$0\")\"\n"
#if SupportsXnu()
@ -526,10 +588,11 @@ apesh: .ascii "'\n#'\"\n" # sixth edition shebang
.ascii "fi\n"
.ascii "exit $R\n"
.endobj apesh
#endif /* SupportsWindows() || SupportsUefi() || SupportsXnu() */
#endif /* SupportsWindows() || SupportsMetal() || SupportsXnu() */
#if SupportsSystemv() || SupportsMetal()
.section .elf.phdrs,"a",@progbits
.long PT_LOAD # text segment
.long PT_LOAD
.long PF_R|PF_X
.stub ape_rom_offset,quad
.stub ape_rom_vaddr,quad
@ -537,7 +600,7 @@ apesh: .ascii "'\n#'\"\n" # sixth edition shebang
.stub ape_rom_filesz,quad
.stub ape_rom_memsz,quad
.stub ape_rom_align,quad
.long PT_LOAD # data segment
.long PT_LOAD
.long PF_R|PF_W
.stub ape_ram_offset,quad
.stub ape_ram_vaddr,quad
@ -545,20 +608,16 @@ apesh: .ascii "'\n#'\"\n" # sixth edition shebang
.stub ape_ram_filesz,quad
.stub ape_ram_memsz,quad
.stub ape_ram_align,quad
#if SupportsLinux()
// Linux ignores mprotect() and returns 0 without this lool
// It has nothing to do with the stack, which is still exec
.long PT_GNU_STACK # p_type
.long PF_R|PF_W # p_flags
.quad 0 # p_offset
.quad 0 # p_vaddr
.quad 0 # p_paddr
.quad 0 # p_filesz
.quad 0 # p_memsz
.quad 16 # p_align
#endif
.long PT_GNU_STACK
.long PF_R|PF_W
.stub ape_stack_offset,quad
.stub ape_stack_vaddr,quad
.stub ape_stack_paddr,quad
.stub ape_stack_filesz,quad
.stub ape_stack_memsz,quad
.stub ape_stack_align,quad
#if SupportsOpenbsd() || SupportsNetbsd()
.long PT_NOTE # notes
.long PT_NOTE
.long PF_R
.stub ape_note_offset,quad
.stub ape_note_vaddr,quad
@ -568,6 +627,7 @@ apesh: .ascii "'\n#'\"\n" # sixth edition shebang
.stub ape_note_align,quad
#endif
.previous
#endif /* SupportsSystemv() || SupportsMetal() */
#if SupportsOpenbsd()
.section .note.openbsd.ident,"a",@progbits
@ -597,8 +657,6 @@ netbsd.ident:
.previous
#endif /* SupportsNetbsd() */
#endif /* SupportsSystemv() */
/*
@ -812,7 +870,7 @@ PETEXT = 0b01110000000000000000000001100000
PEDATA = 0b11000000000000000000000011000000
PEIMPS = 0b11000000000000000000000001000000
#if SupportsWindows() || SupportsUefi()
#if SupportsWindows() || SupportsMetal()
.section .pe.header,"a",@progbits
.align __SIZEOF_POINTER__
@ -832,7 +890,7 @@ ape_pe: .ascin "PE",4
.long 0 # SizeOfUninitializedData
.long RVA(ape_pe_entry) # EntryPoint
.long 0 # BaseOfCode
.quad IMAGE_BASE_VIRTUAL # ImageBase
.quad ape_pe_base # ImageBase
.long 4096 # SectionAlignment
.long 4096 # FileAlignment
.short v_ntversion # MajorOperatingSystemVersion
@ -846,11 +904,7 @@ ape_pe: .ascin "PE",4
.long RVA(_ehead) # SizeOfHeaders
.long 0 # Checksum
.short v_ntsubsystem # Subsystem: 0=Neutral,2=GUI,3=Console
#if SupportsWindows()
.short DLLEXE # DllCharacteristics
#else
.short 0 # DllCharacteristics
#endif
.stub v_ntdllchar,short # DllCharacteristics
.quad 0x0000000000100000 # StackReserve
.quad 0x00000000000fc000 # StackCommit
.quad 0 # HeapReserve
@ -858,12 +912,8 @@ ape_pe: .ascin "PE",4
.long 0 # LoaderFlags
.long 16 # NumberOfDirectoryEntries
.long 0,0 # ExportsDirectory
#if SupportsWindows()
.long RVA(ape_idata_idt) # ImportsDirectory
.stub ape_idata,long # ImportsDirectory
.stub ape_idata_idtsize,long # ImportsDirectorySize
#else
.long 0,0 # ImportsDirectory
#endif
.long 0,0 # ResourcesDirectory
.long 0,0 # ExceptionsDirectory
.long 0,0 # SecurityDirectory
@ -874,12 +924,8 @@ ape_pe: .ascin "PE",4
.long 0,0 # ThreadLocalStorage
.long 0,0 # LoadConfigurationDirectory
.long 0,0 # BoundImportDirectory
#if SupportsWindows()
.long RVA(ape_idata_iat) # ImportAddressDirectory
.stub ape_idata,long # ImportAddressDirectory
.stub ape_idata_iatsize,long # ImportAddressDirectorySize
#else
.long 0,0 # ImportAddressDirectory
#endif
.long 0,0 # DelayImportDescriptor
.long 0,0 # ComPlusRuntimeHeader
.long 0,0 # Reserved
@ -896,7 +942,7 @@ ape_pe: .ascin "PE",4
.long 0 # Line Number Table Offset
.short 0 # Relocation Count
.short 0 # Line Number Count
.long PETEXT # Flags
.long PETEXT # Flags
.previous
.section .pe.sections,"a",@progbits
@ -909,10 +955,10 @@ ape_pe: .ascin "PE",4
.long 0 # Line Number Table Offset
.short 0 # Relocation Count
.short 0 # Line Number Count
.long PEDATA # Flags
.long PEDATA # Flags
.previous
#endif /* SupportsWindows() || SupportsUefi() */
#endif /* SupportsWindows() || SupportsMetal() */
.section .idata.ro.idt.1,"a",@progbits
.type ape_idata_idtend,@object
@ -950,13 +996,6 @@ ape_idata_iatend:
better code/data separation (.head is rwx[real] rx[long]) */
// NUL-Terminated Strings.
ape.str:
str.ape:
.byte 0xe0,0x63,0xe7,0xe6,0xe0,0x6c,0x6c,0x79 #αcτµαlly
.byte 0x20,0x70,0xeb,0x72,0xe7,0xe0,0x62,0x6c # pδrταbl
.byte 0xee,0x20,0xee,0x78,0xee,0x63,0xe6,0xe7 #ε εxεcµτ
.byte 0xe0,0x62,0x6c,0xee,0x0d,0x0a,0x00 #αblε.
.endobj str.ape
str.error:
.asciz "error: "
.endobj str.error
@ -969,19 +1008,12 @@ str.cpuid:
str.oldskool:
.asciz "oldskool"
.endobj str.oldskool
str.dsknfo:
.asciz "dsknfo"
.endobj str.dsknfo
str.e820:
.asciz "e820"
.endobj str.e820
str.memory:
.asciz "nomem"
.endobj str.memory
str.long:
.asciz "nolong"
.endobj str.long
.endobj ape.str
// Serial Line Configuration (8250 UART 16550)
// If it's hacked, it'll at least get hacked very slowly.
@ -1071,8 +1103,8 @@ ape_grub:
.align 4
ape_grub_entry:
.code32
cmp $GRUB_EAX,%eax
jne triplf
/ cmp $GRUB_EAX,%eax
/ jne triplf
push $0
popf
mov $0x40,%dl
@ -1088,18 +1120,12 @@ ape_grub_entry:
the default mode of operation on modern cpus */
nop
nop
nop
nop
realmodeloader:
call16 rlinit
call16 sinit4
mov $REAL(str.ape),%di
call16 rvputs
call rlinit
call sinit4
.optfn _start16
call16 _start16
call16 longmodeloader
call _start16
call longmodeloader
.endfn realmodeloader
.section .sort.text.real.init.1,"ax",@progbits
@ -1112,86 +1138,6 @@ rlinit: .previous/*
ret
.previous
// Initializes present PC serial lines.
sinit4: mov $4,%cx
mov $kBiosDataAreaXlm+COM1,%si
0: lodsw
test %ax,%ax
jz 1f
push %cx
push %si
xchg %ax,%di
mov $REAL(sconf),%si
call16 sinit
pop %si
pop %cx
1: loop 0b
ret
.endfn sinit4,global,hidden
// Initializes Serial Line Communications 8250 UART 16550A
//
// @param word di tty port
// @param char (*{es:,e,r}si)[4] register initial values
// @mode long,legacy,real
// @see www.lammertbies.nl/comm/info/serial-uart.html
sinit: mov %di,%dx
test %dx,%dx
jz 2f
push %dx
push %si
xorw %cx,%cx
mov $UART_LCR,%cl
add %cx,%dx
lodsb %ds:(%si),%al
pop %si
or $UART_DLAB,%al
out %al,%dx
pop %dx
1: lodsb %ds:(%si),%al
out %al,%dx
add $1,%dx
sub $1,%cx
jns 1b
2: ret
.endfn sinit,global,hidden
// Video put string.
//
// @param di is the string
// @mode real
rvputs: push %bp
push %bx
mov %di,%si
0: lodsb
test %al,%al
je 1f
mov $7,%bx # normal mda/cga style page zero
mov $0x0e,%ah # teletype output al cp437
int $0x10 # vidya service
jmp 0b
1: pop %bx
pop %bp
ret
.endfn rvputs
// Abnormally halts startup.
//
// @param di message
// @mode real
// @noreturn
rldie: push %di
mov $REAL(str.error),%di
call16 rvputs
pop %di
call16 rvputs
mov $REAL(str.crlf),%di
call16 rvputs
xor %ax,%ax # get keystroke
int $0x16 # keyboard service
call16 triplf
.endfn rldie
/*
@ -1239,18 +1185,11 @@ rldie: push %di
long mode is long */
longmodeloader:
call16 lcheck
call16 a20
mov $XLM(E820),%di
mov $XLM_E820_SIZE,%si
call16 e820
jc 9f
call16 unreal
// call hiload
call16 pinit
call16 golong
9: mov $REAL(str.e820),%ax
call16 rldie
call lcheck
call a20
call e820
call pinit
call golong
.endfn longmodeloader
// Long Mode Hardware Check
@ -1286,35 +1225,25 @@ lcheck: pushf # check for i8086 / i8088 / i80186
jne 10f
xor %ax,%ax
1: ret
9: mov $REAL(str.oldskool),%ax
9: mov $REAL(str.oldskool),%di
jmp 20f
10: mov $REAL(str.long),%ax
10: mov $REAL(str.long),%di
jmp 20f
12: mov $REAL(str.cpuid),%ax
jmp 20f
20: call16 rldie
12: mov $REAL(str.cpuid),%di
20: call rldie
.endfn lcheck
// Gets memory map from BIOS.
//
// @param di paragraph aligned buffer
// @param si bytes in buffer to fill
// @return number of bytes written or CF on error
// @mode real
e820: push %bp
mov %sp,%bp
pushl $'S'<<24|'M'<<16|'A'<<8|'P' # magic @ -4(%bp)
push %bx
shr $4,%di
e820: mov $0x0510>>4,%di # mman::e820
mov %di,%es
xor %edi,%edi # es:di is destination buffer
xor %ebx,%ebx # ebx is an api state tracker
1: mov $0xE820,%eax # magic
mov $8+8+4+4,%ecx # sizeof(struct SmapEntry)
mov -4(%bp),%edx # magic
mov $0x534d4150,%edx # magic number
int $0x15 # ax,bx,cx,dx,di ax,bx,cx
jc 9f # cf = unsupported or abuse
cmp -4(%bp),%eax # more magic means success
cmp %edx,%eax # more magic means success
jne 9f
test %cx,%cx # discard empty results
jz 5f
@ -1324,78 +1253,14 @@ e820: push %bp
jnz 5f
4: add $8+8+4+4,%di # keep entry
5: test %ebx,%ebx # last entry?
jz 7f
cmp %si,%di # out of buf?
jz 8f
cmp $0x1000,%di
jb 1b
7: mov %di,%ax
8: pop %bx
leave
ret
9: stc
jmp 8b
8: ret
9: mov $REAL(str.e820),%di
call rldie
.endfn e820
// Unreal Mode.
// Makes 4gb of real memory accessible via %fs segment.
unreal: cli
lgdt REAL(gdt)
mov %cr0,%eax
or $CR0_PE,%al
mov %eax,%cr0
jmp 1f
1: mov $GDT_LEGACY_DATA,%cx
mov %cx,%fs
and $~CR0_PE,%al
mov %eax,%cr0
ljmp $0,$REAL(1f)
1: sti
ret
.endfn unreal
// Loads remainder of executable off disk.
hiload: push %bx
mov $IMAGE_BASE_REAL,%esi # relocate, again
mov $IMAGE_BASE_PHYSICAL,%ebx
mov $v_ape_realsectors,%ecx
shl $9,%ecx
or $-4,%edx
0: add $4,%edx
cmp %edx,%ecx
je 1f
mov %fs:(%esi,%edx),%eax
mov %eax,%fs:(%ebx,%edx)
jmp 0b
1: lea (%ebx,%edx),%ebx
mov $v_ape_highsectors,%di # then copy rest off disk
mov $REAL_SCRATCH_AREA>>4,%ax # to real memory buffer
mov %ax,%es
mov XLM(LOADSTATE)+0,%ax
mov XLM(LOADSTATE)+2,%cx
mov XLM(LOADSTATE)+4,%dx
0: test %di,%di
jz 9f
mov %di,%ax
push %bx
xor %bx,%bx
call16 pcread
pop %bx
sub %ax,%di
push %cx
mov %ax,%cx # copy real buffer to high
shl $9,%cx # no way bios loaded >64k
xor %si,%si
1: mov %es:(%si),%eax
mov %eax,%fs:(%ebx)
add $4,%ebx
add $4,%si
sub $4,%cx
jnz 1b
pop %cx
jmp 0b
9: pop %bx
ret
.endfn hiload
// Asks keyboard to grant system 65,519 more bytes of memory.
//
// Yup.
@ -1426,26 +1291,26 @@ a20: cli
pop %ds
jne 3f
mov $1,%ax
call16 1f
call 1f
mov $0xad,%al
out %al,$0x64
call16 1f
call 1f
mov $0xd0,%al
out %al,$0x64
call16 2f
call 2f
in $0x60,%al
push %ax
call16 1f
call 1f
mov $0xd1,%al
out %al,$0x64
call16 1f
call 1f
pop %ax
or $2,%al
out %al,$0x60
call16 1f
call 1f
mov $0xae,%al
out %al,$0x64
call16 1f
call 1f
jmp a20
1: in $0x64,%al
test $2,%al
@ -1460,33 +1325,26 @@ a20: cli
.endfn a20
// Initializes long mode paging.
//
// Modern computers access memory via four levels of indirection:
//
// register char (*(*(*(*ram)[512])[512])[512])[4096] asm(cr3)
//
// Your page tables grow down in memory, starting from the real
// stack segment base. This function only defines enough tables
// to get us started.
#define TIP REAL_STACK_FRAME
pinit: push %ds
mov $(TIP-0x4000)>>4,%ax
#define SEG 0x79000
mov $SEG>>4,%ax
mov %ax,%ds
movl $TIP-0x2000+PAGE_V+PAGE_RW,0x3000 # PML4TPDPT
movl $TIP-0x3000+PAGE_V+PAGE_RW,0x2000 # PDPTPDT
movl $TIP-0x4000+PAGE_V+PAGE_RW,0x1000 # PDTPD
mov $0x100000/0x1000,%cx # PD512kb
movl $0x7d000+PAGE_V+PAGE_RW,0x7e000-SEG # PDPTPML4T (+)
movl $0x7c000+PAGE_V+PAGE_RW,0x7e800-SEG # PDPTPML4T (-)
movl $0x7b000+PAGE_V+PAGE_RW,0x7d000-SEG # PDTPDPT (+)
movl $0x7a000+PAGE_V+PAGE_RW,0x7c000-SEG # PDTPDPT (-)
movl $0x79000+PAGE_V+PAGE_RW,0x7b000-SEG # PDPDT (+)
movl $0x79000+PAGE_V+PAGE_RW,0x7a000-SEG # PDPDT (-)
mov $512,%cx # PD±2MB
mov $PAGE_V+PAGE_RW,%eax
xor %si,%si
0: mov %eax,(%si)
add $0x1000,%eax
add $8,%si
loop 0b
movb $0,0 # unmap null
pop %ds
movl $TIP-0x4000,XLM(PAGE_TABLE_STACK_POINTER) # STACKXLM
mov $TIP-0x1000,%eax # PML4TCR3
mov $0x7e000,%eax # PML4TCR3
mov %eax,%cr3
pop %ds
ret
.endfn pinit
@ -1494,7 +1352,7 @@ pinit: push %ds
//
// @see Intel Manual V3A §4.1.2
golong: cli
lidt XLM(BADIDT)
lidt 0x1522 # mman::bad_idt
mov %cr4,%eax
or $CR4_PAE|CR4_PGE|CR4_OSFXSR,%eax
mov %eax,%cr4
@ -1511,7 +1369,6 @@ golong: cli
.endfn golong
// Long mode is long.
// @noreturn
.code64
long: push $GDT_LONG_DATA
pop %rax
@ -1520,39 +1377,59 @@ long: push $GDT_LONG_DATA
mov %eax,%es
mov %eax,%fs
mov %eax,%gs
mov $0x80000,%esp
xor %r12d,%r12d
xor %r13d,%r13d
xor %r14d,%r14d
xor %r15d,%r15d
xor %ebx,%ebx
xor %ebp,%ebp
mov $REAL_STACK_FRAME+FRAMESIZE,%esp
call __map_image
ezlea metal.thunk,ax
push %rbp
mov $0x0500,%rdi # mman
mov %cr3,%rsi
mov $IMAGE_BASE_REAL,%edx
call __map_phdrs
push $0x037f
fldcw (%rsp)
movabs $1f,%rax
jmp *%rax
.endfn long
// Long mode in virtual address space.
// @noreturn
metal.thunk:
1: movabs $ape_stack_vaddr,%rsp
add $ape_stack_memsz,%rsp
#if USE_SYMBOL_HACK
.byte 0x0f,0x1f,0207 # nop rdi binbase
.long (IMAGE_BASE_VIRTUAL-IMAGE_BASE_REAL)/512
#endif
// 𝑠𝑙𝑖𝑑𝑒
.endfn metal.thunk
metal: xor %eax,%eax # clear bss
mov $ape_bss_vaddr,%edi
mov $ape_bss_memsz,%ecx
rep stosb
0: .weak __hostos
movl $0,0x7b000 # unmap null 2mb
.weak __hostos
ezlea __hostos,ax
test %rax,%rax
jz 1f
movb $METAL,(%rax)
1: push $0 # auxv[0][1]
push $0 # auxv[0][0]
push $0 # envp[0]
push $0 # argv[0]
push $0 # argc
xor %edi,%edi # not freebsd
1: xor %eax,%eax
xor %ecx,%ecx
xor %edx,%edx
xor %edi,%edi
xor %esi,%esi
xor %r8d,%r8d
xor %r9d,%r9d
xor %r10d,%r10d
xor %r11d,%r11d
push $0 # auxv[1][1]
push $0 # auxv[1][0]
push $.Larg0 # auxv[0][1]
push $31 # auxv[0][0] AT_EXECFN
push $0 # envp[1]
push $.Lenv0 # envp[0]
push $0 # argv[1]
push $.Larg0 # argv[0]
push $1 # argc
jmp _start
.endfn metal
.endfn long
.rodata.str1.1
.Larg0: .asciz "ape.com"
.Lenv0: .asciz "METAL=1"
.previous
#endif /* SupportsMetal() */

View file

@ -175,7 +175,7 @@
#ifdef __LINKER__
#include "ape/macros.internal.h"
#include "ape/config.h"
#include "ape/relocations.h"
#include "libc/dce.h"
#include "libc/nt/pedef.internal.h"
#include "libc/zip.h"
@ -196,11 +196,12 @@ SECTIONS {
/*BEGIN: linux addressability guarantee */
/*BEGIN: bsd addressability guarantee */
.head SEGMENT_START("text-segment", IMAGE_BASE_VIRTUAL) : {
.head SEGMENT_START("text-segment", IMAGE_BASE_VIRTUAL) : AT(IMAGE_BASE_REAL) {
HIDDEN(_base = .);
/* Real Mode */
KEEP(*(.head))
KEEP(*(.text.head))
/* Executable & Linkable Format */
. = ALIGN(__SIZEOF_POINTER__);
@ -220,16 +221,14 @@ SECTIONS {
HIDDEN(ape_pe_sections = .);
KEEP(*(.pe.sections))
HIDDEN(ape_pe_sections_end = .);
. += 1;
/* Mach-O */
KEEP(*(.macho))
. = ALIGN(__SIZEOF_POINTER__);
HIDDEN(ape_macho_end = .);
. += 1;
KEEP(*(.ape.pad.head))
. = ALIGN(SupportsWindows() || SupportsUefi() ? PAGESIZE : 16);
. = ALIGN(SupportsWindows() || SupportsMetal() ? PAGESIZE : 16);
HIDDEN(_ehead = .);
} :Head
@ -239,8 +238,8 @@ SECTIONS {
/* Code that needs to be addressable in Real Mode */
*(.text.real)
KEEP(*(SORT_BY_NAME(.sort.text.real.*)))
*(.rodata.real)
KEEP(*(SORT_BY_NAME(.sort.rodata.real.*)))
/**(.rodata.real)
KEEP(*(SORT_BY_NAME(.sort.rodata.real.*)))*/
HIDDEN(_ereal = .);
/*END: realmode addressability guarantee */
@ -282,7 +281,6 @@ SECTIONS {
KEEP(*(.ape.pad.privileged));
HIDDEN(__privileged_start = .);
HIDDEN(__test_end = .);
. += 1;
*(.privileged)
HIDDEN(__privileged_end = .);
@ -308,7 +306,6 @@ SECTIONS {
/* Windows DLL Import Directory */
KEEP(*(.idata.ro));
KEEP(*(SORT_BY_NAME(.idata.ro.*)))
. += 1;
. = ALIGN(__SIZEOF_POINTER__);
PROVIDE_HIDDEN(__init_array_start = .);
@ -381,11 +378,6 @@ SECTIONS {
KEEP(*(SORT_BY_NAME(.sort.bss.*)))
/* eXtreme Low Memory w/ Userspace Remapping */
. = ALIGN(0x1000);
*(.xlm)
. = ALIGN(0x1000);
. = ALIGN(0x10000); /* for brk()/sbrk() allocation */
HIDDEN(_end = .);
PROVIDE_HIDDEN(end = .);
@ -465,6 +457,13 @@ HIDDEN(ape_ram_memsz = ADDR(.bss) + SIZEOF(.bss) - ape_ram_vaddr);
HIDDEN(ape_ram_align = PAGESIZE);
HIDDEN(ape_ram_rva = RVA(ape_ram_vaddr));
HIDDEN(ape_stack_offset = ape_ram_offset + ape_ram_filesz);
HIDDEN(ape_stack_vaddr = 0x700000000000 - STACKSIZE);
HIDDEN(ape_stack_paddr = ape_ram_paddr + ape_ram_filesz);
HIDDEN(ape_stack_filesz = 0);
HIDDEN(ape_stack_memsz = STACKSIZE);
HIDDEN(ape_stack_align = 16);
HIDDEN(ape_note_offset = ape_rom_offset + (ape_note - ape_rom_vaddr));
HIDDEN(ape_note_vaddr = ape_note);
HIDDEN(ape_note_paddr = ape_rom_paddr + ape_note_offset);
@ -500,14 +499,18 @@ SHSTUB2(ape_macho_dd_skip, RVA(ape_macho) / 8);
SHSTUB2(ape_macho_dd_count, (ape_macho_end - ape_macho) / 8);
#endif
#if SupportsWindows() || SupportsUefi()
#if SupportsWindows() || SupportsMetal()
#define LINK_WINDOWS (SupportsWindows() && !DEFINED(EfiMain))
PFSTUB4(ape_pe_offset, ape_pe - ape_mz);
HIDDEN(ape_pe_optsz = ape_pe_sections - (ape_pe + 24));
HIDDEN(ape_pe_shnum = (ape_pe_sections_end - ape_pe_sections) / 40);
HIDDEN(ape_idata_idtsize = ape_idata_idtend - ape_idata_idt);
HIDDEN(ape_idata_iatsize = ape_idata_iatend - ape_idata_iat);
HIDDEN(ape_pe_base = IMAGE_BASE_VIRTUAL);
HIDDEN(ape_idata = LINK_WINDOWS ? RVA(ape_idata_iat) : 0);
HIDDEN(ape_idata_iatsize = LINK_WINDOWS ? ape_idata_iatend - ape_idata_iat : 0);
HIDDEN(ape_idata = LINK_WINDOWS ? RVA(ape_idata_idt) : 0);
HIDDEN(ape_idata_idtsize = LINK_WINDOWS ? ape_idata_idtend - ape_idata_idt : 0);
HIDDEN(v_ntversion = LINK_WINDOWS ? 6 : 1);
HIDDEN(v_ntdllchar = LINK_WINDOWS ? 288 : 0);
HIDDEN(v_ntsubversion = LINK_WINDOWS ? 6 : 5);
HIDDEN(v_ntsubsystem = (LINK_WINDOWS
? (DEFINED(GetMessage)
@ -519,7 +522,7 @@ HIDDEN(ape_pe_entry = LINK_WINDOWS ? WinMain : EfiMain);
#if SupportsMetal()
HIDDEN(v_ape_realsectors =
MIN(REAL_SCRATCH_AREA - IMAGE_BASE_REAL,
MIN(0x70000 - IMAGE_BASE_REAL,
ROUNDUP(RVA(_edata), 4096)) / 512);
HIDDEN(v_ape_realpages = v_ape_realsectors / (4096 / 512));
HIDDEN(v_ape_highsectors =
@ -609,7 +612,7 @@ CHURN(v_ape_realsectors);
#if SupportsXnu()
CHURN(ape_macho);
#endif
#if SupportsWindows() || SupportsUefi()
#if SupportsWindows() || SupportsMetal()
CHURN(ape_mz);
CHURN(ape_pe);
CHURN(ape_pe_offset);

View file

@ -31,12 +31,10 @@ APE_HDRS = $(filter %.h,$(APE_FILES))
APE_INCS = $(filter %.inc,$(APE_FILES))
APE_SRCS = $(filter %.S,$(APE_FILES))
APE_OBJS = $(APE_SRCS:%.S=o/$(MODE)/%.o)
APE_DEPS = $(APE_LIB)
APE_CHECKS = $(APE_HDRS:%=o/%.ok)
o/$(MODE)/ape/ape.lds: \
ape/ape.lds \
ape/config.h \
ape/macros.internal.h \
libc/dce.h \
libc/zip.h
@ -49,6 +47,4 @@ $(APE_OBJS): $(BUILD_FILES) \
ape/ape.mk
.PHONY: o/$(MODE)/ape
o/$(MODE)/ape: $(APE) \
$(APE_CHECKS) \
o/$(MODE)/ape/lib
o/$(MODE)/ape: $(APE) $(APE_CHECKS)

View file

@ -1,118 +0,0 @@
#ifndef APE_CONFIG_H_
#define APE_CONFIG_H_
#include "ape/relocations.h"
#include "libc/macros.h"
/*
* Post-Initialization Read-Only Code Size Threshold.
*
* An executable needs to have at least this much code, before the
* linker adds non-mandatory 4kb alignments. The benefit is better
* memory protection. The tradeoff is sparser binaries.
*/
#ifndef APE_PIRO_THRESHOLD
#ifdef CONFIG_DBG
#define APE_PIRO_THRESHOLD 0x1000
#else
#define APE_PIRO_THRESHOLD 0x10000
#endif
#endif
#ifndef METAL_STDIN
#define METAL_STDIN COM1
#endif
#ifndef METAL_STDOUT
#define METAL_STDOUT COM1
#endif
#ifndef METAL_STDERR
#define METAL_STDERR COM1
#endif
#ifndef VIDYA_MODE
#define VIDYA_MODE VIDYA_MODE_CGA
#endif
/* FPU Control Word (x87) Exception Masks
@see Intel Manual V1 §8.1.5
IM: Invalid Operation
DM: Denormal Operand
ZM: Zero Divide
OM: Overflow
UM: Underflow
PM: Precision
PC: Precision Control
{float,,double,long double}
RC: Rounding Control
{even, -, +, 0}
drr*/
#define X87_NORMAL 0b000000000001101111111
#define X87_DTOA 0b000000000001000000000
#define X87_DTOA_MASK 0b000000000001100000000
#ifndef X87_DEFAULT
#define X87_DEFAULT X87_NORMAL
#endif
#ifndef UART_BAUD_RATE
#define UART_BAUD_RATE 9600 /* bits per second ∈ [50,115200] */
#endif
#define UART_CONF_DLR (1843200 /*hz*/ / 16 /*wut*/ / (UART_BAUD_RATE))
#ifndef UART_CONF_IIR
/* ┌interrupt trigger level {1,4,8,14}
enable 64 byte fifo (UART 16750+)
select dma mode
clear transmit fifo
clear receive fifo
enable fifos*/
#define UART_CONF_IIR 0b00000000
#endif
#ifndef UART_CONF_LCR
/* ┌dlab: flips configuration mode state
enable break signal
parity {none,odd,even,high,low}
extra stop bit
data word length (bits+5)
*/
#define UART_CONF_LCR 0b01000011
#endif
#define XLM(VAR) (XLM_BASE_REAL + XLM_##VAR)
#define XLMV(VAR) (__xlm + XLM_##VAR)
#define XLM_BASE_REAL 0x1000
#define XLM_E820 0
#define XLM_E820_SIZE 0x2000
#define XLM_BIOS_DATA_AREA 0x2000
#define XLM_BIOS_DATA_AREA_SIZE 256
#define XLM_DRIVE_BASE_TABLE 0x2200 /* drive values are contiguous */
#define XLM_DRIVE_BASE_TABLE_SIZE 11
#define XLM_DRIVE_TYPE 0x220b
#define XLM_DRIVE_TYPE_SIZE 1
#define XLM_DRIVE_LAST_SECTOR 0x220c /* 1-based inclusive, e.g. 18 */
#define XLM_DRIVE_LAST_SECTOR_SIZE 1
#define XLM_DRIVE_LAST_CYLINDER 0x220d /* 0-based incl, e.g. 79 */
#define XLM_DRIVE_LAST_CYLINDER_SIZE 2
#define XLM_DRIVE_ATTACHED 0x220f
#define XLM_DRIVE_ATTACHED_SIZE 1
#define XLM_DRIVE_LAST_HEAD 0x2210 /* 0-based inclusive, e.g. 1 */
#define XLM_DRIVE_LAST_HEAD_SIZE 1
#define XLM_DRIVE 0x2211
#define XLM_DRIVE_SIZE 1
#define XLM_HAVEEXTMEMKB 0x2212
#define XLM_HAVEEXTMEMKB_SIZE 4
#define XLM_VIDEO_POSITION_FAR_POINTER 0x2216 /* video cursor far pointer */
#define XLM_VIDEO_POSITION_FAR_POINTER_SIZE 4
#define XLM_PAGE_TABLE_STACK_POINTER 0x2220
#define XLM_PAGE_TABLE_STACK_POINTER_SIZE 8
#define XLM_BADIDT 0x2230
#define XLM_BADIDT_SIZE 6
#define XLM_LOADSTATE 0x2240
#define XLM_LOADSTATE_SIZE 8
#define XLM_SIZE ROUNDUP(XLM_LOADSTATE + XLM_LOADSTATE_SIZE, 0x1000)
#define IMAGE_BASE_REAL (XLM_BASE_REAL + XLM_SIZE)
#if !defined(__LINKER__) && !defined(__ASSEMBLER__)
extern char __xlm[XLM_SIZE];
#endif /* !defined(__LINKER__) && !defined(__ASSEMBLER__) */
#endif /* APE_CONFIG_H_ */

View file

@ -1,45 +0,0 @@
#-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐
#───vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi───────────────────────┘
PKGS += APE_LIB
APE_LIB_ARTIFACTS += APE_LIB_A
APE_LIB = $(APE_LIB_A_DEPS) $(APE_LIB_A)
APE_LIB_A = o/$(MODE)/ape/lib/apelib.a
APE_LIB_A_FILES := $(wildcard ape/lib/*)
APE_LIB_A_HDRS = $(filter %.h,$(APE_LIB_A_FILES))
APE_LIB_A_SRCS_S = $(filter %.S,$(APE_LIB_A_FILES))
APE_LIB_A_SRCS_C = $(filter %.c,$(APE_LIB_A_FILES))
APE_LIB_A_SRCS = \
$(APE_LIB_A_SRCS_S) \
$(APE_LIB_A_SRCS_C)
APE_LIB_A_OBJS = \
$(APE_LIB_A_SRCS_S:%.S=o/$(MODE)/%.o) \
$(APE_LIB_A_SRCS_C:%.c=o/$(MODE)/%.o)
APE_LIB_A_DIRECTDEPS = \
LIBC_NEXGEN32E \
LIBC_INTRIN \
LIBC_STR \
LIBC_STUBS
APE_LIB_A_CHECKS = $(APE_LIB_A_HDRS:%=o/$(MODE)/%.ok)
APE_LIB_A_DEPS = $(call uniq,$(foreach x,$(APE_LIB_A_DIRECTDEPS),$($(x))))
$(APE_LIB_A): ape/lib/ $(APE_LIB_A).pkg $(APE_LIB_A_OBJS)
$(APE_LIB_A).pkg: $(APE_LIB_A_OBJS) $(foreach x,$(APE_LIB_A_DIRECTDEPS),$($(x)_A).pkg)
APE_LIB_LIBS = $(foreach x,$(APE_LIB_ARTIFACTS),$($(x)))
APE_LIB_SRCS = $(foreach x,$(APE_LIB_ARTIFACTS),$($(x)_SRCS))
APE_LIB_HDRS = $(foreach x,$(APE_LIB_ARTIFACTS),$($(x)_HDRS))
APE_LIB_BINS = $(foreach x,$(APE_LIB_ARTIFACTS),$($(x)_BINS))
APE_LIB_CHECKS = $(foreach x,$(APE_LIB_ARTIFACTS),$($(x)_CHECKS))
APE_LIB_OBJS = $(foreach x,$(APE_LIB_ARTIFACTS),$($(x)_OBJS))
$(APE_LIB_OBJS): $(BUILD_FILES) libc/str/str.mk
.PHONY: o/$(MODE)/ape/lib
o/$(MODE)/ape/lib: \
$(APE_LIB_CHECKS) \
$(APE_LIB_A)

View file

@ -1,35 +0,0 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 sw=8 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 "ape/macros.internal.h"
#include "ape/notice.inc"
.section .real,"ax",@progbits
.source __FILE__
.code16
// Resets personal computer.
//
// @param di drive number, e.g. A:\ is 0x00, C:\ is 0x80
// @mode real
// @noreturn
bootdr: push %bp
mov %sp,%bp
mov %di,%dx
int $0x19
ljmp $0xf000,$0xfff0
.endfn bootdr,globl

View file

@ -1,37 +0,0 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 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 "ape/lib/pc.h"
#include "ape/config.h"
#include "ape/macros.internal.h"
#include "ape/notice.inc"
.section .real,"ax",@progbits
.source __FILE__
.code16
.globl e820map
.hidden e820map
.type e820map,@object
.size e820map,XLM_E820_SIZE
e820map = ape_xlm + XLM_E820
.globl e820map_xlm
.hidden e820map_xlm
.type e820map_xlm,@object
.size e820map_xlm,XLM_E820_SIZE
e820map_xlm = XLM(E820)

View file

@ -1,55 +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 "ape/config.h"
#include "ape/lib/pc.h"
#include "libc/bits/bits.h"
#include "libc/macros.h"
/**
* Virtualizes physical memory.
*
* This function removes memory holes (discovered by e820() earlier) and
* creates the illusion of flat contiguous memory for as much RAM as the
* BIOS reports usable. Memory is safe to use and remap afterwards.
*
* @see ape/ape.S
*/
textreal void flattenhighmemory(struct SmapEntry *e820, struct PageTable *pml4t,
uint64_t *ptsp) {
uint64_t *entry, paddr, vaddr;
struct SmapEntry *smap, *hole;
for (smap = hole = e820, vaddr = IMAGE_BASE_VIRTUAL; smap->size; ++smap) {
while (smap->size && smap->type != kMemoryUsable) smap++;
paddr = ROUNDUP(MAX(IMAGE_BASE_PHYSICAL, smap->addr), PAGESIZE);
while (paddr < ROUNDDOWN(smap->addr + smap->size, PAGESIZE)) {
while (hole->size &&
(hole->type == kMemoryUsable || hole->addr + hole->size < paddr)) {
hole++;
}
if (paddr >= hole->addr && paddr < hole->addr + hole->size) {
paddr = ROUNDUP(hole->addr + hole->size, PAGESIZE);
} else {
entry = __getpagetableentry(vaddr, 3, pml4t, ptsp);
*entry = paddr | PAGE_V | PAGE_RW;
vaddr += 0x1000;
paddr += 0x1000;
}
}
}
}

View file

@ -1,31 +0,0 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 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 "ape/lib/pc.h"
#include "ape/config.h"
#include "ape/macros.internal.h"
#include "ape/notice.inc"
.section .real,"ax",@progbits
.source __FILE__
.code16
.globl g_pml4t
.hidden g_pml4t
.type g_pml4t,@object
.size g_pml4t,0x1000
g_pml4t = REAL_STACK_FRAME - 0x1000

View file

@ -1,37 +0,0 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 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 "ape/lib/pc.h"
#include "ape/config.h"
#include "ape/macros.internal.h"
#include "ape/notice.inc"
.section .real,"ax",@progbits
.source __FILE__
.code16
.globl g_ptsp
.hidden g_ptsp
.type g_ptsp,@object
.size g_ptsp,XLM_PAGE_TABLE_STACK_POINTER_SIZE
g_ptsp = ape_xlm + XLM_PAGE_TABLE_STACK_POINTER
.globl g_ptsp_xlm
.hidden g_ptsp_xlm
.type g_ptsp_xlm,@object
.size g_ptsp_xlm,XLM_PAGE_TABLE_STACK_POINTER_SIZE
g_ptsp_xlm = XLM(PAGE_TABLE_STACK_POINTER)

View file

@ -1,42 +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 "ape/lib/pc.h"
#include "libc/assert.h"
static textreal uint64_t __pushpagetable(uint64_t *ptsp) {
return (*ptsp -= PAGESIZE) | PAGE_V | PAGE_RW;
}
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 & 0xfff));
assert(!((uintptr_t)pml4t & 0xfff));
shift = 39;
for (;;) {
entry = &pml4t->p[(vaddr >> shift) & 511];
if (!depth--) return entry;
shift -= 9;
if (!*entry) *entry = __pushpagetable(ptsp);
pml4t = (void *)(*entry & PAGE_TA);
}
}

View file

@ -1,45 +0,0 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 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 "ape/lib/pc.h"
#include "ape/config.h"
#include "ape/macros.internal.h"
#include "ape/notice.inc"
.section .real,"ax",@progbits
.source __FILE__
.code16
.globl kBiosDataArea
.hidden kBiosDataArea
.type kBiosDataArea,@object
.size kBiosDataArea,XLM_BIOS_DATA_AREA_SIZE
kBiosDataArea = ape_xlm + XLM_BIOS_DATA_AREA
.globl kBiosDataAreaXlm
.hidden kBiosDataAreaXlm
.type kBiosDataAreaXlm,@object
.size kBiosDataAreaXlm,XLM_BIOS_DATA_AREA_SIZE
kBiosDataAreaXlm = XLM(BIOS_DATA_AREA)
.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
mov $XLM_BIOS_DATA_AREA_SIZE,%cx
rep movsb
.previous

View file

@ -1,26 +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 "ape/lib/pc.h"
textreal void pageunmap(int64_t vaddr) {
uint64_t *entry;
entry = __getpagetableentry(vaddr, 3, &g_pml4t, &g_ptsp_xlm);
*entry &= ~PAGE_V;
asm volatile("invlpg\t(%0)" : /* no outputs */ : "r"(vaddr) : "memory");
}

View file

@ -1,46 +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 "ape/lib/pc.h"
textreal static unsigned smapcount(const struct SmapEntry *se) {
unsigned i = 0;
while (se[i].size) ++i;
return i;
}
textreal static void smapsorter(size_t n, struct SmapEntry a[n]) {
struct SmapEntry t;
unsigned i, j;
for (i = 1; i < n; ++i) {
j = i;
t = a[i];
while (j > 0 && (intptr_t)t.addr - (intptr_t)a[j - 1].addr) {
a[j] = a[j - 1];
--j;
}
a[j] = t;
}
}
/**
* Sorts BIOS e820 memory map.
*/
textreal void smapsort(struct SmapEntry *smap) {
smapsorter(smapcount(smap), smap);
}

View file

@ -26,13 +26,6 @@
* @fileoverview Macros relevant to αcτµαlly pδrταblε εxεcµταblε.
*/
// Calls function in real mode.
// It's needed because LLVM 8 LLD doesn't support R_X86_64_PC16.
.macro call16 name:req
mov $REAL(\name),%ax
call *%ax
.endm
// Calls near (i.e. pc+pcrel<64kB) FUNCTION.
// @mode long,legacy,real
// @cost 9 bytes overhead

View file

@ -11,6 +11,8 @@
In some cases it's necessary to use addend macros that change virtual
addresses into the other two types: physical and real. */
#define IMAGE_BASE_REAL 0x2000
#ifndef IMAGE_BASE_VIRTUAL
#define IMAGE_BASE_VIRTUAL 0x400000
#endif
@ -19,26 +21,6 @@
#define IMAGE_BASE_PHYSICAL 0x100000
#endif
#ifndef REAL_SCRATCH_AREA
/**
* Location of anything goes memory for real mode.
*
* The MBR won't load program content beyond this address, so we have
* room for buffers, page tables, etc. before we reach the stack frame.
*/
#define REAL_SCRATCH_AREA 0x40000
#endif
#ifndef REAL_STACK_FRAME
/**
* Location of real mode 64kb stack frame.
*
* This address was chosen because memory beyond 0x80000 can't be
* accessed safely without consulting e820.
*/
#define REAL_STACK_FRAME 0x70000
#endif
/**
* Returns Relative Virtual Address.
*/

Binary file not shown.

View file

@ -166,7 +166,8 @@ DEFAULT_LDFLAGS = \
--gc-sections \
--build-id=none \
--no-dynamic-linker \
-z max-page-size=0x1000
-z max-page-size=0x1000 \
--cref -Map=$@.map
ZIPOBJ_FLAGS = \
-b$(IMAGE_BASE_VIRTUAL)

44
examples/e820.c Normal file
View file

@ -0,0 +1,44 @@
#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/fmt/itoa.h"
#include "libc/macros.h"
#include "libc/runtime/e820.internal.h"
#include "libc/runtime/pc.internal.h"
#include "libc/stdio/stdio.h"
const char *DescribeMemoryType(int type) {
switch (type) {
case kMemoryUsable:
return "kMemoryUsable";
case kMemoryUnusable:
return "kMemoryUnusable";
case kMemoryAcpiReclaimable:
return "kMemoryAcpiReclaimable";
case kMemoryAcpiNvs:
return "kMemoryAcpiNvs";
case kMemoryBad:
return "kMemoryBad";
default:
return "UNKNOWN";
}
}
int main(int argc, char *argv[]) {
int i;
const char *ts;
struct mman *mm;
mm = (struct mman *)(BANE + 0x0500);
for (i = 0; i < mm->e820n; ++i) {
printf("%p-%p %s\n", mm->e820[i].addr, mm->e820[i].size,
DescribeMemoryType(mm->e820[i].type));
}
for (;;) asm("pause");
return 0;
}

View file

@ -33,7 +33,6 @@ EXAMPLES_BINS = \
$(EXAMPLES_COMS:%=%.dbg)
EXAMPLES_DIRECTDEPS = \
APE_LIB \
DSP_CORE \
DSP_SCALE \
DSP_TTY \

19
examples/malloc.c Normal file
View file

@ -0,0 +1,19 @@
#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/mem/mem.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
int main(int argc, char *argv[]) {
char *s = malloc(1024 * 1024 * 2 + argc);
strcpy(s, "hello");
puts(s);
return 0;
}

View file

@ -1,12 +0,0 @@
#ifndef COSMOPOLITAN_LIBC_CALLS_EFI_H_
#define COSMOPOLITAN_LIBC_CALLS_EFI_H_
#include "libc/nt/efi.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
extern EFI_HANDLE __efi_image_handle;
extern EFI_SYSTEM_TABLE *__efi_system_table;
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_CALLS_EFI_H_ */

View file

@ -31,9 +31,9 @@ int fstat(int fd, struct stat *st) {
if (__isfdkind(fd, kFdZip)) {
return weaken(__zipos_fstat)(
(struct ZiposHandle *)(intptr_t)g_fds.p[fd].handle, st);
} else if (!IsWindows() && !IsMetal() && !IsUefi()) {
} else if (!IsWindows() && !IsMetal()) {
return sys_fstat(fd, st);
} else if (IsMetal() || IsUefi()) {
} else if (IsMetal()) {
return fstat_metal(fd, st);
} else {
if (!__isfdkind(fd, kFdFile)) return ebadf();

View file

@ -30,7 +30,7 @@ hidden textstartup void InitializeFileDescriptors(void) {
fds = VEIL("r", &g_fds);
pushmov(&fds->n, ARRAYLEN(fds->__init_p));
fds->p = fds->__init_p;
if (IsMetal() || IsUefi()) {
if (IsMetal()) {
pushmov(&fds->f, 3ull);
fds->__init_p[STDIN_FILENO].kind = pushpop(kFdSerial);
fds->__init_p[STDOUT_FILENO].kind = pushpop(kFdSerial);

View file

@ -197,7 +197,7 @@ u32 sys_getgid(void) hidden;
u32 sys_getsid(int) hidden;
u32 sys_gettid(void) hidden;
u32 sys_getuid(void) hidden;
void *sys_mmap(void *, u64, u32, u32, i64, i64, i64) hidden;
void *__sys_mmap(void *, u64, u32, u32, i64, i64, i64) hidden;
void *sys_mremap(void *, u64, u64, i32, void *) hidden;
void sys_exit(int) hidden;
@ -295,12 +295,6 @@ unsigned __wincrash_nt(struct NtExceptionPointers *);
int fstat_metal(int, struct stat *);
/*───────────────────────────────────────────────────────────────────────────│─╗
cosmopolitan § syscalls » uefi
*/
int sys_nanosleep_uefi(const struct timespec *, struct timespec *);
/*───────────────────────────────────────────────────────────────────────────│─╗
cosmopolitan § syscalls » drivers
*/

View file

@ -29,12 +29,10 @@ int nanosleep(const struct timespec *req, struct timespec *rem) {
if (req->tv_sec < 0 || !(0 <= req->tv_nsec && req->tv_nsec <= 999999999)) {
return einval();
}
if (!IsWindows() && !IsMetal() && !IsUefi() && !IsXnu()) {
if (!IsWindows() && !IsMetal() && !IsXnu()) {
return sys_nanosleep(req, rem);
} else if (IsXnu()) {
return sys_nanosleep_xnu(req, rem);
} else if (IsUefi()) {
return sys_nanosleep_uefi(req, rem);
} else if (IsMetal()) {
return enosys(); /* TODO: Sleep on Metal */
} else {

View file

@ -16,9 +16,9 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "ape/lib/pc.h"
#include "libc/calls/internal.h"
#include "libc/nexgen32e/uart.internal.h"
#include "libc/runtime/pc.internal.h"
static bool IsDataAvailable(struct Fd *fd) {
return inb(fd->handle + UART_LSR) & UART_TTYDA;

View file

@ -36,8 +36,7 @@ ssize_t readv(int fd, const struct iovec *iov, int iovlen) {
if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip) {
return weaken(__zipos_read)(
(struct ZiposHandle *)(intptr_t)g_fds.p[fd].handle, iov, iovlen, -1);
} else if ((SupportsMetal() || SupportsUefi()) && fd < g_fds.n &&
g_fds.p[fd].kind == kFdSerial) {
} else if (SupportsMetal() && fd < g_fds.n && g_fds.p[fd].kind == kFdSerial) {
return readv_serial(&g_fds.p[fd], iov, iovlen);
} else if (!IsWindows()) {
return sys_readv(fd, iov, iovlen);

View file

@ -144,7 +144,7 @@ int(sigaction)(int sig, const struct sigaction *act, struct sigaction *oldact) {
sizeof(struct sigaction) > sizeof(struct sigaction_freebsd) &&
sizeof(struct sigaction) > sizeof(struct sigaction_openbsd) &&
sizeof(struct sigaction) > sizeof(struct sigaction_netbsd));
if (IsMetal() || IsUefi()) return enosys(); /* TODO: Signals on Metal */
if (IsMetal()) return enosys(); /* TODO: Signals on Metal */
if (!(0 < sig && sig < NSIG)) return einval();
if (sig == SIGKILL || sig == SIGSTOP) return einval();
if (!act) {

View file

@ -16,9 +16,9 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "ape/lib/pc.h"
#include "libc/calls/internal.h"
#include "libc/nexgen32e/uart.internal.h"
#include "libc/runtime/pc.internal.h"
ssize_t writev_serial(struct Fd *fd, const struct iovec *iov, int iovlen) {
size_t i, j, wrote = 0;

View file

@ -39,8 +39,7 @@ ssize_t writev(int fd, const struct iovec *iov, int iovlen) {
if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip) {
return weaken(__zipos_write)(
(struct ZiposHandle *)(intptr_t)g_fds.p[fd].handle, iov, iovlen, -1);
} else if ((SupportsMetal() || SupportsUefi()) && fd < g_fds.n &&
g_fds.p[fd].kind == kFdSerial) {
} else if (SupportsMetal() && fd < g_fds.n && g_fds.p[fd].kind == kFdSerial) {
return writev_serial(&g_fds.p[fd], iov, iovlen);
} else if (!IsWindows()) {
return sys_writev(fd, iov, iovlen);

View file

@ -21,7 +21,6 @@
#include "libc/notice.inc"
#include "libc/runtime/internal.h"
.section .start,"ax",@progbits
.align 16
// System Five userspace program entrypoint.
//
@ -37,7 +36,7 @@ _start:
#endif
0: mov (%rsp),%ebx # argc
lea 8(%rsp),%rsi # argv
lea 24(%rsp,%rbx,8),%rdx # envp
lea 16(%rsp,%rbx,8),%rdx # envp
.frame0
// bofram 9f
.weak ape_idata_iat

View file

@ -20,7 +20,6 @@
#define OPENBSD 16
#define FREEBSD 32
#define NETBSD 64
#define UEFI 128
#ifdef NDEBUG
#define NoDebug() 1
@ -73,7 +72,6 @@
#define SupportsLinux() ((SUPPORT_VECTOR & LINUX) == LINUX)
#define SupportsMetal() ((SUPPORT_VECTOR & METAL) == METAL)
#define SupportsWindows() ((SUPPORT_VECTOR & WINDOWS) == WINDOWS)
#define SupportsUefi() ((SUPPORT_VECTOR & UEFI) == UEFI)
#define SupportsXnu() ((SUPPORT_VECTOR & XNU) == XNU)
#define SupportsFreebsd() ((SUPPORT_VECTOR & FREEBSD) == FREEBSD)
#define SupportsOpenbsd() ((SUPPORT_VECTOR & OPENBSD) == OPENBSD)
@ -86,7 +84,6 @@
#define IsLinux() (SupportsLinux() && (__hostos & LINUX))
#define IsMetal() (SupportsMetal() && (__hostos & METAL))
#define IsWindows() (SupportsWindows() && (__hostos & WINDOWS))
#define IsUefi() (SupportsUefi() && (__hostos & UEFI))
#define IsXnu() (SupportsXnu() && (__hostos & XNU))
#define IsFreebsd() (SupportsFreebsd() && (__hostos & FREEBSD))
#define IsOpenbsd() (SupportsOpenbsd() && (__hostos & OPENBSD))
@ -97,7 +94,6 @@
#define IsLinux() $LINUX,__hostos(%rip)
#define IsMetal() $METAL,__hostos(%rip)
#define IsWindows() $WINDOWS,__hostos(%rip)
#define IsUefi() $UEFI,__hostos(%rip)
#define IsBsd() $XNU|FREEBSD|OPENBSD|NETBSD,__hostos(%rip)
#define IsXnu() $XNU,__hostos(%rip)
#define IsFreebsd() $FREEBSD,__hostos(%rip)

View file

@ -603,6 +603,7 @@ typedef uint64_t uintmax_t;
#define textstartup _Section(".text.startup") noinstrument
#define textexit _Section(".text.exit") noinstrument
#define textreal _Section(".text.real")
#define texthead _Section(".text.head")
#define textwindows _Section(".text.windows")
#define antiquity _Section(".text.antiquity")
#else
@ -610,6 +611,7 @@ typedef uint64_t uintmax_t;
#define textstartup
#define textexit
#define textreal
#define texthead
#define textwindows
#define antiquity
#endif

View file

@ -28,7 +28,7 @@
#include "libc/mem/hook/hook.internal.h"
#include "libc/nt/enum/version.h"
#include "libc/nt/runtime.h"
#include "libc/runtime/directmap.h"
#include "libc/runtime/directmap.internal.h"
#include "libc/runtime/memtrack.h"
#include "libc/runtime/runtime.h"
#include "libc/sysv/consts/auxv.h"
@ -744,7 +744,7 @@ void __asan_map_shadow(uintptr_t p, size_t n) {
b = ROUNDUP((uintptr_t)SHADOW(ROUNDUP((uintptr_t)p + n, 8)), 1 << 16) >> 16;
for (; a < b; ++a) {
if (!__asan_is_mapped(a)) {
sm = weaken(__mmap)(
sm = weaken(sys_mmap)(
(void *)((uintptr_t)a << 16), 1 << 16, PROT_READ | PROT_WRITE,
MAP_PRIVATE | *weaken(MAP_ANONYMOUS) | MAP_FIXED, -1, 0);
if (sm.addr == MAP_FAILED ||
@ -796,7 +796,7 @@ static textstartup void __asan_shadow_existing_mappings(void) {
}
static textstartup bool IsMemoryManagementRuntimeLinked(void) {
return weaken(_mmi) && weaken(__mmap) && weaken(MAP_ANONYMOUS) &&
return weaken(_mmi) && weaken(sys_mmap) && weaken(MAP_ANONYMOUS) &&
weaken(FindMemoryInterval) && weaken(TrackMemoryInterval);
}
@ -809,7 +809,7 @@ textstartup void __asan_init(int argc, char **argv, char **envp,
__asan_exit(0); /* So `make MODE=dbg test` passes w/ Windows7 */
}
REQUIRE(_mmi);
REQUIRE(__mmap);
REQUIRE(sys_mmap);
REQUIRE(MAP_ANONYMOUS);
REQUIRE(FindMemoryInterval);
REQUIRE(TrackMemoryInterval);

View file

@ -27,6 +27,9 @@
.macro .real
.section .text.real,"ax",@progbits
.endm
.macro .head
.section .text.head,"ax",@progbits
.endm
.macro .text.startup
.section .text.startup,"ax",@progbits
.endm

View file

@ -16,7 +16,7 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "ape/lib/pc.h"
#include "libc/runtime/pc.internal.h"
#include "libc/dce.h"
#include "libc/macros.h"
#include "libc/nexgen32e/kcpuids.h"

View file

@ -17,7 +17,6 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "ape/macros.internal.h"
#include "ape/config.h"
.real
.source __FILE__
.code16 # .code32 .code64
@ -26,7 +25,8 @@
//
// @see youtu.be/GIKfEAF2Yhw?t=67
// @mode long,legacy,real
triplf: push %bp
triplf: ud2
push %bp
mov %sp,%bp
sub $8,%sp
movpp %bp,%si

View file

@ -1,32 +0,0 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 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 "libc/macros.h"
#include "libc/notice.inc"
#include "ape/config.h"
// eXtreme Low Memory.
// @see ape/config.h
.section .xlm,"aw",@nobits
.align 4096
__xlm: .rept XLM_SIZE
.byte 0
.endr
.endobj __xlm,globl,hidden
.previous
.source __FILE__

View file

@ -258,6 +258,9 @@ typedef EFI_STATUS(EFIAPI *EFI_GET_MEMORY_MAP)(
typedef EFI_STATUS(EFIAPI *EFI_ALLOCATE_POOL)(EFI_MEMORY_TYPE PoolType,
uintptr_t Size, void *out_Buffer);
typedef EFI_STATUS(EFIAPI *EFI_FREE_POOL)(void *Buffer);
typedef void(EFIAPI *EFI_SET_MEM)(void *Buffer, uintptr_t Size, uint8_t Value);
typedef void(EFIAPI *EFI_COPY_MEM)(void *Destination, void *Source,
uintptr_t Length);
typedef EFI_STATUS(EFIAPI *EFI_CHECK_EVENT)(EFI_EVENT Event);
typedef EFI_STATUS(EFIAPI *EFI_CLOSE_EVENT)(EFI_EVENT Event);
@ -346,6 +349,8 @@ typedef EFI_STATUS(EFIAPI *EFI_IMAGE_LOAD)(bool BootPolicy,
uintptr_t SourceSize,
EFI_HANDLE *out_ImageHandle);
typedef EFI_STATUS(EFIAPI *EFI_IMAGE_UNLOAD)(EFI_HANDLE ImageHandle);
typedef EFI_STATUS(EFIAPI *EFI_EXIT_BOOT_SERVICES)(EFI_HANDLE ImageHandle,
uintptr_t MapKey);
typedef struct {
EFI_TABLE_HEADER Hdr;
@ -393,7 +398,7 @@ typedef struct {
void *StartImage;
EFI_EXIT Exit;
EFI_IMAGE_UNLOAD UnloadImage;
void *ExitBootServices;
EFI_EXIT_BOOT_SERVICES ExitBootServices;
EFI_GET_NEXT_MONOTONIC_COUNT GetNextMonotonicCount;
EFI_STALL Stall;
EFI_SET_WATCHDOG_TIMER SetWatchdogTimer;
@ -408,8 +413,8 @@ typedef struct {
void *InstallMultipleProtocolInterfaces;
void *UninstallMultipleProtocolInterfaces;
void *CalculateCrc32;
void *CopyMem;
void *SetMem;
EFI_COPY_MEM CopyMem;
EFI_SET_MEM SetMem;
EFI_CREATE_EVENT_EX CreateEventEx;
} EFI_BOOT_SERVICES;

View file

@ -16,13 +16,13 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "ape/lib/pc.h"
#include "libc/bits/bits.h"
#include "libc/calls/calls.h"
#include "libc/dce.h"
#include "libc/nexgen32e/msr.h"
#include "libc/nexgen32e/x86feature.h"
#include "libc/runtime/interruptiblecall.h"
#include "libc/runtime/pc.internal.h"
#include "libc/sysv/consts/sig.h"
#include "libc/sysv/errfuns.h"

View file

@ -17,19 +17,48 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/calls/efi.h"
#include "libc/nt/efi.h"
#include "libc/macros.h"
#include "libc/runtime/directmap.internal.h"
#include "libc/runtime/pc.internal.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/map.h"
#include "libc/sysv/consts/prot.h"
#include "libc/sysv/errfuns.h"
int sys_nanosleep_uefi(const struct timespec *req, struct timespec *rem) {
if (__efi_system_table->BootServices->Stall(
req->tv_sec * 1000000 + req->tv_nsec / 1000) == EFI_SUCCESS) {
if (rem) {
rem->tv_sec = 0;
rem->tv_nsec = 0;
static uint64_t sys_mmap_metal_break;
noasan struct DirectMap sys_mmap_metal(void *paddr, size_t size, int prot,
int flags, int fd, int64_t off) {
size_t i;
struct mman *mm;
struct DirectMap res;
uint64_t addr, page, *pte, *pml4t;
mm = (struct mman *)(BANE + 0x0500);
pml4t = __get_pml4t();
size = ROUNDUP(size, 4096);
addr = (uint64_t)paddr;
if (!(flags & MAP_FIXED)) {
for (i = 0; i < size; i += 4096) {
pte = __get_virtual(mm, pml4t, addr, false);
if (pte && (*pte & PAGE_V)) {
addr = MAX(addr, sys_mmap_metal_break) + i + 4096;
i = 0;
}
}
return 0;
} else {
return eintr();
sys_mmap_metal_break = MAX(addr + size, sys_mmap_metal_break);
}
for (i = 0; i < size; i += 4096) {
page = __new_page(mm);
pte = __get_virtual(mm, pml4t, addr + i, true);
if (pte && page) {
__clear_page(BANE + page);
*pte = page | ((prot & PROT_WRITE) ? PAGE_RW : 0) | PAGE_U | PAGE_V;
} else {
addr = -1;
break;
}
}
res.addr = (void *)addr;
res.maphandle = -1;
return res;
}

View file

@ -24,7 +24,7 @@
#include "libc/nt/memory.h"
#include "libc/nt/runtime.h"
#include "libc/nt/struct/overlapped.h"
#include "libc/runtime/directmap.h"
#include "libc/runtime/directmap.internal.h"
#include "libc/sysv/consts/map.h"
#include "libc/sysv/consts/prot.h"

View file

@ -18,7 +18,7 @@
*/
#include "libc/calls/internal.h"
#include "libc/nt/runtime.h"
#include "libc/runtime/directmap.h"
#include "libc/runtime/directmap.internal.h"
/**
* Obtains memory mapping directly from system.
@ -28,11 +28,13 @@
* bypassed by calling this function. However the caller is responsible
* for passing the magic memory handle on Windows NT to CloseHandle().
*/
noasan struct DirectMap __mmap(void *addr, size_t size, int prot, int flags,
int fd, int64_t off) {
if (!IsWindows()) {
return (struct DirectMap){sys_mmap(addr, size, prot, flags, fd, off, off),
noasan struct DirectMap sys_mmap(void *addr, size_t size, int prot, int flags,
int fd, int64_t off) {
if (!IsWindows() && !IsMetal()) {
return (struct DirectMap){__sys_mmap(addr, size, prot, flags, fd, off, off),
kNtInvalidHandleValue};
} else if (IsMetal()) {
return sys_mmap_metal(addr, size, prot, flags, fd, off);
} else {
return sys_mmap_nt(addr, size, prot, flags,
fd != -1 ? g_fds.p[fd].handle : kNtInvalidHandleValue,

View file

@ -8,8 +8,10 @@ struct DirectMap {
int64_t maphandle;
};
struct DirectMap __mmap(void *, size_t, int, int, int, int64_t);
struct DirectMap sys_mmap(void *, size_t, int, int, int, int64_t);
struct DirectMap sys_mmap_nt(void *, size_t, int, int, int64_t, int64_t);
struct DirectMap sys_mmap_metal(void *, size_t, int, int, int, int64_t);
int sys_munmap_metal(void *, size_t);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */

View file

@ -0,0 +1,21 @@
#ifndef COSMOPOLITAN_LIBC_RUNTIME_E820_H_
#define COSMOPOLITAN_LIBC_RUNTIME_E820_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
struct SmapEntry {
uint64_t addr;
uint64_t size;
enum {
kMemoryUsable = 1,
kMemoryUnusable = 2,
kMemoryAcpiReclaimable = 3,
kMemoryAcpiNvs = 4,
kMemoryBad = 5
} type;
uint32_t acpi3;
};
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_RUNTIME_E820_H_ */

View file

@ -16,17 +16,23 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/efi.h"
#include "libc/bits/bits.h"
#include "libc/dce.h"
#include "libc/macros.h"
#include "libc/nt/efi.h"
#include "libc/nt/thunk/msabi.h"
#include "libc/runtime/e820.internal.h"
#include "libc/runtime/internal.h"
#include "libc/runtime/pc.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
/* TOOD: Why can't we change CR3? Could it really need PML5T? */
/* TOOD: Why does QEMU in UEFI mode take ten seconds to boot? */
struct EfiArgs {
char *args[4096];
char argblock[ARG_MAX];
char *Args[0x400 / sizeof(char *)];
char ArgBlock[0xC00];
};
static const EFI_GUID kEfiLoadedImageProtocol = LOADED_IMAGE_PROTOCOL;
@ -36,15 +42,14 @@ static const EFI_GUID kEfiLoadedImageProtocol = LOADED_IMAGE_PROTOCOL;
*
* This entrypoint is mutually exclusive from WinMain since
* Windows apps and EFI apps use the same PE binary format.
* By default, we build binaries to support Windows. If you
* want to your APE executable to boot on UEFI instead then
* you need to run the following build command:
* So if you want to trade away Windows so that you can use
* UEFI instead of the normal BIOS boot process, do this:
*
* make -j8 CPPFLAGS=-DSUPPORT_VECTOR=251
* STATIC_YOINK("EfiMain");
* int main() { ... }
*
* That'll remove all the Windows code and turn EFI on. You
* can also remove by BIOS code too, by changing 251 to 249
* but it shouldn't matter. Here's how to emulate EFI apps:
* You can use QEMU to test this, but please note that UEFI
* goes thousands of times slower than the normal BIOS boot
*
* qemu-system-x86_64 \
* -bios OVMF.fd \
@ -54,41 +59,129 @@ static const EFI_GUID kEfiLoadedImageProtocol = LOADED_IMAGE_PROTOCOL;
* FS0:
* deathstar.com
*
* If you're using the amalgamated release binaries then it
* should be possible to enable UEFI mode by having this at
* the top of your main source file to hint the APE linker:
*
* STATIC_YOINK("EfiMain");
* int main() { ... }
*
* @see libc/dce.h
*/
__msabi noasan EFI_STATUS EfiMain(EFI_HANDLE ImageHandle,
EFI_SYSTEM_TABLE *SystemTable) {
intptr_t argc;
struct EfiArgs *ea;
EFI_LOADED_IMAGE *img;
extern char os asm("__hostos");
os = UEFI;
__efi_image_handle = ImageHandle;
__efi_system_table = SystemTable;
SystemTable->BootServices->AllocatePool(EfiConventionalMemory, sizeof(*ea),
&ea);
bool ispml5t;
int type, x87cw;
struct mman *mm;
uint32_t DescVersion;
uintptr_t i, j, MapSize;
struct EfiArgs *ArgBlock;
EFI_LOADED_IMAGE *ImgInfo;
EFI_MEMORY_DESCRIPTOR *Map;
uintptr_t Args, MapKey, DescSize;
uint64_t p, pe, cr4, *m, *pd, *sp, *pml4t, *pdt1, *pdt2, *pdpt1, *pdpt2;
extern char __os asm("__hostos");
__os = METAL;
/*
* Allocates and clears PC-compatible memory and copies image.
*/
SystemTable->BootServices->AllocatePages(
EfiConventionalMemory, AllocateAddress,
MAX(2 * 1024 * 1024, 1024 * 1024 + (_end - _base)) / 4096, 0);
SystemTable->BootServices->SetMem(0, 0x80000, 0);
SystemTable->BootServices->CopyMem((void *)(1024 * 1024), _base,
_end - _base);
/*
* Converts UEFI shell arguments to argv.
*/
ArgBlock = (struct EfiArgs *)0x7e000;
SystemTable->BootServices->HandleProtocol(ImageHandle,
&kEfiLoadedImageProtocol, &img);
argc = GetDosArgv(img->LoadOptions, ea->argblock, ARG_MAX, ea->args,
ARRAYLEN(ea->args));
asm("push\t$0\n\t" /* auxv[0][1] */
"push\t$0\n\t" /* auxv[0][0] */
"push\t$0\n\t" /* envp[0] */
"sub\t%2,%%rsp\n\t"
"mov\t%%rsp,%%rdi\n\t"
"rep movsb\n\t" /* argv */
"push\t%0\n\t" /* argc */
"xor\t%%edi,%%edi\n\t"
".weak\t_start\n\t"
"jmp\t_start"
: /* no outputs */
: "a"(argc), "S"(ea->args), "c"((argc + 1) * 8));
&kEfiLoadedImageProtocol, &ImgInfo);
Args = GetDosArgv(ImgInfo->LoadOptions, ArgBlock->ArgBlock,
sizeof(ArgBlock->ArgBlock), ArgBlock->Args,
ARRAYLEN(ArgBlock->Args));
/*
* Asks UEFI which parts of our RAM we're allowed to use.
*/
Map = NULL;
MapSize = 0;
SystemTable->BootServices->GetMemoryMap(&MapSize, Map, &MapKey, &DescSize,
&DescVersion);
SystemTable->BootServices->AllocatePool(EfiLoaderData, MapSize, Map);
SystemTable->BootServices->GetMemoryMap(&MapSize, Map, &MapKey, &DescSize,
&DescVersion);
asm("xor\t%0,%0" : "=r"(mm)); /* gcc assumes null isn't mapped */
for (j = i = 0; i < MapSize / sizeof(EFI_MEMORY_DESCRIPTOR); ++i) {
if (Map[i].Type != EfiConventionalMemory) continue;
mm->e820[j].addr = Map[i].PhysicalStart;
mm->e820[j].size = Map[i].NumberOfPages * 4096;
mm->e820[j].type = kMemoryUsable;
++j;
}
SystemTable->BootServices->FreePool(Map);
/*
* Sets up page tables.
*/
pd = (uint64_t *)0x79000;
pdt1 = (uint64_t *)0x7b000;
pdt2 = (uint64_t *)0x7a000;
pdpt1 = (uint64_t *)0x7d000;
pdpt2 = (uint64_t *)0x7c000;
pml4t = (uint64_t *)0x7e000;
for (i = 0; i < 512; ++i) {
pd[i] = 0x1000 * i + PAGE_V + PAGE_RW;
}
pdt1[0] = (intptr_t)pd + PAGE_V + PAGE_RW;
pdt2[0] = (intptr_t)pd + PAGE_V + PAGE_RW;
pdpt1[0] = (intptr_t)pdt1 + PAGE_V + PAGE_RW;
pdpt2[0] = (intptr_t)pdt2 + PAGE_V + PAGE_RW;
pml4t[0] = (intptr_t)pdpt1 + PAGE_V + PAGE_RW;
pml4t[256] = (intptr_t)pdpt2 + PAGE_V + PAGE_RW;
__map_phdrs(mm, pml4t, 1024 * 1024);
/*
* Asks UEFI to handover control?
*/
SystemTable->BootServices->ExitBootServices(ImageHandle, MapKey);
/*
* Launches program.
*/
asm volatile("fldcw\t%3\n\t"
"mov\t%4,%%cr3\n\t"
".weak\tape_stack_vaddr\n\t"
".weak\tape_stack_memsz\n\t"
"movabs\t$ape_stack_vaddr,%%rsp\n\t"
"add\t$ape_stack_memsz,%%rsp\n\t"
"push\t$0\n\t" /* auxv[1][1] */
"push\t$0\n\t" /* auxv[1][0] */
"push\t(%1)\n\t" /* auxv[0][1] */
"push\t$31\n\t" /* auxv[0][0] AT_EXECFN */
"push\t$0\n\t" /* envp[0] */
"sub\t%2,%%rsp\n\t"
"mov\t%%rsp,%%rdi\n\t"
"rep movsb\n\t" /* argv */
"push\t%0\n\t" /* argc */
"xor\t%%edi,%%edi\n\t"
"xor\t%%eax,%%eax\n\t"
"xor\t%%ebx,%%ebx\n\t"
"xor\t%%ecx,%%ecx\n\t"
"xor\t%%edx,%%edx\n\t"
"xor\t%%edi,%%edi\n\t"
"xor\t%%esi,%%esi\n\t"
"xor\t%%ebp,%%ebp\n\t"
"xor\t%%r8d,%%r8d\n\t"
"xor\t%%r9d,%%r9d\n\t"
"xor\t%%r10d,%%r10d\n\t"
"xor\t%%r11d,%%r11d\n\t"
"xor\t%%r12d,%%r12d\n\t"
"xor\t%%r13d,%%r13d\n\t"
"xor\t%%r14d,%%r14d\n\t"
"xor\t%%r15d,%%r15d\n\t"
".weak\t_start\n\t"
"jmp\t_start"
: /* no outputs */
: "a"(Args), "S"(ArgBlock->Args), "c"((Args + 1) * 8),
"m"(x87cw), "r"(pml4t)
: "memory");
unreachable;
}

View file

@ -20,8 +20,8 @@
#include "libc/runtime/internal.h"
#include "libc/runtime/runtime.h"
extern const uintptr_t __fini_array_start[];
extern const uintptr_t __fini_array_end[];
extern const uintptr_t __fini_array_start[] __attribute__((__weak__));
extern const uintptr_t __fini_array_end[] __attribute__((__weak__));
/**
* Exits process with grace.
@ -39,7 +39,7 @@ wontreturn void exit(int exitcode) {
if (weaken(__cxa_finalize)) {
weaken(__cxa_finalize)(NULL);
}
for (p = *weaken(__fini_array_end); p > *weaken(__fini_array_start);) {
for (p = __fini_array_end; p > __fini_array_start;) {
((void (*)(void))(*--p))();
}
_Exit(exitcode);

View file

@ -21,11 +21,14 @@
/**
* Terminates process, ignoring destructors and atexit() handlers.
*
* @param rc is exit code [0,256)
* When running on bare metal, this function will reboot your computer
* by hosing the interrupt descriptors and triple faulting the system.
*
* @param exitcode is masked with 255
* @asyncsignalsafe
* @vforksafe
* @noreturn
*/
wontreturn void _exit(int rc) {
_Exit(rc);
wontreturn void _exit(int exitcode) {
_Exit(exitcode);
}

View file

@ -16,29 +16,36 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/efi.h"
#include "libc/calls/internal.h"
#include "libc/dce.h"
#include "libc/nexgen32e/vendor.internal.h"
#include "libc/nt/runtime.h"
#include "libc/runtime/runtime.h"
#include "libc/nt/thunk/msabi.h"
#include "libc/sysv/consts/nr.h"
/**
* Terminates process, ignoring destructors and atexit() handlers.
*
* @param rc is exit code [0,256)
* When running on bare metal, this function will reboot your computer
* by hosing the interrupt descriptors and triple faulting the system.
*
* @param exitcode is masked with 255
* @asyncsignalsafe
* @vforksafe
* @noreturn
*/
wontreturn void _Exit(int rc) {
if ((!IsWindows() && !IsMetal() && !IsUefi()) ||
(IsMetal() && IsGenuineCosmo())) {
sys_exit(rc);
} else if (IsUefi()) {
__efi_system_table->BootServices->Exit(__efi_image_handle, rc, 0, NULL);
privileged wontreturn void _Exit(int exitcode) {
if ((!IsWindows() && !IsMetal()) || (IsMetal() && IsGenuineCosmo())) {
asm volatile("syscall"
: /* no outputs */
: "a"(__NR_exit_group), "D"(exitcode)
: "memory");
} else if (IsWindows()) {
ExitProcess(rc & 0xff);
extern void(__msabi * __imp_ExitProcess)(uint32_t);
__imp_ExitProcess(exitcode & 0xff);
}
triplf();
asm("push\t$0\n\t"
"cli\n\t"
"lidt\t(%rsp)");
for (;;) asm("ud2");
}

View file

@ -36,7 +36,7 @@
#include "libc/nt/signals.h"
#include "libc/nt/synchronization.h"
#include "libc/nt/thread.h"
#include "libc/runtime/directmap.h"
#include "libc/runtime/directmap.internal.h"
#include "libc/runtime/memtrack.h"
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"

View file

@ -1,7 +1,7 @@
/*-*- 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
Copyright 2021 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
@ -16,21 +16,65 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "ape/lib/pc.h"
#include "ape/relocations.h"
#include "libc/nexgen32e/uart.internal.h"
#include "libc/runtime/pc.internal.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_REAL + a) | k;
#define PUTC(C) \
do { \
while (!(inb(0x3F8 + UART_LSR) & UART_TTYTXR)) { \
asm("pause"); \
} \
outb(0x3F8, C); \
} while (0)
/**
* Prints string to serial port.
*
* This only supports %d and %s. It'll will work even if .rodata hasn't
* been loaded into memory yet.
*/
hidden textreal void(MetalPrintf)(const char *fmt, ...) {
int i;
char c;
unsigned u;
va_list va;
const char *s;
unsigned long d;
va_start(va, fmt);
for (;;) {
switch ((c = *fmt++)) {
case '\0':
va_end(va);
return;
case '%':
switch ((c = *fmt++)) {
case 's':
for (s = va_arg(va, const char *); s && *s; ++s) {
PUTC(*s);
}
break;
case 'd':
d = va_arg(va, unsigned long);
for (i = 16; i--;) {
u = (d >> (i * 4)) & 0xf;
if (u < 10) {
c = '0' + u;
} else {
u -= 10;
c = 'a' + u;
}
PUTC(c);
}
break;
default:
PUTC(c);
break;
}
break;
default:
PUTC(c);
break;
}
}
}
textreal void __map_image(void) {
__map_segment(PAGE_V | PAGE_U, 0, (uintptr_t)_etext - IMAGE_BASE_VIRTUAL);
__map_segment(PAGE_V | PAGE_U | PAGE_RW,
(uintptr_t)_etext - IMAGE_BASE_VIRTUAL,
(uintptr_t)_end - IMAGE_BASE_VIRTUAL);
}

View file

@ -0,0 +1,16 @@
#ifndef COSMOPOLITAN_LIBC_RUNTIME_METALPRINTF_H_
#define COSMOPOLITAN_LIBC_RUNTIME_METALPRINTF_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
void MetalPrintf(const char *, ...);
#define MetalPrintf(FMT, ...) \
do { \
const char StackFmt[] = FMT; \
MetalPrintf(StackFmt, ##__VA_ARGS__); \
} while (0)
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_RUNTIME_METALPRINTF_H_ */

View file

@ -1,5 +1,5 @@
/*-*- 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
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
@ -30,29 +30,131 @@
αcτµαlly pδrταblε εxεcµταblε § green energy
αcτµαlly pδrταblε εxεcµταblε § no-frills virtual memory management
*/
#ifndef APE_LIB_APM_H_
#define APE_LIB_APM_H_
#include "ape/relocations.h"
#include "libc/elf/def.h"
#include "libc/elf/struct/phdr.h"
#include "libc/macros.h"
#include "libc/nexgen32e/uart.internal.h"
#include "libc/runtime/e820.internal.h"
#include "libc/runtime/metalprintf.internal.h"
#include "libc/runtime/pc.internal.h"
#include "libc/runtime/runtime.h"
/**
* @fileoverview Advanced Power Management.
*
* <p>APM is useful for exiting programs, without needing to ask the
* human to flip a physical switch or pass QEMU's -no-reboot flag.
*
* <p><b>Implementation Detail:</b> Supporting ACPI would literally
* require implementing a programming language.
*
* @see APM BIOS Interface Specification v1.2
* @since IBM PC/AT
* Allocates new page of physical memory.
*/
noasan texthead uint64_t __new_page(struct mman *mm) {
uint64_t p;
if (mm->pdpi == mm->e820n) {
/* TODO: reclaim free pages */
return 0;
}
while (mm->pdp >= mm->e820[mm->pdpi].addr + mm->e820[mm->pdpi].size) {
if (++mm->pdpi == mm->e820n) return 0;
mm->pdp = mm->e820[mm->pdpi].addr;
}
p = mm->pdp;
mm->pdp += 4096;
return p;
}
#define APM_SERVICE 0x15
/**
* Returns pointer to page table entry for page at virtual address.
* Additional page tables are allocated if needed as a side-effect.
*/
noasan texthead uint64_t *__get_virtual(struct mman *mm, uint64_t *t,
int64_t vaddr, bool maketables) {
uint64_t *e, p;
unsigned char h;
for (h = 39;; h -= 9) {
e = t + ((vaddr >> h) & 511);
if (h == 12) return e;
if (!(*e & PAGE_V)) {
if (!maketables) return NULL;
if (!(p = __new_page(mm))) return NULL;
*e = p | PAGE_V | PAGE_RW;
}
t = (uint64_t *)(BANE + (*e & PAGE_TA));
}
}
#if !(__ASSEMBLER__ + __LINKER__ + 0)
/**
* Sorts, rounds, and filters BIOS memory map.
*/
static noasan texthead void __normalize_e820(struct mman *mm) {
uint64_t a, b;
uint64_t x, y;
unsigned i, j, n;
for (n = i = 0; mm->e820[i].size; ++i) {
mm->e820[n] = mm->e820[i];
x = mm->e820[n].addr;
y = mm->e820[n].addr + mm->e820[n].size;
a = ROUNDUP(x, 4096);
b = ROUNDDOWN(y, 4096) - a;
if (b > 0 && mm->e820[i].type == kMemoryUsable) {
mm->e820[n].addr = a;
mm->e820[n].size = b;
++n;
}
}
for (i = 1; i < n; ++i) {
for (j = i; j > 0 && mm->e820[i].addr < mm->e820[j - 1].addr; --j) {
mm->e820[j] = mm->e820[j - 1];
}
mm->e820[j] = mm->e820[i];
}
mm->pdp = MAX(0x80000, mm->e820[0].addr);
mm->pdpi = 0;
mm->e820n = n;
}
void apmoff(void) wontreturn;
/**
* Identity maps all usable physical memory to its negative address.
*/
static noasan texthead void __invert_memory(struct mman *mm, uint64_t *pml4t) {
uint64_t i, j, *m, p, pe;
for (i = 0; i < mm->e820n; ++i) {
for (p = mm->e820[i].addr, pe = mm->e820[i].addr + mm->e820[i].size;
p + 0x200000 < pe; p += 4096) {
m = __get_virtual(mm, pml4t, BANE + p, true);
if (m && !(*m & PAGE_V)) {
*m = p | PAGE_V | PAGE_RW;
}
}
}
}
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* APE_LIB_APM_H_ */
noasan texthead void __setup_mman(struct mman *mm, uint64_t *pml4t) {
__normalize_e820(mm);
__invert_memory(mm, pml4t);
}
/**
* Maps APE-defined ELF program headers into memory and clears BSS.
*/
noasan textreal void __map_phdrs(struct mman *mm, uint64_t *pml4t, uint64_t b) {
struct Elf64_Phdr *p;
uint64_t i, f, v, m, *e;
extern char ape_phdrs[] __attribute__((__weak__));
extern char ape_phdrs_end[] __attribute__((__weak__));
__setup_mman(mm, pml4t);
for (p = (struct Elf64_Phdr *)REAL(ape_phdrs), m = 0;
p < (struct Elf64_Phdr *)REAL(ape_phdrs_end); ++p) {
if (p->p_type == PT_LOAD || p->p_type == PT_GNU_STACK) {
f = PAGE_V | PAGE_U;
if (p->p_flags & PF_W) f |= PAGE_RW;
for (i = 0; i < p->p_memsz; i += 4096) {
if (i < p->p_filesz) {
v = b + p->p_offset + i;
m = MAX(m, v);
} else {
v = __clear_page(__new_page(mm));
}
*__get_virtual(mm, pml4t, p->p_vaddr + i, true) = (v & PAGE_TA) | f;
}
}
}
mm->pdp = MAX(mm->pdp, m);
}

View file

@ -0,0 +1,24 @@
#ifndef COSMOPOLITAN_LIBC_RUNTIME_MMAN_H_
#define COSMOPOLITAN_LIBC_RUNTIME_MMAN_H_
#include "libc/runtime/e820.internal.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
struct mman {
int64_t pdp; /* 0x0500 */
int32_t pdpi; /* 0x0508 */
int32_t e820n; /* 0x050a */
struct SmapEntry e820[256]; /* 0x0510 */
char pc_drive_base_table[11]; /* 0x1510 */
unsigned char pc_drive_type; /* 0x151b */
unsigned char pc_drive_last_sector; /* 0x151c */
unsigned short pc_drive_last_cylinder; /* 0x151d */
unsigned char pc_drives_attached; /* 0x151f */
unsigned char pc_drive_last_head; /* 0x1520 */
unsigned char pc_drive; /* 0x1521 */
char bad_idt[6]; /* 0x1522 */
};
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_RUNTIME_MMAN_H_ */

View file

@ -24,7 +24,7 @@
#include "libc/intrin/asan.internal.h"
#include "libc/macros.h"
#include "libc/rand/rand.h"
#include "libc/runtime/directmap.h"
#include "libc/runtime/directmap.internal.h"
#include "libc/runtime/memtrack.h"
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
@ -87,10 +87,10 @@ void *mmap(void *addr, size_t size, int prot, int flags, int fd, int64_t off) {
}
f = flags | MAP_FIXED;
if (IsOpenbsd() && (f & MAP_GROWSDOWN)) { /* openbsd:dubstack */
dm = __mmap(addr, size, prot, f & ~MAP_GROWSDOWN, fd, off);
dm = sys_mmap(addr, size, prot, f & ~MAP_GROWSDOWN, fd, off);
if (dm.addr == MAP_FAILED) return MAP_FAILED;
}
dm = __mmap(addr, size, prot, f, fd, off);
dm = sys_mmap(addr, size, prot, f, fd, off);
if (dm.addr == MAP_FAILED || dm.addr != addr) {
return MAP_FAILED;
}

View file

@ -16,8 +16,18 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/efi.h"
#include "libc/nt/efi.h"
#include "libc/runtime/directmap.internal.h"
#include "libc/runtime/pc.internal.h"
EFI_HANDLE __efi_image_handle;
EFI_SYSTEM_TABLE *__efi_system_table;
int sys_munmap_metal(void *addr, size_t size) {
size_t i;
uint64_t *e;
struct mman *mm;
mm = (struct mman *)(BANE + 0x0500);
for (i = 0; i < size; i += 4096) {
e = __get_virtual(mm, __get_pml4t(), (uint64_t)addr + i, false);
if (e) *e = ~PAGE_V;
invlpg(e);
}
return 0;
}

View file

@ -19,6 +19,7 @@
#include "libc/calls/internal.h"
#include "libc/dce.h"
#include "libc/macros.h"
#include "libc/runtime/directmap.internal.h"
#include "libc/runtime/memtrack.h"
#include "libc/runtime/runtime.h"
#include "libc/sysv/errfuns.h"
@ -46,5 +47,6 @@ int munmap(void *addr, size_t size) {
if (!ALIGNED(addr) || !CANONICAL(addr) || !size) return einval();
if (UntrackMemoryIntervals(addr, size) == -1) return -1;
if (IsWindows()) return 0;
if (IsMetal()) sys_munmap_metal(addr, size);
return sys_munmap(addr, size);
}

View file

@ -32,9 +32,12 @@
αcτµαlly pδrταblε εxεcµταblε § ibm personal computer
*/
#ifndef APE_LIB_PC_H_
#define APE_LIB_PC_H_
#ifndef COSMOPOLITAN_LIBC_RUNTIME_PC_H_
#define COSMOPOLITAN_LIBC_RUNTIME_PC_H_
#include "libc/runtime/e820.internal.h"
#include "libc/runtime/mman.internal.h"
#define BANE -140737488355328
#define BOOTSIG 0xaa55 /* master boot record signature */
#define PC_BIOS_DATA_AREA 0x400
@ -154,35 +157,13 @@
#define PAGE_4KB /* */ 0b010000000
#define PAGE_2MB /* */ 0b110000000
#define PAGE_1GB /* */ 0b110000000
#define PAGE_TA 0b11111111111111111111111111111111111111000000000000
#define PAGE_PA2 0b11111111111111111111111111111000000000000000000000
#define PAGE_TA 0x00007ffffffff000
#define PAGE_PA2 0x00007fffffe00000
#define PAGE_XD 0x8000000000000000
#if !(__ASSEMBLER__ + __LINKER__ + 0)
#include "ape/config.h"
struct thatispacked GlobalDescriptorTable {
uint16_t size;
uint64_t *entries;
};
/**
* Memory hole map.
* @see wiki.osdev.org/Detecting_Memory_(x86)
* @since 2002
*/
struct SmapEntry {
uint64_t addr;
uint64_t size;
enum {
kMemoryUsable = 1,
kMemoryUnusable = 2,
kMemoryAcpiReclaimable = 3,
kMemoryAcpiNvs = 4,
kMemoryBad = 5
} type;
uint32_t __acpi3; /* is abstracted */
};
#define invlpg(p) asm volatile("invlpg\t(%0)" : : "r"(p) : "memory")
struct IdtDescriptor {
uint16_t offset_1; /* offset bits 0..15 */
@ -194,37 +175,10 @@ struct IdtDescriptor {
uint32_t zero; /* reserved */
};
struct thatispacked PageTable {
uint64_t p[512];
} forcealign(PAGESIZE);
extern struct PageTable g_pml4t;
extern struct GlobalDescriptorTable gdt;
extern const unsigned char kBiosDataArea[256];
extern const unsigned char kBiosDataAreaXlm[256];
extern struct SmapEntry e820map[XLM_E820_SIZE / sizeof(struct SmapEntry)];
extern struct SmapEntry e820map_xlm[XLM_E820_SIZE / sizeof(struct SmapEntry)];
extern uint64_t g_ptsp;
extern uint64_t g_ptsp_xlm;
void bootdr(char drive) wontreturn;
void smapsort(struct SmapEntry *);
uint64_t *__getpagetableentry(int64_t, unsigned, struct PageTable *,
uint64_t *);
void flattenhighmemory(struct SmapEntry *, struct PageTable *, uint64_t *);
void pageunmap(int64_t);
forceinline unsigned long eflags(void) {
unsigned long res;
asm("pushf\n\t"
"pop\t%0"
: "=rm"(res));
return res;
}
uint64_t *__get_virtual(struct mman *, uint64_t *, int64_t, bool);
uint64_t __clear_page(uint64_t);
uint64_t __new_page(struct mman *);
void __map_phdrs(struct mman *, uint64_t *, uint64_t);
forceinline unsigned char inb(unsigned short port) {
unsigned char al;
@ -238,5 +192,22 @@ forceinline void outb(unsigned short port, unsigned char byte) {
: "a"(byte), "dN"(port));
}
#define __clear_page(page) \
({ \
long di, cx; \
uintptr_t Page = (uintptr_t)(page); \
asm("rep stosb" \
: "=D"(di), "=c"(cx), "=m"(*(char(*)[4096])Page) \
: "0"(Page), "1"(4096), "a"(0)); \
Page; \
})
#define __get_pml4t() \
({ \
intptr_t cr3; \
asm("mov\t%%cr3,%0" : "=r"(cr3)); \
(uint64_t *)(BANE + cr3); \
})
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* APE_LIB_PC_H_ */
#endif /* COSMOPOLITAN_LIBC_RUNTIME_PC_H_ */

View file

@ -76,6 +76,10 @@ o/$(MODE)/libc/runtime/winmain.greg.o: \
OVERRIDE_CFLAGS += \
$(NO_MAGIC)
o/$(MODE)/libc/runtime/mman.greg.o: \
OVERRIDE_CFLAGS += \
-ffreestanding
o/$(MODE)/libc/runtime/ftrace.greg.o: \
OVERRIDE_CFLAGS += \
-mgeneral-regs-only

View file

@ -36,7 +36,7 @@
#include "libc/nt/process.h"
#include "libc/nt/runtime.h"
#include "libc/nt/struct/teb.h"
#include "libc/runtime/directmap.h"
#include "libc/runtime/directmap.internal.h"
#include "libc/runtime/internal.h"
#include "libc/runtime/memtrack.h"
#include "libc/runtime/runtime.h"
@ -74,7 +74,7 @@ static noasan textwindows void NormalizeCmdExe(int version) {
hstdout = GetStdHandle(pushpop(kNtStdOutputHandle));
hstderr = GetStdHandle(pushpop(kNtStdErrorHandle));
if (GetFileType((handle = hstdin)) == kNtFileTypeChar) {
SetTrueColor();
/* SetTrueColor(); */
SetConsoleCP(kNtCpUtf8);
GetConsoleMode(handle, &mode);
SetConsoleMode(handle, mode | kNtEnableProcessedInput |
@ -84,7 +84,7 @@ static noasan textwindows void NormalizeCmdExe(int version) {
}
if (GetFileType((handle = hstdout)) == kNtFileTypeChar ||
GetFileType((handle = hstderr)) == kNtFileTypeChar) {
SetTrueColor();
/* SetTrueColor(); */
SetConsoleOutputCP(kNtCpUtf8);
GetConsoleMode(handle, &mode);
SetConsoleMode(

View file

@ -0,0 +1,2 @@
.include "o/libc/sysv/macros.internal.inc"
.scall __sys_mmap,0x0c50c51dd20c5009,globl,hidden

View file

@ -1,2 +0,0 @@
.include "o/libc/sysv/macros.internal.inc"
.scall sys_mmap,0x0c50c51dd20c5009,globl,hidden

View file

@ -44,7 +44,7 @@ scall __sys_lstat 0x1b90280282154006 globl hidden # needs __stat2linux(); block
scall sys_poll 0x0d10fc0d120e6007 globl hidden
scall sys_ppoll 0xfff06d221ffff10f globl hidden # consider INTON/INTOFF tutorial in examples/unbourne.c
scall sys_lseek 0x0c70c71de20c7008 globl hidden # netbsd+openbsd:evilpad
scall sys_mmap 0x0c50c51dd20c5009 globl hidden # netbsd+openbsd:pad
scall __sys_mmap 0x0c50c51dd20c5009 globl hidden # netbsd+openbsd:pad
scall sys_msync 0x115100041204101a globl hidden
scall sys_mprotect 0x04a04a04a204a00a globl hidden
scall sys_munmap 0x049049049204900b globl hidden

View file

@ -104,7 +104,7 @@ __systemfive:
.privileged
.Lanchorpoint:
#if SupportsLinux() || SupportsMetal() || SupportsUefi()
#if SupportsLinux() || SupportsMetal()
systemfive_linux:
and $0xfff,%eax
cmp $0xfff,%eax
@ -198,10 +198,6 @@ systemfive_xnu:
testb $XNU,(%rdi) # @see libc/crt/crt.S
jnz _init_systemfive_xnu
#endif
#if SupportsUefi()
testb $UEFI,(%rdi) # @see ape/ape.S
jnz _init_systemfive_uefi
#endif
#if SupportsMetal()
testb $METAL,(%rdi) # @see ape/ape.S
jnz _init_systemfive_metal
@ -240,13 +236,6 @@ _init_systemfive_metal:
ezlea syscon_linux,si
jmp _init_systemfive_os
#endif
#if SupportsUefi()
_init_systemfive_uefi:
pushb systemfive_linux-.Lanchorpoint
push $UEFI
ezlea syscon_linux,si
jmp _init_systemfive_os
#endif
#if SupportsWindows()
_init_systemfive_windows:
pushb systemfive_enosys-.Lanchorpoint
@ -323,20 +312,22 @@ _init_systemfive_magnums:
// 𝑠𝑙𝑖𝑑𝑒
#if SupportsSystemv() && !defined(TINY)
_init_systemfive_stack: # determinism ftw!
#if SupportsWindows() || SupportsMetal() || SupportsUefi()
testb $WINDOWS|METAL|UEFI,__hostos(%rip)
#if SupportsWindows() || SupportsMetal()
testb $WINDOWS|METAL,__hostos(%rip)
jnz _init_systemfive_done
#endif
push %rdi
push %rsi
mov __NR_mmap,%eax
mov $0x700000000000-STACKSIZE,%rdi
mov $STACKSIZE,%esi
movabs $ape_stack_vaddr,%rdi
mov $ape_stack_memsz,%esi
mov $PROT_READ|PROT_WRITE,%edx
mov $MAP_PRIVATE|MAP_FIXED,%r10d
or MAP_ANONYMOUS,%r10d
or $-1,%r8d
xor %r9d,%r9d
push %rdi # vaddr of stack
push %rsi # size of stack
push %r9 # openbsd:pad
push %r9 # openbsd:align
#if SupportsOpenbsd()
@ -351,6 +342,8 @@ _init_systemfive_stack: # determinism ftw!
syscall
pop %r9
pop %r9
pop %r9 # size of stack
pop %r11 # vaddr of stack
jnc 2f
1: mov %eax,%edi
mov __NR_exit_group,%eax
@ -360,17 +353,23 @@ _init_systemfive_stack: # determinism ftw!
.weak _mmi
ezlea _mmi,cx
test %rcx,%rcx
push %r9 # save the stack size
jz 3f
lea -1(%r11,%r9),%r9 # need incl. interval
shr $16,%r11 # for the stack range
shr $16,%r9
movb $1,(%rcx) # _mmi.i
movl $(0x700000000000-STACKSIZE)>>16,8(%rcx) # _mmi.p[0].x
movl $(0x700000000000-1)>>16,12(%rcx) # _mmi.p[0].y
mov %r11d,8(%rcx) # _mmi.p[0].x
mov %r9d,12(%rcx) # _mmi.p[0].y
mov %edx,20(%rcx) # _mmi.p[0].prot
mov %r10d,24(%rcx) # _mmi.p[0].flags
3: pop %rsi
3: pop %r9 # restore stack size
pop %rsi
pop %rdi
leave
pop %rcx
lea STACKSIZE-16(%rax),%rsp # openbsd:stackbound
lea (%rax,%r9),%rsp
sub $ape_stack_align,%rsp # openbsd:stackbound
mov %rbp,(%rsp)
push %rcx
push %rbp
@ -414,7 +413,7 @@ syscon_end:
.type syscon_end,@object
.globl syscon_start
.globl syscon_end
#if SupportsLinux() || SupportsMetal() || SupportsUefi()
#if SupportsLinux() || SupportsMetal()
.section .sort.rodata.syscon.linux.1,"a",@progbits
.align 1
syscon_linux:/*
@ -468,3 +467,7 @@ syscon_windows:/*
.type syscon_windows,@object
.globl syscon_windows
#endif
.weak ape_stack_vaddr
.weak ape_stack_memsz
.weak ape_stack_align

View file

@ -78,7 +78,6 @@ LIBC_TESTLIB_A_OBJS = \
$(LIBC_TESTLIB_A_ASSETS:%=o/$(MODE)/%.zip.o)
LIBC_TESTLIB_A_DIRECTDEPS = \
APE_LIB \
LIBC_ALG \
LIBC_CALLS \
LIBC_FMT \

View file

@ -16,7 +16,7 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "ape/lib/pc.h"
#include "libc/runtime/pc.internal.h"
#include "libc/macros.h"
.source __FILE__

View file

@ -16,7 +16,7 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "ape/lib/pc.h"
#include "libc/runtime/pc.internal.h"
#include "libc/macros.h"
.source __FILE__

View file

@ -16,7 +16,7 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "ape/lib/pc.h"
#include "libc/runtime/pc.internal.h"
#include "libc/macros.h"
.source __FILE__

View file

@ -16,7 +16,7 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "ape/lib/pc.h"
#include "libc/runtime/pc.internal.h"
#include "libc/macros.h"
.source __FILE__

View file

@ -16,7 +16,7 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "ape/lib/pc.h"
#include "libc/runtime/pc.internal.h"
#include "libc/macros.h"
.source __FILE__

View file

@ -16,7 +16,7 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "ape/lib/pc.h"
#include "libc/runtime/pc.internal.h"
#include "libc/macros.h"
// Rounds to nearest integer, away from zero.

View file

@ -16,7 +16,7 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "ape/lib/pc.h"
#include "libc/runtime/pc.internal.h"
#include "libc/macros.h"
.source __FILE__

View file

@ -16,7 +16,7 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "ape/lib/pc.h"
#include "libc/runtime/pc.internal.h"
#include "libc/macros.h"
.source __FILE__

View file

@ -27,7 +27,6 @@ LIBC_ZIPOS_A_CHECKS = \
$(LIBC_ZIPOS_A_HDRS:%=o/$(MODE)/%.ok)
LIBC_ZIPOS_A_DIRECTDEPS = \
APE_LIB \
LIBC_CALLS \
LIBC_MEM \
LIBC_NEXGEN32E \

View file

@ -1,65 +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 "ape/lib/pc.h"
#include "libc/mem/mem.h"
#include "libc/runtime/gc.h"
#include "libc/str/str.h"
#include "libc/testlib/testlib.h"
TEST(getpagetableentry, testLowestAddress) {
static struct PageTable pml4t;
static struct PageTable stack[3];
uint64_t ptsp = (uintptr_t)&stack + sizeof(stack);
memset(&pml4t, 0, sizeof(pml4t));
memset(&stack, 0, sizeof(stack));
uint64_t vaddr = 0;
uint64_t paddr = 0x31337000;
*__getpagetableentry(vaddr, 3, &pml4t, &ptsp) = paddr | PAGE_V;
EXPECT_EQ(&stack[2].p[0], pml4t.p[0] & PAGE_TA); /* pml4t → pdpt */
EXPECT_EQ(&stack[1].p[0], stack[2].p[0] & PAGE_TA); /* pdpt → pdt */
EXPECT_EQ(&stack[0].p[0], stack[1].p[0] & PAGE_TA); /* pdt → pd */
EXPECT_EQ(stack[0].p[0] & PAGE_TA, paddr); /* page */
EXPECT_EQ(&stack, ptsp);
EXPECT_TRUE(pml4t.p[0] & PAGE_V);
EXPECT_TRUE(stack[2].p[0] & PAGE_V);
EXPECT_TRUE(stack[1].p[0] & PAGE_V);
EXPECT_TRUE(stack[0].p[0] & PAGE_V);
EXPECT_FALSE(stack[0].p[1] & PAGE_V);
}
TEST(getpagetableentry, testHigherAddress) {
static struct PageTable pml4t;
static struct PageTable stack[3];
uint64_t ptsp = (uintptr_t)&stack + sizeof(stack);
memset(&pml4t, 0, sizeof(pml4t));
memset(&stack, 0, sizeof(stack));
uint64_t vaddr = 0x133731337000;
uint64_t paddr = 0x123000;
*__getpagetableentry(vaddr, 3, &pml4t, &ptsp) = paddr | PAGE_V;
EXPECT_EQ(&stack[2].p[0], pml4t.p[38] & PAGE_TA); /* pml4t → pdpt */
EXPECT_EQ(&stack[1].p[0], stack[2].p[220] & PAGE_TA); /* pdpt → pdt */
EXPECT_EQ(&stack[0].p[0], stack[1].p[393] & PAGE_TA); /* pdt → pd */
EXPECT_EQ(stack[0].p[311] & PAGE_TA, paddr); /* page */
EXPECT_EQ(&stack, ptsp);
EXPECT_TRUE(pml4t.p[38] & PAGE_V);
EXPECT_TRUE(stack[2].p[220] & PAGE_V);
EXPECT_TRUE(stack[1].p[393] & PAGE_V);
EXPECT_TRUE(stack[0].p[311] & PAGE_V);
EXPECT_FALSE(stack[0].p[0] & PAGE_V);
}

View file

@ -1,81 +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 "ape/lib/pc.h"
#include "libc/mem/mem.h"
#include "libc/str/str.h"
#include "libc/testlib/testlib.h"
TEST(smapsort, testEmpty_doesntOverrunBuffer) {
struct SmapEntry *smap = malloc(sizeof(struct SmapEntry));
memset(smap, 0, sizeof(struct SmapEntry));
smapsort(smap);
EXPECT_EQ(0, smap[0].addr);
EXPECT_EQ(0, smap[0].size);
free(smap);
}
/* TEST(smapsort, testSorted_doesNothing) { */
/* struct SmapEntry *smap = tmalloc(4 * sizeof(struct SmapEntry)); */
/* memset(smap, 0, 4 * sizeof(struct SmapEntry)); */
/* smap[0].addr = 0; */
/* smap[0].size = 0x7000; */
/* smap[0].type = kMemoryUsable; */
/* smap[1].addr = 0x7000; */
/* smap[1].size = 0x1000; */
/* smap[1].type = kMemoryUnusable; */
/* smap[2].addr = 0x14000; */
/* smap[2].size = 0x1000; */
/* smap[2].type = kMemoryBad; */
/* smapsort(smap); */
/* EXPECT_EQ(0, smap[0].addr); */
/* EXPECT_EQ(0x7000, smap[0].size); */
/* EXPECT_EQ(kMemoryUsable, smap[0].type); */
/* EXPECT_EQ(0x7000, smap[1].addr); */
/* EXPECT_EQ(0x1000, smap[1].size); */
/* EXPECT_EQ(kMemoryUnusable, smap[1].type); */
/* EXPECT_EQ(0x14000, smap[2].addr); */
/* EXPECT_EQ(0x1000, smap[2].size); */
/* EXPECT_EQ(kMemoryBad, smap[2].type); */
/* tfree(smap); */
/* } */
/* TEST(smapsort, testUnsorted_sortsByAddress) { */
/* struct SmapEntry *smap = tmalloc(4 * sizeof(struct SmapEntry)); */
/* memset(smap, 0, 4 * sizeof(struct SmapEntry)); */
/* smap[2].addr = 0; */
/* smap[2].size = 0x7000; */
/* smap[2].type = kMemoryUsable; */
/* smap[0].addr = 0x7000; */
/* smap[0].size = 0x1000; */
/* smap[0].type = kMemoryUnusable; */
/* smap[1].addr = 0x14000; */
/* smap[1].size = 0x1000; */
/* smap[1].type = kMemoryBad; */
/* smapsort(smap); */
/* EXPECT_EQ(0, smap[0].addr); */
/* EXPECT_EQ(0x7000, smap[0].size); */
/* EXPECT_EQ(kMemoryUsable, smap[0].type); */
/* EXPECT_EQ(0x7000, smap[1].addr); */
/* EXPECT_EQ(0x1000, smap[1].size); */
/* EXPECT_EQ(kMemoryUnusable, smap[1].type); */
/* EXPECT_EQ(0x14000, smap[2].addr); */
/* EXPECT_EQ(0x1000, smap[2].size); */
/* EXPECT_EQ(kMemoryBad, smap[2].type); */
/* tfree(smap); */
/* } */

View file

@ -1,55 +0,0 @@
#-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐
#───vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi───────────────────────┘
PKGS += TEST_APE_LIB
TEST_APE_LIB_SRCS := $(wildcard test/ape/lib/*.c)
TEST_APE_LIB_SRCS_TEST = $(filter %_test.c,$(TEST_APE_LIB_SRCS))
TEST_APE_LIB_OBJS = \
$(TEST_APE_LIB_SRCS:%.c=o/$(MODE)/%.o)
TEST_APE_LIB_COMS = \
$(TEST_APE_LIB_SRCS:%.c=o/$(MODE)/%.com)
TEST_APE_LIB_BINS = \
$(TEST_APE_LIB_COMS) \
$(TEST_APE_LIB_COMS:%=%.dbg)
TEST_APE_LIB_TESTS = \
$(TEST_APE_LIB_SRCS_TEST:%.c=o/$(MODE)/%.com.ok)
TEST_APE_LIB_CHECKS = \
$(TEST_APE_LIB_SRCS_TEST:%.c=o/$(MODE)/%.com.runs)
TEST_APE_LIB_DIRECTDEPS = \
APE_LIB \
LIBC_INTRIN \
LIBC_LOG \
LIBC_MEM \
LIBC_NEXGEN32E \
LIBC_RUNTIME \
LIBC_STR \
LIBC_STUBS \
LIBC_TESTLIB \
LIBC_X
TEST_APE_LIB_DEPS := \
$(call uniq,$(foreach x,$(TEST_APE_LIB_DIRECTDEPS),$($(x))))
o/$(MODE)/test/ape/lib.pkg: \
$(TEST_APE_LIB_OBJS) \
$(foreach x,$(TEST_APE_LIB_DIRECTDEPS),$($(x)_A).pkg)
o/$(MODE)/test/ape/lib/%.com.dbg: \
$(TEST_APE_LIB_DEPS) \
o/$(MODE)/test/ape/lib/%.o \
o/$(MODE)/test/ape/lib.pkg \
$(LIBC_TESTMAIN) \
$(CRT) \
$(APE)
@$(APELINK)
.PHONY: o/$(MODE)/test/ape/lib
o/$(MODE)/test/ape/lib: $(TEST_APE_LIB_BINS) \
$(TEST_APE_LIB_CHECKS)

View file

@ -1,5 +0,0 @@
#-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐
#───vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi───────────────────────┘
.PHONY: o/$(MODE)/test/ape
o/$(MODE)/test/ape: o/$(MODE)/test/ape/lib

View file

@ -2,8 +2,7 @@
#───vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi───────────────────────┘
.PHONY: o/$(MODE)/test
o/$(MODE)/test: o/$(MODE)/test/ape \
o/$(MODE)/test/dsp \
o/$(MODE)/test: o/$(MODE)/test/dsp \
o/$(MODE)/test/libc \
o/$(MODE)/test/net \
o/$(MODE)/test/tool

View file

@ -3,7 +3,7 @@
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
STATIC_YOINK("__mmap"); /* asan needs it */
STATIC_YOINK("sys_mmap"); /* asan needs it */
STATIC_YOINK("TrackMemoryInterval"); /* asan needs it */
#define ASSERT(x, y) Assert2(x, y, #y, __FILE__, __LINE__)

View file

@ -2109,9 +2109,9 @@ static void OnE820(void) {
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, m->real.n);
Write32(p + 014, 1);
Write64(p + 0, 0);
Write64(p + 8, m->real.n);
Write32(p + 16, 1);
memcpy(m->real.p + addr, p, sizeof(p));
SetWriteAddr(m, addr, sizeof(p));
Write32(m->cx, sizeof(p));
@ -2716,6 +2716,7 @@ static void Tui(void) {
ExecuteInstruction(m);
++opcount;
if (!(action & CONTINUE) || interactive) {
if (!(action & CONTINUE)) ReactiveDraw();
ScrollMemoryViews();
}
} else {
@ -2737,8 +2738,11 @@ static void Tui(void) {
} while (tuimode);
} else {
if (OnHalt(interrupt)) {
ReactiveDraw();
ScrollMemoryViews();
goto KeepGoing;
}
ReactiveDraw();
ScrollOp(&pan.disassembly, GetDisIndex());
}
TuiCleanup();

View file

@ -115,6 +115,7 @@ struct Command command;
const char *const kSafeEnv[] = {
"ADDR2LINE", // needed by GetAddr2linePath
"MAKEFLAGS", // needed by IsRunningUnderMake
"MODE", // needed by test scripts
"PATH", // needed by clang
"PWD", // just seems plain needed
"TERM", // needed by IsTerminalInarticulate

View file

@ -281,9 +281,8 @@ int main(int argc, char *argv[]) {
struct stat st;
const char *path;
if (argc == 1) {
path = "o/v127/examples/hello2.com.dbg";
/* fprintf(stderr, "USAGE: %s ELF\n", program_invocation_name); */
/* exit(1); */
fprintf(stderr, "USAGE: %s ELF\n", program_invocation_name);
exit(1);
} else {
path = argv[1];
}

View file

@ -100,6 +100,7 @@ static void DisLoadElfSyms(struct Dis *d, struct Elf *elf) {
d->syms.p[j].unique = i;
d->syms.p[j].size = st[i].st_size;
d->syms.p[j].name = st[i].st_name;
CHECK_GE(st[i].st_value, 0);
d->syms.p[j].addr = st[i].st_value;
d->syms.p[j].rank =
-islocal + -isweak + -isabs + isprotected + isobject + isfunc;
@ -112,7 +113,14 @@ static void DisLoadElfSyms(struct Dis *d, struct Elf *elf) {
}
static void DisSortSyms(struct Dis *d) {
size_t i, j;
qsort(d->syms.p, d->syms.i, sizeof(struct DisSym), (void *)DisSymCompare);
for (i = 0; i < d->syms.i; ++i) {
if (!strcmp("_end", d->syms.stab + d->syms.p[i].name)) {
d->syms.i = i;
break;
}
}
}
static void DisCanonizeSyms(struct Dis *d) {
@ -178,6 +186,10 @@ long DisFindSym(struct Dis *d, int64_t addr) {
l = m + 1;
}
}
if (r && d->syms.p[r - 1].addr < 256) {
/* XXX: prevent skewed binbase from doing weirdness */
return -1;
}
if (r && (addr == d->syms.p[r - 1].addr ||
(addr > d->syms.p[r - 1].addr &&
(addr <= d->syms.p[r - 1].addr + d->syms.p[r - 1].size ||

View file

@ -16,9 +16,8 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "ape/config.h"
#include "ape/lib/pc.h"
#include "libc/math.h"
#include "libc/runtime/pc.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
#include "tool/build/lib/case.h"
@ -988,7 +987,7 @@ static void OpFnop(struct Machine *m) {
}
void OpFinit(struct Machine *m) {
m->fpu.cw = X87_NORMAL;
m->fpu.cw = 0x037f;
m->fpu.sw = 0;
m->fpu.tw = -1;
}

View file

@ -194,6 +194,7 @@
"forcealign"
"typeof"
"textreal"
"texthead"
"autotype"
"_Section"
"_Vector_size"))

View file

@ -18,7 +18,6 @@ TOOL_NET_BINS = \
$(TOOL_NET_COMS:%=%.dbg)
TOOL_NET_DIRECTDEPS = \
APE_LIB \
LIBC_ALG \
LIBC_BITS \
LIBC_CALLS \