mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-01-31 03:27:39 +00:00
b420ed8248
This change gets the Python codebase into a state where it conforms to the conventions of this codebase. It's now possible to include headers from Python, without worrying about ordering. Python has traditionally solved that problem by "diamonding" everything in Python.h, but that's problematic since it means any change to any Python header invalidates all the build artifacts. Lastly it makes tooling not work. Since it is hard to explain to Emacs when I press C-c C-h to add an import line it shouldn't add the header that actually defines the symbol, and instead do follow the nonstandard Python convention. Progress has been made on letting Python load source code from the zip executable structure via the standard C library APIs. System calss now recognizes zip!FILENAME alternative URIs as equivalent to zip:FILENAME since Python uses colon as its delimiter. Some progress has been made on embedding the notice license terms into the Python object code. This is easier said than done since Python has an extremely complicated ownership story. - Some termios APIs have been added - Implement rewinddir() dirstream API - GetCpuCount() API added to Cosmopolitan Libc - More bugs in Cosmopolitan Libc have been fixed - zipobj.com now has flags for mangling the path - Fixed bug a priori with sendfile() on certain BSDs - Polyfill F_DUPFD and F_DUPFD_CLOEXEC across platforms - FIOCLEX / FIONCLEX now polyfilled for fast O_CLOEXEC changes - APE now supports a hybrid solution to no-self-modify for builds - Many BSD-only magnums added, e.g. O_SEARCH, O_SHLOCK, SF_NODISKIO
1607 lines
No EOL
72 KiB
ArmAsm
1607 lines
No EOL
72 KiB
ArmAsm
/*-*- 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. │
|
||
╠──────────────────────────────────────────────────────────────────────────────╣
|
||
│░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░│
|
||
│░░░░░░░█▀█░█▀█░▀█▀░█░█░█▀█░█░░░█░░░█░█░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░│
|
||
│░░░░░░░█▀█░█░▄░░█░░█░█░█▀█░█░░░█░░░▀█▀░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░│
|
||
│░░░░░░░▀░▀░▀▀▀░░▀░░▀▀▀░▀░▀░▀▀▀░▀▀▀░░▀░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░│
|
||
│░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░│
|
||
│░░░░░░░█▀█░█▀█░█▀█░▀█▀░█▀█░█▀█░█░░░█▀▀░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░│
|
||
│░░░░░░░█▀▀░█ █░██▀░░█░░█▀█░█▀█░█░░░█▀▀░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░│
|
||
│░░░░░░░▀░░░▀▀▀░▀░▀░░▀░░▀░▀░▀▀▀░▀▀▀░▀▀▀░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░│
|
||
│░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░│
|
||
│░░░░░░░█▀▀░█░█░█▀▀░█▀█░█░█░▀█▀░█▀█░█▀█░█░░█▀▀░░░░░░░░░░░░░░░░░░░░░░░░▄▄░░░▐█░░│
|
||
│░░░░░░░█▀▀░▄▀▄░█▀▀░█░▄░█░█░░█░░█▀█░█▀█░█░░█▀▀░░░░░░░░░░░░▄▄▄░░░▄██▄░░█▀░░░█░▄░│
|
||
│░░░░░░░▀▀▀░▀░▀░▀▀▀░▀▀▀░▀▀▀░░▀░░▀░▀░▀▀▀░▀▀░▀▀▀░░░░░░░░░░▄██▀█▌░██▄▄░░▐█▀▄░▐█▀░░│
|
||
│░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▐█▀▀▌░░░▄▀▌░▌░█░▌░░▌░▌░░│
|
||
╠──────────────────────────────────────────────────────▌▀▄─▐──▀▄─▐▄─▐▄▐▄─▐▄─▐▄─│
|
||
│ αcτµαlly pδrταblε εxεcµταblε § program header │
|
||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||
#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/runtime/pc.internal.h"
|
||
#include "libc/sysv/consts/prot.h"
|
||
|
||
#define USE_SYMBOL_HACK 1
|
||
|
||
.section .text,"ax",@progbits
|
||
.align __SIZEOF_POINTER__
|
||
.previous
|
||
.section .rodata,"a",@progbits
|
||
.align __SIZEOF_POINTER__
|
||
__ro: .endobj __ro,globl,hidden # ←for gdb readibility
|
||
.previous
|
||
.section .data,"aw",@progbits
|
||
.align __SIZEOF_POINTER__
|
||
.previous
|
||
.section .bss,"aw",@nobits
|
||
.align __SIZEOF_POINTER__
|
||
.previous
|
||
.section .rodata.str1.1,"a",@progbits
|
||
cstr: .endobj cstr,globl,hidden # ←for gdb readibility
|
||
.previous
|
||
.section .head,"ax",@progbits
|
||
|
||
/* ████████ ████████ ███████████
|
||
██░░░░▒▒██ ██░░░░▒▒██ ████░░░░░░░░░▒▒████
|
||
██░░░░░░██ ██░░░░▒▒██ ██░░░░▒▒███████░░░░▒▒██
|
||
██░░░░░░▒▒██ ░██░░░░░░▒▒██ ██░░▒▒██ ██░░▒▒██
|
||
██░░▒▒░░░░██ ░██░░░░░░▒▒██ ██░░▒▒██ ████████
|
||
██░░▒▒▒▒░░▒▒██ ██▓░░░░▒▒░░▒▒██ ██░░▒▒▒▒███████
|
||
██░░▒▒██░░░░██ ██▓░░░░██░░▒▒██ ████░░░░░░░▒▒████
|
||
██░░▒▒████░░▒▒██░░░░░████░░▒▒██ ███████░░░░▒▒██
|
||
██░░▒▒████░░░░██░░░░░████░░▒▒██ ██████ ██░░░░▒▒██
|
||
██░░▒▒██ ██░░▒▒░░▒██ ██░░▒▒██ ██░░░░██ ██░░▒▒██
|
||
██░░▒▒██ ██░░░░░░▒██ ██░░▒▒██ ██░░░░█████████░░░░▒▒██
|
||
██░░▒▒██ ▓▓▒▒░░▒▒▒▓▓ ██░░▒▒██ ▓▓▒▒░░▓▓▓▓▓▓▓▓▓░░░░▓▓▓▓
|
||
██░░▒▒██ ██░░██▓ ██░░▒▒██ ██░░░░░░░░░░░░░▒▒██
|
||
████████████████████▓ ██████████████ ███████████████
|
||
██▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓█████▓▓░░▓▓░░▓▓░░████░░░░░░░░░░░░░░░████
|
||
██▓▓▓▓▓▓▓▓▓▓▓▓▓▓█████▓▓░░▓▓░░▓▓░░████░░░░░░░░░░░░░░░░░░░░░██
|
||
██▓▓▓▓▓▓▓▓▓▓▓▓▓▓██▓▓▒░░▓▓░░▓▓░░▓▓██░░░░░░░░░░░░░░░░░░░░░░░░░██
|
||
██▓▓▓▓▓▓██████████░░▒▓▓▓▓██████▓▓██░░░░░░███████████▓▓░░░░▓▓██
|
||
██▓▓▓▓▓▓████████░░▓▓▓▓▓██▓▓▓▓██████░░░░████░░▒▓▓██ ██▓▓▓▓▓▓██
|
||
██▓▓▓▓▓▓████████▓▓░░▒████▓▓▓▓██████░░░░██▓▓▓▓▒░░██ ██████
|
||
██▓▓▓▓▓▓██ ██░░▓▓▓▓▓██▓▓▓▓██ ██▓▓░░████░░▒▓▓██████
|
||
██▓▓▓▓▓▓██ ██▓▓░░▒████▓▓▓▓██ ██▓▓██▓▓▓▓▒░░██░░░░████
|
||
██▓▓▓▓▓▓██ ██░░▓▓▓▓▓██▓▓▓▓██ ██████░░▒▓▓██░░░░░░░░██
|
||
██▓▓▓▓▓▓██ ██▓▓░░▒████▓▓▓▓██ ██▓▓▓▓▒░░██▓▓░░░░░░░░██
|
||
██▓▓▓▓▓▓██ ██░░▓▓▓████▓▓▓▓██ ████████░░▒▓▓████▓▓░░░░░░██
|
||
██▓▓▓▓▓▓██ ██░░▒██▓▓▓▓████ ██░░░░░░██▓▓███ ██░░░░░░██
|
||
██▓▓▓▓▓▓█████████████▓▓▓▓██████████▓▓░░░░░░█████████░░░░░░░░██
|
||
██▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓████▓▓░░██▓▓░░░░░░░░░░░░░░░░░░░░░▓▓██
|
||
██▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓████▓▓░░▓▓██▓▓▓▓░░░░░░░░░░░░░░░░░▓▓▓▓██
|
||
██▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓████▓▓░░▓▓░░▓▓██▓▓▓▓▓▓░░░░░░░░░░░▓▓▓▓▓▓██
|
||
██▓▓█████████████████████▓▓██▓▓██▓▓████▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓██
|
||
███████████████████████████▓▓██▓▓██▓▓████▓▓▓▓▓▓▓▓▓▓▓▓▓████
|
||
██████████████████▓ ██████████████ █████████████
|
||
╔──────────────────────────────────────────────────────────────────────────────╗
|
||
│ αcτµαlly pδrταblε εxεcµταblε § the old technology │
|
||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||
|
||
#if SupportsWindows() || SupportsMetal() || SupportsXnu()
|
||
|
||
// MZ Literally Executable Header
|
||
//
|
||
// This is the beginning of the program file and it can serve as an
|
||
// entrypoint too. It shouldn't matter if the program is running on
|
||
// Linux, Windows, etc. Please note if the underlying machine isn't
|
||
// a machine, this header may need to morph itself to say the magic
|
||
// words, e.g. ⌂ELF, which also works fine as a generic entrypoint.
|
||
//
|
||
// @param dl is drive number
|
||
// @noreturn
|
||
ape_mz: .asciz "MZqFpD='\n" # Mark 'Zibo' Joseph Zbikowski
|
||
.short 0x1000 # MZ: lowers upper bound load / 16
|
||
.short 0xf800 # MZ: roll greed on bss
|
||
.short 0 # MZ: lower bound on stack segment
|
||
.short 0 # MZ: initialize stack pointer
|
||
.short 0 # MZ: ∑bₙ checksum don't bother
|
||
.short 0x0100 # MZ: initial ip value
|
||
.short 0x0800 # MZ: increases cs load lower bound
|
||
.short 0x0040 # MZ: reloc table offset
|
||
.short 0 # MZ: overlay number
|
||
.org 0x24 # MZ: bytes reserved for you
|
||
.ascii "JT" # MZ: OEM identifier
|
||
.short 0 # MZ: OEM information
|
||
.org 0x40-4 # MZ: bytes reserved for you
|
||
#if SupportsWindows() || SupportsMetal()
|
||
.long RVA(ape_pe) # PE: the new technology
|
||
#else
|
||
.long 0
|
||
#endif
|
||
.endfn ape_mz,globl,hidden
|
||
|
||
#else /* !(SupportsWindows() || SupportsMetal() || SupportsXnu()) */
|
||
|
||
// ELF Literally Executable Header
|
||
//
|
||
// If we don't need to support Microsoft or Apple then we can
|
||
// produce a conventional executable without the shell script
|
||
//
|
||
// @param dl is drive number
|
||
// @noreturn
|
||
.ascii "\177ELF" # 0x0: ⌂ELF
|
||
.byte ELFCLASS64 # 4: long mode
|
||
.byte ELFDATA2LSB # 5: little endian
|
||
.byte 1 # 6: elf v1.o
|
||
.byte ELFOSABI_FREEBSD # 7: FreeBSD
|
||
.byte 0 # 8: os/abi ver.
|
||
.align 8,0 # 9: padding
|
||
.short ET_EXEC # 10: εxεcµταblε
|
||
.short EM_NEXGEN32E # 12: NexGen32e
|
||
.long 1 # 14: elf v1.o
|
||
.quad ape_elf_entry # 18: e_entry
|
||
.quad ape_elf_phoff # 20: e_phoff
|
||
.quad ape_elf_shoff # 28: e_shoff
|
||
.long 0 # 30: e_flags
|
||
.short 64 # 34: e_ehsize
|
||
.short 56 # 36: e_phentsize
|
||
.short ape_elf_phnum # 38: e_phnum
|
||
.short 0 # 3a: e_shentsize
|
||
.short ape_elf_shnum # 3c: e_shnum
|
||
.short ape_elf_shstrndx # 3e: e_shstrndx
|
||
|
||
#endif /* SupportsWindows() || SupportsMetal() || SupportsXnu() */
|
||
|
||
#if SupportsMetal()
|
||
|
||
// Disk Operating System Stub
|
||
//
|
||
// @param dl is drive number
|
||
// @noreturn
|
||
.org 0x40 # mz/elf header length
|
||
stub: mov $0x40,%dl # *literally* dos
|
||
jmp 1f # good bios skips here
|
||
1: jmp pc # thus avoiding heroics
|
||
nop # system five bootpoint
|
||
.org 0x48,0x90 # note ⌂ELF means JG 47
|
||
jmp 3f # MZ also means pop r10
|
||
2: sub $8,%rsp # a.k.a. dec %ax sub %sp
|
||
xor %edx,%edx # MZ ate BIOS drive code
|
||
3: .byte 0xbd,0,0 # a.k.a. mov imm,%bp
|
||
jmp pc # real mode, is real
|
||
jmp _start # surprise it's unix
|
||
.endfn stub
|
||
|
||
/*─────────────────────────────────────────────────────────────────────────────╗
|
||
│ αcτµαlly pδrταblε εxεcµταblε § ibm personal computer │
|
||
╚──────────────────────────────────────────────────────────────────────────────┘
|
||
IBM designed BIOS to run programs by handing over the computer
|
||
to a program as soon as its first sector is loaded. That gives
|
||
us control over user-facing latency, even though the next step
|
||
will generally be asking the BIOS to load more.
|
||
|
||
The process is trivial enough that this entrypoint can support
|
||
handoffs from alternative program-loaders e.g. Grub and MS-DOS
|
||
so long as they either load our full program, or implement the
|
||
PC BIOS disk service API.
|
||
|
||
Since so many different implementations of these APIs have been
|
||
built the last forty years these routines also canonicalize the
|
||
cpu and program state, as it is written in the System V ABI. */
|
||
|
||
// Initializes program and jumps to real mode loader.
|
||
//
|
||
// @param dl drive number (use 0x40 to skip bios disk load)
|
||
// @mode real
|
||
// @noreturn
|
||
pc: cld
|
||
.code16
|
||
#if USE_SYMBOL_HACK
|
||
.byte 0x0f,0x1f,0207 # nop rdi binbase
|
||
.short (0x7c00-IMAGE_BASE_VIRTUAL)/512
|
||
#endif
|
||
mov $0x70000>>4,%di # we need a stack
|
||
xor %cx,%cx # 0x7f000-0x80000
|
||
mov %cx,%es
|
||
rlstack %di,%cx
|
||
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 IMAGE_BASE_REAL>>4
|
||
push %ax
|
||
pop %es
|
||
xor %di,%di
|
||
mov $512,%cx
|
||
rep movsb
|
||
#if USE_SYMBOL_HACK
|
||
.byte 0x0f,0x1f,0207 # nop rdi binbase
|
||
.short (IMAGE_BASE_REAL-0x7c00)/512
|
||
#endif
|
||
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
|
||
je 6f
|
||
call dsknfo
|
||
pop %es # restore IMAGE_BASE_REAL>>4
|
||
mov $1,%al # current sector
|
||
xor %cx,%cx # current cylinder
|
||
xor %dh,%dh # current head
|
||
mov $v_ape_realsectors,%di # total sectors
|
||
3: call pcread
|
||
dec %di
|
||
jnz 3b
|
||
6: ljmp $0,$REAL(realmodeloader)
|
||
.endfn pc
|
||
|
||
// Determines disk geometry.
|
||
//
|
||
// We use imperial measurements for storage systems so the software
|
||
// can have an understanding of physical locality, which deeply
|
||
// impacts the latency of operations.
|
||
//
|
||
// - 160KB: 40 cylinders × 1 head × 8 sectors × 512 = 163,840
|
||
// - 180KB: 40 cylinders × 1 head × 9 sectors × 512 = 184,320
|
||
// - 320KB: 40 cylinders × 2 heads × 8 sectors × 512 = 327,680
|
||
// - 360KB: 40 cylinders × 2 heads × 9 sectors × 512 = 368,640
|
||
// - 720KB: 80 cylinders × 2 heads × 9 sectors × 512 = 737,280
|
||
// - 1.2MB: 80 cylinders × 2 heads × 15 sectors × 512 = 1,228,800
|
||
// - 1.44MB: 80 cylinders × 2 heads × 18 sectors × 512 = 1,474,560
|
||
//
|
||
// Terminology
|
||
//
|
||
// - Heads are also known as Tracks
|
||
//
|
||
// Disk Base Table
|
||
//
|
||
// 0: specify byte 1, step-rate time, head unload time
|
||
// 1: specify byte 2, head load time, DMA mode
|
||
// 2: timer ticks to wait before disk motor shutoff
|
||
// 3: bytes per sector code
|
||
// 0: 128 bytes 2: 512 bytes
|
||
// 1: 256 bytes 3: 1024 bytes
|
||
// 4: sectors per track (last sector number)
|
||
// 5: inter-block gap length/gap between sectors
|
||
// 6: data length, if sector length not specified
|
||
// 7: gap length between sectors for format
|
||
// 8: fill byte for formatted sectors
|
||
// 9: head settle time in milliseconds
|
||
// 10: motor startup time in eighths of a second
|
||
//
|
||
// @param dl drive number
|
||
// @return dl = pc_drive (corrected if clobbered by header)
|
||
// pc_drive
|
||
// pc_drive_type
|
||
// pc_drive_heads
|
||
// pc_drive_last_cylinder
|
||
// pc_drive_last_sector
|
||
// @clob ax, cx, dx, di, si, es, flags
|
||
// @since IBM Personal Computer XT
|
||
dsknfo: push %bx
|
||
1: push %dx
|
||
mov $0x08,%ah # get disk params
|
||
int $0x13
|
||
jc 9f
|
||
mov %cl,%bh
|
||
and $0b00111111,%bh
|
||
and $0b11000000,%cl
|
||
rol %cl
|
||
rol %cl
|
||
xchg %cl,%ch
|
||
push %ds # disk base table in es:di
|
||
movpp %es,%ds
|
||
xor %si,%si
|
||
mov %si,%es
|
||
mov $0x1510,%si # mman::pc_drive_base_table
|
||
xchg %si,%di
|
||
movsw #→ headunloadtime, headloadtime
|
||
movsw #→ shutofftime, bytespersector
|
||
movsw #→ sectorspertrack, sectorgap
|
||
movsw #→ datalength, formatgap
|
||
movsw #→ formatfill, settletime
|
||
movsb #→ startuptime
|
||
pop %ds
|
||
xchg %bx,%ax
|
||
stosw #→ pc_drive_type, pc_drive_last_sector
|
||
xchg %cx,%ax
|
||
stosw #→ pc_drive_last_cylinder
|
||
xchg %dx,%ax
|
||
stosw #→ pc_drives_attached, pc_drive_last_head
|
||
pop %ax
|
||
stosb #→ pc_drive
|
||
xchg %ax,%dx
|
||
pop %bx
|
||
ret
|
||
9: pop %dx
|
||
8: xor $0x80,%dl # try cycling drive a/c
|
||
xor %ax,%ax # reset disk
|
||
int $0x13
|
||
jc 8b
|
||
jmp 1b
|
||
.endfn dsknfo
|
||
|
||
// Reads disk sector via BIOS.
|
||
//
|
||
// @param al sector number
|
||
// @param es destination memory address >> 4
|
||
// @param cx cylinder number
|
||
// @param dh head number
|
||
// @param dl drive number
|
||
// @return number of sectors actually read
|
||
pcread: push %ax
|
||
push %cx
|
||
xchg %cl,%ch
|
||
ror %cl
|
||
ror %cl
|
||
or %al,%cl
|
||
xor %bx,%bx # es:bx is destination addr
|
||
mov $1,%al # read only one disk sector
|
||
mov $2,%ah # read disk sectors ordinal
|
||
int $0x13
|
||
pop %cx
|
||
pop %ax
|
||
jc 9f
|
||
mov %es,%si # addr += 512
|
||
add $512>>4,%si
|
||
mov %si,%es
|
||
inc %al # ++sector
|
||
cmp 0x151c,%al # mman::pc_drive_last_sector
|
||
jbe 2f
|
||
mov $1,%al
|
||
inc %dh # ++head
|
||
cmp 0x1520,%dh # mman::pc_drive_last_head
|
||
jbe 2f
|
||
xor %dh,%dh
|
||
inc %cx # ++cylinder
|
||
2: ret
|
||
9: push %ax
|
||
xor %ax,%ax # try disk reset on error
|
||
int $0x13
|
||
pop %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 ─╬─│┼
|
||
╚────────────────────────────────────────────────────────────────────────────│*/
|
||
|
||
// Partition Table.
|
||
ape.mbrpad:
|
||
.org 0x1b4
|
||
.endobj ape.mbrpad
|
||
ape_disk:
|
||
.stub ape.diskid,quad
|
||
.org 0x1be,0x00
|
||
.macro .partn x
|
||
.stub ape.part\x\().status,byte # 0=absent / 0x80=present
|
||
.stub ape.part\x\().first.head,byte # in low 6 bits
|
||
.stub ape.part\x\().first.cylinder,byte
|
||
.stub ape.part\x\().first.sector,byte
|
||
.stub ape.part\x\().filesystem,byte
|
||
.stub ape.part\x\().last.head,byte
|
||
.stub ape.part\x\().last.cylinder,byte
|
||
.stub ape.part\x\().last.sector,byte
|
||
.stub ape.part\x\().lba,long # c₀*Cₙ + h₀*Hₙ + s₀*Sₙ
|
||
.stub ape.part\x\().sector.count,long # sectors are 512 bytes
|
||
.endm
|
||
.partn 1
|
||
.partn 2
|
||
.partn 3
|
||
.partn 4
|
||
.org 0x1fe
|
||
.short BOOTSIG
|
||
.endobj ape_disk
|
||
|
||
#endif /* SupportsMetal() */
|
||
|
||
/* ▄▄▄
|
||
▄▄▄ ▀▓▓▒▄
|
||
▄▓▒▒░ ▀▓▒▒▒▄
|
||
▄▓▓▓▒▀ ▄▄▄▄ ▒▓▒▒░▒▄
|
||
▄▓▓▓▒▓ ▄▄▓██▓▓▓▓▒▒▒▒▓▓▄▄▓▓▒▒▒░░▒
|
||
▓▓▓▓▒▒▒▄▄ ░▒█▓▓▓▓▓▓▓▓▓▒▒▒▒▒▒▒▒▒▒▒▓▒░░▒░
|
||
██▓▓▓▒▒░░▒▒▒▒▓▓▓▓▓▓▒▓▒░▒▒░▀▒▒▒▒░▀░▒▒▒░▒
|
||
▓▓▓▓▓▓▓▒▒▒▒▒▒▓▓▒▓▓▒▒▒░▒▒░░ ░▒▒░ ░▒▒▒▒
|
||
▀▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▒▒░░▒░░ ░▒▒ ░ ▀▒▒
|
||
▀▓▓█▓▓▓▓▓▓▓▓▓▓▒▒░░▒▒░░ ░░░▓░ ▓░░░▒
|
||
▀▀█▓███▓▓▓▓▓▒▒░░░▒░░ ░█▓░█▓░█▓▓▄▒░
|
||
░▓██▓▓▓▓▓▒▒░░░▒░░ ░████▓▒▓█▓▀░▀▄
|
||
░▓██▓▓▓▓▓▒▒▒░░░▒░░ ▒██▓▒▒▒▒▒▒░░░▒
|
||
████▓▓▓▓▓▒▒▒▒▒▒▒▒▒░░▒▓▓▒░░░░▒░░░▒░ ░░░░░
|
||
░▓███▓▓▓▓▓▒▒░░░░░░░▒▒▒▒▒▒▒▒▒▒▒░░░ ░░░░░ ░
|
||
▓███▓▓▓▓▓▒▓▒▒▒▒░░░░░░░░░▒▓▒▒░▀ ░░░ ░░░░░
|
||
▀▒██▓▓▓▓▒▒▒▓▓▓▓▒▒▒▒▒▒▒▓▀▀░ ░░░░░░░░░ ░
|
||
▓▓▓▓▓▓▓▒▓▒▒▒▒▓▓▓▒▀░ ░░░░░▄░░░ ░░░ ░░░░░░
|
||
▓▓▓▒▒▒▒▒▒▒▒▒▒▒▓ █▓▒░░▒░░░░ ░░░░░░░░
|
||
▄▓▓▓▒▒▒▒▒░░░░░░░▒▄▄▄░▒▓▓▒▒░▀░
|
||
░▓█▓▓▒▒▒▒▒▒▒▒▒▒▒▒▒▒▓▓▓▓▓▓▒░░░▒ besiyata
|
||
▓▓█▓▓▒▓▓▓▒▒▒░░░░░░▒▓▓▓▓▒▒▒▒▒░ dishmaya
|
||
▓▓█▓▓▓▓▓▓▒▒▒░░░░░░░▒▓▓▒▀▀▀
|
||
▓▓██▓▓▓▓▓▓▓▒▒▒▒▒▒▒▒▒▒▀
|
||
█▓▓█▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▀
|
||
▒▓▓▓▓▀░░▒▓▓▓▓▓▓▓▓▒▒░░▒
|
||
▄▓▓▀░░░▄▓▓▓▓▒▒▒▒▒░░░░▄░
|
||
▄███▄▄▓▓▓▓▓▓▓▒▒▒▒▒░░▒▒░
|
||
▄▓▓▓█▓█▓▓███▓▓▓▓▓▓▓▓▓▓▓░
|
||
▄░▓▓▓▓▓▓▀▒▓▓▓▒▒▓▒░░░▒▓▒░░░▓
|
||
▄▄▄░▒▓▓▓▓▓▓░▀▀ ▓▓▒░▓▒▒▒▒▒▒▒▒▒▒▄░░▀▀░░ ▄▄▄▄
|
||
▄▄▄▒▒▓▓█▓▓▓▓▓▀▀▀▀▀ ▓▓▓▓▓▒▒▒▒▒▒▒▒▒▒▒▒▒▀░░▀░░▒▒▒░░░ ░░░░░
|
||
▄▓▓▓▒▀▀ ▓▒▓▓▓▓▓▒▒▒▒▒▒▒▒▓░░░ ▒▒▒░░░░░░░░▒
|
||
█▓▓▒ ▄▄▄ ▀▓▒▓▒▒▒▓▓▓▓▓▓▒▒▒░░░░░░░░░▒▒░░░░░░░
|
||
▀▓▓▓▓▒▄▄▒▒▒▒▒▒▄▄ ▀▀▀▀░░▒▒▒▒░░░░░░
|
||
▀▀▀▓▓▓▓▒▒▒▒▒▓▓▄▄
|
||
╔────────────────────────────────────────────────────────────────────────────│─╗
|
||
│ αcτµαlly pδrταblε εxεcµταblε § bell system five ─╬─│┼
|
||
╚────────────────────────────────────────────────────────────────────────────│─╝
|
||
the bourne executable & linkable format */
|
||
|
||
#if SupportsWindows() || SupportsMetal() || SupportsXnu()
|
||
apesh: .ascii "'\n#'\"\n" # sixth edition shebang
|
||
// Until all operating systems can be updated to support APE,
|
||
// we have a beautiful, yet imperfect workaround, which is to
|
||
// modify the binary to follow the local system's convention.
|
||
// There isn't a one-size-fits-all approach for this, thus we
|
||
// present two choices.
|
||
#ifndef APE_NO_MODIFY_SELF
|
||
// The default behavior is: to overwrite the header in place.
|
||
// We prefer this because it's a tiny constant one time cost.
|
||
// We simply printf a 64-byte header and call execve() again.
|
||
.ascii "o=\"$(command -v \"$0\")\"\n"
|
||
#ifdef APE_BUILDSAFE
|
||
// This code is intended for binaries in build/bootstrap/. It
|
||
// causes them to not self-modify since they're checked-in to
|
||
// version control. It assumes cosmopolitan's build prefix is
|
||
// being used by convention and that the program has the noop
|
||
// flag -n which is used to prime the binary.
|
||
.ascii "if [ ${o##o/} = $o ]; then\n"
|
||
.ascii " if ! [ o/$o -nt $o ]; then\n"
|
||
.ascii " mkdir -p o/${o%/*} || exit\n"
|
||
.ascii " cp -f $o o/$o.$$ || exit\n"
|
||
.ascii " o/$o.$$ -n || exit\n"
|
||
.ascii " mv -f o/$o.$$ o/$o || exit\n"
|
||
.ascii " fi\n"
|
||
.ascii " exec o/$o \"$@\"\n"
|
||
.ascii "fi\n"
|
||
#endif
|
||
#else
|
||
// The alternative behavior is to copy to $TMPDIR and edit.
|
||
// This imposes a variety of caveats of its own that should
|
||
// be considered by the user beforehand, such as whether or
|
||
// not /tmp is considered trustworthy on a given system, or
|
||
// if the administrator chose to mount it with noexec. It's
|
||
// up to the user to decide what's best in those situations
|
||
// and also note that argv[0] and getauxval(AT_EXECFN) will
|
||
// change as a result of this, and lastly note we don't try
|
||
// to cleanup the tmp copies for the sake of efficiency. It
|
||
// should also be noted that if $0 has directory components
|
||
// then permission clashes can happen between system users,
|
||
// since only root is able to set the sticky bit, which can
|
||
// be addressed simply by overriding the TMPDIR environment
|
||
.ascii "o=\"${TMPDIR:-/tmp}/$0\"\n"
|
||
.ascii "if [ ! -e \"$o\" ]; then\n"
|
||
.ascii "d=\"$o\"\n"
|
||
.ascii "o=\"$o.$$\"\n"
|
||
.ascii "mkdir -p \"${o%/*}\" 2>/dev/null\n"
|
||
.ascii "cp -f \"$0\" \"$o\" || exit 120\n"
|
||
#endif /* APE_NO_MODIFY_SELF */
|
||
#if SupportsXnu()
|
||
.ascii "if [ -d /Applications ]; then\n"
|
||
.ascii "dd if=\"$o\""
|
||
.ascii " of=\"$o\""
|
||
.ascii " bs=8"
|
||
.ascii " skip=\""
|
||
.shstub ape_macho_dd_skip,2
|
||
.ascii "\" count=\""
|
||
.shstub ape_macho_dd_count,2
|
||
.ascii "\" conv=notrunc 2>/dev/null\n"
|
||
.ascii "el"
|
||
#endif /* XNU */
|
||
.ascii "if exec 7<> \"$o\"; then\n"
|
||
.ascii "printf '"
|
||
.ascii "\\177ELF" # 0x0: ⌂ELF
|
||
.ascii "\\2" # 4: long mode
|
||
.ascii "\\1" # 5: little endian
|
||
.ascii "\\1" # 6: elf v1.o
|
||
.ascii "\\011" # 7: FreeBSD
|
||
.ascii "\\0" # 8: os/abi ver.
|
||
.ascii "\\0\\0\\0" # 9: padding 3/7
|
||
.ascii "\\0\\0\\0\\0" # padding 4/7
|
||
.ascii "\\2\\0" # 10: εxεcµταblε
|
||
.ascii "\\076\\0" # 12: NexGen32e
|
||
.ascii "\\1\\0\\0\\0" # 14: elf v1.o
|
||
.shstub ape_elf_entry,8 # 18: e_entry
|
||
.shstub ape_elf_phoff,8 # 20: e_phoff
|
||
.shstub ape_elf_shoff,8 # 28: e_shoff
|
||
.ascii "\\0\\0\\0\\0" # 30: e_flags
|
||
.ascii "\\100\\0" # 34: e_ehsize
|
||
.ascii "\\070\\0" # 36: e_phentsize
|
||
.shstub ape_elf_phnum,2 # 38: e_phnum
|
||
.ascii "\\0\\0" # 3a: e_shentsize
|
||
.shstub ape_elf_shnum,2 # 3c: e_shnum
|
||
.shstub ape_elf_shstrndx,2 # 3e: e_shstrndx
|
||
.ascii "' >&7\n"
|
||
.ascii "exec 7<&-\n"
|
||
.ascii "else\n"
|
||
.ascii "exit 121\n"
|
||
.ascii "fi\n"
|
||
#ifndef APE_NO_MODIFY_SELF
|
||
.ascii "exec \"$0\" \"$@\"\n" # optimistic execution
|
||
#else
|
||
.ascii "mv -f \"$o\" \"$d\" 2>/dev/null\n"
|
||
.ascii "o=\"$d\"\n"
|
||
.ascii "fi\n"
|
||
.ascii "exec \"$o\" \"$@\"\n"
|
||
#endif /* APE_NO_MODIFY_SELF */
|
||
.ascii "R=$?\n"
|
||
.ascii "\n"
|
||
.ascii "if [ $R -eq 126 ] && [ \"$(uname -m)\" != x86_64 ]; then\n"
|
||
.ascii "if Q=\"$(command -v qemu-x86_64)\"; then\n"
|
||
.ascii "exec \"$Q\" \"$o\" \"$@\"\n"
|
||
.ascii "else\n"
|
||
.ascii "echo error: need qemu-x86_64 >&2\n"
|
||
.ascii "fi\n"
|
||
#ifndef APE_NO_MODIFY_SELF
|
||
.ascii "elif [ $R -eq 127 ]; then\n" # means argv[0] was wrong
|
||
.ascii " exec \"$o\" \"$@\"\n" # so do a path resolution
|
||
#endif /* APE_NO_MODIFY_SELF */
|
||
.ascii "fi\n"
|
||
.ascii "exit $R\n"
|
||
.endobj apesh
|
||
#endif /* SupportsWindows() || SupportsMetal() || SupportsXnu() */
|
||
|
||
#if SupportsSystemv() || SupportsMetal()
|
||
.section .elf.phdrs,"a",@progbits
|
||
.long PT_LOAD
|
||
.long PF_R|PF_X
|
||
.stub ape_rom_offset,quad
|
||
.stub ape_rom_vaddr,quad
|
||
.stub ape_rom_paddr,quad
|
||
.stub ape_rom_filesz,quad
|
||
.stub ape_rom_memsz,quad
|
||
.stub ape_rom_align,quad
|
||
.long PT_LOAD
|
||
.long PF_R|PF_W
|
||
.stub ape_ram_offset,quad
|
||
.stub ape_ram_vaddr,quad
|
||
.stub ape_ram_paddr,quad
|
||
.stub ape_ram_filesz,quad
|
||
.stub ape_ram_memsz,quad
|
||
.stub ape_ram_align,quad
|
||
.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
|
||
.long PF_R
|
||
.stub ape_note_offset,quad
|
||
.stub ape_note_vaddr,quad
|
||
.stub ape_note_paddr,quad
|
||
.stub ape_note_filesz,quad
|
||
.stub ape_note_memsz,quad
|
||
.stub ape_note_align,quad
|
||
#endif
|
||
.previous
|
||
#endif /* SupportsSystemv() || SupportsMetal() */
|
||
|
||
#if SupportsOpenbsd()
|
||
.section .note.openbsd.ident,"a",@progbits
|
||
openbsd.ident:
|
||
.long 2f-1f
|
||
.long 4f-3f
|
||
.long 1
|
||
1: .asciz "OpenBSD"
|
||
2: .align 4
|
||
3: .long 0
|
||
4: .size openbsd.ident,.-openbsd.ident
|
||
.type openbsd.ident,@object
|
||
.previous
|
||
#endif /* SupportsOpenbsd() */
|
||
|
||
#if SupportsNetbsd()
|
||
.section .note.netbsd.ident,"a",@progbits
|
||
netbsd.ident:
|
||
.long 2f-1f
|
||
.long 4f-3f
|
||
.long 1
|
||
1: .asciz "NetBSD"
|
||
2: .align 4
|
||
3: .long 901000000
|
||
4: .size netbsd.ident,.-netbsd.ident
|
||
.type netbsd.ident,@object
|
||
.previous
|
||
#endif /* SupportsNetbsd() */
|
||
|
||
/* ▄▄███▄
|
||
▄▄████████▄
|
||
▄█████████████▄
|
||
▄▄███▓▓▓▓▓▓▓▓▓▓▓███▄
|
||
▄▄█████▓▓▓█████████▓▓▓██▄
|
||
▄▄████████▓▓▓███████▓▓▓▓▓████▄
|
||
▄█████░░░████▓▓█████▓▓▓▓█████████▄
|
||
▄▄█████████░░░███▓▓█▓▓▓▓▒███████▓▓▒███▄
|
||
▄██████████████░░░██▓▓▓▓███████████▓▓█████▄
|
||
██████████████████░░░██▓▓▓█████████▓▓▓███████▄
|
||
███░░░░░░█████████▓░░███▓▓▓▓▓▓▓▓▓▓▓█████▒▒▒██▄
|
||
█░███░░░██░░░░░░░░░██░░██████████████▒▒▒▒██████▄
|
||
███████░░░█████████░░░░░░█████████▒▒▒▒▒██████████▄
|
||
█████ ██░░░███████████████████▒▒▒▒▒██░▒▒██████████▄
|
||
██████ ██░░░██████████████░███▒████████▒▒██████████▄
|
||
████████ ███░░█████████████░░████████████▒▒███████████
|
||
█████████ ███░░███████████░░██████████████▒▒███████████
|
||
▄██████████ ██████████████ ░░███████████████▒▒███████████
|
||
████████████ ███░░░░░█████░░█████████████████▒▒██████ █
|
||
█████████████ ██████░░░░░░░▒█████████████████████ ████▀
|
||
█████████████ ██████████░░░░░░░░░███████████ ████████
|
||
█████████████ ████████░░███████░░░██████ ▓██████████
|
||
█████████████ ██████░░░████████████ █████████████
|
||
╔────────────────────────────────────────────────────────────────────────────│─╗
|
||
│ αcτµαlly pδrταblε εxεcµταblε § nexstep carnegie melon mach object format ─╬─│┼
|
||
╚────────────────────────────────────────────────────────────────────────────│─╝
|
||
@note hey xnu before we get upx'd email feedback jtunney@gmail.com
|
||
@see OS X ABI Mach-O File Format Reference, Apple Inc. 2009-02-04
|
||
@see System V Application Binary Interface NexGen32e Architecture
|
||
Processor Supplement, Version 1.0, December 5th, 2018 */
|
||
|
||
#if SupportsXnu()
|
||
.section .macho,"a",@progbits
|
||
.align __SIZEOF_POINTER__
|
||
|
||
ape_macho:
|
||
.long 0xFEEDFACE+1
|
||
.long MAC_CPU_NEXGEN32E
|
||
.long MAC_CPU_NEXGEN32E_ALL
|
||
.long MAC_EXECUTE
|
||
.long 5 # number of load commands
|
||
.long 60f-10f # size of all load commands
|
||
.long MAC_NOUNDEFS # flags
|
||
.long 0 # reserved
|
||
10: .long MAC_LC_SEGMENT_64
|
||
.long 20f-10b # unmaps first page dir
|
||
.ascin "__PAGEZERO",16 # consistent with linux
|
||
.quad 0,0x200000,0,0 # which forbids mem <2m
|
||
.long 0,0,0,0
|
||
20: .long MAC_LC_SEGMENT_64
|
||
.long 30f-20b
|
||
.ascin "__TEXT",16
|
||
.stub ape_rom_vaddr,quad
|
||
.stub ape_rom_memsz,quad
|
||
.stub ape_rom_offset,quad
|
||
.stub ape_rom_filesz,quad
|
||
.long PROT_EXEC|PROT_READ|PROT_WRITE # maxprot
|
||
.long PROT_EXEC|PROT_READ # initprot
|
||
.long 1 # segment section count
|
||
.long 0 # flags
|
||
210: .ascin "__text",16 # section name (.text)
|
||
.ascin "__TEXT",16
|
||
.stub ape_text_vaddr,quad
|
||
.stub ape_text_memsz,quad
|
||
.stub ape_text_offset,long
|
||
.long 12 # align 2**12 = 4096
|
||
.long 0 # reloc table offset
|
||
.long 0 # relocation count
|
||
.long MAC_S_ATTR_SOME_INSTRUCTIONS # section type & attributes
|
||
.long 0,0,0 # reserved
|
||
30: .long MAC_LC_SEGMENT_64
|
||
.long 40f-30b
|
||
.ascin "__DATA",16
|
||
.stub ape_ram_vaddr,quad
|
||
.stub ape_ram_memsz,quad
|
||
.stub ape_ram_offset,quad
|
||
.stub ape_ram_filesz,quad
|
||
.long PROT_EXEC|PROT_READ|PROT_WRITE # maxprot
|
||
.long PROT_READ|PROT_WRITE # initprot
|
||
.long 2 # segment section count
|
||
.long 0 # flags
|
||
310: .ascin "__data",16 # section name (.data)
|
||
.ascin "__DATA",16
|
||
.stub ape_data_vaddr,quad
|
||
.stub ape_data_memsz,quad
|
||
.stub ape_data_offset,long
|
||
.long 12 # align 2**12 = 4096
|
||
.long 0 # reloc table offset
|
||
.long 0 # relocation count
|
||
.long 0 # section type & attributes
|
||
.long 0,0,0 # reserved
|
||
320: .ascin "__bss",16 # section name (.bss)
|
||
.ascin "__DATA",16
|
||
.stub ape_bss_vaddr,quad # virtual address
|
||
.stub ape_bss_memsz,quad # memory size
|
||
.long 0 # file offset
|
||
.long 12 # align 2**12 = 4096
|
||
.long 0 # reloc table offset
|
||
.long 0 # relocation count
|
||
.long MAC_S_ZEROFILL # section type & attributes
|
||
.long 0,0,0 # reserved
|
||
40: .long MAC_LC_UUID
|
||
.long 50f-40b
|
||
.stub ape_uuid1,quad
|
||
.stub ape_uuid2,quad
|
||
50: .long MAC_LC_UNIXTHREAD
|
||
.long 60f-50b # cmdsize
|
||
.long MAC_THREAD_NEXGEN32E # flavaflav
|
||
.long (520f-510f)/4 # count
|
||
510: .quad 0 # rax
|
||
.quad IMAGE_BASE_VIRTUAL # rbx
|
||
.quad 0 # rcx
|
||
.quad 0 # rdx
|
||
.quad 0 # rdi
|
||
.quad 0 # rsi
|
||
.quad 0 # rbp
|
||
.quad 0 # rsp
|
||
.quad 0 # r8
|
||
.quad 0 # r9
|
||
.quad 0 # r10
|
||
.quad 0 # r11
|
||
.quad 0 # r12
|
||
.quad 0 # r13
|
||
.quad 0 # r14
|
||
.quad 0 # r15
|
||
.quad _xnu # rip
|
||
.quad 0 # rflags
|
||
.quad 0 # cs
|
||
.quad 0 # fs
|
||
.quad 0 # gs
|
||
520:
|
||
60:
|
||
|
||
.endobj ape_macho,globl,hidden
|
||
.previous /* .macho */
|
||
#endif /* SupportsXnu() */
|
||
|
||
/* ░░░░
|
||
▒▒▒░░░▒▒▒▒▒▒▒▓▓▓░
|
||
▒▒▒▒░░░▒▒▒▒▒▒▓▓▓▓▓▓░
|
||
▒▒▒▒░░░▒▒▒▒▒▒▒▓▓▓▓▓▓ ▒▓░
|
||
▒▒▒░░░░▒▒▒▒▒▒▓▓▓▓▓▓ ▓▓▓▓▓▓▒ ▒▒▒▓▓█
|
||
▒▒▒▒░░░▒▒▒▒▒▒▒▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▒▒▒▒▒▒▒▒▒▒▓▓▓
|
||
░▒▒▒░░░░▒▒▒▒▒▒▓▓▓▓▓▓ █▓▓▓▓▓▓▓▒▒▒▒▒▒▒▒▒▒▓▓█
|
||
▒▒▒▒░░░▒▒▒▒▒▒▒▓▓▓▓▓░ ▓▓▓▓▓▓▓▓▒▒▒▒▒▒▒▒▒▒▓▓▓
|
||
▒▒▒▒░░░▒▒▒▒▒▒▒▓▓▓▓▓▓ ▒▓▓▓▓▓▓▓▓▒▒▒▒▒▒▒▒▒▒▓▓▒
|
||
▒▒▒▒▓▓ ▓▒▒▓▓▓▓ ▓▓▓▓▓▓▓▓▒▒▒▒▒▒▒▒▒▒▓▓█
|
||
▒▓ ▓▓▓▓▓▓▓▓▓▒▒▒▒▒▒▒▒▒▒▓▓
|
||
░░░░░░░░░░░▒▒▒▒ ▓▓▓▓▓▓▓▓▒▒▒▒▒▒▒▒▒▒▓▓█
|
||
▒▒░░░░░░░░░░▒▒▒▒▒▓▓▓ ▓▓▓▓▓▒▒▒▒▒▒▒▒▒▒▓▓▓
|
||
░▒░░░░░░░░░░░▒▒▒▒▒▓▓ ▓░ ░▓███▓
|
||
▒▒░░░░░░░░░░▒▒▒▒▒▓▓░ ▒▓▓▓▒▒▒ ░▒▒▒▓ ████████████
|
||
▒▒░░░░░░░░░░░▒▒▒▒▒▓▓ ▒▓▓▓▓▒▒▒▒▒▒▒▒░░░▒▒▒▒▒░ ░███
|
||
▒░░░░░░░░░░░▒▒▒▒▒▓▓ ▓▓▓▓▒▒▒▒▒▒▒▒░░░░▒▒▒▒▓ ███
|
||
▒▒░░░░░░░░░░▒▒▒▒▒▒▓▓ ▒▓▓▓▒▒▒▒▒▒▒▒░░░░▒▒▒▒▒ ▓██
|
||
▒░░░░░░░░░░░▒▒▒▒▒▓▓ ▓▓▓▓▒▒▒▒▒▒▒▒░░░▒▒▒▒▒▓ ▓██
|
||
▒▒░░░▒▒▒░░░▒▒░▒▒▒▓▓▒ ▒▓▓▓▒▒▒▒▒▒▒▒░░░░▒▒▒▒▒ ███
|
||
░▒▓ ░▓▓▓▓▒▒▒▒▒▒▒▒░░░░▒▒▒▒▓ ▓██
|
||
╔─────────────────────────────────────────────────────────────────▀▀▀────────│─╗
|
||
│ αcτµαlly pδrταblε εxεcµταblε § the new technology ─╬─│┼
|
||
╚────────────────────────────────────────────────────────────────────────────│─╝
|
||
The Portable Executable Format
|
||
|
||
@see https://docs.microsoft.com/en-us/windows/desktop/debug/pe-format
|
||
@see "The Portable Executable File Format from Top to Bottom",
|
||
Randy Kath, Microsoft Developer Network Technology Group. */
|
||
|
||
// ┌14:Uniprocessor Machine ┌─────────────────────────┐
|
||
// │┌13:DLL │ PE File Characteristics │
|
||
// ││┌12:System ├─────────────────────────┤
|
||
// │││┌11:If Net Run From Swap │ r │ reserved │
|
||
// ││││┌10:If Removable Run From Swap │ d │ deprecated │
|
||
// │││││┌9:Debug Stripped │ D │ deprecated with │
|
||
// ││││││┌8:32bit Machine │ │ extreme prejudice │
|
||
// │││││││ ┌5:Large Address Aware └───┴─────────────────────┘
|
||
// │││││││ │ ┌1:Executable
|
||
// │││││││ │ │┌0:Relocs Stripped
|
||
// d│││││││dr│Ddd││
|
||
PEEXE = 0b00000001000100011
|
||
|
||
// ┌15:TERMINAL_SERVER_AWARE ┌─────────────────────────┐
|
||
// │┌14:GUARD_CF │ PE DLL Characteristics │
|
||
// ││┌13:WDM_DRIVER ├─────────────────────────┤
|
||
// │││┌12:APPCONTAINER │ r │ reserved │
|
||
// ││││┌11:NO_BIND └───┴─────────────────────┘
|
||
// │││││┌10:NO_SEH
|
||
// ││││││┌9:NO_ISOLATION
|
||
// │││││││┌8:NX_COMPAT
|
||
// ││││││││┌7:FORCE_INTEGRITY
|
||
// │││││││││┌6:DYNAMIC_BASE
|
||
// ││││││││││┌5:HIGH_ENTROPY_VA
|
||
// │││││││││││rrrrr
|
||
DLLSTD = 0b0000000100100000
|
||
DLLPIE = 0b0000000001100000
|
||
DLLEXE = DLLSTD
|
||
|
||
// ┌31:Writeable ┌─────────────────────────┐
|
||
// │┌30:Readable │ PE Section Flags │
|
||
// ││┌29:Executable ├─────────────────────────┤
|
||
// │││┌28:Shareable │ o │ for object files │
|
||
// ││││┌27:Unpageable │ r │ reserved │
|
||
// │││││┌26:Uncacheable └───┴─────────────────────┘
|
||
// ││││││┌25:Discardable
|
||
// │││││││┌24:Contains Extended Relocations
|
||
// ││││││││ ┌15:Contains Global Pointer (GP) Relative Data
|
||
// ││││││││ │ ┌7:Contains Uninitialized Data
|
||
// ││││││││ │ │┌6:Contains Initialized Data
|
||
// ││││││││ o │ ││┌5:Contains Code
|
||
// ││││││││┌┴─┐rrrr│ ooror│││rorrr
|
||
PETEXT = 0b01110000000000000000000001100000
|
||
PEDATA = 0b11000000000000000000000011000000
|
||
PEIMPS = 0b11000000000000000000000001000000
|
||
|
||
#if SupportsWindows() || SupportsMetal()
|
||
|
||
.section .pe.header,"a",@progbits
|
||
.align __SIZEOF_POINTER__
|
||
ape_pe: .ascin "PE",4
|
||
.short kNtImageFileMachineNexgen32e
|
||
.stub ape_pe_shnum,short # NumberOfSections
|
||
.long 0x5c64126b # TimeDateStamp
|
||
.long 0 # PointerToSymbolTable
|
||
.long 0 # NumberOfSymbols
|
||
.stub ape_pe_optsz,short # SizeOfOptionalHeader
|
||
.short PEEXE # Characteristics
|
||
.short kNtPe64bit # Optional Header Magic
|
||
.byte 14 # MajorLinkerVersion
|
||
.byte 15 # MinorLinkerVersion
|
||
.long 0 # SizeOfCode
|
||
.long 0 # SizeOfInitializedData
|
||
.long 0 # SizeOfUninitializedData
|
||
.long RVA(ape_pe_entry) # EntryPoint
|
||
.long 0 # BaseOfCode
|
||
.quad ape_pe_base # ImageBase
|
||
.long 4096 # SectionAlignment
|
||
.long 4096 # FileAlignment
|
||
.short v_ntversion # MajorOperatingSystemVersion
|
||
.short 0 # MinorOperatingSystemVersion
|
||
.short 0 # MajorImageVersion
|
||
.short 0 # MinorImageVersion
|
||
.short v_ntsubversion # MajorSubsystemVersion
|
||
.short 0 # MinorSubsystemVersion
|
||
.long 0 # Win32VersionValue
|
||
.long RVA(_end) # SizeOfImage
|
||
.long RVA(_ehead) # SizeOfHeaders
|
||
.long 0 # Checksum
|
||
.short v_ntsubsystem # Subsystem: 0=Neutral,2=GUI,3=Console
|
||
.stub v_ntdllchar,short # DllCharacteristics
|
||
.quad 0x0000000000100000 # StackReserve
|
||
.quad 0x00000000000fc000 # StackCommit
|
||
.quad 0 # HeapReserve
|
||
.quad 0 # HeapCommit
|
||
.long 0 # LoaderFlags
|
||
.long 16 # NumberOfDirectoryEntries
|
||
.long 0,0 # ExportsDirectory
|
||
.stub ape_idata,long # ImportsDirectory
|
||
.stub ape_idata_idtsize,long # ImportsDirectorySize
|
||
.long 0,0 # ResourcesDirectory
|
||
.long 0,0 # ExceptionsDirectory
|
||
.long 0,0 # SecurityDirectory
|
||
.long 0,0 # BaseRelocationTable
|
||
.long 0,0 # DebugDirectory
|
||
.long 0,0 # DescriptionString
|
||
.long 0,0 # MachineSpecific
|
||
.long 0,0 # ThreadLocalStorage
|
||
.long 0,0 # LoadConfigurationDirectory
|
||
.long 0,0 # BoundImportDirectory
|
||
.stub ape_idata,long # ImportAddressDirectory
|
||
.stub ape_idata_iatsize,long # ImportAddressDirectorySize
|
||
.long 0,0 # DelayImportDescriptor
|
||
.long 0,0 # ComPlusRuntimeHeader
|
||
.long 0,0 # Reserved
|
||
.endobj ape_pe,globl
|
||
.previous
|
||
|
||
.section .pe.sections,"a",@progbits
|
||
.ascin ".text",8 # Section Name
|
||
.stub ape_text_memsz,long # Virtual Size or Physical Address
|
||
.stub ape_text_rva,long # Relative Virtual Address
|
||
.stub ape_text_filesz,long # Physical Size
|
||
.stub ape_text_offset,long # Physical Offset
|
||
.long 0 # Relocation Table Offset
|
||
.long 0 # Line Number Table Offset
|
||
.short 0 # Relocation Count
|
||
.short 0 # Line Number Count
|
||
.long PETEXT # Flags
|
||
.previous
|
||
|
||
.section .pe.sections,"a",@progbits
|
||
.ascin ".data",8 # Section Name
|
||
.stub ape_ram_memsz,long # Virtual Size or Physical Address
|
||
.stub ape_ram_rva,long # Relative Virtual Address
|
||
.stub ape_ram_filesz,long # Physical Size
|
||
.stub ape_ram_offset,long # Physical Offset
|
||
.long 0 # Relocation Table Offset
|
||
.long 0 # Line Number Table Offset
|
||
.short 0 # Relocation Count
|
||
.short 0 # Line Number Count
|
||
.long PEDATA # Flags
|
||
.previous
|
||
|
||
#endif /* SupportsWindows() || SupportsMetal() */
|
||
|
||
.section .idata.ro.idt.1,"a",@progbits
|
||
.type ape_idata_idtend,@object
|
||
.type ape_idata_idt,@object
|
||
.globl ape_idata_idt,ape_idata_idtend
|
||
.hidden ape_idata_idt,ape_idata_idtend
|
||
ape_idata_idt:
|
||
.previous/*
|
||
...
|
||
decentralized content
|
||
...
|
||
*/.section .idata.ro.idt.3,"a",@progbits
|
||
.long 0,0,0,0,0
|
||
ape_idata_idtend:
|
||
.previous
|
||
|
||
.section .piro.data.sort.iat.1,"aw",@progbits
|
||
.type ape_idata_iatend,@object
|
||
.type ape_idata_iat,@object
|
||
.globl ape_idata_iat,ape_idata_iatend
|
||
.hidden ape_idata_iat,ape_idata_iatend
|
||
ape_idata_iat:
|
||
.previous/*
|
||
...
|
||
decentralized content
|
||
...
|
||
*/.section .piro.data.sort.iat.3,"aw",@progbits
|
||
ape_idata_iatend:
|
||
.previous
|
||
|
||
#if SupportsMetal()
|
||
/*─────────────────────────────────────────────────────────────────────────────╗
|
||
│ αcτµαlly pδrταblε εxεcµταblε § early-stage read-only data │
|
||
╚──────────────────────────────────────────────────────────────────────────────╝
|
||
better code/data separation (.head is rwx[real] rx[long]) */
|
||
|
||
// NUL-Terminated Strings.
|
||
str.error:
|
||
.asciz "error: "
|
||
.endobj str.error
|
||
str.crlf:
|
||
.asciz "\r\n"
|
||
.endobj str.crlf
|
||
str.cpuid:
|
||
.asciz "cpuid"
|
||
.endobj str.cpuid
|
||
str.oldskool:
|
||
.asciz "oldskool"
|
||
.endobj str.oldskool
|
||
str.e820:
|
||
.asciz "e820"
|
||
.endobj str.e820
|
||
str.long:
|
||
.asciz "nolong"
|
||
.endobj str.long
|
||
|
||
// Serial Line Configuration (8250 UART 16550)
|
||
// If it's hacked, it'll at least get hacked very slowly.
|
||
sconf: .short 1843200/*hz*/ / 16/*wut*/ / 9600/*baud*/
|
||
//
|
||
// ┌interrupt trigger level {1,4,8,14}
|
||
// │ ┌enable 64 byte fifo (UART 16750+)
|
||
// │ │ ┌select dma mode
|
||
// │ │ │┌clear transmit fifo
|
||
// │ │ ││┌clear receive fifo
|
||
// ├┐│ │││┌enable fifos
|
||
.byte 0b00000000
|
||
//
|
||
// ┌dlab: flips configuration mode state
|
||
// │┌enable break signal
|
||
// ││ ┌parity {none,odd,even,high,low}
|
||
// ││ │ ┌extra stop bit
|
||
// ││ │ │┌data word length (bits+5)
|
||
// ││┌┴┐│├┐
|
||
.byte 0b01000011
|
||
.endobj sconf,global,hidden
|
||
|
||
// Global Descriptor Table
|
||
//
|
||
// @note address portion only concern legacy modes
|
||
.align 8
|
||
gdt: .short 2f-1f # table byte length
|
||
.long REAL(1f),0 # table address
|
||
.zero 2
|
||
1:
|
||
// ┌G:granularity (1 → limit *= 0x1000)
|
||
// │┌D/B:default operation size (0 = 16|64bit, 1 = 32-bit)
|
||
// ││┌L:long mode
|
||
// │││┌AVL:this bit is thine (1<<52)
|
||
// ││││ ┌P:present
|
||
// ││││ │┌DPL:privilege
|
||
// ││││ ││ ┌─────────data/code(1)
|
||
// ││││ ││ │┌────data(0)──────code(1)
|
||
// ││││ ││ ││┌───conforming───expand-down
|
||
// ││││ ││ │││┌──writeable────readable
|
||
// ││││ ││ ││││┌─accessed─────accessed
|
||
// ││││ ││ │││││
|
||
// ││││ ┌──││─│││││───────────────────────────────┐
|
||
// ┌───││││─│──││─│││││───────────┐ │
|
||
// ┌───┴──┐││││┌┴─┐│├┐│││││┌──────────┴───────────┐┌──────┴───────┐
|
||
// │ ││││││ ││││││││││ base address││ segment limit│
|
||
// │ ││││││ ││││││││││ 32 bits││ 20 bits│
|
||
// │ ││││││ ││││││││││ ││ │
|
||
// 6666555555555544444444443333333333222222222211111111110000000000
|
||
// 3210987654321098765432109876543210987654321098765432109876543210
|
||
// │ ││││││ ││││││││││ ││ │
|
||
.quad 0b0000000000000000000000000000000000000000000000000000000000000000 # 0
|
||
.quad 0b0000000000001111100110100000000000000000000000001111111111111111 # 8
|
||
.quad 0b0000000000001111100100100000000000000000000000001111111111111111 #16
|
||
.quad 0b0000000011001111100110100000000000000000000000001111111111111111 #24
|
||
.quad 0b0000000011001111100100100000000000000000000000001111111111111111 #32
|
||
.quad 0b0000000010101111100110110000000000000000000000001111111111111111 #40
|
||
.quad 0b0000000010101111100100110000000000000000000000001111111111111111 #48
|
||
2: .endobj gdt,global,hidden
|
||
|
||
/*─────────────────────────────────────────────────────────────────────────────╗
|
||
│ αcτµαlly pδrταblε εxεcµταblε § multiboot stub │
|
||
╚──────────────────────────────────────────────────────────────────────────────╝
|
||
boot modernized for the nineties */
|
||
|
||
#define GRUB_MAGIC 0x1BADB002
|
||
#define GRUB_EAX 0x2BADB002
|
||
#define GRUB_AOUT (1 << 16)
|
||
#define GRUB_CHECKSUM(FLAGS) (-(GRUB_MAGIC + (FLAGS)) & 0xffffffff)
|
||
|
||
// Grub Header.
|
||
.align 4
|
||
ape_grub:
|
||
.long GRUB_MAGIC # Magic
|
||
.long GRUB_AOUT # Flags
|
||
.long GRUB_CHECKSUM(GRUB_AOUT) # Checksum
|
||
.long RVA(ape_grub) # HeaderPhysicalAddress
|
||
.long IMAGE_BASE_PHYSICAL # TextPhysicalAddress
|
||
.long PHYSICAL(_edata) # LoadEndPhysicalAddress
|
||
.long PHYSICAL(_end) # BssEndPhysicalAddress
|
||
.long RVA(ape_grub_entry) # EntryPhysicalAddress
|
||
.endobj ape_grub,globl
|
||
|
||
// Grub Entrypoint.
|
||
// Takes CPU out of legacy mode and jumps to normal entrypoint.
|
||
// @noreturn
|
||
.align 4
|
||
ape_grub_entry:
|
||
.code32
|
||
// cmp $GRUB_EAX,%eax
|
||
// jne triplf
|
||
push $0
|
||
popf
|
||
mov $0x40,%dl
|
||
mov %cr0,%eax
|
||
and $~CR0_PE,%eax
|
||
mov %eax,%cr0
|
||
ljmpw $0,$REAL(pc)
|
||
.code16
|
||
.endfn ape_grub_entry
|
||
|
||
/*─────────────────────────────────────────────────────────────────────────────╗
|
||
│ αcτµαlly pδrταblε εxεcµταblε § real mode │
|
||
╚──────────────────────────────────────────────────────────────────────────────╝
|
||
the default mode of operation on modern cpus */
|
||
|
||
realmodeloader:
|
||
call rlinit
|
||
call sinit4
|
||
.optfn _start16
|
||
call _start16
|
||
call longmodeloader
|
||
.endfn realmodeloader
|
||
|
||
.section .sort.text.real.init.1,"ax",@progbits
|
||
.type rlinit,@function
|
||
rlinit: .previous/*
|
||
...
|
||
decentralized function
|
||
...
|
||
*/.section .sort.text.real.init.3,"ax",@progbits
|
||
ret
|
||
.previous
|
||
|
||
/* █ █▒
|
||
█ █
|
||
█▓▄ █ █
|
||
▒▓ ░█░ ░▒▓▓███░ █▒
|
||
▒▓ ▒▓███▓▒░ ░▓
|
||
█ ▓░
|
||
▄██░ █
|
||
▓▓ ▓██░ ▓█░▓█ ▒▓
|
||
▒█ ░█ █ ░▓ █ █
|
||
█░ █ ░▓ ▀▒ █░ █
|
||
█▒ ▀▒░ ▓▓
|
||
▄▄▄▓████▓▓▒░ █ ▄▄▄▄▓▓▓█▓▓▓▓▒░ ▒█
|
||
▄▓▓▀ ▒ ░█ ▄▓▀ ░███▒
|
||
▓▀ ░░ ▀▓▄▄▄▒▒ █
|
||
█ ░░█▒ ▒█ ▒▓ █
|
||
▀█ ▄▄▄▄▄▄▄▄▄▄ ▀▀░▓██▓ █
|
||
▀■▄▄▄■▀ ▀▀█▄ █
|
||
▀▀█▄ █
|
||
▀█▄ █
|
||
█▌ █
|
||
█▌ █
|
||
█▌ █
|
||
█▌ █
|
||
█▌ █
|
||
█▌ █
|
||
█▌ █
|
||
█▌ █
|
||
█▌ █
|
||
█▌ █
|
||
█▌ █
|
||
█▌ █
|
||
█▌ █
|
||
█▌ █
|
||
█▌ █
|
||
█▌ █
|
||
█▌ █
|
||
█▌ █
|
||
█▌ █
|
||
█▌ █
|
||
█▌ █
|
||
█▌ █
|
||
╔──────────────────────────────────────────────────────────────────────────▀─│─╗
|
||
│ αcτµαlly pδrταblε εxεcµταblε § long mode loader ─╬─│┼
|
||
╚────────────────────────────────────────────────────────────────────────────│─╝
|
||
long mode is long */
|
||
|
||
longmodeloader:
|
||
call lcheck
|
||
call a20
|
||
call e820
|
||
call pinit
|
||
call golong
|
||
.endfn longmodeloader
|
||
|
||
// Long Mode Hardware Check
|
||
lcheck: pushf # check for i8086 / i8088 / i80186
|
||
pop %ax
|
||
test $0x80,%ah # see intel manual volume 1 20.1.2
|
||
jnz 9f # we now assume 32bit is supported
|
||
pushfl # now check for i386 or early i486
|
||
pop %eax # test ability to change cpuid bit
|
||
mov %eax,%ecx
|
||
mov $1<<21,%ebx
|
||
xor %ebx,%eax
|
||
push %eax
|
||
popfl
|
||
pushfl
|
||
pop %eax
|
||
cmp %eax,%ecx
|
||
je 12f # we assume cpuid inst is available
|
||
or %ebx,%eax # puts cpuid bit in the on position
|
||
push %eax
|
||
popfl
|
||
mov $0x80000000,%edi # get amd ext cpuid thingy length
|
||
mov %edi,%eax
|
||
inc %edi
|
||
cpuid # clobbers eax, ebx, ecx, and edx
|
||
cmp %edi,%eax
|
||
jl 10f
|
||
mov %edi,%eax
|
||
cpuid
|
||
mov $1<<29,%edi # need nexgen32e long mode support
|
||
and %edi,%edx
|
||
cmp %edi,%edx
|
||
jne 10f
|
||
xor %ax,%ax
|
||
1: ret
|
||
9: mov $REAL(str.oldskool),%di
|
||
jmp 20f
|
||
10: mov $REAL(str.long),%di
|
||
jmp 20f
|
||
12: mov $REAL(str.cpuid),%di
|
||
20: call rldie
|
||
.endfn lcheck
|
||
|
||
// Gets memory map from BIOS.
|
||
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 $0x534d4150,%edx # magic number
|
||
int $0x15 # ax,bx,cx,dx,di → ax,bx,cx
|
||
jc 9f # cf = unsupported or abuse
|
||
cmp %edx,%eax # more magic means success
|
||
jne 9f
|
||
test %cx,%cx # discard empty results
|
||
jz 5f
|
||
cmp $8+8+4+1,%cx # discard if ignore flag
|
||
jb 4f
|
||
testb $1/*ignore*/,8+8+4/*SmapEntry::__acpi3*/(%di)
|
||
jnz 5f
|
||
4: add $8+8+4+4,%di # keep entry
|
||
5: test %ebx,%ebx # last entry?
|
||
jz 8f
|
||
cmp $0x1000,%di
|
||
jb 1b
|
||
8: ret
|
||
9: mov $REAL(str.e820),%di
|
||
call rldie
|
||
.endfn e820
|
||
|
||
// Asks keyboard to grant system 65,519 more bytes of memory.
|
||
//
|
||
// Yup.
|
||
//
|
||
// @assume realmode && df=0
|
||
// @clob ax,di,si,es,flags
|
||
// @mode real
|
||
// @see wiki.osdev.org/A20_Line
|
||
a20: cli
|
||
push %ds
|
||
xor %ax,%ax
|
||
mov %ax,%es
|
||
dec %ax
|
||
mov %ax,%ds
|
||
mov $0x0500,%di
|
||
mov $0x0510,%si
|
||
mov %es:(%di),%al
|
||
push %ax
|
||
mov %ds:(%si),%al
|
||
push %ax
|
||
movb $0x00,%es:(%di)
|
||
movb $0xff,%ds:(%si)
|
||
cmpb $0xff,%es:(%di)
|
||
pop %ax
|
||
mov %al,%ds:(%si)
|
||
pop %ax
|
||
mov %al,%es:(%di)
|
||
pop %ds
|
||
jne 3f
|
||
mov $1,%ax
|
||
call 1f
|
||
mov $0xad,%al
|
||
out %al,$0x64
|
||
call 1f
|
||
mov $0xd0,%al
|
||
out %al,$0x64
|
||
call 2f
|
||
in $0x60,%al
|
||
push %ax
|
||
call 1f
|
||
mov $0xd1,%al
|
||
out %al,$0x64
|
||
call 1f
|
||
pop %ax
|
||
or $2,%al
|
||
out %al,$0x60
|
||
call 1f
|
||
mov $0xae,%al
|
||
out %al,$0x64
|
||
call 1f
|
||
jmp a20
|
||
1: in $0x64,%al
|
||
test $2,%al
|
||
jnz 1b
|
||
ret
|
||
2: in $0x64,%al
|
||
test $1,%al
|
||
jz 2b
|
||
ret
|
||
3: sti
|
||
5: ret
|
||
.endfn a20
|
||
|
||
// Initializes long mode paging.
|
||
pinit: push %ds
|
||
#define SEG 0x79000
|
||
mov $SEG>>4,%ax
|
||
mov %ax,%ds
|
||
movl $0x7d000+PAGE_V+PAGE_RW,0x7e000-SEG # PDPT←PML4T (+)
|
||
movl $0x7c000+PAGE_V+PAGE_RW,0x7e800-SEG # PDPT←PML4T (-)
|
||
movl $0x7b000+PAGE_V+PAGE_RW,0x7d000-SEG # PDT←PDPT (+)
|
||
movl $0x7a000+PAGE_V+PAGE_RW,0x7c000-SEG # PDT←PDPT (-)
|
||
movl $0x79000+PAGE_V+PAGE_RW,0x7b000-SEG # PD←PDT (+)
|
||
movl $0x79000+PAGE_V+PAGE_RW,0x7a000-SEG # PD←PDT (-)
|
||
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
|
||
mov $0x7e000,%eax # PML4T←CR3
|
||
mov %eax,%cr3
|
||
pop %ds
|
||
ret
|
||
.endfn pinit
|
||
|
||
// Switch from Real Mode → Long Mode
|
||
//
|
||
// @see Intel Manual V3A §4.1.2
|
||
golong: cli
|
||
lidt 0x1522 # mman::bad_idt
|
||
mov %cr4,%eax
|
||
or $CR4_PAE|CR4_PGE|CR4_OSFXSR,%eax
|
||
mov %eax,%cr4
|
||
movl $EFER,%ecx
|
||
rdmsr
|
||
or $EFER_LME|EFER_SCE,%eax
|
||
wrmsr
|
||
lgdt REAL(gdt)
|
||
mov %cr0,%eax
|
||
or $CR0_PE|CR0_PG|CR0_MP,%eax
|
||
and $~CR0_EM,%eax
|
||
mov %eax,%cr0
|
||
ljmp $GDT_LONG_CODE,$REAL(long)
|
||
.endfn golong
|
||
|
||
// Long mode is long.
|
||
.code64
|
||
long: push $GDT_LONG_DATA
|
||
pop %rax
|
||
mov %eax,%ds
|
||
mov %eax,%ss
|
||
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
|
||
push %rbp
|
||
mov $0x0500,%rdi # mman
|
||
mov %cr3,%rsi
|
||
mov $IMAGE_BASE_REAL,%edx
|
||
call __map_phdrs
|
||
push $0x037f
|
||
fldcw (%rsp)
|
||
movabs $kernel,%rax
|
||
jmp *%rax
|
||
.endfn long
|
||
|
||
/* ▄▄▒▀▀▀▀▒▒▄
|
||
█████▓▓▄░░░░ ▒▒▄
|
||
▐█▓▓█▓▄█████▓░ ▀▒▄
|
||
▓█▓▓▓▓▓▓▓▓▓█▓ ░▀▒░
|
||
▀▀▓█▓▓▓▓▓▓█▓ ░▀▒▄▄▒▄▄▄▒▒▒▀▀▀▀▀▀▀▀▀▀▀▀▀▀▒▒▄▒
|
||
▀▓▓█▓▓▓▓▓▄ ░ ░▀▒▄▄ ▄
|
||
▀█▓▓▓▓▓▄░ ░▀▒░ ▄▓▌
|
||
▀█▓▓▓▓▓█▓░ ░▀▄░ ░▄▓██░
|
||
▀█▓▓▓▓▓█▄ ░▀▒▄▄▄▄▄▄▄▄▒▀▓█▓█▓░
|
||
▀█▓▓▓▓█▓░ ░▄▓█▓▓█▓▄▌
|
||
▀█▓▓▓▓▓▄ ▄▄▄▓▓██▓▓▒▒░ ▒▒▄▓█▓▓▓▓█▓
|
||
▀█▓▓▓▓▓▓▄▄░ ░▄▄▓██▓▓▓▓▓██████████████▓▓▓▓▓▓█▀
|
||
▐█▓▓▓▓▓▓▓██▓▓▄▄▄▄▄▄▄▄▄▓▓██▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓█████████▓▓▀
|
||
▀▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓█░ ░░░░░░
|
||
▄░▓█▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓█▌
|
||
█▓▄▀▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓██▓▓▀▀▀▀▀▀▀▓█▓▓▓▓▓▓▓▓▓▓▓▓
|
||
▐█▓█▓░▓█▓▓▓▓▓▓▓█▀▀▀▀▒░ ▐▓▓▓▓▓▓▄▒▀▓█▓▓▓▓▓▓▓▓█▌
|
||
▐█▓▓▓█▒▀█▓▓▓▓▓▓█▌ ▀█▓▓▓▓▓█▄░▀▓▓█▓▓▓▓▓▓█░
|
||
█▓▓▓▓▓█░▐█▓▓▓▓▓█▌ ▀▓█▓▓▓▓█▌ ░▀█▓▓▓▓▓█▄
|
||
█▓▓▓▓█▌ ░█▓▓▓▓▓█░ ▓█▓▓▓▓▓░ ▒█▓▓▓▓▓█░
|
||
█▓▓▓▓█░ █▓▓▓▓▓█░ █▓▓▓▓▓█░ ▐█▓▓▓▓█▌
|
||
▐█▓▓▓▓▓▄ █▓▓▓▓▓█ ░▄▄▓█▓▓▓▓▓█░ ▐█▓▓▓▓█░
|
||
▓█▓▓▓█▓▐█▓▓▓▓█▌ ▓██▓▓▓▓▓▓█▀ ▓█▓▓▓▓█
|
||
▀▓██▒▄█▓▓▓▓▓█░ ░█▓▓▓▓▓██▀░ ░▓█▓▓▓▓█▌
|
||
░░█▓▓▓▓▓█▓ ░▀▀▀▀▀▀ ▓█▓▓▓▓▓▓
|
||
╔───────────────────────────────────────────────────────────▀▀▀▀▀▀───────────│─╗
|
||
│ αcτµαlly pδrταblε εxεcµταblε § cosmopolitan libc runtime runtime ─╬─│┼
|
||
╚────────────────────────────────────────────────────────────────────────────│*/
|
||
kernel: movabs $ape_stack_vaddr,%rsp
|
||
add $ape_stack_memsz,%rsp
|
||
movl $0,0x7b000 # unmap null 2mb
|
||
#if USE_SYMBOL_HACK
|
||
.byte 0x0f,0x1f,0207 # nop rdi binbase
|
||
.long (IMAGE_BASE_VIRTUAL-IMAGE_BASE_REAL)/512
|
||
#endif
|
||
.weak __hostos
|
||
ezlea __hostos,ax
|
||
test %rax,%rax
|
||
jz 1f
|
||
movb $METAL,(%rax)
|
||
1: push $0
|
||
mov %rsp,%rbp
|
||
mov .Lenv0(%rip),%rax
|
||
mov %rax,(%rbp) # envp[0][0]
|
||
push $0 # argv[0][0]
|
||
push $0 # auxv[1][1]
|
||
push $0 # auxv[1][0]
|
||
push %rbp # auxv[0][1]
|
||
push $31 # auxv[0][0] AT_EXECFN
|
||
push $0 # envp[1]
|
||
push $.Lenv0 # envp[0]
|
||
push $0 # argv[1]
|
||
push %rbp # argv[0]
|
||
push $1 # argc
|
||
xor %ebp,%ebp
|
||
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
|
||
jmp _start
|
||
.endfn kernel
|
||
|
||
.rodata
|
||
.Lenv0: .asciz "METAL=1"
|
||
.previous
|
||
|
||
#endif /* SupportsMetal() */
|
||
|
||
// Avoid linker script variables appearing as code in objdump.
|
||
.macro .ldsvar name:req
|
||
.type \name,@object
|
||
.weak \name
|
||
.endm
|
||
.ldsvar _end
|
||
.ldsvar _etext
|
||
.ldsvar v_ape_realsectors
|
||
.ldsvar v_ape_highsectors
|
||
.ldsvar ape_idata_ro
|
||
.ldsvar ape_pad_rodata
|
||
.ldsvar ape_piro
|
||
.ldsvar ape_piro_end
|
||
.type ape_macho_end,@object
|
||
.type ape_note,@object
|
||
.type ape_note_end,@object
|
||
.type ape_note_vaddr,@object
|
||
.type ape_phdrs,@object
|
||
.type ape_pe_sections,@object
|
||
.type ape_pe_sections_end,@object
|
||
.type ape_text_nops,@object
|
||
.type __test_end,@object
|
||
|
||
.section .commentprologue,"a",@progbits
|
||
.type kLegalNotices,@object
|
||
.hidden kLegalNotices
|
||
kLegalNotices:/*
|
||
...
|
||
decentralized content
|
||
...
|
||
*/.previous
|
||
.section .commentepilogue,"a",@progbits
|
||
.byte 0
|
||
.previous
|
||
|
||
.section .ape.pad.head,"a",@progbits
|
||
.type ape_pad_head,@object
|
||
.hidden ape_pad_head
|
||
ape_pad_head:
|
||
.previous
|
||
|
||
.section .ape.pad.text,"a",@progbits
|
||
.type ape_pad_text,@object
|
||
.hidden ape_pad_text
|
||
ape_pad_text:
|
||
.previous
|
||
|
||
.section .ape.pad.privileged,"a",@progbits
|
||
.type ape_pad_privileged,@object
|
||
.hidden ape_pad_privileged
|
||
ape_pad_privileged:
|
||
.previous
|
||
|
||
.section .ape.pad.rodata,"a",@progbits
|
||
.type ape_pad_rodata,@object
|
||
.hidden ape_pad_rodata
|
||
ape_pad_rodata:
|
||
.previous
|
||
|
||
.section .ape.pad.data,"a",@progbits
|
||
.type ape_pad_data,@object
|
||
.hidden ape_pad_data
|
||
ape_pad_data:
|
||
.previous
|
||
|
||
.section .idata.ro,"a",@progbits
|
||
.type ape_idata_ro,@object
|
||
.hidden ape_idata_ro
|
||
ape_idata_ro:
|
||
.previous
|
||
|
||
.section .dataprologue,"aw",@progbits
|
||
.type __data_start,@object
|
||
.globl __data_start
|
||
.hidden __data_start
|
||
__data_start:
|
||
.previous
|
||
|
||
.end
|
||
|