From 44dc43fcb5b9ccf90d5729dce1c1a2e8fc3338ca Mon Sep 17 00:00:00 2001 From: tkchia Date: Sat, 26 Aug 2023 22:23:17 +0000 Subject: [PATCH] [metal] Get zipos working again for legacy BIOS boot examples/hellolua.c now runs again when booted as a legacy BIOS disk image. - output number of sectors to load as a patchable variable; for now the patching is done by tool/build/zipcopy.c - remove references to _ezip - add tweaks to metal mmap() - implement lseek() & fstat() for metal memory files --- ape/ape.S | 72 +++++++++++++++++++------------- ape/ape.lds | 11 ++--- ape/sections.internal.h | 1 - build/bootstrap/zipcopy.com | Bin 49448 -> 61440 bytes libc/calls/fstat-metal.c | 33 ++++++++++----- libc/calls/internal.h | 1 + libc/calls/lseek-metal.c | 50 ++++++++++++++++++++++ libc/calls/lseek.c | 4 +- libc/calls/metalfile.c | 5 +-- libc/calls/metalfile.internal.h | 1 + libc/intrin/directmap-metal.c | 10 ++++- libc/intrin/interrupts.S | 1 + tool/build/zipcopy.c | 26 +++++++++++- 13 files changed, 160 insertions(+), 55 deletions(-) create mode 100644 libc/calls/lseek-metal.c diff --git a/ape/ape.S b/ape/ape.S index 348f21912..ecbc5834b 100644 --- a/ape/ape.S +++ b/ape/ape.S @@ -152,10 +152,13 @@ ape_mz: .short 0x0800 // MZ: increases cs load lower bound .short 0x0040 // MZ: reloc table offset .short 0 // MZ: overlay number + .ascii "'<<'@'\n" .org 0x24 // MZ: bytes reserved for you .ascii "JT" // MZ: OEM identifier - .short 0 // MZ: OEM information - .ascii "' <<'@'\n" + .short 1 // MZ: OEM information +__ape_com_sectors: + .short v_ape_allsectors // total number of sectors to load; + .endobj __ape_com_sectors,globl // to be patched by Cosmo tools .org 0x40-4 // MZ: bytes reserved for you #if SupportsWindows() || SupportsMetal() .long RVA(ape_pe) // PE: the new technology @@ -220,7 +223,7 @@ stub: mov $0x40,%dl // *literally* dos 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 +2: push %rax // a.k.a. push %ax 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 @@ -291,7 +294,11 @@ pc: cld mov $1,%al // current sector xor %cx,%cx // current cylinder xor %dh,%dh // current head - mov $v_ape_realsectors,%di // total sectors + mov $v_ape_maxrealsectors,%di // no. sectors for base memory + mov REAL(__ape_com_sectors),%bp + cmp %bp,%di + jb 3f + mov %bp,%di 3: call pcread mov %es,%si // addr += 512 add $512>>4,%si @@ -417,13 +424,12 @@ pcread: push %ax 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 + mov $0x0201,%ax // read only one disk sector int $0x13 pop %cx pop %ax jc 9f - inc %al // ++sector + inc %ax // ++sector cmp mm+"struct mman::pc_drive_last_sector",%al jbe 2f mov $1,%al @@ -480,7 +486,7 @@ sinit4: mov $4,%cx jz 1f push %cx push %si - xchg %ax,%di + xchg %ax,%dx mov $REAL(sconf),%si call sinit pop %si @@ -491,18 +497,16 @@ sinit4: mov $4,%cx // Initializes Serial Line Communications 8250 UART 16550A // -// @param word di tty port +// @param word dx tty port // @param char (*{es:,e,r}si)[4] register initial values +// @clob dx // @mode long,legacy,real // @see www.lammertbies.nl/comm/info/serial-uart.html -sinit: mov %di,%dx - test %dx,%dx +sinit: test %dx,%dx jz 2f push %dx push %si - xor %cx,%cx - mov $UART_LCR,%cl - add %cx,%dx + add $UART_LCR,%dx lodsb %ds:(%si),%al pop %si or $UART_DLAB,%al @@ -1515,7 +1519,11 @@ cpyhi: push %es call unreal mov $IMAGE_BASE_REAL,%esi mov $IMAGE_BASE_PHYSICAL,%edi - mov $v_ape_realdwords,%ecx + mov $v_ape_maxrealsectors,%ecx + cmp %bp,%cx + jb 1f + mov %bp,%cx +1: shl $9-2,%ecx // convert sector count to dword count cld rep movsl %ds:(%esi),%es:(%edi) sti @@ -1545,13 +1553,16 @@ unreal: push %ds pop %ds ret -// Reads any remaining program pages into memory which have not yet -// been read by the boot sector. +// Reads any remaining program & data sectors into memory which have not +// yet been read by the boot sector. // -// @clob eax, ecx, dx, esi, edi, bp -loadhi: mov $v_ape_highsectors,%bp - test %bp,%bp - jz 9f +// @return ebp physical address after end of loaded sectors +// @clob eax, ecx, dx, esi, edi +loadhi: +#define SEG 0x79000 + mov $IMAGE_BASE_PHYSICAL+v_ape_maxrealbytes-SEG,%edi + sub $v_ape_maxrealsectors,%bp + jbe 9f mov $mm+"struct mman::pc_drive",%si cld lodsb //← pc_drive @@ -1565,8 +1576,6 @@ loadhi: mov $v_ape_highsectors,%bp xchg %ax,%cx mov (%si),%dh #← pc_drive_next_head push %es -#define SEG 0x79000 - mov $IMAGE_BASE_PHYSICAL+v_ape_realbytes-SEG,%edi push $SEG>>4 pop %es 0: call pcread @@ -1584,7 +1593,8 @@ loadhi: mov $v_ape_highsectors,%bp dec %bp jnz 0b pop %es -9: ret +9: lea SEG(%edi),%ebp + ret // Initializes long mode paging. pinit: push %ds @@ -1638,6 +1648,8 @@ golong: cli .endfn golong // Long mode is long. +// +// @param ebp physical address after end of loaded sectors .code64 long: movabs $BANE+PHYSICAL(0f),%rax jmp *%rax @@ -1653,12 +1665,12 @@ long: movabs $BANE+PHYSICAL(0f),%rax xor %r13d,%r13d xor %r14d,%r14d xor %r15d,%r15d - xor %ebx,%ebx - xor %ebp,%ebp mov $mm,%rdi mov %cr3,%rsi mov $IMAGE_BASE_PHYSICAL,%edx - lea v_ape_allbytes(%rdx),%ecx + mov %ebp,%ecx + xor %ebx,%ebx + xor %ebp,%ebp call __map_phdrs push $0x037f fldcw (%rsp) @@ -1792,9 +1804,9 @@ kernel: movabs $ape_stack_vaddr,%rsp .endm .ldsvar _end .ldsvar _etext - .ldsvar v_ape_realsectors - .ldsvar v_ape_realbytes - .ldsvar v_ape_highsectors + .ldsvar v_ape_maxrealsectors + .ldsvar v_ape_maxrealbytes + .ldsvar v_ape_allsectors .ldsvar ape_idata_ro .ldsvar ape_piro .ldsvar ape_piro_end diff --git a/ape/ape.lds b/ape/ape.lds index 944c9829f..273099ab6 100644 --- a/ape/ape.lds +++ b/ape/ape.lds @@ -436,7 +436,6 @@ SECTIONS { /*END: NT FORK COPYING */ _edata = .; PROVIDE(edata = .); - _ezip = .; /* <-- very deprecated */ } :Ram . = ALIGN(CONSTANT(COMMONPAGESIZE)); @@ -632,12 +631,10 @@ APE_DECLARE_FIXED_DECIMAL(IDENTITY, blink_xnu_aarch64_size); #endif /* APE_IS_SHELL_SCRIPT */ #if SupportsMetal() -v_ape_realsectors = MIN(0x70000 - IMAGE_BASE_REAL, ROUNDUP(RVA(_ezip), 512)) / 512; -v_ape_realbytes = v_ape_realsectors * 512; -v_ape_realdwords = v_ape_realsectors * (512 / 4); -v_ape_allsectors = ROUNDUP(RVA(_ezip), 512) / 512; -v_ape_allbytes = v_ape_allsectors * 512; -v_ape_highsectors = MIN(0xffff, v_ape_allsectors - v_ape_realsectors); +v_ape_maxrealbytes = ROUNDUP(0x70000 - IMAGE_BASE_REAL, 512); +v_ape_maxrealsectors = v_ape_maxrealbytes / 512; +v_ape_allbytes = ROUNDUP(_edata - __executable_start, 512); +v_ape_allsectors = v_ape_allbytes / 512; TSSDESCSTUB2(_tss, _tss, _tss_end ? _tss_end - _tss - 1 : 0); #endif diff --git a/ape/sections.internal.h b/ape/sections.internal.h index cec1745dd..ae2193a7a 100644 --- a/ape/sections.internal.h +++ b/ape/sections.internal.h @@ -9,7 +9,6 @@ extern unsigned char __privileged_start[] __attribute__((__weak__)); extern unsigned char _ehead[] __attribute__((__weak__)); extern unsigned char _etext[] __attribute__((__weak__)); extern unsigned char _edata[] __attribute__((__weak__)); -extern unsigned char _ezip[] __attribute__((__weak__)); extern unsigned char _end[] __attribute__((__weak__)); extern unsigned char _ereal[] __attribute__((__weak__)); extern unsigned char _tdata_start[] __attribute__((__weak__)); diff --git a/build/bootstrap/zipcopy.com b/build/bootstrap/zipcopy.com index a448c6cf8231be8785194c651a01744f8bbcd706..ae8cdc8ae55bf5bb6e9b788bd2395ffcfa841bfa 100755 GIT binary patch delta 27294 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 = g_fds.p[fd].handle; - st->st_rdev = g_fds.p[fd].handle; - st->st_nlink = 1; - st->st_mode = S_IFCHR | 0600; - st->st_blksize = 1; - return 0; - } else { - return ebadf(); + struct MetalFile *file; + if (fd < 0 || fd >= g_fds.n) return einval(); + switch (g_fds.p[fd].kind) { + case kFdSerial: + bzero(st, sizeof(*st)); + st->st_dev = g_fds.p[fd].handle; + st->st_rdev = g_fds.p[fd].handle; + st->st_nlink = 1; + st->st_mode = S_IFCHR | 0600; + st->st_blksize = 1; + return 0; + case kFdFile: + file = (struct MetalFile *)g_fds.p[fd].handle; + bzero(st, sizeof(*st)); + st->st_nlink = 1; + st->st_size = file->size; + st->st_mode = S_IFREG | 0600; + st->st_blksize = 1; + return 0; + default: + return ebadf(); } } diff --git a/libc/calls/internal.h b/libc/calls/internal.h index 41dabb0f3..16145b0a4 100644 --- a/libc/calls/internal.h +++ b/libc/calls/internal.h @@ -43,6 +43,7 @@ forceinline bool __isfdkind(int fd, int kind) { int _check_interrupts(int); int sys_close_nt(struct Fd *, int); int sys_openat_metal(int, const char *, int, unsigned); +int64_t sys_lseek_metal(struct Fd *, int64_t, int); COSMOPOLITAN_C_END_ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ diff --git a/libc/calls/lseek-metal.c b/libc/calls/lseek-metal.c new file mode 100644 index 000000000..a004b7e35 --- /dev/null +++ b/libc/calls/lseek-metal.c @@ -0,0 +1,50 @@ +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2020 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/calls/calls.h" +#include "libc/calls/internal.h" +#include "libc/calls/metalfile.internal.h" +#include "libc/calls/struct/fd.internal.h" +#include "libc/sysv/errfuns.h" + +int64_t sys_lseek_metal(struct Fd *fd, int64_t offset, int whence) { + size_t new_pos; + struct MetalFile *file; + switch (fd->kind) { + case kFdFile: + file = (struct MetalFile *)fd->handle; + switch (whence) { + case SEEK_SET: + new_pos = offset; + break; + case SEEK_CUR: + new_pos = file->pos + offset; + break; + case SEEK_END: + new_pos = file->size + offset; + break; + default: + return einval(); + } + if (new_pos > file->size) return einval(); + file->pos = new_pos; + return new_pos; + default: + return ebadf(); + } +} diff --git a/libc/calls/lseek.c b/libc/calls/lseek.c index fff3b7efe..71bf8f36c 100644 --- a/libc/calls/lseek.c +++ b/libc/calls/lseek.c @@ -77,9 +77,11 @@ */ int64_t lseek(int fd, int64_t offset, int whence) { int64_t rc; - if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip) { + if (fd >= 0 && fd < g_fds.n && g_fds.p[fd].kind == kFdZip) { rc = _weaken(__zipos_seek)( (struct ZiposHandle *)(intptr_t)g_fds.p[fd].handle, offset, whence); + } else if (fd >= 0 && fd < g_fds.n && IsMetal()) { + rc = sys_lseek_metal(g_fds.p + fd, offset, whence); } else if (IsLinux() || IsXnu() || IsFreebsd() || IsOpenbsd()) { rc = sys_lseek(fd, offset, whence, 0); } else if (IsNetbsd()) { diff --git a/libc/calls/metalfile.c b/libc/calls/metalfile.c index 3b46de96e..a657b0b3c 100644 --- a/libc/calls/metalfile.c +++ b/libc/calls/metalfile.c @@ -53,7 +53,7 @@ void *__ape_com_base; size_t __ape_com_size = 0; textstartup dontasan void InitializeMetalFile(void) { - if (IsMetal()) { + if (IsMetal() && _weaken(__ape_com_sectors)) { /* * Copy out a pristine image of the program — before the program might * decide to modify its own .data section. @@ -63,8 +63,7 @@ textstartup dontasan void InitializeMetalFile(void) { * The zipos code will automatically arrange to do this. Alternatively, * user code can __static_yoink this symbol. */ - size_t size = ROUNDUP(_ezip - __executable_start, 4096); - // TODO(jart): Restore support for ZIPOS on metal. + size_t size = ROUNDUP((size_t)__ape_com_sectors * 512, 4096); void *copied_base; struct DirectMap dm; dm = sys_mmap_metal(NULL, size, PROT_READ | PROT_WRITE, diff --git a/libc/calls/metalfile.internal.h b/libc/calls/metalfile.internal.h index a7586c85d..5a59c8c98 100644 --- a/libc/calls/metalfile.internal.h +++ b/libc/calls/metalfile.internal.h @@ -11,6 +11,7 @@ struct MetalFile { extern void *__ape_com_base; extern size_t __ape_com_size; +extern uint16_t __ape_com_sectors; // ape/ape.S COSMOPOLITAN_C_END_ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ diff --git a/libc/intrin/directmap-metal.c b/libc/intrin/directmap-metal.c index 463ac7637..11eb13ed9 100644 --- a/libc/intrin/directmap-metal.c +++ b/libc/intrin/directmap-metal.c @@ -16,6 +16,7 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/assert.h" #include "libc/calls/calls.h" #include "libc/calls/internal.h" #include "libc/calls/metalfile.internal.h" @@ -46,6 +47,10 @@ dontasan struct DirectMap sys_mmap_metal(void *vaddr, size_t size, int prot, struct mman *mm; struct DirectMap res; uint64_t addr, faddr = 0, page, e, *pte, *fdpte, *pml4t; + if ((uintptr_t)BANE + size < (uintptr_t)BANE) { + assert(false); + return bad_mmap(); + } mm = __get_mm(); pml4t = __get_pml4t(); size = ROUNDUP(size, 4096); @@ -69,11 +74,14 @@ dontasan struct DirectMap sys_mmap_metal(void *vaddr, size_t size, int prot, } else { addr = ROUNDUP(addr, 4096); } - for (i = 0; i < size; i += 4096) { + i = 0; + while (i < size) { pte = __get_virtual(mm, pml4t, addr + i, false); if (pte && (*pte & (PAGE_V | PAGE_RSRV))) { addr = MAX(addr, sys_mmap_metal_break) + i + 4096; i = 0; + } else { + i += 4096; } } sys_mmap_metal_break = MAX(addr + size, sys_mmap_metal_break); diff --git a/libc/intrin/interrupts.S b/libc/intrin/interrupts.S index 933278725..557ca2b2c 100644 --- a/libc/intrin/interrupts.S +++ b/libc/intrin/interrupts.S @@ -25,6 +25,7 @@ │ OTHER DEALINGS IN THE SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/dce.h" +#include "libc/intrin/kprintf.h" #include "libc/macros.internal.h" #include "libc/runtime/pc.internal.h" diff --git a/tool/build/zipcopy.c b/tool/build/zipcopy.c index 8772dbf3a..7e85dd501 100644 --- a/tool/build/zipcopy.c +++ b/tool/build/zipcopy.c @@ -23,11 +23,15 @@ #include "libc/elf/struct/shdr.h" #include "libc/errno.h" #include "libc/fmt/magnumstrs.internal.h" +#include "libc/intrin/newbie.h" #include "libc/limits.h" +#include "libc/nt/struct/imagedosheader.internal.h" +#include "libc/runtime/pc.internal.h" #include "libc/runtime/runtime.h" #include "libc/stdio/stdio.h" #include "libc/str/str.h" #include "libc/sysv/consts/map.h" +#include "libc/sysv/consts/msync.h" #include "libc/sysv/consts/o.h" #include "libc/sysv/consts/prot.h" #include "libc/zip.internal.h" @@ -109,6 +113,25 @@ static void GetOpts(int argc, char *argv[]) { outpath = argv[optind + 1]; } +static void BiosZipFix(unsigned long cdest) { + struct NtImageDosHeader head; + size_t hd_sz = sizeof(head); + size_t e_oemid = offsetof(struct NtImageDosHeader, e_oemid); + size_t e_oeminfo = offsetof(struct NtImageDosHeader, e_oeminfo); + if (outsize < hd_sz) return; + if (pread(outfd, &head, hd_sz, 0) != hd_sz) return; + if (READ64LE((uint8_t *)&head) != READ64LE("MZqFpD='") && + READ64LE((uint8_t *)&head) != READ64LE("jartsr='")) return; + if (le16toh(head.e_oemid) != READ16LE("JT") || + le16toh(head.e_oeminfo) != 1) return; + // patch executable head so that it will load the right count of sectors + // when run as a legacy BIOS disk image + head.e_res2[0] = htole16(ROUNDUP(cdest, 0x200) / 0x200); + if (pwrite(outfd, &head, hd_sz, 0) != hd_sz) { + SysDie(outpath, "head pwrite"); + } +} + static void CopyZip(void) { char *secstrs; int rela, recs; @@ -176,7 +199,7 @@ static void CopyZip(void) { } // write output - if ((outfd = open(outpath, O_WRONLY | O_CREAT, 0644)) == -1) { + if ((outfd = open(outpath, O_RDWR | O_CREAT, 0644)) == -1) { SysDie(outpath, "open"); } if ((outsize = lseek(outfd, 0, SEEK_END)) == -1) { @@ -205,6 +228,7 @@ static void CopyZip(void) { if (pwrite(outfd, eocd, length, cdest) != length) { SysDie(outpath, "eocd pwrite"); } + BiosZipFix(cdest); if (close(outfd)) { SysDie(outpath, "close"); }