/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│ │ vi: set noet ft=asm ts=8 sw=8 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2020 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #ifndef APE_MACROS_H_ #define APE_MACROS_H_ #include "libc/macros.internal.h" #ifdef __ASSEMBLER__ /* clang-format off */ // Initializes real mode stack. // The most holiest of holy code. // @mode real // @see www.pcjs.org/pubs/pc/reference/intel/8086/ .macro rlstack seg:req addr:req cli mov \seg,%ss mov \addr,%sp sti .endm // Symbolic Linker-Defined Binary Content. .macro .stub name:req kind:req default type=@object .ifnb \default .equ \name,\default .endif .\kind \name .type \name,\type .weak \name .hidden \name .endm // Symbolic Linker-Defined Binary-Encoded-Bourne Content. // @param units is the number of encoded 32-bit values to insert, // e.g. \000 can be encoded as 0x3030305c. .macro .shstub name:req num:req ss \name,0 .if \num>1 ss \name,1 .if \num>2 ss \name,2 ss \name,3 .if \num>4 ss \name,4 ss \name,5 ss \name,6 ss \name,7 .endif .endif .endif .endm .macro ss name n .stub \name\()_bcs\n,long .endm // Task State Segment Descriptor Entries. .macro .tssdescstub name:req .ifndef \name .weak \name .set \name,0 .endif .ifndef \name\()_end .weak \name\()_end .set \name\()_end,0 .endif .stub \name\()_desc_ent0,quad .stub \name\()_desc_ent1,quad .endm /* clang-format on */ #elif defined(__LINKER__) #define BCX_NIBBLE(X) ((((X)&0xf) > 0x9) ? ((X)&0xf) + 0x37 : ((X)&0xf) + 0x30) #define BCX_OCTET(X) ((BCX_NIBBLE((X) >> 4) << 8) | (BCX_NIBBLE((X) >> 0) << 0)) #define BCX_INT16(X) ((BCX_OCTET((X) >> 8) << 16) | (BCX_OCTET((X) >> 0) << 0)) #define BCXSTUB(SYM, X) \ HIDDEN(SYM##_bcx0 = BCX_INT16((X) >> 48)); \ HIDDEN(SYM##_bcx1 = BCX_INT16((X) >> 32)); \ HIDDEN(SYM##_bcx2 = BCX_INT16((X) >> 16)); \ HIDDEN(SYM##_bcx3 = BCX_INT16((X) >> 0)) /** * Binary coded backslash octet support. * *

This allows linker scripts to generate printf commands. */ #define BCO_OCTET(X) (((X)&0x7) + 0x30) #define BCOB_UNIT(X) \ ((BCO_OCTET((X) >> 0) << 24) | (BCO_OCTET((X) >> 3) << 16) | \ (BCO_OCTET(((X)&0xff) >> 6) << 8) | 0x5c) #define PFBYTE(SYM, X, I) HIDDEN(SYM##_bcs##I = BCOB_UNIT((X) >> ((I)*8))) #define PFSTUB2(SYM, X) \ HIDDEN(SYM = (X)); \ PFBYTE(SYM, X, 0); \ PFBYTE(SYM, X, 1) #define PFSTUB4(SYM, X) \ PFSTUB2(SYM, X); \ PFBYTE(SYM, X, 2); \ PFBYTE(SYM, X, 3) #define PFSTUB8(SYM, X) \ PFSTUB4(SYM, X); \ PFBYTE(SYM, X, 4); \ PFBYTE(SYM, X, 5); \ PFBYTE(SYM, X, 6); \ PFBYTE(SYM, X, 7) /** * Binary coded decimal support. * *

This allows linker scripts to generate dd commands, e.g. ape.lds. * There are a few ways to pad each number to the necessary 8 bytes. * Spaces cannot be prepended because busybox refuses to parse them. * Zeros cannot be prepended because Mac will take numbers as octal. * That leaves appending spaces. The user's shell ought to treat any * unquoted run of spaces as if there was only one, so this is safe. */ #define SHSTUB2(SYM, X) \ HIDDEN(SYM##_bcs0 = BCD_LEFT(X)); \ HIDDEN(SYM##_bcs1 = BCD_RIGHT(X)) #define BCD_SMEAR(X) ((X) + (X) * 10000) #define BCD_LEFT(X) \ (((X)) < 10000 ? BCD_RIGHT(BCD_SMEAR(X)) | 0x10 \ : (X) < 100000 ? BCD_RIGHT(BCD_SMEAR((X) / 10)) \ : (X) < 1000000 ? BCD_RIGHT(BCD_SMEAR((X) / 100)) \ : (X) < 10000000 ? BCD_RIGHT(BCD_SMEAR((X) / 1000)) \ : (X) < 100000000 ? BCD_RIGHT(BCD_SMEAR((X) / 10000)) \ : 0xffffffffffffffff) #define BCD_RIGHT(X) \ (((X)) < 10000 ? 0x20202020 \ : (X) < 100000 ? 0x20202030 + \ (X) % 10 \ : (X) < 1000000 ? 0x20203030 + \ ((X) / 10) % 10 + \ (X) % 10 * 0x100 \ : (X) < 10000000 ? 0x20303030 + \ ((X) / 100) % 10 + \ ((X) / 10) % 10 * 0x100 + \ (X) % 10 * 0x10000 \ : (X) < 100000000 ? 0x30303030 + \ ((X) / 1000) % 10 + \ ((X) / 100) % 10 * 0x100 + \ ((X) / 10) % 10 * 0x10000 + \ (X) % 10 * 0x1000000 \ : 0xffffffffffffffff) /** * Laying out the GDT entries for a TSS for bare metal operation. */ #define TSSDESCSTUB2(SYM, BASE, LIM) \ HIDDEN(SYM##_desc_ent0 = TSSDESC_ENT0(BASE, LIM)); \ HIDDEN(SYM##_desc_ent1 = TSSDESC_ENT1(BASE)); \ ASSERT((LIM) >= 0 && (LIM) <= 0xffff, "bare metal TSS is suspiciously fat") #define TSSDESC_ENT0(BASE, LIM) \ (((LIM) << 0 & 0x000000000000ffff) | \ ((BASE) << 16 & 0x000000ffffff0000) | \ 0x89 << 40 | \ ((LIM) >> 16 << 48 & 0x000f000000000000) | \ 0x2 << 52 | \ ((BASE) >> 24 << 56 & 0xff00000000000000)) #define TSSDESC_ENT1(BASE) \ ((BASE) >> 32 << 0 & 0x00000000ffffffff) #endif /* __ASSEMBLER__ */ #endif /* APE_MACROS_H_ */