|
|
/*-*- 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 │ |
|
|
│ │ |
|
|
│ This program is free software; you can redistribute it and/or modify │ |
|
|
│ it under the terms of the GNU General Public License as published by │ |
|
|
│ the Free Software Foundation; version 2 of the License. │ |
|
|
│ │ |
|
|
│ This program is distributed in the hope that it will be useful, but │ |
|
|
│ WITHOUT ANY WARRANTY; without even the implied warranty of │ |
|
|
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │ |
|
|
│ General Public License for more details. │ |
|
|
│ │ |
|
|
│ You should have received a copy of the GNU General Public License │ |
|
|
│ along with this program; if not, write to the Free Software │ |
|
|
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │ |
|
|
│ 02110-1301 USA │ |
|
|
╠──────────────────────────────────────────────────────────────────────────────╣ |
|
|
│░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░│ |
|
|
│░░░░░░░█▀█░█▀█░▀█▀░█░█░█▀█░█░░░█░░░█░█░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░│ |
|
|
│░░░░░░░█▀█░█░▄░░█░░█░█░█▀█░█░░░█░░░▀█▀░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░│ |
|
|
│░░░░░░░▀░▀░▀▀▀░░▀░░▀▀▀░▀░▀░▀▀▀░▀▀▀░░▀░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░│ |
|
|
│░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░│ |
|
|
│░░░░░░░█▀█░█▀█░█▀█░▀█▀░█▀█░█▀█░█░░░█▀▀░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░│ |
|
|
│░░░░░░░█▀▀░█ █░██▀░░█░░█▀█░█▀█░█░░░█▀▀░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░│ |
|
|
│░░░░░░░▀░░░▀▀▀░▀░▀░░▀░░▀░▀░▀▀▀░▀▀▀░▀▀▀░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░│ |
|
|
│░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░│ |
|
|
│░░░░░░░█▀▀░█░█░█▀▀░█▀█░█░█░▀█▀░█▀█░█▀█░█░░█▀▀░░░░░░░░░░░░░░░░░░░░░░░░▄▄░░░▐█░░│ |
|
|
│░░░░░░░█▀▀░▄▀▄░█▀▀░█░▄░█░█░░█░░█▀█░█▀█░█░░█▀▀░░░░░░░░░░░░▄▄▄░░░▄██▄░░█▀░░░█░▄░│ |
|
|
│░░░░░░░▀▀▀░▀░▀░▀▀▀░▀▀▀░▀▀▀░░▀░░▀░▀░▀▀▀░▀▀░▀▀▀░░░░░░░░░░▄██▀█▌░██▄▄░░▐█▀▄░▐█▀░░│ |
|
|
│░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▐█▀▀▌░░░▄▀▌░▌░█░▌░░▌░▌░░│ |
|
|
╠──────────────────────────────────────────────────────▌▀▄─▐──▀▄─▐▄─▐▄▐▄─▐▄─▐▄─│ |
|
|
│ αcτµαlly pδrταblε εxεcµταblε § program header │ |
|
|
╚─────────────────────────────────────────────────────────────────────────────*/ |
|
|
#include "ape/config.h" |
|
|
#include "ape/lib/apm.h" |
|
|
#include "ape/lib/pc.h" |
|
|
#include "ape/macros.h" |
|
|
#include "ape/notice.inc" |
|
|
#include "ape/relocations.h" |
|
|
#include "libc/elf/def.h" |
|
|
#include "libc/macho.h" |
|
|
#include "libc/nexgen32e/uart.h" |
|
|
#include "libc/nexgen32e/vidya.h" |
|
|
#include "libc/nt/pedef.h" |
|
|
#include "libc/nexgen32e/vidya.h" |
|
|
#include "libc/dce.h" |
|
|
#include "libc/sysv/consts/prot.h" |
|
|
|
|
|
#define USE_SYMBOL_HACK 0 |
|
|
|
|
|
.source "NOTICE" |
|
|
.source "ape/ape.S" |
|
|
.source "ape/ape.lds" |
|
|
.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,"aMS",@progbits |
|
|
cstr: .endobj cstr,globl,hidden # ←for gdb readibility |
|
|
.previous |
|
|
.section .sort.rodata.real.str1.1,"aMS",@progbits |
|
|
rlstr: .endobj rlstr,globl,hidden # ←for gdb readibility |
|
|
.previous |
|
|
.section .head,"ax",@progbits |
|
|
|
|
|
/* ████████ ████████ ███████████ |
|
|
██░░░░▒▒██ ██░░░░▒▒██ ████░░░░░░░░░▒▒████ |
|
|
██░░░░░░██ ██░░░░▒▒██ ██░░░░▒▒███████░░░░▒▒██ |
|
|
██░░░░░░▒▒██ ░██░░░░░░▒▒██ ██░░▒▒██ ██░░▒▒██ |
|
|
██░░▒▒░░░░██ ░██░░░░░░▒▒██ ██░░▒▒██ ████████ |
|
|
██░░▒▒▒▒░░▒▒██ ██▓░░░░▒▒░░▒▒██ ██░░▒▒▒▒███████ |
|
|
██░░▒▒██░░░░██ ██▓░░░░██░░▒▒██ ████░░░░░░░▒▒████ |
|
|
██░░▒▒████░░▒▒██░░░░░████░░▒▒██ ███████░░░░▒▒██ |
|
|
██░░▒▒████░░░░██░░░░░████░░▒▒██ ██████ ██░░░░▒▒██ |
|
|
██░░▒▒██ ██░░▒▒░░▒██ ██░░▒▒██ ██░░░░██ ██░░▒▒██ |
|
|
██░░▒▒██ ██░░░░░░▒██ ██░░▒▒██ ██░░░░█████████░░░░▒▒██ |
|
|
██░░▒▒██ ▓▓▒▒░░▒▒▒▓▓ ██░░▒▒██ ▓▓▒▒░░▓▓▓▓▓▓▓▓▓░░░░▓▓▓▓ |
|
|
██░░▒▒██ ██░░██▓ ██░░▒▒██ ██░░░░░░░░░░░░░▒▒██ |
|
|
████████████████████▓ ██████████████ ███████████████ |
|
|
██▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓█████▓▓░░▓▓░░▓▓░░████░░░░░░░░░░░░░░░████ |
|
|
██▓▓▓▓▓▓▓▓▓▓▓▓▓▓█████▓▓░░▓▓░░▓▓░░████░░░░░░░░░░░░░░░░░░░░░██ |
|
|
██▓▓▓▓▓▓▓▓▓▓▓▓▓▓██▓▓▒░░▓▓░░▓▓░░▓▓██░░░░░░░░░░░░░░░░░░░░░░░░░██ |
|
|
██▓▓▓▓▓▓██████████░░▒▓▓▓▓██████▓▓██░░░░░░███████████▓▓░░░░▓▓██ |
|
|
██▓▓▓▓▓▓████████░░▓▓▓▓▓██▓▓▓▓██████░░░░████░░▒▓▓██ ██▓▓▓▓▓▓██ |
|
|
██▓▓▓▓▓▓████████▓▓░░▒████▓▓▓▓██████░░░░██▓▓▓▓▒░░██ ██████ |
|
|
██▓▓▓▓▓▓██ ██░░▓▓▓▓▓██▓▓▓▓██ ██▓▓░░████░░▒▓▓██████ |
|
|
██▓▓▓▓▓▓██ ██▓▓░░▒████▓▓▓▓██ ██▓▓██▓▓▓▓▒░░██░░░░████ |
|
|
██▓▓▓▓▓▓██ ██░░▓▓▓▓▓██▓▓▓▓██ ██████░░▒▓▓██░░░░░░░░██ |
|
|
██▓▓▓▓▓▓██ ██▓▓░░▒████▓▓▓▓██ ██▓▓▓▓▒░░██▓▓░░░░░░░░██ |
|
|
██▓▓▓▓▓▓██ ██░░▓▓▓████▓▓▓▓██ ████████░░▒▓▓████▓▓░░░░░░██ |
|
|
██▓▓▓▓▓▓██ ██░░▒██▓▓▓▓████ ██░░░░░░██▓▓███ ██░░░░░░██ |
|
|
██▓▓▓▓▓▓█████████████▓▓▓▓██████████▓▓░░░░░░█████████░░░░░░░░██ |
|
|
██▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓████▓▓░░██▓▓░░░░░░░░░░░░░░░░░░░░░▓▓██ |
|
|
██▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓████▓▓░░▓▓██▓▓▓▓░░░░░░░░░░░░░░░░░▓▓▓▓██ |
|
|
██▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓████▓▓░░▓▓░░▓▓██▓▓▓▓▓▓░░░░░░░░░░░▓▓▓▓▓▓██ |
|
|
██▓▓█████████████████████▓▓██▓▓██▓▓████▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓██ |
|
|
███████████████████████████▓▓██▓▓██▓▓████▓▓▓▓▓▓▓▓▓▓▓▓▓████ |
|
|
██████████████████▓ ██████████████ █████████████ |
|
|
╔──────────────────────────────────────────────────────────────────────────────╗ |
|
|
│ αcτµαlly pδrταblε εxεcµταblε § the old technology │ |
|
|
╚─────────────────────────────────────────────────────────────────────────────*/ |
|
|
|
|
|
/ 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. |
|
|
/ |
|
|
/ @see www.delorie.com/djgpp/doc/exe/ |
|
|
/ @noreturn |
|
|
ape.mz: .ascii "MZ" # Mark 'Zibo' Joseph Zbikowski |
|
|
jno 2f # MZ: bytes on last page |
|
|
jo 2f # MZ: 512-byte pages in file |
|
|
.ascii "='" # MZ: reloc table entry count |
|
|
.ascii "\n\0" # MZ: data segment file offset / 16 |
|
|
.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 |
|
|
.long RVA(ape.pe) # PE: the new technology |
|
|
.endfn ape.mz,globl,hidden |
|
|
|
|
|
/ Disk Operating System Stub |
|
|
/ @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 |
|
|
.code16 |
|
|
pc: cld |
|
|
#if USE_SYMBOL_HACK |
|
|
.byte 0x0f,0x1f,0207 # nop rdi binbase |
|
|
.short (0x7c00-IMAGE_BASE_VIRTUAL)/512 |
|
|
#endif |
|
|
mov $REAL_STACK_FRAME>>4,%di # we need a stack |
|
|
xor %cx,%cx |
|
|
mov %cx,%es |
|
|
rlstack %di,%cx |
|
|
push %cs # memcpy() [relocate this page] |
|
|
pop %ds |
|
|
call 1f |
|
|
1: pop %si |
|
|
sub $RVA(1b),%si |
|
|
mov $IMAGE_BASE_REAL>>4,%ax |
|
|
push %ax # save real base |
|
|
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) # 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 |
|
|
mov %ax,%es |
|
|
xor %ax,%ax |
|
|
xor %di,%di |
|
|
rep stosb |
|
|
cmp $0x40,%dl # statfs() [disk geometry] |
|
|
je 6f |
|
|
call dsknfo |
|
|
pop %es # restore real base |
|
|
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: 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) |
|
|
.endfn pc,globl,hidden |
|
|
|
|
|
/ 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: 1 head × 40 cylinders × 8 sectors × 512 = 163,840 |
|
|
/ - 180KB: 1 head × 40 cylinders × 9 sectors × 512 = 184,320 |
|
|
/ - 320KB: 2 heads × 40 cylinders × 8 sectors × 512 = 327,680 |
|
|
/ - 360KB: 2 heads × 40 cylinders × 9 sectors × 512 = 368,640 |
|
|
/ - 720KB: 2 heads × 80 cylinders × 9 sectors × 512 = 737,280 |
|
|
/ - 1.2MB: 2 heads × 80 cylinders × 15 sectors × 512 = 1,228,800 |
|
|
/ - 1.44MB: 2 heads × 80 cylinders × 18 sectors × 512 = 1,474,560 |
|
|
/ |
|
|
/ Terminology |
|
|
/ |
|
|
/ - Cylinder / Tracks should mean the same thing |
|
|
/ - Heads / Sides / Spindles should mean the same thing |
|
|
/ |
|
|
/ 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 $XLM(DRIVE_BASE_TABLE),%si |
|
|
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 |
|
|
add $512>>4,%si |
|
|
mov %si,%es |
|
|
inc %al |
|
|
cmp XLM(DRIVE_LAST_SECTOR),%al |
|
|
jbe 2f |
|
|
mov $1,%al |
|
|
inc %cx |
|
|
cmp XLM(DRIVE_LAST_CYLINDER),%cx |
|
|
jbe 2f |
|
|
xor %cx,%cx |
|
|
inc %dh |
|
|
2: ret |
|
|
9: push %ax |
|
|
xor %ax,%ax # try disk reset on error |
|
|
int $0x13 |
|
|
pop %ax |
|
|
jmp 1b |
|
|
.endfn pcread |
|
|
|
|
|
/*───────────────────────────────────────────────────────────────────────────│─╗ |
|
|
│ αcτµαlly pδrταblε εxεcµταblε § partition table ─╬─│┼ |
|
|
╚────────────────────────────────────────────────────────────────────────────│*/ |
|
|
|
|
|
/ Partition Table. |
|
|
.Lape.mbrpad: |
|
|
.org 0x1b4 |
|
|
.endobj .Lape.mbrpad |
|
|
ape_disk: |
|
|
.stub .Lape.diskid,quad |
|
|
.org 0x1be,0x00 |
|
|
.macro .partn x |
|
|
.stub .Lape.part\x\().status,byte # 0=absent / 0x80=present |
|
|
.stub .Lape.part\x\().first.head,byte # in low 6 bits |
|
|
.stub .Lape.part\x\().first.cylinder,byte |
|
|
.stub .Lape.part\x\().first.sector,byte |
|
|
.stub .Lape.part\x\().filesystem,byte |
|
|
.stub .Lape.part\x\().last.head,byte |
|
|
.stub .Lape.part\x\().last.cylinder,byte |
|
|
.stub .Lape.part\x\().last.sector,byte |
|
|
.stub .Lape.part\x\().lba,long # c₀*Cₙ + h₀*Hₙ + s₀*Sₙ |
|
|
.stub .Lape.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 |
|
|
|
|
|
/* ▄▄▄ |
|
|
▄▄▄ ▀▓▓▒▄ |
|
|
▄▓▒▒░ ▀▓▒▒▒▄ |
|
|
▄▓▓▓▒▀ ▄▄▄▄ ▒▓▒▒░▒▄ |
|
|
▄▓▓▓▒▓ ▄▄▓██▓▓▓▓▒▒▒▒▓▓▄▄▓▓▒▒▒░░▒ |
|
|
▓▓▓▓▒▒▒▄▄ ░▒█▓▓▓▓▓▓▓▓▓▒▒▒▒▒▒▒▒▒▒▒▓▒░░▒░ |
|
|
██▓▓▓▒▒░░▒▒▒▒▓▓▓▓▓▓▒▓▒░▒▒░▀▒▒▒▒░▀░▒▒▒░▒ |
|
|
▓▓▓▓▓▓▓▒▒▒▒▒▒▓▓▒▓▓▒▒▒░▒▒░░ ░▒▒░ ░▒▒▒▒ |
|
|
▀▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▒▒░░▒░░ ░▒▒ ░ ▀▒▒ |
|
|
▀▓▓█▓▓▓▓▓▓▓▓▓▓▒▒░░▒▒░░ ░░░▓░ ▓░░░▒ |
|
|
▀▀█▓███▓▓▓▓▓▒▒░░░▒░░ ░█▓░█▓░█▓▓▄▒░ |
|
|
░▓██▓▓▓▓▓▒▒░░░▒░░ ░████▓▒▓█▓▀░▀▄ |
|
|
░▓██▓▓▓▓▓▒▒▒░░░▒░░ ▒██▓▒▒▒▒▒▒░░░▒ |
|
|
████▓▓▓▓▓▒▒▒▒▒▒▒▒▒░░▒▓▓▒░░░░▒░░░▒░ ░░░░░ |
|
|
░▓███▓▓▓▓▓▒▒░░░░░░░▒▒▒▒▒▒▒▒▒▒▒░░░ ░░░░░ ░ |
|
|
▓███▓▓▓▓▓▒▓▒▒▒▒░░░░░░░░░▒▓▒▒░▀ ░░░ ░░░░░ |
|
|
▀▒██▓▓▓▓▒▒▒▓▓▓▓▒▒▒▒▒▒▒▓▀▀░ ░░░░░░░░░ ░ |
|
|
▓▓▓▓▓▓▓▒▓▒▒▒▒▓▓▓▒▀░ ░░░░░▄░░░ ░░░ ░░░░░░ |
|
|
▓▓▓▒▒▒▒▒▒▒▒▒▒▒▓ █▓▒░░▒░░░░ ░░░░░░░░ |
|
|
▄▓▓▓▒▒▒▒▒░░░░░░░▒▄▄▄░▒▓▓▒▒░▀░ |
|
|
░▓█▓▓▒▒▒▒▒▒▒▒▒▒▒▒▒▒▓▓▓▓▓▓▒░░░▒ besiyata |
|
|
▓▓█▓▓▒▓▓▓▒▒▒░░░░░░▒▓▓▓▓▒▒▒▒▒░ dishmaya |
|
|
▓▓█▓▓▓▓▓▓▒▒▒░░░░░░░▒▓▓▒▀▀▀ |
|
|
▓▓██▓▓▓▓▓▓▓▒▒▒▒▒▒▒▒▒▒▀ |
|
|
█▓▓█▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▀ |
|
|
▒▓▓▓▓▀░░▒▓▓▓▓▓▓▓▓▒▒░░▒ |
|
|
▄▓▓▀░░░▄▓▓▓▓▒▒▒▒▒░░░░▄░ |
|
|
▄███▄▄▓▓▓▓▓▓▓▒▒▒▒▒░░▒▒░ |
|
|
▄▓▓▓█▓█▓▓███▓▓▓▓▓▓▓▓▓▓▓░ |
|
|
▄░▓▓▓▓▓▓▀▒▓▓▓▒▒▓▒░░░▒▓▒░░░▓ |
|
|
▄▄▄░▒▓▓▓▓▓▓░▀▀ ▓▓▒░▓▒▒▒▒▒▒▒▒▒▒▄░░▀▀░░ ▄▄▄▄ |
|
|
▄▄▄▒▒▓▓█▓▓▓▓▓▀▀▀▀▀ ▓▓▓▓▓▒▒▒▒▒▒▒▒▒▒▒▒▒▀░░▀░░▒▒▒░░░ ░░░░░ |
|
|
▄▓▓▓▒▀▀ ▓▒▓▓▓▓▓▒▒▒▒▒▒▒▒▓░░░ ▒▒▒░░░░░░░░▒ |
|
|
█▓▓▒ ▄▄▄ ▀▓▒▓▒▒▒▓▓▓▓▓▓▒▒▒░░░░░░░░░▒▒░░░░░░░ |
|
|
▀▓▓▓▓▒▄▄▒▒▒▒▒▒▄▄ ▀▀▀▀░░▒▒▒▒░░░░░░ |
|
|
▀▀▀▓▓▓▓▒▒▒▒▒▓▓▄▄ |
|
|
╔────────────────────────────────────────────────────────────────────────────│─╗ |
|
|
│ αcτµαlly pδrταblε εxεcµταblε § bell system five ─╬─│┼ |
|
|
╚────────────────────────────────────────────────────────────────────────────│─╝ |
|
|
the bourne executable & linkable format */ |
|
|
|
|
|
apesh: .ascii "'\n#'\"\n" # sixth edition shebang |
|
|
.ascii "o=\"$(command -v \"$0\")\"\n" |
|
|
.ascii "if [ -d /Applications ]; then\n" |
|
|
.ascii "dd if=\"$o\"" |
|
|
.ascii " of=\"$o\"" |
|
|
.ascii " bs=8" |
|
|
.ascii " skip=\"" |
|
|
.shstub .Lape.macho.dd.skip,2 |
|
|
.ascii "\" count=\"" |
|
|
.shstub .Lape.macho.dd.count,2 |
|
|
.ascii "\" conv=notrunc 2>/dev/null\n" |
|
|
.ascii "elif 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 .Lape.elf.entry,8 # 18: e_entry |
|
|
.shstub .Lape.elf.phoff,8 # 20: e_phoff |
|
|
.shstub .Lape.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 .Lape.elf.phnum,2 # 38: e_phnum |
|
|
.ascii "\\0\\0" # 3a: e_shentsize |
|
|
.shstub .Lape.elf.shnum,2 # 3c: e_shnum |
|
|
.shstub .Lape.elf.shstrndx,2 # 3e: e_shstrndx |
|
|
.ascii "' >&7\n" |
|
|
.ascii "exec 7<&-\n" |
|
|
.ascii "fi\n" |
|
|
.ascii "exec \"$0\" \"$@\"\n" # etxtbsy tail recursion |
|
|
.ascii "R=$?\n" # architecture optimistic |
|
|
.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\" \"$0\" \"$@\"\n" |
|
|
.ascii "else\n" |
|
|
.ascii "echo error: need qemu-x86_64 >&2\n" |
|
|
.ascii "fi\n" |
|
|
.ascii "elif [ $R -eq 127 ]; then\n" # means argv[0] was wrong |
|
|
.ascii " exec \"$o\" \"$@\"\n" # so do a path resolution |
|
|
.ascii "fi\n" |
|
|
.ascii "exit $R\n" |
|
|
.endobj apesh |
|
|
|
|
|
.section .elf.phdrs,"a",@progbits |
|
|
.align __SIZEOF_POINTER__ |
|
|
.type ape.phdrs,@object |
|
|
.globl ape.phdrs |
|
|
ape.phdrs: |
|
|
.long PT_LOAD # text segment |
|
|
.long PF_R|PF_X |
|
|
.stub .Lape.rom.offset,quad |
|
|
.stub .Lape.rom.vaddr,quad |
|
|
.stub .Lape.rom.paddr,quad |
|
|
.stub .Lape.rom.filesz,quad |
|
|
.stub .Lape.rom.memsz,quad |
|
|
.stub .Lape.rom.align,quad |
|
|
.align __SIZEOF_POINTER__ |
|
|
.long PT_LOAD # data segment |
|
|
.long PF_R|PF_W |
|
|
.stub .Lape.ram.offset,quad |
|
|
.stub .Lape.ram.vaddr,quad |
|
|
.stub .Lape.ram.paddr,quad |
|
|
.stub .Lape.ram.filesz,quad |
|
|
.stub .Lape.ram.memsz,quad |
|
|
.stub .Lape.ram.align,quad |
|
|
/ Linux ignores mprotect() and returns 0 without this lool |
|
|
/ It has nothing to do with the stack, which is still exec |
|
|
.align __SIZEOF_POINTER__ |
|
|
.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 |
|
|
.align __SIZEOF_POINTER__ |
|
|
.long PT_NOTE # openbsd note |
|
|
.long PF_R |
|
|
.stub .Lape.note.offset,quad |
|
|
.stub .Lape.note.vaddr,quad |
|
|
.stub .Lape.note.paddr,quad |
|
|
.stub .Lape.note.filesz,quad |
|
|
.stub .Lape.note.memsz,quad |
|
|
.stub .Lape.note.align,quad |
|
|
.previous |
|
|
|
|
|
.section .note.openbsd.ident,"a",@progbits |
|
|
.Lopenbsd.ident: |
|
|
.long 8 |
|
|
.long 4 |
|
|
.long 0x1 |
|
|
.asciz "OpenBSD" |
|
|
.long 0 |
|
|
.size .Lopenbsd.ident,.-.Lopenbsd.ident |
|
|
.type .Lopenbsd.ident,@object |
|
|
.previous |
|
|
|
|
|
/* ▄▄███▄ |
|
|
▄▄████████▄ |
|
|
▄█████████████▄ |
|
|
▄▄███▓▓▓▓▓▓▓▓▓▓▓███▄ |
|
|
▄▄█████▓▓▓█████████▓▓▓██▄ |
|
|
▄▄████████▓▓▓███████▓▓▓▓▓████▄ |
|
|
▄█████░░░████▓▓█████▓▓▓▓█████████▄ |
|
|
▄▄█████████░░░███▓▓█▓▓▓▓▒███████▓▓▒███▄ |
|
|
▄██████████████░░░██▓▓▓▓███████████▓▓█████▄ |
|
|
██████████████████░░░██▓▓▓█████████▓▓▓███████▄ |
|
|
███░░░░░░█████████▓░░███▓▓▓▓▓▓▓▓▓▓▓█████▒▒▒██▄ |
|
|
█░███░░░██░░░░░░░░░██░░██████████████▒▒▒▒██████▄ |
|
|
███████░░░█████████░░░░░░█████████▒▒▒▒▒██████████▄ |
|
|
█████ ██░░░███████████████████▒▒▒▒▒██░▒▒██████████▄ |
|
|
██████ ██░░░██████████████░███▒████████▒▒██████████▄ |
|
|
████████ ███░░█████████████░░████████████▒▒███████████ |
|
|
█████████ ███░░███████████░░██████████████▒▒███████████ |
|
|
▄██████████ ██████████████ ░░███████████████▒▒███████████ |
|
|
████████████ ███░░░░░█████░░█████████████████▒▒██████ █ |
|
|
█████████████ ██████░░░░░░░▒█████████████████████ ████▀ |
|
|
█████████████ ██████████░░░░░░░░░███████████ ████████ |
|
|
█████████████ ████████░░███████░░░██████ ▓██████████ |
|
|
█████████████ ██████░░░████████████ █████████████ |
|
|
╔────────────────────────────────────────────────────────────────────────────│─╗ |
|
|
│ α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 */ |
|
|
|
|
|
.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 .Lape.rom.vaddr,quad |
|
|
.stub .Lape.rom.memsz,quad |
|
|
.stub .Lape.rom.offset,quad |
|
|
.stub .Lape.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 .Lape.text.vaddr,quad |
|
|
.stub .Lape.text.memsz,quad |
|
|
.stub .Lape.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 .Lape.ram.vaddr,quad |
|
|
.stub .Lape.ram.memsz,quad |
|
|
.stub .Lape.ram.offset,quad |
|
|
.stub .Lape.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 .Lape.data.vaddr,quad |
|
|
.stub .Lape.data.memsz,quad |
|
|
.stub .Lape.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 .Lape.bss.vaddr,quad # virtual address |
|
|
.stub .Lape.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 uuid1_,quad |
|
|
.stub 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 _start_xnu # rip |
|
|
.quad 0 # rflags |
|
|
.quad 0 # cs |
|
|
.quad 0 # fs |
|
|
.quad 0 # gs |
|
|
520: |
|
|
60: |
|
|
|
|
|
.endobj ape.macho,globl,hidden |
|
|
.previous /* .macho */ |
|
|
|
|
|
/* ░░░░ |
|
|
▒▒▒░░░▒▒▒▒▒▒▒▓▓▓░ |
|
|
▒▒▒▒░░░▒▒▒▒▒▒▓▓▓▓▓▓░ |
|
|
▒▒▒▒░░░▒▒▒▒▒▒▒▓▓▓▓▓▓ ▒▓░ |
|
|
▒▒▒░░░░▒▒▒▒▒▒▓▓▓▓▓▓ ▓▓▓▓▓▓▒ ▒▒▒▓▓█ |
|
|
▒▒▒▒░░░▒▒▒▒▒▒▒▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▒▒▒▒▒▒▒▒▒▒▓▓▓ |
|
|
░▒▒▒░░░░▒▒▒▒▒▒▓▓▓▓▓▓ █▓▓▓▓▓▓▓▒▒▒▒▒▒▒▒▒▒▓▓█ |
|
|
▒▒▒▒░░░▒▒▒▒▒▒▒▓▓▓▓▓░ ▓▓▓▓▓▓▓▓▒▒▒▒▒▒▒▒▒▒▓▓▓ |
|
|
▒▒▒▒░░░▒▒▒▒▒▒▒▓▓▓▓▓▓ ▒▓▓▓▓▓▓▓▓▒▒▒▒▒▒▒▒▒▒▓▓▒ |
|
|
▒▒▒▒▓▓ ▓▒▒▓▓▓▓ ▓▓▓▓▓▓▓▓▒▒▒▒▒▒▒▒▒▒▓▓█ |
|
|
▒▓ ▓▓▓▓▓▓▓▓▓▒▒▒▒▒▒▒▒▒▒▓▓ |
|
|
░░░░░░░░░░░▒▒▒▒ ▓▓▓▓▓▓▓▓▒▒▒▒▒▒▒▒▒▒▓▓█ |
|
|
▒▒░░░░░░░░░░▒▒▒▒▒▓▓▓ ▓▓▓▓▓▒▒▒▒▒▒▒▒▒▒▓▓▓ |
|
|
░▒░░░░░░░░░░░▒▒▒▒▒▓▓ ▓░ ░▓███▓ |
|
|
▒▒░░░░░░░░░░▒▒▒▒▒▓▓░ ▒▓▓▓▒▒▒ ░▒▒▒▓ ████████████ |
|
|
▒▒░░░░░░░░░░░▒▒▒▒▒▓▓ ▒▓▓▓▓▒▒▒▒▒▒▒▒░░░▒▒▒▒▒░ ░███ |
|
|
▒░░░░░░░░░░░▒▒▒▒▒▓▓ ▓▓▓▓▒▒▒▒▒▒▒▒░░░░▒▒▒▒▓ ███ |
|
|
▒▒░░░░░░░░░░▒▒▒▒▒▒▓▓ ▒▓▓▓▒▒▒▒▒▒▒▒░░░░▒▒▒▒▒ ▓██ |
|
|
▒░░░░░░░░░░░▒▒▒▒▒▓▓ ▓▓▓▓▒▒▒▒▒▒▒▒░░░▒▒▒▒▒▓ ▓██ |
|
|
▒▒░░░▒▒▒░░░▒▒░▒▒▒▓▓▒ ▒▓▓▓▒▒▒▒▒▒▒▒░░░░▒▒▒▒▒ ███ |
|
|
░▒▓ ░▓▓▓▓▒▒▒▒▒▒▒▒░░░░▒▒▒▒▓ ▓██ |
|
|
╔─────────────────────────────────────────────────────────────────▀▀▀────────│─╗ |
|
|
│ α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││ |
|
|
.LPEEXE = 0b0000001000100011 |
|
|
|
|
|
/ ┌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 |
|
|
.LDLLSTD = 0b0000000100100000 |
|
|
.LDLLPIE = 0b0000000001000000 |
|
|
.LDLLEXE = .LDLLSTD |
|
|
|
|
|
/ ┌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 |
|
|
.LPETEXT = 0b01110000000000000000000001100000 |
|
|
.LPEDATA = 0b11000000000000000000000011000000 |
|
|
.LPEIMPS = 0b11000000000000000000000001000000 |
|
|
|
|
|
.section .pe.header,"a",@progbits |
|
|
.align __SIZEOF_POINTER__ |
|
|
ape.pe: .ascin "PE",4 |
|
|
.short kNtImageFileMachineNexgen32e |
|
|
.stub .Lape.pe.shnum,short # NumberOfSections |
|
|
.long 0x5c64126b # TimeDateStamp |
|
|
.long 0 # PointerToSymbolTable |
|
|
.long 0 # NumberOfSymbols |
|
|
.stub .Lape.pe.optsz,short # SizeOfOptionalHeader |
|
|
.short .LPEEXE # Characteristics |
|
|
.short kNtPe64bit # Optional Header Magic |
|
|
.byte 14 # MajorLinkerVersion |
|
|
.byte 15 # MinorLinkerVersion |
|
|
.long 0 # SizeOfCode |
|
|
.long 0 # SizeOfInitializedData |
|
|
.long 0 # SizeOfUninitializedData |
|
|
.long RVA(WinMain) # EntryPoint |
|
|
.long 0 # BaseOfCode |
|
|
.quad IMAGE_BASE_VIRTUAL # ImageBase |
|
|
.long 4096 # SectionAlignment |
|
|
.long 4096 # FileAlignment |
|
|
.short 6 # MajorOperatingSystemVersion |
|
|
.short 0 # MinorOperatingSystemVersion |
|
|
.short 0 # MajorImageVersion |
|
|
.short 0 # MinorImageVersion |
|
|
.short 6 # 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 |
|
|
.short .LDLLEXE # DllCharacteristics |
|
|
.quad 0x0000000000080000 # StackReserve |
|
|
.quad 0x0000000000080000 # StackCommit |
|
|
.quad 0 # HeapReserve |
|
|
.quad 0 # HeapCommit |
|
|
.long 0 # LoaderFlags |
|
|
.long 16 # NumberOfDirectoryEntries |
|
|
.long 0,0 # ExportsDirectory |
|
|
.long RVA(idata.idt) # ImportsDirectory |
|
|
.stub .Lidata.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 |
|
|
.long RVA(idata.iat) # ImportAddressDirectory |
|
|
.stub .Lidata.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 .Lape.text.memsz,long # Virtual Size or Physical Address |
|
|
.stub .Lape.text.rva,long # Relative Virtual Address |
|
|
.stub .Lape.text.filesz,long # Physical Size |
|
|
.stub .Lape.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 .LPETEXT # Flags |
|
|
.previous |
|
|
|
|
|
.section .pe.sections,"a",@progbits |
|
|
.ascin ".data",8 # Section Name |
|
|
.stub .Lape.ram.memsz,long # Virtual Size or Physical Address |
|
|
.stub .Lape.ram.rva,long # Relative Virtual Address |
|
|
.stub .Lape.ram.filesz,long # Physical Size |
|
|
.stub .Lape.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 .LPEDATA # Flags |
|
|
.previous |
|
|
|
|
|
.section .idata.ro.idt.1,"a",@progbits |
|
|
.type idata.idtend,@object |
|
|
.type idata.idt,@object |
|
|
.globl idata.idt,idata.idtend |
|
|
.hidden idata.idt,idata.idtend |
|
|
idata.idt: |
|
|
.previous/* |
|
|
... |
|
|
decentralized content |
|
|
... |
|
|
*/.section .idata.ro.idt.3,"a",@progbits |
|
|
.long 0,0,0,0,0 |
|
|
idata.idtend: |
|
|
.previous |
|
|
|
|
|
.section .piro.data.sort.iat.1,"aw",@progbits |
|
|
.type idata.iatend,@object |
|
|
.type idata.iat,@object |
|
|
.globl idata.iat,idata.iatend |
|
|
.hidden idata.iat,idata.iatend |
|
|
idata.iat: |
|
|
.previous/* |
|
|
... |
|
|
decentralized content |
|
|
... |
|
|
*/.section .piro.data.sort.iat.3,"aw",@progbits |
|
|
idata.iatend: |
|
|
.previous |
|
|
|
|
|
/*─────────────────────────────────────────────────────────────────────────────╗ |
|
|
│ α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. |
|
|
ape.str: |
|
|
.Lstr.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 .Lstr.ape |
|
|
.Lstr.error: |
|
|
.asciz "error: " |
|
|
.endobj .Lstr.error |
|
|
.Lstr.crlf: |
|
|
.asciz "\r\n" |
|
|
.endobj .Lstr.crlf |
|
|
.Lstr.cpuid: |
|
|
.asciz "cpuid" |
|
|
.endobj .Lstr.cpuid |
|
|
.Lstr.oldskool: |
|
|
.asciz "oldskool" |
|
|
.endobj .Lstr.oldskool |
|
|
.Lstr.dsknfo: |
|
|
.asciz "dsknfo" |
|
|
.endobj .Lstr.dsknfo |
|
|
.Lstr.e820: |
|
|
.asciz "e820" |
|
|
.endobj .Lstr.e820 |
|
|
.Lstr.memory: |
|
|
.asciz "nomem" |
|
|
.endobj .Lstr.memory |
|
|
.Lstr.long: |
|
|
.asciz "nolong" |
|
|
.endobj .Lstr.long |
|
|
.endobj ape.str |
|
|
|
|
|
/ 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,hidden |
|
|
|
|
|
/ 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 */ |
|
|
|
|
|
nop |
|
|
nop |
|
|
nop |
|
|
nop |
|
|
realmodeloader: |
|
|
call rlinit |
|
|
call sinit4 |
|
|
mov $REAL(.Lstr.ape),%di |
|
|
call rvputs |
|
|
.optfn _start16 |
|
|
call _start16 |
|
|
call longmodeloader |
|
|
.endfn realmodeloader,globl,hidden |
|
|
|
|
|
.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 |
|
|
|
|
|
/ 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 |
|
|
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 |
|
|
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 |
|
|
|
|
|
/ Abnormally exits program. |
|
|
/ |
|
|
/ @param di message |
|
|
/ @mode real |
|
|
/ @noreturn |
|
|
rldie: call rlpute |
|
|
call rloff |
|
|
.endfn rldie,globl,hidden |
|
|
|
|
|
/ Shuts down machine. |
|
|
/ |
|
|
/ @mode real |
|
|
/ @noreturn |
|
|
rloff: mov $kBiosDataAreaXlm+COM1,%di |
|
|
mov $4,%si |
|
|
call sflush |
|
|
call apmoff |
|
|
.endfn rloff,globl,hidden |
|
|
|
|
|
/ Prints error message. |
|
|
/ |
|
|
/ @param di message |
|
|
/ @mode real |
|
|
rlpute: mov kBiosDataAreaXlm+METAL_STDERR(%bx),%si |
|
|
test %si,%si |
|
|
jnz 1f |
|
|
mov kBiosDataAreaXlm+METAL_STDOUT,%si |
|
|
1: xor %ax,%ax |
|
|
push %ax |
|
|
push %si |
|
|
mov $REAL(.Lstr.crlf),%ax |
|
|
push %ax |
|
|
push %si |
|
|
push %di |
|
|
push %si |
|
|
mov $REAL(.Lstr.error),%ax |
|
|
push %ax |
|
|
1: pop %di |
|
|
test %di,%di |
|
|
jz 2f |
|
|
pop %si |
|
|
call rlput2 |
|
|
jmp 1b |
|
|
2: ret |
|
|
.endfn rlpute,globl,hidden |
|
|
|
|
|
/ Prints string to both video and serial. |
|
|
/ |
|
|
/ @param di NUL-terminated string |
|
|
/ @param si serial port |
|
|
/ @mode real |
|
|
rlput2: push %di |
|
|
push %si |
|
|
call rvputs |
|
|
pop %si |
|
|
pop %di |
|
|
test %si,%si |
|
|
jz 1f |
|
|
call sputs |
|
|
1: ret |
|
|
.endfn rlput2,globl,hidden |
|
|
|
|
|
/ Video put string. |
|
|
/ |
|
|
/ @param di is the string |
|
|
/ @mode real |
|
|
rvputs: mov %di,%si |
|
|
0: lodsb |
|
|
test %al,%al |
|
|
je 1f |
|
|
call rvputc |
|
|
jmp 0b |
|
|
1: ret |
|
|
.endfn rvputs,globl,hidden |
|
|
|
|
|
/ Video put char. |
|
|
/ |
|
|
/ @param al is the char |
|
|
/ @mode real |
|
|
rvputc: push %bx # don't clobber bp,bx,di,si,cx |
|
|
push %bp # original ibm pc scroll up bug |
|
|
mov $7,%bx # normal mda/cga style page zero |
|
|
mov $0x0e,%ah # teletype output al cp437 |
|
|
int $0x10 # vidya service |
|
|
pop %bp # preserves al |
|
|
pop %bx |
|
|
ret |
|
|
.endfn rvputc |
|
|
|
|
|
/ Writes string to serial line. |
|
|
/ |
|
|
/ @param di NUL-terminated string |
|
|
/ @param si serial port |
|
|
/ @mode long,legacy,real |
|
|
sputs: push %bx |
|
|
mov %di,%bx |
|
|
1: xchg %bx,%si |
|
|
lodsb |
|
|
xchg %bx,%si |
|
|
test %al,%al |
|
|
jz 2f |
|
|
mov %ax,%di |
|
|
push %si |
|
|
rlcall sputc |
|
|
pop %si |
|
|
jmp 1b |
|
|
2: pop %bx |
|
|
ret |
|
|
.endfn sputs,globl |
|
|
|
|
|
/ Waits for serial lines to become idle. |
|
|
/ |
|
|
/ @param di short array of serial ports (0 means not present) |
|
|
/ @param si number of items in array |
|
|
/ @mode long,legacy,real |
|
|
sflush: mov %si,%cx |
|
|
mov %di,%si |
|
|
xor %dx,%dx |
|
|
0: lodsb |
|
|
mov %al,%dl |
|
|
lodsb |
|
|
mov %al,%dh |
|
|
test %ax,%ax |
|
|
jz 2f |
|
|
add $UART_LSR,%dx |
|
|
mov $UART_TTYIDL,%ah |
|
|
1: in %dx,%al |
|
|
and %ah,%al |
|
|
rep |
|
|
nop |
|
|
jz 1b |
|
|
loop 0b |
|
|
2: ret |
|
|
.endfn sflush,globl |
|
|
|
|
|
/ Transmits byte over serial line. |
|
|
/ |
|
|
/ This is both blocking and asynchronous. |
|
|
/ |
|
|
/ @param di character to send |
|
|
/ @param si serial port |
|
|
/ @mode long,legacy,real |
|
|
/ @see ttytxr |
|
|
sputc: push %ax |
|
|
push %cx |
|
|
push %dx |
|
|
mov %si,%dx |
|
|
add $UART_LSR,%dx |
|
|
mov $UART_TTYTXR,%ah |
|
|
1: in %dx,%al |
|
|
and %ah,%al |
|
|
jnz 2f |
|
|
rep |
|
|
nop |
|
|
jmp 1b |
|
|
2: mov %di,%ax |
|
|
mov %si,%dx |
|
|
out %al,%dx |
|
|
pop %dx |
|
|
pop %cx |
|
|
pop %ax |
|
|
ret |
|
|
.endfn sputc,globl |
|
|
|
|
|
/ Shuts down personal computer. |
|
|
/ |
|
|
/ @mode real |
|
|
/ @noreturn |
|
|
apmoff: mov $0x5300,%ax # apm installation check |
|
|
xor %bx,%bx # for the apm bios itself |
|
|
int $APM_SERVICE |
|
|
jc 1f |
|
|
cmp $'P<<8|'M,%bx # did apm bios service interrupt? |
|
|
jne 1f |
|
|
mov $0x5301,%ax # real mode interface connect |
|
|
xor %bx,%bx # to apm bios device |
|
|
int $APM_SERVICE # ignore errors e.g. already connected |
|
|
xor %bx,%bx |
|
|
xor %cx,%cx |
|
|
mov $0x5307,%ax # set power state |
|
|
mov $1,%bl # for all devices within my dominion |
|
|
mov $3,%cl # to off |
|
|
int $APM_SERVICE |
|
|
1: call panic |
|
|
.endfn apmoff,globl |
|
|
|
|
|
/* █ █▒ |
|
|
█ █ |
|
|
█▓▄ █ █ |
|
|
▒▓ ░█░ ░▒▓▓███░ █▒ |
|
|
▒▓ ▒▓███▓▒░ ░▓ |
|
|
█ ▓░ |
|
|
▄██░ █ |
|
|
▓▓ ▓██░ ▓█░▓█ ▒▓ |
|
|
▒█ ░█ █ ░▓ █ █ |
|
|
█░ █ ░▓ ▀▒ █░ █ |
|
|
█▒ ▀▒░ ▓▓ |
|
|
▄▄▄▓████▓▓▒░ █ ▄▄▄▄▓▓▓█▓▓▓▓▒░ ▒█ |
|
|
▄▓▓▀ ▒ ░█ ▄▓▀ ░███▒ |
|
|
▓▀ ░░ ▀▓▄▄▄▒▒ █ |
|
|
█ ░░█▒ ▒█ ▒▓ █ |
|
|
▀█ ▄▄▄▄▄▄▄▄▄▄ ▀▀░▓██▓ █ |
|
|
▀■▄▄▄■▀ ▀▀█▄ █ |
|
|
▀▀█▄ █ |
|
|
▀█▄ █ |
|
|
█▌ █ |
|
|
█▌ █ |
|
|
█▌ █ |
|
|
█▌ █ |
|
|
█▌ █ |
|
|
█▌ █ |
|
|
█▌ █ |
|
|
█▌ █ |
|
|
█▌ █ |
|
|
█▌ █ |
|
|
█▌ █ |
|
|
█▌ █ |
|
|
█▌ █ |
|
|
█▌ █ |
|
|
█▌ █ |
|
|
█▌ █ |
|
|
█▌ █ |
|
|
█▌ █ |
|
|
█▌ █ |
|
|
█▌ █ |
|
|
█▌ █ |
|
|
█▌ █ |
|
|
╔──────────────────────────────────────────────────────────────────────────▀─│─╗ |
|
|
│ αcτµαlly pδrταblε εxεcµταblε § long mode loader ─╬─│┼ |
|
|
╚────────────────────────────────────────────────────────────────────────────│─╝ |
|
|
long mode is long */ |
|
|
|
|
|
longmodeloader: |
|
|
call lcheck |
|
|
call a20 |
|
|
mov $XLM(E820),%di |
|
|
mov $XLM_E820_SIZE,%si |
|
|
call e820 |
|
|
jc 9f |
|
|
call unreal |
|
|
/ call hiload |
|
|
jmp golong |
|
|
9: mov $REAL(.Lstr.e820),%ax |
|
|
call rldie |
|
|
.endfn longmodeloader,globl,hidden |
|
|
|
|
|
/ 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(.Lstr.oldskool),%ax |
|
|
jmp 20f |
|
|
10: mov $REAL(.Lstr.long),%ax |
|
|
jmp 20f |
|
|
12: mov $REAL(.Lstr.cpuid),%ax |
|
|
jmp 20f |
|
|
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 |
|
|
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 |
|
|
int $0x15 # ax,bx,cx,dx,d |