mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-02-25 07:19:02 +00:00
Add UEFI support
This is mutually exclusive with Windows support. Documentation for how to use it has been written in libc/runtime/efimain.c
This commit is contained in:
parent
c6c9b5dfde
commit
537c21338b
24 changed files with 1381 additions and 391 deletions
49
ape/ape.S
49
ape/ape.S
|
@ -105,7 +105,7 @@ rlstr: .endobj rlstr,globl,hidden # ←for gdb readibility
|
||||||
│ αcτµαlly pδrταblε εxεcµταblε § the old technology │
|
│ αcτµαlly pδrταblε εxεcµταblε § the old technology │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
|
|
||||||
#if SupportsWindows() || SupportsXnu()
|
#if SupportsWindows() || SupportsUefi() || SupportsXnu()
|
||||||
|
|
||||||
// MZ Literally Executable Header
|
// MZ Literally Executable Header
|
||||||
//
|
//
|
||||||
|
@ -131,14 +131,14 @@ ape_mz: .asciz "MZqFpD='\n" # Mark 'Zibo' Joseph Zbikowski
|
||||||
.ascii "JT" # MZ: OEM identifier
|
.ascii "JT" # MZ: OEM identifier
|
||||||
.short 0 # MZ: OEM information
|
.short 0 # MZ: OEM information
|
||||||
.org 0x40-4 # MZ: bytes reserved for you
|
.org 0x40-4 # MZ: bytes reserved for you
|
||||||
#if SupportsWindows()
|
#if SupportsWindows() || SupportsUefi()
|
||||||
.long RVA(ape_pe) # PE: the new technology
|
.long RVA(ape_pe) # PE: the new technology
|
||||||
#else
|
#else
|
||||||
.long 0
|
.long 0
|
||||||
#endif
|
#endif
|
||||||
.endfn ape_mz,globl,hidden
|
.endfn ape_mz,globl,hidden
|
||||||
|
|
||||||
#else /* !(SupportsWindows() || SupportsXnu()) */
|
#else /* !(SupportsWindows() || SupportsUefi() || SupportsXnu()) */
|
||||||
|
|
||||||
// ELF Literally Executable Header
|
// ELF Literally Executable Header
|
||||||
//
|
//
|
||||||
|
@ -168,7 +168,7 @@ ape_mz: .asciz "MZqFpD='\n" # Mark 'Zibo' Joseph Zbikowski
|
||||||
.short ape_elf_shnum # 3c: e_shnum
|
.short ape_elf_shnum # 3c: e_shnum
|
||||||
.short ape_elf_shstrndx # 3e: e_shstrndx
|
.short ape_elf_shstrndx # 3e: e_shstrndx
|
||||||
|
|
||||||
#endif /* SupportsWindows() || SupportsXnu() */
|
#endif /* SupportsWindows() || SupportsUefi() || SupportsXnu() */
|
||||||
|
|
||||||
#if SupportsMetal()
|
#if SupportsMetal()
|
||||||
|
|
||||||
|
@ -471,7 +471,7 @@ ape_disk:
|
||||||
|
|
||||||
#if SupportsSystemv()
|
#if SupportsSystemv()
|
||||||
|
|
||||||
#if SupportsWindows() || SupportsXnu()
|
#if SupportsWindows() || SupportsUefi() || SupportsXnu()
|
||||||
apesh: .ascii "'\n#'\"\n" # sixth edition shebang
|
apesh: .ascii "'\n#'\"\n" # sixth edition shebang
|
||||||
.ascii "o=\"$(command -v \"$0\")\"\n"
|
.ascii "o=\"$(command -v \"$0\")\"\n"
|
||||||
#if SupportsXnu()
|
#if SupportsXnu()
|
||||||
|
@ -526,7 +526,7 @@ apesh: .ascii "'\n#'\"\n" # sixth edition shebang
|
||||||
.ascii "fi\n"
|
.ascii "fi\n"
|
||||||
.ascii "exit $R\n"
|
.ascii "exit $R\n"
|
||||||
.endobj apesh
|
.endobj apesh
|
||||||
#endif /* SupportsWindows() || SupportsXnu() */
|
#endif /* SupportsWindows() || SupportsUefi() || SupportsXnu() */
|
||||||
|
|
||||||
.section .elf.phdrs,"a",@progbits
|
.section .elf.phdrs,"a",@progbits
|
||||||
.long PT_LOAD # text segment
|
.long PT_LOAD # text segment
|
||||||
|
@ -812,7 +812,7 @@ PETEXT = 0b01110000000000000000000001100000
|
||||||
PEDATA = 0b11000000000000000000000011000000
|
PEDATA = 0b11000000000000000000000011000000
|
||||||
PEIMPS = 0b11000000000000000000000001000000
|
PEIMPS = 0b11000000000000000000000001000000
|
||||||
|
|
||||||
#if SupportsWindows()
|
#if SupportsWindows() || SupportsUefi()
|
||||||
|
|
||||||
.section .pe.header,"a",@progbits
|
.section .pe.header,"a",@progbits
|
||||||
.align __SIZEOF_POINTER__
|
.align __SIZEOF_POINTER__
|
||||||
|
@ -830,23 +830,27 @@ ape_pe: .ascin "PE",4
|
||||||
.long 0 # SizeOfCode
|
.long 0 # SizeOfCode
|
||||||
.long 0 # SizeOfInitializedData
|
.long 0 # SizeOfInitializedData
|
||||||
.long 0 # SizeOfUninitializedData
|
.long 0 # SizeOfUninitializedData
|
||||||
.long RVA(WinMain) # EntryPoint
|
.long RVA(ape_pe_entry) # EntryPoint
|
||||||
.long 0 # BaseOfCode
|
.long 0 # BaseOfCode
|
||||||
.quad IMAGE_BASE_VIRTUAL # ImageBase
|
.quad IMAGE_BASE_VIRTUAL # ImageBase
|
||||||
.long 4096 # SectionAlignment
|
.long 4096 # SectionAlignment
|
||||||
.long 4096 # FileAlignment
|
.long 4096 # FileAlignment
|
||||||
.short 6 # MajorOperatingSystemVersion
|
.short v_ntversion # MajorOperatingSystemVersion
|
||||||
.short 0 # MinorOperatingSystemVersion
|
.short 0 # MinorOperatingSystemVersion
|
||||||
.short 0 # MajorImageVersion
|
.short 0 # MajorImageVersion
|
||||||
.short 0 # MinorImageVersion
|
.short 0 # MinorImageVersion
|
||||||
.short 6 # MajorSubsystemVersion
|
.short v_ntsubversion # MajorSubsystemVersion
|
||||||
.short 0 # MinorSubsystemVersion
|
.short 0 # MinorSubsystemVersion
|
||||||
.long 0 # Win32VersionValue
|
.long 0 # Win32VersionValue
|
||||||
.long RVA(_end) # SizeOfImage
|
.long RVA(_end) # SizeOfImage
|
||||||
.long RVA(_ehead) # SizeOfHeaders
|
.long RVA(_ehead) # SizeOfHeaders
|
||||||
.long 0 # Checksum
|
.long 0 # Checksum
|
||||||
.short v_ntsubsystem # Subsystem: 0=Neutral,2=GUI,3=Console
|
.short v_ntsubsystem # Subsystem: 0=Neutral,2=GUI,3=Console
|
||||||
|
#if SupportsWindows()
|
||||||
.short DLLEXE # DllCharacteristics
|
.short DLLEXE # DllCharacteristics
|
||||||
|
#else
|
||||||
|
.short 0 # DllCharacteristics
|
||||||
|
#endif
|
||||||
.quad 0x0000000000100000 # StackReserve
|
.quad 0x0000000000100000 # StackReserve
|
||||||
.quad 0x00000000000fc000 # StackCommit
|
.quad 0x00000000000fc000 # StackCommit
|
||||||
.quad 0 # HeapReserve
|
.quad 0 # HeapReserve
|
||||||
|
@ -854,8 +858,12 @@ ape_pe: .ascin "PE",4
|
||||||
.long 0 # LoaderFlags
|
.long 0 # LoaderFlags
|
||||||
.long 16 # NumberOfDirectoryEntries
|
.long 16 # NumberOfDirectoryEntries
|
||||||
.long 0,0 # ExportsDirectory
|
.long 0,0 # ExportsDirectory
|
||||||
|
#if SupportsWindows()
|
||||||
.long RVA(ape_idata_idt) # ImportsDirectory
|
.long RVA(ape_idata_idt) # ImportsDirectory
|
||||||
.stub ape_idata_idtsize,long # ImportsDirectorySize
|
.stub ape_idata_idtsize,long # ImportsDirectorySize
|
||||||
|
#else
|
||||||
|
.long 0,0 # ImportsDirectory
|
||||||
|
#endif
|
||||||
.long 0,0 # ResourcesDirectory
|
.long 0,0 # ResourcesDirectory
|
||||||
.long 0,0 # ExceptionsDirectory
|
.long 0,0 # ExceptionsDirectory
|
||||||
.long 0,0 # SecurityDirectory
|
.long 0,0 # SecurityDirectory
|
||||||
|
@ -866,8 +874,12 @@ ape_pe: .ascin "PE",4
|
||||||
.long 0,0 # ThreadLocalStorage
|
.long 0,0 # ThreadLocalStorage
|
||||||
.long 0,0 # LoadConfigurationDirectory
|
.long 0,0 # LoadConfigurationDirectory
|
||||||
.long 0,0 # BoundImportDirectory
|
.long 0,0 # BoundImportDirectory
|
||||||
|
#if SupportsWindows()
|
||||||
.long RVA(ape_idata_iat) # ImportAddressDirectory
|
.long RVA(ape_idata_iat) # ImportAddressDirectory
|
||||||
.stub ape_idata_iatsize,long # ImportAddressDirectorySize
|
.stub ape_idata_iatsize,long # ImportAddressDirectorySize
|
||||||
|
#else
|
||||||
|
.long 0,0 # ImportAddressDirectory
|
||||||
|
#endif
|
||||||
.long 0,0 # DelayImportDescriptor
|
.long 0,0 # DelayImportDescriptor
|
||||||
.long 0,0 # ComPlusRuntimeHeader
|
.long 0,0 # ComPlusRuntimeHeader
|
||||||
.long 0,0 # Reserved
|
.long 0,0 # Reserved
|
||||||
|
@ -900,7 +912,7 @@ ape_pe: .ascin "PE",4
|
||||||
.long PEDATA # Flags
|
.long PEDATA # Flags
|
||||||
.previous
|
.previous
|
||||||
|
|
||||||
#endif /* SupportsWindows() */
|
#endif /* SupportsWindows() || SupportsUefi() */
|
||||||
|
|
||||||
.section .idata.ro.idt.1,"a",@progbits
|
.section .idata.ro.idt.1,"a",@progbits
|
||||||
.type ape_idata_idtend,@object
|
.type ape_idata_idtend,@object
|
||||||
|
@ -1524,22 +1536,21 @@ metal.thunk:
|
||||||
#endif
|
#endif
|
||||||
// 𝑠𝑙𝑖𝑑𝑒
|
// 𝑠𝑙𝑖𝑑𝑒
|
||||||
.endfn metal.thunk
|
.endfn metal.thunk
|
||||||
metal:
|
metal: xor %eax,%eax # clear bss
|
||||||
xor %eax,%eax # clear bss
|
|
||||||
mov $ape_bss_vaddr,%edi
|
mov $ape_bss_vaddr,%edi
|
||||||
mov $ape_bss_memsz,%ecx
|
mov $ape_bss_memsz,%ecx
|
||||||
rep stosb
|
rep stosb
|
||||||
.weak __hostos
|
0: .weak __hostos
|
||||||
ezlea __hostos,ax
|
ezlea __hostos,ax
|
||||||
test %rax,%rax
|
test %rax,%rax
|
||||||
jz 1f
|
jz 1f
|
||||||
movb $METAL,(%rax)
|
movb $METAL,(%rax)
|
||||||
1: push $0 # auxv
|
1: push $0 # auxv[0][1]
|
||||||
push $0
|
push $0 # auxv[0][0]
|
||||||
push $0 # envp
|
push $0 # envp[0]
|
||||||
push $0 # auxv
|
push $0 # argv[0]
|
||||||
push $0 # argc
|
push $0 # argc
|
||||||
xor %edi,%edi
|
xor %edi,%edi # not freebsd
|
||||||
jmp _start
|
jmp _start
|
||||||
.endfn metal
|
.endfn metal
|
||||||
|
|
||||||
|
|
16
ape/ape.lds
16
ape/ape.lds
|
@ -229,7 +229,7 @@ SECTIONS {
|
||||||
. += 1;
|
. += 1;
|
||||||
|
|
||||||
KEEP(*(.ape.pad.head))
|
KEEP(*(.ape.pad.head))
|
||||||
. = ALIGN(SupportsWindows() ? PAGESIZE : 16);
|
. = ALIGN(SupportsWindows() || SupportsUefi() ? PAGESIZE : 16);
|
||||||
HIDDEN(_ehead = .);
|
HIDDEN(_ehead = .);
|
||||||
} :Head
|
} :Head
|
||||||
|
|
||||||
|
@ -500,15 +500,21 @@ SHSTUB2(ape_macho_dd_skip, RVA(ape_macho) / 8);
|
||||||
SHSTUB2(ape_macho_dd_count, (ape_macho_end - ape_macho) / 8);
|
SHSTUB2(ape_macho_dd_count, (ape_macho_end - ape_macho) / 8);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if SupportsWindows()
|
#if SupportsWindows() || SupportsUefi()
|
||||||
|
#define LINK_WINDOWS (SupportsWindows() && !DEFINED(EfiMain))
|
||||||
PFSTUB4(ape_pe_offset, ape_pe - ape_mz);
|
PFSTUB4(ape_pe_offset, ape_pe - ape_mz);
|
||||||
HIDDEN(ape_pe_optsz = ape_pe_sections - (ape_pe + 24));
|
HIDDEN(ape_pe_optsz = ape_pe_sections - (ape_pe + 24));
|
||||||
HIDDEN(ape_pe_shnum = (ape_pe_sections_end - ape_pe_sections) / 40);
|
HIDDEN(ape_pe_shnum = (ape_pe_sections_end - ape_pe_sections) / 40);
|
||||||
HIDDEN(ape_idata_idtsize = ape_idata_idtend - ape_idata_idt);
|
HIDDEN(ape_idata_idtsize = ape_idata_idtend - ape_idata_idt);
|
||||||
HIDDEN(ape_idata_iatsize = ape_idata_iatend - ape_idata_iat);
|
HIDDEN(ape_idata_iatsize = ape_idata_iatend - ape_idata_iat);
|
||||||
HIDDEN(v_ntsubsystem = (DEFINED(GetMessage)
|
HIDDEN(v_ntversion = LINK_WINDOWS ? 6 : 1);
|
||||||
|
HIDDEN(v_ntsubversion = LINK_WINDOWS ? 6 : 5);
|
||||||
|
HIDDEN(v_ntsubsystem = (LINK_WINDOWS
|
||||||
|
? (DEFINED(GetMessage)
|
||||||
? kNtImageSubsystemWindowsGui
|
? kNtImageSubsystemWindowsGui
|
||||||
: kNtImageSubsystemWindowsCui));
|
: kNtImageSubsystemWindowsCui)
|
||||||
|
: kNtImageSubsystemEfiApplication));
|
||||||
|
HIDDEN(ape_pe_entry = LINK_WINDOWS ? WinMain : EfiMain);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if SupportsMetal()
|
#if SupportsMetal()
|
||||||
|
@ -603,7 +609,7 @@ CHURN(v_ape_realsectors);
|
||||||
#if SupportsXnu()
|
#if SupportsXnu()
|
||||||
CHURN(ape_macho);
|
CHURN(ape_macho);
|
||||||
#endif
|
#endif
|
||||||
#if SupportsWindows()
|
#if SupportsWindows() || SupportsUefi()
|
||||||
CHURN(ape_mz);
|
CHURN(ape_mz);
|
||||||
CHURN(ape_pe);
|
CHURN(ape_pe);
|
||||||
CHURN(ape_pe_offset);
|
CHURN(ape_pe_offset);
|
||||||
|
|
|
@ -95,7 +95,7 @@ CONFIG_COPTS += \
|
||||||
$(SANITIZER)
|
$(SANITIZER)
|
||||||
|
|
||||||
TARGET_ARCH ?= \
|
TARGET_ARCH ?= \
|
||||||
-msse3
|
-march=native
|
||||||
|
|
||||||
OVERRIDE_CCFLAGS += \
|
OVERRIDE_CCFLAGS += \
|
||||||
-fno-pie
|
-fno-pie
|
||||||
|
|
|
@ -91,7 +91,6 @@ FTRACE = \
|
||||||
-pg
|
-pg
|
||||||
|
|
||||||
SANITIZER = \
|
SANITIZER = \
|
||||||
-fsanitize=leak \
|
|
||||||
-fsanitize=address
|
-fsanitize=address
|
||||||
|
|
||||||
NO_MAGIC = \
|
NO_MAGIC = \
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
|
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||||
│vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi│
|
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
│ Copyright 2021 Justine Alexandra Roberts Tunney │
|
||||||
│ │
|
│ │
|
||||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||||
│ any purpose with or without fee is hereby granted, provided that the │
|
│ any purpose with or without fee is hereby granted, provided that the │
|
||||||
|
@ -16,30 +16,8 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/dce.h"
|
#include "libc/calls/efi.h"
|
||||||
#include "libc/runtime/internal.h"
|
#include "libc/nt/efi.h"
|
||||||
#include "libc/macros.h"
|
|
||||||
.privileged
|
|
||||||
|
|
||||||
// Terminates process, ignoring destructors and atexit() handlers.
|
EFI_HANDLE __efi_image_handle;
|
||||||
//
|
EFI_SYSTEM_TABLE *__efi_system_table;
|
||||||
// @param edi is exit code ∈ [0,256)
|
|
||||||
// @asyncsignalsafe
|
|
||||||
// @vforksafe
|
|
||||||
// @noreturn
|
|
||||||
_Exit: push %rbp
|
|
||||||
mov %rsp,%rbp
|
|
||||||
#if SupportsWindows()
|
|
||||||
testb IsWindows()
|
|
||||||
jz 1f
|
|
||||||
sub $32,%rsp
|
|
||||||
movzbl %dil,%ecx # %ERRORLEVEL% is limitless
|
|
||||||
call *__imp_ExitProcess(%rip)
|
|
||||||
#endif
|
|
||||||
1: mov __NR_exit_group(%rip),%eax
|
|
||||||
syscall
|
|
||||||
#if SupportsMetal()
|
|
||||||
call triplf
|
|
||||||
#endif
|
|
||||||
.endfn _Exit,globl,protected
|
|
||||||
.hidden __NR_exit_group
|
|
12
libc/calls/efi.h
Normal file
12
libc/calls/efi.h
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
#ifndef COSMOPOLITAN_LIBC_CALLS_EFI_H_
|
||||||
|
#define COSMOPOLITAN_LIBC_CALLS_EFI_H_
|
||||||
|
#include "libc/nt/efi.h"
|
||||||
|
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||||
|
COSMOPOLITAN_C_START_
|
||||||
|
|
||||||
|
extern EFI_HANDLE __efi_image_handle;
|
||||||
|
extern EFI_SYSTEM_TABLE *__efi_system_table;
|
||||||
|
|
||||||
|
COSMOPOLITAN_C_END_
|
||||||
|
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||||
|
#endif /* COSMOPOLITAN_LIBC_CALLS_EFI_H_ */
|
|
@ -31,9 +31,9 @@ int fstat(int fd, struct stat *st) {
|
||||||
if (__isfdkind(fd, kFdZip)) {
|
if (__isfdkind(fd, kFdZip)) {
|
||||||
return weaken(__zipos_fstat)(
|
return weaken(__zipos_fstat)(
|
||||||
(struct ZiposHandle *)(intptr_t)g_fds.p[fd].handle, st);
|
(struct ZiposHandle *)(intptr_t)g_fds.p[fd].handle, st);
|
||||||
} else if (!IsWindows() && !IsMetal()) {
|
} else if (!IsWindows() && !IsMetal() && !IsUefi()) {
|
||||||
return sys_fstat(fd, st);
|
return sys_fstat(fd, st);
|
||||||
} else if (IsMetal()) {
|
} else if (IsMetal() || IsUefi()) {
|
||||||
return fstat_metal(fd, st);
|
return fstat_metal(fd, st);
|
||||||
} else {
|
} else {
|
||||||
if (!__isfdkind(fd, kFdFile)) return ebadf();
|
if (!__isfdkind(fd, kFdFile)) return ebadf();
|
||||||
|
|
|
@ -30,7 +30,7 @@ hidden textstartup void InitializeFileDescriptors(void) {
|
||||||
fds = VEIL("r", &g_fds);
|
fds = VEIL("r", &g_fds);
|
||||||
pushmov(&fds->n, ARRAYLEN(fds->__init_p));
|
pushmov(&fds->n, ARRAYLEN(fds->__init_p));
|
||||||
fds->p = fds->__init_p;
|
fds->p = fds->__init_p;
|
||||||
if (IsMetal()) {
|
if (IsMetal() || IsUefi()) {
|
||||||
pushmov(&fds->f, 3ull);
|
pushmov(&fds->f, 3ull);
|
||||||
fds->__init_p[STDIN_FILENO].kind = pushpop(kFdSerial);
|
fds->__init_p[STDIN_FILENO].kind = pushpop(kFdSerial);
|
||||||
fds->__init_p[STDOUT_FILENO].kind = pushpop(kFdSerial);
|
fds->__init_p[STDOUT_FILENO].kind = pushpop(kFdSerial);
|
||||||
|
|
|
@ -199,6 +199,7 @@ u32 sys_gettid(void) hidden;
|
||||||
u32 sys_getuid(void) hidden;
|
u32 sys_getuid(void) hidden;
|
||||||
void *sys_mmap(void *, u64, u32, u32, i64, i64, i64) hidden;
|
void *sys_mmap(void *, u64, u32, u32, i64, i64, i64) hidden;
|
||||||
void *sys_mremap(void *, u64, u64, i32, void *) hidden;
|
void *sys_mremap(void *, u64, u64, i32, void *) hidden;
|
||||||
|
void sys_exit(int) hidden;
|
||||||
|
|
||||||
/*───────────────────────────────────────────────────────────────────────────│─╗
|
/*───────────────────────────────────────────────────────────────────────────│─╗
|
||||||
│ cosmopolitan § syscalls » system five » support ─╬─│┼
|
│ cosmopolitan § syscalls » system five » support ─╬─│┼
|
||||||
|
@ -294,6 +295,12 @@ unsigned __wincrash_nt(struct NtExceptionPointers *);
|
||||||
|
|
||||||
int fstat_metal(int, struct stat *);
|
int fstat_metal(int, struct stat *);
|
||||||
|
|
||||||
|
/*───────────────────────────────────────────────────────────────────────────│─╗
|
||||||
|
│ cosmopolitan § syscalls » uefi ─╬─│┼
|
||||||
|
╚────────────────────────────────────────────────────────────────────────────│*/
|
||||||
|
|
||||||
|
int sys_nanosleep_uefi(const struct timespec *, struct timespec *);
|
||||||
|
|
||||||
/*───────────────────────────────────────────────────────────────────────────│─╗
|
/*───────────────────────────────────────────────────────────────────────────│─╗
|
||||||
│ cosmopolitan § syscalls » drivers ─╬─│┼
|
│ cosmopolitan § syscalls » drivers ─╬─│┼
|
||||||
╚────────────────────────────────────────────────────────────────────────────│*/
|
╚────────────────────────────────────────────────────────────────────────────│*/
|
||||||
|
|
35
libc/calls/nanosleep-uefi.c
Normal file
35
libc/calls/nanosleep-uefi.c
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
/*-*- 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 2021 Justine Alexandra Roberts Tunney │
|
||||||
|
│ │
|
||||||
|
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||||
|
│ any purpose with or without fee is hereby granted, provided that the │
|
||||||
|
│ 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/efi.h"
|
||||||
|
#include "libc/nt/efi.h"
|
||||||
|
#include "libc/sysv/errfuns.h"
|
||||||
|
|
||||||
|
int sys_nanosleep_uefi(const struct timespec *req, struct timespec *rem) {
|
||||||
|
if (__efi_system_table->BootServices->Stall(
|
||||||
|
req->tv_sec * 1000000 + req->tv_nsec / 1000) == EFI_SUCCESS) {
|
||||||
|
if (rem) {
|
||||||
|
rem->tv_sec = 0;
|
||||||
|
rem->tv_nsec = 0;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return eintr();
|
||||||
|
}
|
||||||
|
}
|
|
@ -26,10 +26,15 @@
|
||||||
*/
|
*/
|
||||||
int nanosleep(const struct timespec *req, struct timespec *rem) {
|
int nanosleep(const struct timespec *req, struct timespec *rem) {
|
||||||
if (!req) return efault();
|
if (!req) return efault();
|
||||||
if (!IsWindows() && !IsMetal() && !IsXnu()) {
|
if (req->tv_sec < 0 || !(0 <= req->tv_nsec && req->tv_nsec <= 999999999)) {
|
||||||
|
return einval();
|
||||||
|
}
|
||||||
|
if (!IsWindows() && !IsMetal() && !IsUefi() && !IsXnu()) {
|
||||||
return sys_nanosleep(req, rem);
|
return sys_nanosleep(req, rem);
|
||||||
} else if (IsXnu()) {
|
} else if (IsXnu()) {
|
||||||
return sys_nanosleep_xnu(req, rem);
|
return sys_nanosleep_xnu(req, rem);
|
||||||
|
} else if (IsUefi()) {
|
||||||
|
return sys_nanosleep_uefi(req, rem);
|
||||||
} else if (IsMetal()) {
|
} else if (IsMetal()) {
|
||||||
return enosys(); /* TODO: Sleep on Metal */
|
return enosys(); /* TODO: Sleep on Metal */
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -36,7 +36,8 @@ ssize_t readv(int fd, const struct iovec *iov, int iovlen) {
|
||||||
if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip) {
|
if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip) {
|
||||||
return weaken(__zipos_read)(
|
return weaken(__zipos_read)(
|
||||||
(struct ZiposHandle *)(intptr_t)g_fds.p[fd].handle, iov, iovlen, -1);
|
(struct ZiposHandle *)(intptr_t)g_fds.p[fd].handle, iov, iovlen, -1);
|
||||||
} else if (SupportsMetal() && fd < g_fds.n && g_fds.p[fd].kind == kFdSerial) {
|
} else if ((SupportsMetal() || SupportsUefi()) && fd < g_fds.n &&
|
||||||
|
g_fds.p[fd].kind == kFdSerial) {
|
||||||
return readv_serial(&g_fds.p[fd], iov, iovlen);
|
return readv_serial(&g_fds.p[fd], iov, iovlen);
|
||||||
} else if (!IsWindows()) {
|
} else if (!IsWindows()) {
|
||||||
return sys_readv(fd, iov, iovlen);
|
return sys_readv(fd, iov, iovlen);
|
||||||
|
|
|
@ -144,7 +144,7 @@ int(sigaction)(int sig, const struct sigaction *act, struct sigaction *oldact) {
|
||||||
sizeof(struct sigaction) > sizeof(struct sigaction_freebsd) &&
|
sizeof(struct sigaction) > sizeof(struct sigaction_freebsd) &&
|
||||||
sizeof(struct sigaction) > sizeof(struct sigaction_openbsd) &&
|
sizeof(struct sigaction) > sizeof(struct sigaction_openbsd) &&
|
||||||
sizeof(struct sigaction) > sizeof(struct sigaction_netbsd));
|
sizeof(struct sigaction) > sizeof(struct sigaction_netbsd));
|
||||||
if (IsMetal()) return enosys(); /* TODO: Signals on Metal */
|
if (IsMetal() || IsUefi()) return enosys(); /* TODO: Signals on Metal */
|
||||||
if (!(0 < sig && sig < NSIG)) return einval();
|
if (!(0 < sig && sig < NSIG)) return einval();
|
||||||
if (sig == SIGKILL || sig == SIGSTOP) return einval();
|
if (sig == SIGKILL || sig == SIGSTOP) return einval();
|
||||||
if (!act) {
|
if (!act) {
|
||||||
|
|
|
@ -39,7 +39,8 @@ ssize_t writev(int fd, const struct iovec *iov, int iovlen) {
|
||||||
if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip) {
|
if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip) {
|
||||||
return weaken(__zipos_write)(
|
return weaken(__zipos_write)(
|
||||||
(struct ZiposHandle *)(intptr_t)g_fds.p[fd].handle, iov, iovlen, -1);
|
(struct ZiposHandle *)(intptr_t)g_fds.p[fd].handle, iov, iovlen, -1);
|
||||||
} else if (SupportsMetal() && fd < g_fds.n && g_fds.p[fd].kind == kFdSerial) {
|
} else if ((SupportsMetal() || SupportsUefi()) && fd < g_fds.n &&
|
||||||
|
g_fds.p[fd].kind == kFdSerial) {
|
||||||
return writev_serial(&g_fds.p[fd], iov, iovlen);
|
return writev_serial(&g_fds.p[fd], iov, iovlen);
|
||||||
} else if (!IsWindows()) {
|
} else if (!IsWindows()) {
|
||||||
return sys_writev(fd, iov, iovlen);
|
return sys_writev(fd, iov, iovlen);
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#define OPENBSD 16
|
#define OPENBSD 16
|
||||||
#define FREEBSD 32
|
#define FREEBSD 32
|
||||||
#define NETBSD 64
|
#define NETBSD 64
|
||||||
|
#define UEFI 128
|
||||||
|
|
||||||
#ifdef NDEBUG
|
#ifdef NDEBUG
|
||||||
#define NoDebug() 1
|
#define NoDebug() 1
|
||||||
|
@ -72,6 +73,7 @@
|
||||||
#define SupportsLinux() ((SUPPORT_VECTOR & LINUX) == LINUX)
|
#define SupportsLinux() ((SUPPORT_VECTOR & LINUX) == LINUX)
|
||||||
#define SupportsMetal() ((SUPPORT_VECTOR & METAL) == METAL)
|
#define SupportsMetal() ((SUPPORT_VECTOR & METAL) == METAL)
|
||||||
#define SupportsWindows() ((SUPPORT_VECTOR & WINDOWS) == WINDOWS)
|
#define SupportsWindows() ((SUPPORT_VECTOR & WINDOWS) == WINDOWS)
|
||||||
|
#define SupportsUefi() ((SUPPORT_VECTOR & UEFI) == UEFI)
|
||||||
#define SupportsXnu() ((SUPPORT_VECTOR & XNU) == XNU)
|
#define SupportsXnu() ((SUPPORT_VECTOR & XNU) == XNU)
|
||||||
#define SupportsFreebsd() ((SUPPORT_VECTOR & FREEBSD) == FREEBSD)
|
#define SupportsFreebsd() ((SUPPORT_VECTOR & FREEBSD) == FREEBSD)
|
||||||
#define SupportsOpenbsd() ((SUPPORT_VECTOR & OPENBSD) == OPENBSD)
|
#define SupportsOpenbsd() ((SUPPORT_VECTOR & OPENBSD) == OPENBSD)
|
||||||
|
@ -84,6 +86,7 @@
|
||||||
#define IsLinux() (SupportsLinux() && (__hostos & LINUX))
|
#define IsLinux() (SupportsLinux() && (__hostos & LINUX))
|
||||||
#define IsMetal() (SupportsMetal() && (__hostos & METAL))
|
#define IsMetal() (SupportsMetal() && (__hostos & METAL))
|
||||||
#define IsWindows() (SupportsWindows() && (__hostos & WINDOWS))
|
#define IsWindows() (SupportsWindows() && (__hostos & WINDOWS))
|
||||||
|
#define IsUefi() (SupportsUefi() && (__hostos & UEFI))
|
||||||
#define IsXnu() (SupportsXnu() && (__hostos & XNU))
|
#define IsXnu() (SupportsXnu() && (__hostos & XNU))
|
||||||
#define IsFreebsd() (SupportsFreebsd() && (__hostos & FREEBSD))
|
#define IsFreebsd() (SupportsFreebsd() && (__hostos & FREEBSD))
|
||||||
#define IsOpenbsd() (SupportsOpenbsd() && (__hostos & OPENBSD))
|
#define IsOpenbsd() (SupportsOpenbsd() && (__hostos & OPENBSD))
|
||||||
|
@ -94,6 +97,7 @@
|
||||||
#define IsLinux() $LINUX,__hostos(%rip)
|
#define IsLinux() $LINUX,__hostos(%rip)
|
||||||
#define IsMetal() $METAL,__hostos(%rip)
|
#define IsMetal() $METAL,__hostos(%rip)
|
||||||
#define IsWindows() $WINDOWS,__hostos(%rip)
|
#define IsWindows() $WINDOWS,__hostos(%rip)
|
||||||
|
#define IsUefi() $UEFI,__hostos(%rip)
|
||||||
#define IsBsd() $XNU|FREEBSD|OPENBSD|NETBSD,__hostos(%rip)
|
#define IsBsd() $XNU|FREEBSD|OPENBSD|NETBSD,__hostos(%rip)
|
||||||
#define IsXnu() $XNU,__hostos(%rip)
|
#define IsXnu() $XNU,__hostos(%rip)
|
||||||
#define IsFreebsd() $FREEBSD,__hostos(%rip)
|
#define IsFreebsd() $FREEBSD,__hostos(%rip)
|
||||||
|
|
|
@ -59,7 +59,7 @@
|
||||||
|
|
||||||
#define _KCPUIDS_VENDOR() \
|
#define _KCPUIDS_VENDOR() \
|
||||||
(((kCpuids[KCPUIDS_0H][KCPUIDS_EBX] >> 000) & 0xff) ^ \
|
(((kCpuids[KCPUIDS_0H][KCPUIDS_EBX] >> 000) & 0xff) ^ \
|
||||||
((kCpuids[KCPUIDS_0H][KCPUIDS_EDX] >> 010) & 0xff))
|
((kCpuids[KCPUIDS_0H][KCPUIDS_ECX] >> 010) & 0xff))
|
||||||
|
|
||||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||||
#endif /* COSMOPOLITAN_LIBC_NEXGEN32E_VENDOR_H_ */
|
#endif /* COSMOPOLITAN_LIBC_NEXGEN32E_VENDOR_H_ */
|
||||||
|
|
424
libc/nt/efi.h
Normal file
424
libc/nt/efi.h
Normal file
|
@ -0,0 +1,424 @@
|
||||||
|
#ifndef COSMOPOLITAN_LIBC_NT_EFI_H_
|
||||||
|
#define COSMOPOLITAN_LIBC_NT_EFI_H_
|
||||||
|
/*
|
||||||
|
▐██ ░█████████▓ ▐██▌ ██▓░ ▐█▌ ▐██ ░██░ ▓█▌ ▓██▒ ▓██
|
||||||
|
▐██ ░██░ ▒█▓██░ ████░ ▐█▌ ▐██ ░██░ ▓█▌ ▓███░ ▓███
|
||||||
|
▐██ ░██░ ██░▐█▓ ██▒▓█░ ▐█▌ ▐██ ░██░ ▓█▌ ▓█▌▓█░ ▓█▒██
|
||||||
|
▐██ ░██░ ▐█▌ ▓█▌ ██░░▓█░▐█▌ ▐██ ░██░ ▓█▌ ▓█▌░█▓▓█▒░██
|
||||||
|
▐██ ░██░ ▒██▓█████░ ██░ ░▓▓▓█▌ ▐██ ░██░ ██░ ▓█▌ ░██▌ ░██
|
||||||
|
▐██ ░██░ ▓█▌ ▓█▓ ██░ ░███▌ ▐██ ▐██▄▄▄▓█▓ ▓█▌ ░██
|
||||||
|
╔────────────────────────────────────────────────────────────────────────────│─╗
|
||||||
|
│ αcτµαlly pδrταblε εxεcµταblε § the unified extensible firmware interface ─╬─│┼
|
||||||
|
╚────────────────────────────────────────────────────────────────────────────│*/
|
||||||
|
|
||||||
|
#define EFI_SUCCESS 0x8000000000000000
|
||||||
|
#define EFI_LOAD_ERROR 0x8000000000000001
|
||||||
|
#define EFI_INVALID_PARAMETER 0x8000000000000002
|
||||||
|
#define EFI_UNSUPPORTED 0x8000000000000003
|
||||||
|
#define EFI_BAD_BUFFER_SIZE 0x8000000000000004
|
||||||
|
#define EFI_BUFFER_TOO_SMALL 0x8000000000000005
|
||||||
|
#define EFI_NOT_READY 0x8000000000000006
|
||||||
|
#define EFI_DEVICE_ERROR 0x8000000000000007
|
||||||
|
#define EFI_WRITE_PROTECTED 0x8000000000000008
|
||||||
|
#define EFI_OUT_OF_RESOURCES 0x8000000000000009
|
||||||
|
#define EFI_VOLUME_CORRUPTED 0x800000000000000a
|
||||||
|
#define EFI_VOLUME_FULL 0x800000000000000b
|
||||||
|
#define EFI_NO_MEDIA 0x800000000000000c
|
||||||
|
#define EFI_MEDIA_CHANGED 0x800000000000000d
|
||||||
|
#define EFI_NOT_FOUND 0x800000000000000e
|
||||||
|
#define EFI_ACCESS_DENIED 0x800000000000000f
|
||||||
|
#define EFI_NO_RESPONSE 0x8000000000000010
|
||||||
|
#define EFI_NO_MAPPING 0x8000000000000011
|
||||||
|
#define EFI_TIMEOUT 0x8000000000000012
|
||||||
|
#define EFI_NOT_STARTED 0x8000000000000013
|
||||||
|
#define EFI_ALREADY_STARTED 0x8000000000000014
|
||||||
|
#define EFI_ABORTED 0x8000000000000015
|
||||||
|
#define EFI_ICMP_ERROR 0x8000000000000016
|
||||||
|
#define EFI_TFTP_ERROR 0x8000000000000017
|
||||||
|
#define EFI_PROTOCOL_ERROR 0x8000000000000018
|
||||||
|
|
||||||
|
#define EFI_VARIABLE_NON_VOLATILE 0x00000001
|
||||||
|
#define EFI_VARIABLE_BOOTSERVICE_ACCESS 0x00000002
|
||||||
|
#define EFI_VARIABLE_RUNTIME_ACCESS 0x00000004
|
||||||
|
#define EFI_VARIABLE_HARDWARE_ERROR_RECORD 0x00000008
|
||||||
|
#define EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS 0x00000010
|
||||||
|
#define EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS 0x00000020
|
||||||
|
#define EFI_VARIABLE_APPEND_WRITE 0x00000040
|
||||||
|
|
||||||
|
#define EFI_MEMORY_UC 0x0000000000000001U
|
||||||
|
#define EFI_MEMORY_WC 0x0000000000000002U
|
||||||
|
#define EFI_MEMORY_WT 0x0000000000000004U
|
||||||
|
#define EFI_MEMORY_WB 0x0000000000000008U
|
||||||
|
#define EFI_MEMORY_UCE 0x0000000000000010U
|
||||||
|
#define EFI_MEMORY_WP 0x0000000000001000U
|
||||||
|
#define EFI_MEMORY_RP 0x0000000000002000U
|
||||||
|
#define EFI_MEMORY_XP 0x0000000000004000U
|
||||||
|
#define EFI_MEMORY_RO 0x0000000000020000U
|
||||||
|
#define EFI_MEMORY_NV 0x0000000000008000U
|
||||||
|
#define EFI_MEMORY_MORE_RELIABLE 0x0000000000010000U
|
||||||
|
#define EFI_MEMORY_RUNTIME 0x8000000000000000U
|
||||||
|
|
||||||
|
#define EFI_OPTIONAL_PTR 0x00000001
|
||||||
|
|
||||||
|
#define EFI_SCAN_NULL 0x0000
|
||||||
|
#define EFI_SCAN_UP 0x0001
|
||||||
|
#define EFI_SCAN_DOWN 0x0002
|
||||||
|
#define EFI_SCAN_RIGHT 0x0003
|
||||||
|
#define EFI_SCAN_LEFT 0x0004
|
||||||
|
#define EFI_SCAN_HOME 0x0005
|
||||||
|
#define EFI_SCAN_END 0x0006
|
||||||
|
#define EFI_SCAN_INSERT 0x0007
|
||||||
|
#define EFI_SCAN_DELETE 0x0008
|
||||||
|
#define EFI_SCAN_PAGE_UP 0x0009
|
||||||
|
#define EFI_SCAN_PAGE_DOWN 0x000A
|
||||||
|
#define EFI_SCAN_F1 0x000B
|
||||||
|
#define EFI_SCAN_F2 0x000C
|
||||||
|
#define EFI_SCAN_F3 0x000D
|
||||||
|
#define EFI_SCAN_F4 0x000E
|
||||||
|
#define EFI_SCAN_F5 0x000F
|
||||||
|
#define EFI_SCAN_F6 0x0010
|
||||||
|
#define EFI_SCAN_F7 0x0011
|
||||||
|
#define EFI_SCAN_F8 0x0012
|
||||||
|
#define EFI_SCAN_F9 0x0013
|
||||||
|
#define EFI_SCAN_F10 0x0014
|
||||||
|
#define EFI_SCAN_ESC 0x0017
|
||||||
|
|
||||||
|
#define EFI_EVT_TIMER 0x80000000
|
||||||
|
#define EFI_EVT_RUNTIME 0x40000000
|
||||||
|
#define EFI_EVT_NOTIFY_WAIT 0x00000100
|
||||||
|
#define EFI_EVT_NOTIFY_SIGNAL 0x00000200
|
||||||
|
#define EFI_EVT_SIGNAL_EXIT_BOOT_SERVICES 0x00000201
|
||||||
|
#define EFI_EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE 0x60000202
|
||||||
|
#define EFI_EVT_RUNTIME_CONTEXT 0x20000000
|
||||||
|
|
||||||
|
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||||
|
COSMOPOLITAN_C_START_
|
||||||
|
|
||||||
|
#define EFIAPI __attribute__((__ms_abi__))
|
||||||
|
#define EFI_STATUS uint64_t
|
||||||
|
#define EFI_EVENT uintptr_t
|
||||||
|
#define EFI_HANDLE uintptr_t
|
||||||
|
|
||||||
|
typedef struct _EFI_SIMPLE_TEXT_INPUT_PROTOCOL EFI_SIMPLE_TEXT_INPUT_PROTOCOL;
|
||||||
|
typedef struct _EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
EfiReservedMemoryType,
|
||||||
|
EfiLoaderCode,
|
||||||
|
EfiLoaderData,
|
||||||
|
EfiBootServicesCode,
|
||||||
|
EfiBootServicesData,
|
||||||
|
EfiRuntimeServicesCode,
|
||||||
|
EfiRuntimeServicesData,
|
||||||
|
EfiConventionalMemory,
|
||||||
|
EfiUnusableMemory,
|
||||||
|
EfiACPIReclaimMemory,
|
||||||
|
EfiACPIMemoryNVS,
|
||||||
|
EfiMemoryMappedIO,
|
||||||
|
EfiMemoryMappedIOPortSpace,
|
||||||
|
EfiPalCode,
|
||||||
|
EfiPersistentMemory,
|
||||||
|
EfiMaxMemoryType
|
||||||
|
} EFI_MEMORY_TYPE;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
EfiResetCold,
|
||||||
|
EfiResetWarm,
|
||||||
|
EfiResetShutdown,
|
||||||
|
EfiResetPlatformSpecific
|
||||||
|
} EFI_RESET_TYPE;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
AllocateAnyPages,
|
||||||
|
AllocateMaxAddress,
|
||||||
|
AllocateAddress,
|
||||||
|
MaxAllocateType
|
||||||
|
} EFI_ALLOCATE_TYPE;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
TimerCancel,
|
||||||
|
TimerPeriodic,
|
||||||
|
TimerRelative,
|
||||||
|
} EFI_TIMER_DELAY;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint32_t Resolution;
|
||||||
|
uint32_t Accuracy;
|
||||||
|
bool SetsToZero;
|
||||||
|
} EFI_TIME_CAPABILITIES;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint32_t Data1;
|
||||||
|
uint16_t Data2;
|
||||||
|
uint16_t Data3;
|
||||||
|
uint8_t Data4[8];
|
||||||
|
} EFI_GUID;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint16_t Year;
|
||||||
|
uint8_t Month;
|
||||||
|
uint8_t Day;
|
||||||
|
uint8_t Hour;
|
||||||
|
uint8_t Minute;
|
||||||
|
uint8_t Second;
|
||||||
|
uint8_t Pad1;
|
||||||
|
uint32_t Nanosecond;
|
||||||
|
int16_t TimeZone;
|
||||||
|
uint8_t Daylight;
|
||||||
|
uint8_t Pad2;
|
||||||
|
} EFI_TIME;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint32_t Type;
|
||||||
|
uint64_t PhysicalStart;
|
||||||
|
uint64_t VirtualStart;
|
||||||
|
uint64_t NumberOfPages;
|
||||||
|
uint64_t Attribute;
|
||||||
|
} EFI_MEMORY_DESCRIPTOR;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
EFI_GUID VendorGuid;
|
||||||
|
void *VendorTable;
|
||||||
|
} EFI_CONFIGURATION_TABLE;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
EFI_GUID CapsuleGuid;
|
||||||
|
uint32_t HeaderSize;
|
||||||
|
uint32_t Flags;
|
||||||
|
uint32_t CapsuleImageSize;
|
||||||
|
} EFI_CAPSULE_HEADER;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint16_t ScanCode;
|
||||||
|
char16_t UnicodeChar;
|
||||||
|
} EFI_INPUT_KEY;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int32_t MaxMode;
|
||||||
|
int32_t Mode;
|
||||||
|
int32_t Attribute;
|
||||||
|
int32_t CursorColumn;
|
||||||
|
int32_t CursorRow;
|
||||||
|
bool CursorVisible;
|
||||||
|
} EFI_SIMPLE_TEXT_OUTPUT_MODE;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint64_t Signature;
|
||||||
|
uint32_t Revision;
|
||||||
|
uint32_t HeaderSize;
|
||||||
|
uint32_t CRC32;
|
||||||
|
uint32_t Reserved;
|
||||||
|
} EFI_TABLE_HEADER;
|
||||||
|
|
||||||
|
typedef EFI_STATUS(EFIAPI *EFI_EXIT)(EFI_HANDLE ImageHandle,
|
||||||
|
EFI_STATUS ExitStatus,
|
||||||
|
uintptr_t ExitDataSize,
|
||||||
|
char16_t *opt_ExitData);
|
||||||
|
|
||||||
|
typedef EFI_STATUS(EFIAPI *EFI_GET_VARIABLE)(char16_t *VariableName,
|
||||||
|
EFI_GUID *VendorGuid,
|
||||||
|
uint32_t *outopt_Attributes,
|
||||||
|
uintptr_t *inout_DataSize,
|
||||||
|
void *outopt_Data);
|
||||||
|
typedef EFI_STATUS(EFIAPI *EFI_SET_VARIABLE)(char16_t *VariableName,
|
||||||
|
EFI_GUID *VendorGuid,
|
||||||
|
uint32_t Attributes,
|
||||||
|
uintptr_t DataSize, void *Data);
|
||||||
|
typedef EFI_STATUS(EFIAPI *EFI_GET_NEXT_VARIABLE_NAME)(
|
||||||
|
uintptr_t *inout_VariableNameSize, char16_t *inout_VariableName,
|
||||||
|
EFI_GUID *inout_VendorGuid);
|
||||||
|
typedef EFI_STATUS(EFIAPI *EFI_QUERY_VARIABLE_INFO)(
|
||||||
|
uint32_t Attributes, uint64_t *out_MaximumVariableStorageSize,
|
||||||
|
uint64_t *out_RemainingVariableStorageSize,
|
||||||
|
uint64_t *out_MaximumVariableSize);
|
||||||
|
|
||||||
|
typedef EFI_STATUS(EFIAPI *EFI_ALLOCATE_PAGES)(EFI_ALLOCATE_TYPE Type,
|
||||||
|
EFI_MEMORY_TYPE MemoryType,
|
||||||
|
uintptr_t Pages,
|
||||||
|
uint64_t *inout_Memory);
|
||||||
|
typedef EFI_STATUS(EFIAPI *EFI_FREE_PAGES)(uint64_t Memory, uintptr_t Pages);
|
||||||
|
typedef EFI_STATUS(EFIAPI *EFI_GET_MEMORY_MAP)(
|
||||||
|
uintptr_t *inout_MemoryMapSize, EFI_MEMORY_DESCRIPTOR *inout_MemoryMap,
|
||||||
|
uintptr_t *out_MapKey, uintptr_t *out_DescriptorSize,
|
||||||
|
uint32_t *out_DescriptorVersion);
|
||||||
|
|
||||||
|
typedef EFI_STATUS(EFIAPI *EFI_CHECK_EVENT)(EFI_EVENT Event);
|
||||||
|
typedef EFI_STATUS(EFIAPI *EFI_CLOSE_EVENT)(EFI_EVENT Event);
|
||||||
|
typedef EFI_STATUS(EFIAPI *EFI_SIGNAL_EVENT)(EFI_EVENT Event);
|
||||||
|
typedef EFI_STATUS(EFIAPI *EFI_WAIT_FOR_EVENT)(uintptr_t NumberOfEvents,
|
||||||
|
EFI_EVENT *Events,
|
||||||
|
uintptr_t *out_Index);
|
||||||
|
typedef EFI_STATUS(EFIAPI *EFI_SET_TIMER)(EFI_EVENT Event, EFI_TIMER_DELAY Type,
|
||||||
|
uint64_t TriggerTime);
|
||||||
|
typedef void(EFIAPI *EFI_EVENT_NOTIFY)(EFI_EVENT Event, void *Context);
|
||||||
|
typedef EFI_STATUS(EFIAPI *EFI_CREATE_EVENT)(uint32_t Type, uintptr_t NotifyTpl,
|
||||||
|
EFI_EVENT_NOTIFY NotifyFunction,
|
||||||
|
void *NotifyContext,
|
||||||
|
EFI_EVENT *out_Event);
|
||||||
|
typedef EFI_STATUS(EFIAPI *EFI_CREATE_EVENT_EX)(
|
||||||
|
uint32_t Type, uintptr_t NotifyTpl, EFI_EVENT_NOTIFY opt_NotifyFunction,
|
||||||
|
const void *opt_NotifyContext, const EFI_GUID *opt_EventGroup,
|
||||||
|
EFI_EVENT *out_Event);
|
||||||
|
|
||||||
|
typedef EFI_STATUS(EFIAPI *EFI_UPDATE_CAPSULE)(
|
||||||
|
EFI_CAPSULE_HEADER **CapsuleHeaderArray, uintptr_t CapsuleCount,
|
||||||
|
uint64_t opt_ScatterGatherList);
|
||||||
|
typedef EFI_STATUS(EFIAPI *EFI_QUERY_CAPSULE_CAPABILITIES)(
|
||||||
|
EFI_CAPSULE_HEADER **CapsuleHeaderArray, uintptr_t CapsuleCount,
|
||||||
|
uint64_t *out_MaximumCapsuleSize, EFI_RESET_TYPE *out_ResetType);
|
||||||
|
typedef EFI_STATUS(EFIAPI *EFI_GET_WAKEUP_TIME)(bool *out_Enabled,
|
||||||
|
bool *out_Pending,
|
||||||
|
EFI_TIME *out_Time);
|
||||||
|
typedef EFI_STATUS(EFIAPI *EFI_SET_WAKEUP_TIME)(bool Enable,
|
||||||
|
EFI_TIME *opt_Time);
|
||||||
|
typedef EFI_STATUS(EFIAPI *EFI_SET_WATCHDOG_TIMER)(uintptr_t Timeout,
|
||||||
|
uint64_t WatchdogCode,
|
||||||
|
uintptr_t DataSize,
|
||||||
|
char16_t *opt_WatchdogData);
|
||||||
|
|
||||||
|
typedef EFI_STATUS(EFIAPI *EFI_SET_TIME)(EFI_TIME *Time);
|
||||||
|
typedef EFI_STATUS(EFIAPI *EFI_GET_TIME)(
|
||||||
|
EFI_TIME *out_Time, EFI_TIME_CAPABILITIES *outopt_Capabilities);
|
||||||
|
typedef EFI_STATUS(EFIAPI *EFI_GET_NEXT_HIGH_MONO_COUNT)(
|
||||||
|
uint32_t *out_HighCount);
|
||||||
|
typedef EFI_STATUS(EFIAPI *EFI_STALL)(uintptr_t Microseconds);
|
||||||
|
typedef EFI_STATUS(EFIAPI *EFI_GET_NEXT_MONOTONIC_COUNT)(uint64_t *out_Count);
|
||||||
|
|
||||||
|
typedef EFI_STATUS(EFIAPI *EFI_SET_VIRTUAL_ADDRESS_MAP)(
|
||||||
|
uintptr_t MemoryMapSize, uintptr_t DescriptorSize,
|
||||||
|
uint32_t DescriptorVersion, EFI_MEMORY_DESCRIPTOR *VirtualMap);
|
||||||
|
typedef void(EFIAPI *EFI_RESET_SYSTEM)(EFI_RESET_TYPE ResetType,
|
||||||
|
EFI_STATUS ResetStatus,
|
||||||
|
uintptr_t DataSize, void *opt_ResetData);
|
||||||
|
typedef EFI_STATUS(EFIAPI *EFI_CONVERT_POINTER)(uintptr_t DebugDisposition,
|
||||||
|
void **inout_Address);
|
||||||
|
|
||||||
|
typedef EFI_STATUS(EFIAPI *EFI_INPUT_RESET)(
|
||||||
|
EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This, bool ExtendedVerification);
|
||||||
|
typedef EFI_STATUS(EFIAPI *EFI_INPUT_READ_KEY)(
|
||||||
|
EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This, EFI_INPUT_KEY *out_Key);
|
||||||
|
|
||||||
|
typedef EFI_STATUS(EFIAPI *EFI_TEXT_RESET)(
|
||||||
|
EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, bool ExtendedVerification);
|
||||||
|
typedef EFI_STATUS(EFIAPI *EFI_TEXT_STRING)(
|
||||||
|
EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, char16_t *String);
|
||||||
|
typedef EFI_STATUS(EFIAPI *EFI_TEXT_TEST_STRING)(
|
||||||
|
EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, char16_t *String);
|
||||||
|
typedef EFI_STATUS(EFIAPI *EFI_TEXT_QUERY_MODE)(
|
||||||
|
EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, uint64_t ModeNumber,
|
||||||
|
uint64_t *out_Columns, uint64_t *out_Rows);
|
||||||
|
typedef EFI_STATUS(EFIAPI *EFI_TEXT_SET_MODE)(
|
||||||
|
EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, uint64_t ModeNumber);
|
||||||
|
typedef EFI_STATUS(EFIAPI *EFI_TEXT_SET_ATTRIBUTE)(
|
||||||
|
EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, uint64_t Attribute);
|
||||||
|
typedef EFI_STATUS(EFIAPI *EFI_TEXT_CLEAR_SCREEN)(
|
||||||
|
EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This);
|
||||||
|
typedef EFI_STATUS(EFIAPI *EFI_TEXT_SET_CURSOR_POSITION)(
|
||||||
|
EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, uint64_t Column, uint64_t Row);
|
||||||
|
typedef EFI_STATUS(EFIAPI *EFI_TEXT_ENABLE_CURSOR)(
|
||||||
|
EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, bool Visible);
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
EFI_TABLE_HEADER Hdr;
|
||||||
|
EFI_GET_TIME GetTime;
|
||||||
|
EFI_SET_TIME SetTime;
|
||||||
|
EFI_GET_WAKEUP_TIME GetWakeupTime;
|
||||||
|
EFI_SET_WAKEUP_TIME SetWakeupTime;
|
||||||
|
EFI_SET_VIRTUAL_ADDRESS_MAP SetVirtualAddressMap;
|
||||||
|
EFI_CONVERT_POINTER ConvertPointer;
|
||||||
|
EFI_GET_VARIABLE GetVariable;
|
||||||
|
EFI_GET_NEXT_VARIABLE_NAME GetNextVariableName;
|
||||||
|
EFI_SET_VARIABLE SetVariable;
|
||||||
|
EFI_GET_NEXT_HIGH_MONO_COUNT GetNextHighMonotonicCount;
|
||||||
|
EFI_RESET_SYSTEM ResetSystem;
|
||||||
|
EFI_UPDATE_CAPSULE UpdateCapsule;
|
||||||
|
EFI_QUERY_CAPSULE_CAPABILITIES QueryCapsuleCapabilities;
|
||||||
|
EFI_QUERY_VARIABLE_INFO QueryVariableInfo;
|
||||||
|
} EFI_RUNTIME_SERVICES;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
EFI_TABLE_HEADER Hdr;
|
||||||
|
void *RaiseTPL;
|
||||||
|
void *RestoreTPL;
|
||||||
|
EFI_ALLOCATE_PAGES AllocatePages;
|
||||||
|
EFI_FREE_PAGES FreePages;
|
||||||
|
EFI_GET_MEMORY_MAP GetMemoryMap;
|
||||||
|
void *AllocatePool;
|
||||||
|
void *FreePool;
|
||||||
|
EFI_CREATE_EVENT CreateEvent;
|
||||||
|
EFI_SET_TIMER SetTimer;
|
||||||
|
EFI_WAIT_FOR_EVENT WaitForEvent;
|
||||||
|
EFI_SIGNAL_EVENT SignalEvent;
|
||||||
|
EFI_CLOSE_EVENT CloseEvent;
|
||||||
|
EFI_CHECK_EVENT CheckEvent;
|
||||||
|
void *InstallProtocolInterface;
|
||||||
|
void *ReinstallProtocolInterface;
|
||||||
|
void *UninstallProtocolInterface;
|
||||||
|
void *HandleProtocol;
|
||||||
|
void *Reserved;
|
||||||
|
void *RegisterProtocolNotify;
|
||||||
|
void *LocateHandle;
|
||||||
|
void *LocateDevicePath;
|
||||||
|
void *InstallConfigurationTable;
|
||||||
|
void *LoadImage;
|
||||||
|
void *StartImage;
|
||||||
|
EFI_EXIT Exit;
|
||||||
|
void *UnloadImage;
|
||||||
|
void *ExitBootServices;
|
||||||
|
EFI_GET_NEXT_MONOTONIC_COUNT GetNextMonotonicCount;
|
||||||
|
EFI_STALL Stall;
|
||||||
|
EFI_SET_WATCHDOG_TIMER SetWatchdogTimer;
|
||||||
|
void *ConnectController;
|
||||||
|
void *DisconnectController;
|
||||||
|
void *OpenProtocol;
|
||||||
|
void *CloseProtocol;
|
||||||
|
void *OpenProtocolInformation;
|
||||||
|
void *ProtocolsPerHandle;
|
||||||
|
void *LocateHandleBuffer;
|
||||||
|
void *LocateProtocol;
|
||||||
|
void *InstallMultipleProtocolInterfaces;
|
||||||
|
void *UninstallMultipleProtocolInterfaces;
|
||||||
|
void *CalculateCrc32;
|
||||||
|
void *CopyMem;
|
||||||
|
void *SetMem;
|
||||||
|
EFI_CREATE_EVENT_EX CreateEventEx;
|
||||||
|
} EFI_BOOT_SERVICES;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
EFI_TABLE_HEADER Hdr;
|
||||||
|
char16_t *FirmwareVendor;
|
||||||
|
uint32_t FirmwareRevision;
|
||||||
|
EFI_HANDLE ConsoleInHandle;
|
||||||
|
EFI_SIMPLE_TEXT_INPUT_PROTOCOL *ConIn;
|
||||||
|
EFI_HANDLE ConsoleOutHandle;
|
||||||
|
EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *ConOut;
|
||||||
|
EFI_HANDLE StandardErrorHandle;
|
||||||
|
EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *StdErr;
|
||||||
|
EFI_RUNTIME_SERVICES *RuntimeServices;
|
||||||
|
EFI_BOOT_SERVICES *BootServices;
|
||||||
|
uintptr_t NumberOfTableEntries;
|
||||||
|
EFI_CONFIGURATION_TABLE *ConfigurationTable;
|
||||||
|
} EFI_SYSTEM_TABLE;
|
||||||
|
|
||||||
|
struct _EFI_SIMPLE_TEXT_INPUT_PROTOCOL {
|
||||||
|
EFI_INPUT_RESET Reset;
|
||||||
|
EFI_INPUT_READ_KEY ReadKeyStroke;
|
||||||
|
EFI_EVENT WaitForKey;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL {
|
||||||
|
EFI_TEXT_RESET Reset;
|
||||||
|
EFI_TEXT_STRING OutputString;
|
||||||
|
EFI_TEXT_TEST_STRING TestString;
|
||||||
|
EFI_TEXT_QUERY_MODE QueryMode;
|
||||||
|
EFI_TEXT_SET_MODE SetMode;
|
||||||
|
EFI_TEXT_SET_ATTRIBUTE SetAttribute;
|
||||||
|
EFI_TEXT_CLEAR_SCREEN ClearScreen;
|
||||||
|
EFI_TEXT_SET_CURSOR_POSITION SetCursorPosition;
|
||||||
|
EFI_TEXT_ENABLE_CURSOR EnableCursor;
|
||||||
|
EFI_SIMPLE_TEXT_OUTPUT_MODE *Mode;
|
||||||
|
};
|
||||||
|
|
||||||
|
COSMOPOLITAN_C_END_
|
||||||
|
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||||
|
#endif /* COSMOPOLITAN_LIBC_NT_EFI_H_ */
|
|
@ -119,7 +119,7 @@
|
||||||
#define kNtImageSubsystemPosixCui 7
|
#define kNtImageSubsystemPosixCui 7
|
||||||
#define kNtImageSubsystemNativeWindows 8
|
#define kNtImageSubsystemNativeWindows 8
|
||||||
#define kNtImageSubsystemWindowsCeGui 9
|
#define kNtImageSubsystemWindowsCeGui 9
|
||||||
#define kNtImageSubsystemEfiApplication 1
|
#define kNtImageSubsystemEfiApplication 10
|
||||||
#define kNtImageSubsystemEfiBootServiceDriver 11
|
#define kNtImageSubsystemEfiBootServiceDriver 11
|
||||||
#define kNtImageSubsystemEfiRuntimeDriver 12
|
#define kNtImageSubsystemEfiRuntimeDriver 12
|
||||||
#define kNtImageSubsystemEfiRom 13
|
#define kNtImageSubsystemEfiRom 13
|
||||||
|
|
72
libc/runtime/efimain.c
Normal file
72
libc/runtime/efimain.c
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
/*-*- 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 2021 Justine Alexandra Roberts Tunney │
|
||||||
|
│ │
|
||||||
|
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||||
|
│ any purpose with or without fee is hereby granted, provided that the │
|
||||||
|
│ 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/efi.h"
|
||||||
|
#include "libc/dce.h"
|
||||||
|
#include "libc/nt/efi.h"
|
||||||
|
#include "libc/nt/thunk/msabi.h"
|
||||||
|
#include "libc/runtime/runtime.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* EFI Application Entrypoint.
|
||||||
|
*
|
||||||
|
* This entrypoint is mutually exclusive from WinMain since
|
||||||
|
* Windows apps and EFI apps use the same PE binary format.
|
||||||
|
* By default, we build binaries to support Windows. If you
|
||||||
|
* want to your APE executable to boot on UEFI instead then
|
||||||
|
* you need to run the following build command:
|
||||||
|
*
|
||||||
|
* make -j8 CPPFLAGS=-DSUPPORT_VECTOR=251
|
||||||
|
*
|
||||||
|
* That'll remove all the Windows code and turn EFI on. You
|
||||||
|
* can also remove by BIOS code too, by changing 251 to 249
|
||||||
|
* but it shouldn't matter. Here's how to emulate EFI apps:
|
||||||
|
*
|
||||||
|
* qemu-system-x86_64 \
|
||||||
|
* -bios OVMF.fd \
|
||||||
|
* -serial stdio \
|
||||||
|
* -net none \
|
||||||
|
* -drive format=raw,file=fat:rw:o/tool/viz
|
||||||
|
* FS0:
|
||||||
|
* deathstar.com
|
||||||
|
*
|
||||||
|
* If you're using the amalgamated release binaries then it
|
||||||
|
* should be possible to enable UEFI mode by having this at
|
||||||
|
* the top of your main source file to hint the APE linker:
|
||||||
|
*
|
||||||
|
* STATIC_YOINK("EfiMain");
|
||||||
|
* int main() { ... }
|
||||||
|
*
|
||||||
|
* @see libc/dce.h
|
||||||
|
*/
|
||||||
|
__msabi noasan EFI_STATUS EfiMain(EFI_HANDLE ImageHandle,
|
||||||
|
EFI_SYSTEM_TABLE *SystemTable) {
|
||||||
|
extern char os asm("__hostos");
|
||||||
|
os = UEFI;
|
||||||
|
__efi_image_handle = ImageHandle;
|
||||||
|
__efi_system_table = SystemTable;
|
||||||
|
asm("push\t$0\n\t"
|
||||||
|
"push\t$0\n\t"
|
||||||
|
"push\t$0\n\t"
|
||||||
|
"push\t$0\n\t"
|
||||||
|
"push\t$0\n\t"
|
||||||
|
"xor\t%edi,%edi\n\t"
|
||||||
|
".weak\t_start\n\t"
|
||||||
|
"jmp\t_start");
|
||||||
|
unreachable;
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
|
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||||
│vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi│
|
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
│ Copyright 2021 Justine Alexandra Roberts Tunney │
|
||||||
│ │
|
│ │
|
||||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||||
│ any purpose with or without fee is hereby granted, provided that the │
|
│ any purpose with or without fee is hereby granted, provided that the │
|
||||||
|
@ -16,15 +16,16 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/macros.h"
|
#include "libc/runtime/runtime.h"
|
||||||
.privileged
|
|
||||||
.source __FILE__
|
|
||||||
|
|
||||||
// Terminates process, ignoring destructors and atexit() handlers.
|
/**
|
||||||
//
|
* Terminates process, ignoring destructors and atexit() handlers.
|
||||||
// @param edi is exit code ∈ [0,256)
|
*
|
||||||
// @asyncsignalsafe
|
* @param rc is exit code ∈ [0,256)
|
||||||
// @vforksafe
|
* @asyncsignalsafe
|
||||||
// @noreturn
|
* @vforksafe
|
||||||
_exit: jmp _Exit
|
* @noreturn
|
||||||
.endfn _exit,globl,protected
|
*/
|
||||||
|
wontreturn void _exit(int rc) {
|
||||||
|
_Exit(rc);
|
||||||
|
}
|
44
libc/runtime/exit3.c
Normal file
44
libc/runtime/exit3.c
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
/*-*- 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 2021 Justine Alexandra Roberts Tunney │
|
||||||
|
│ │
|
||||||
|
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||||
|
│ any purpose with or without fee is hereby granted, provided that the │
|
||||||
|
│ 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/efi.h"
|
||||||
|
#include "libc/calls/internal.h"
|
||||||
|
#include "libc/dce.h"
|
||||||
|
#include "libc/nexgen32e/vendor.internal.h"
|
||||||
|
#include "libc/nt/runtime.h"
|
||||||
|
#include "libc/runtime/runtime.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Terminates process, ignoring destructors and atexit() handlers.
|
||||||
|
*
|
||||||
|
* @param rc is exit code ∈ [0,256)
|
||||||
|
* @asyncsignalsafe
|
||||||
|
* @vforksafe
|
||||||
|
* @noreturn
|
||||||
|
*/
|
||||||
|
wontreturn void _Exit(int rc) {
|
||||||
|
if ((!IsWindows() && !IsMetal() && !IsUefi()) ||
|
||||||
|
(IsMetal() && IsGenuineCosmo())) {
|
||||||
|
sys_exit(rc);
|
||||||
|
} else if (IsUefi()) {
|
||||||
|
__efi_system_table->BootServices->Exit(__efi_image_handle, rc, 0, NULL);
|
||||||
|
} else if (IsWindows()) {
|
||||||
|
ExitProcess(rc & 0xff);
|
||||||
|
}
|
||||||
|
triplf();
|
||||||
|
}
|
|
@ -73,12 +73,6 @@ void *sbrk(intptr_t);
|
||||||
int brk(void *);
|
int brk(void *);
|
||||||
int NtGetVersion(void);
|
int NtGetVersion(void);
|
||||||
|
|
||||||
/*───────────────────────────────────────────────────────────────────────────│─╗
|
|
||||||
│ cosmopolitan § runtime » optimizations ─╬─│┼
|
|
||||||
╚────────────────────────────────────────────────────────────────────────────│*/
|
|
||||||
|
|
||||||
#define _exit(RC) _Exit(RC)
|
|
||||||
|
|
||||||
COSMOPOLITAN_C_END_
|
COSMOPOLITAN_C_END_
|
||||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||||
#endif /* COSMOPOLITAN_LIBC_RUNTIME_RUNTIME_H_ */
|
#endif /* COSMOPOLITAN_LIBC_RUNTIME_RUNTIME_H_ */
|
||||||
|
|
|
@ -104,7 +104,7 @@ __systemfive:
|
||||||
|
|
||||||
.privileged
|
.privileged
|
||||||
.Lanchorpoint:
|
.Lanchorpoint:
|
||||||
#if SupportsLinux() || SupportsMetal()
|
#if SupportsLinux() || SupportsMetal() || SupportsUefi()
|
||||||
systemfive_linux:
|
systemfive_linux:
|
||||||
and $0xfff,%eax
|
and $0xfff,%eax
|
||||||
cmp $0xfff,%eax
|
cmp $0xfff,%eax
|
||||||
|
@ -194,14 +194,18 @@ systemfive_xnu:
|
||||||
.init.start 300,_init_systemfive
|
.init.start 300,_init_systemfive
|
||||||
push %rbx
|
push %rbx
|
||||||
push %rsi
|
push %rsi
|
||||||
#if SupportsMetal()
|
|
||||||
testb $METAL,(%rdi) # @see ape/ape.S
|
|
||||||
jnz _init_systemfive_metal
|
|
||||||
#endif
|
|
||||||
#if SupportsXnu()
|
#if SupportsXnu()
|
||||||
testb $XNU,(%rdi) # @see libc/crt/crt.S
|
testb $XNU,(%rdi) # @see libc/crt/crt.S
|
||||||
jnz _init_systemfive_xnu
|
jnz _init_systemfive_xnu
|
||||||
#endif
|
#endif
|
||||||
|
#if SupportsUefi()
|
||||||
|
testb $UEFI,(%rdi) # @see ape/ape.S
|
||||||
|
jnz _init_systemfive_uefi
|
||||||
|
#endif
|
||||||
|
#if SupportsMetal()
|
||||||
|
testb $METAL,(%rdi) # @see ape/ape.S
|
||||||
|
jnz _init_systemfive_metal
|
||||||
|
#endif
|
||||||
#if SupportsFreebsd()
|
#if SupportsFreebsd()
|
||||||
testb $FREEBSD,(%rdi) # @see libc/crt/crt.S
|
testb $FREEBSD,(%rdi) # @see libc/crt/crt.S
|
||||||
jnz _init_systemfive_freebsd
|
jnz _init_systemfive_freebsd
|
||||||
|
@ -222,7 +226,7 @@ systemfive_xnu:
|
||||||
lea 2(%eax),%eax
|
lea 2(%eax),%eax
|
||||||
jnz 0b
|
jnz 0b
|
||||||
#endif
|
#endif
|
||||||
#if SupportsLinux() || SupportsMetal()
|
#if SupportsLinux()
|
||||||
_init_systemfive_linux:
|
_init_systemfive_linux:
|
||||||
pushb systemfive_linux-.Lanchorpoint
|
pushb systemfive_linux-.Lanchorpoint
|
||||||
push $LINUX
|
push $LINUX
|
||||||
|
@ -236,6 +240,13 @@ _init_systemfive_metal:
|
||||||
ezlea syscon_linux,si
|
ezlea syscon_linux,si
|
||||||
jmp _init_systemfive_os
|
jmp _init_systemfive_os
|
||||||
#endif
|
#endif
|
||||||
|
#if SupportsUefi()
|
||||||
|
_init_systemfive_uefi:
|
||||||
|
pushb systemfive_linux-.Lanchorpoint
|
||||||
|
push $UEFI
|
||||||
|
ezlea syscon_linux,si
|
||||||
|
jmp _init_systemfive_os
|
||||||
|
#endif
|
||||||
#if SupportsWindows()
|
#if SupportsWindows()
|
||||||
_init_systemfive_windows:
|
_init_systemfive_windows:
|
||||||
pushb systemfive_enosys-.Lanchorpoint
|
pushb systemfive_enosys-.Lanchorpoint
|
||||||
|
@ -312,8 +323,8 @@ _init_systemfive_magnums:
|
||||||
// 𝑠𝑙𝑖𝑑𝑒
|
// 𝑠𝑙𝑖𝑑𝑒
|
||||||
#if SupportsSystemv() && !defined(TINY)
|
#if SupportsSystemv() && !defined(TINY)
|
||||||
_init_systemfive_stack: # determinism ftw!
|
_init_systemfive_stack: # determinism ftw!
|
||||||
#if SupportsWindows()
|
#if SupportsWindows() || SupportsMetal() || SupportsUefi()
|
||||||
testb IsWindows() # already did this
|
testb $WINDOWS|METAL|UEFI,__hostos(%rip)
|
||||||
jnz _init_systemfive_done
|
jnz _init_systemfive_done
|
||||||
#endif
|
#endif
|
||||||
push %rdi
|
push %rdi
|
||||||
|
@ -403,7 +414,7 @@ syscon_end:
|
||||||
.type syscon_end,@object
|
.type syscon_end,@object
|
||||||
.globl syscon_start
|
.globl syscon_start
|
||||||
.globl syscon_end
|
.globl syscon_end
|
||||||
#if SupportsLinux() || SupportsMetal()
|
#if SupportsLinux() || SupportsMetal() || SupportsUefi()
|
||||||
.section .sort.rodata.syscon.linux.1,"a",@progbits
|
.section .sort.rodata.syscon.linux.1,"a",@progbits
|
||||||
.align 1
|
.align 1
|
||||||
syscon_linux:/*
|
syscon_linux:/*
|
||||||
|
|
385
tool/viz/printansi.c
Normal file
385
tool/viz/printansi.c
Normal file
|
@ -0,0 +1,385 @@
|
||||||
|
/*-*- 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 "dsp/core/half.h"
|
||||||
|
#include "dsp/core/twixt8.h"
|
||||||
|
#include "dsp/scale/scale.h"
|
||||||
|
#include "dsp/tty/quant.h"
|
||||||
|
#include "dsp/tty/tty.h"
|
||||||
|
#include "libc/assert.h"
|
||||||
|
#include "libc/bits/bits.h"
|
||||||
|
#include "libc/bits/safemacros.h"
|
||||||
|
#include "libc/calls/calls.h"
|
||||||
|
#include "libc/calls/ioctl.h"
|
||||||
|
#include "libc/calls/struct/stat.h"
|
||||||
|
#include "libc/calls/struct/winsize.h"
|
||||||
|
#include "libc/dce.h"
|
||||||
|
#include "libc/fmt/conv.h"
|
||||||
|
#include "libc/limits.h"
|
||||||
|
#include "libc/log/check.h"
|
||||||
|
#include "libc/log/log.h"
|
||||||
|
#include "libc/macros.h"
|
||||||
|
#include "libc/math.h"
|
||||||
|
#include "libc/mem/mem.h"
|
||||||
|
#include "libc/rand/rand.h"
|
||||||
|
#include "libc/runtime/gc.h"
|
||||||
|
#include "libc/stdio/stdio.h"
|
||||||
|
#include "libc/str/str.h"
|
||||||
|
#include "libc/sysv/consts/ex.h"
|
||||||
|
#include "libc/sysv/consts/exit.h"
|
||||||
|
#include "libc/sysv/consts/fileno.h"
|
||||||
|
#include "libc/sysv/consts/madv.h"
|
||||||
|
#include "libc/sysv/consts/map.h"
|
||||||
|
#include "libc/sysv/consts/o.h"
|
||||||
|
#include "libc/sysv/consts/prot.h"
|
||||||
|
#include "libc/sysv/consts/termios.h"
|
||||||
|
#include "libc/x/x.h"
|
||||||
|
#include "third_party/getopt/getopt.h"
|
||||||
|
#include "third_party/stb/stb_image.h"
|
||||||
|
#include "tool/viz/lib/graphic.h"
|
||||||
|
|
||||||
|
#define SQR(x) ((x) * (x))
|
||||||
|
|
||||||
|
static struct Flags {
|
||||||
|
const char *out;
|
||||||
|
bool invert;
|
||||||
|
bool subpixel;
|
||||||
|
bool unsharp;
|
||||||
|
bool dither;
|
||||||
|
bool ruler;
|
||||||
|
bool trailingnewline;
|
||||||
|
long half;
|
||||||
|
bool full;
|
||||||
|
long width;
|
||||||
|
long height;
|
||||||
|
enum TtyBlocksSelection blocks;
|
||||||
|
enum TtyQuantizationAlgorithm quant;
|
||||||
|
} g_flags;
|
||||||
|
|
||||||
|
static wontreturn void PrintUsage(int rc, FILE *f) {
|
||||||
|
fprintf(f, "Usage: %s%s", program_invocation_name, "\
|
||||||
|
[FLAGS] [PATH]\n\
|
||||||
|
\n\
|
||||||
|
FLAGS\n\
|
||||||
|
\n\
|
||||||
|
-w INT width\n\
|
||||||
|
-h INT height\n\
|
||||||
|
-i invert\n\
|
||||||
|
-? shows this information\n\
|
||||||
|
\n\
|
||||||
|
EXAMPLES\n\
|
||||||
|
\n\
|
||||||
|
printansi.com -w80 -h40 logo.png\n\
|
||||||
|
\n\
|
||||||
|
\n");
|
||||||
|
exit(rc);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ParseNumberOption(const char *arg) {
|
||||||
|
long x;
|
||||||
|
x = strtol(arg, NULL, 0);
|
||||||
|
if (!(1 <= x && x <= INT_MAX)) {
|
||||||
|
fprintf(stderr, "invalid flexidecimal: %s\n\n", arg);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void GetOpts(int *argc, char *argv[]) {
|
||||||
|
int opt;
|
||||||
|
struct winsize ws;
|
||||||
|
g_flags.quant = kTtyQuantTrue;
|
||||||
|
g_flags.blocks = IsWindows() ? kTtyBlocksCp437 : kTtyBlocksUnicode;
|
||||||
|
if (*argc == 2 &&
|
||||||
|
(strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-help") == 0)) {
|
||||||
|
PrintUsage(EXIT_SUCCESS, stdout);
|
||||||
|
}
|
||||||
|
while ((opt = getopt(*argc, argv, "?ivpfrtxads234o:w:h:")) != -1) {
|
||||||
|
switch (opt) {
|
||||||
|
case 'o':
|
||||||
|
g_flags.out = optarg;
|
||||||
|
break;
|
||||||
|
case 'd':
|
||||||
|
g_flags.dither = true;
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
g_flags.unsharp = true;
|
||||||
|
break;
|
||||||
|
case 'w':
|
||||||
|
g_flags.trailingnewline = true;
|
||||||
|
g_flags.width = ParseNumberOption(optarg);
|
||||||
|
break;
|
||||||
|
case 'h':
|
||||||
|
g_flags.trailingnewline = true;
|
||||||
|
g_flags.height = ParseNumberOption(optarg);
|
||||||
|
break;
|
||||||
|
case 'f':
|
||||||
|
g_flags.full = true;
|
||||||
|
break;
|
||||||
|
case 'i':
|
||||||
|
g_flags.invert = true;
|
||||||
|
break;
|
||||||
|
case '2':
|
||||||
|
g_flags.half = true;
|
||||||
|
break;
|
||||||
|
case 'r':
|
||||||
|
g_flags.ruler = true;
|
||||||
|
break;
|
||||||
|
case 'p':
|
||||||
|
g_flags.subpixel = true;
|
||||||
|
break;
|
||||||
|
case 'a':
|
||||||
|
g_flags.quant = kTtyQuantAnsi;
|
||||||
|
break;
|
||||||
|
case 'x':
|
||||||
|
g_flags.quant = kTtyQuantXterm256;
|
||||||
|
break;
|
||||||
|
case 't':
|
||||||
|
g_flags.quant = kTtyQuantTrue;
|
||||||
|
break;
|
||||||
|
case '3':
|
||||||
|
g_flags.blocks = kTtyBlocksCp437;
|
||||||
|
break;
|
||||||
|
case '4':
|
||||||
|
g_flags.blocks = kTtyBlocksUnicode;
|
||||||
|
break;
|
||||||
|
case 'v':
|
||||||
|
++g_loglevel;
|
||||||
|
break;
|
||||||
|
case '?':
|
||||||
|
PrintUsage(EXIT_SUCCESS, stdout);
|
||||||
|
default:
|
||||||
|
PrintUsage(EX_USAGE, stderr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (optind == *argc) {
|
||||||
|
if (!g_flags.out) g_flags.out = "-";
|
||||||
|
argv[(*argc)++] = "-";
|
||||||
|
}
|
||||||
|
if (!g_flags.full && (!g_flags.width || !g_flags.width)) {
|
||||||
|
ws.ws_col = 80;
|
||||||
|
ws.ws_row = 24;
|
||||||
|
if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) != -1 ||
|
||||||
|
ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) != -1) {
|
||||||
|
g_flags.width = ws.ws_col * (1 + !g_flags.half);
|
||||||
|
g_flags.height = ws.ws_row * 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ttyquantsetup(g_flags.quant, kTtyQuantRgb, g_flags.blocks);
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned char ChessBoard(unsigned y, unsigned x, unsigned char a,
|
||||||
|
unsigned char b) {
|
||||||
|
return !((y ^ x) & (1u << 2)) ? a : b;
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned char AlphaBackground(unsigned y, unsigned x) {
|
||||||
|
return ChessBoard(y, x, 255, 200);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *Deblinterlace(long dyn, long dxn, unsigned char dst[3][dyn][dxn],
|
||||||
|
long syn, long sxn, long scn,
|
||||||
|
const unsigned char src[syn][sxn][scn], long y0,
|
||||||
|
long yn, long x0, long xn) {
|
||||||
|
long y, x;
|
||||||
|
unsigned char c;
|
||||||
|
for (y = y0; y < yn; ++y) {
|
||||||
|
for (x = x0; x < xn; ++x) {
|
||||||
|
switch (scn) {
|
||||||
|
case 1:
|
||||||
|
c = src[y][x][0];
|
||||||
|
dst[0][y][x] = c;
|
||||||
|
dst[1][y][x] = c;
|
||||||
|
dst[2][y][x] = c;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
c = twixt8(AlphaBackground(y, x), src[y][x][0], src[y][x][1]);
|
||||||
|
dst[0][y][x] = c;
|
||||||
|
dst[1][y][x] = c;
|
||||||
|
dst[2][y][x] = c;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
dst[0][y][x] = src[y][x][0];
|
||||||
|
dst[1][y][x] = src[y][x][1];
|
||||||
|
dst[2][y][x] = src[y][x][2];
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
c = AlphaBackground(y, x);
|
||||||
|
dst[0][y][x] = twixt8(c, src[y][x][0], src[y][x][3]);
|
||||||
|
dst[1][y][x] = twixt8(c, src[y][x][1], src[y][x][3]);
|
||||||
|
dst[2][y][x] = twixt8(c, src[y][x][2], src[y][x][3]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dst;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *DeblinterlaceSubpixelBgr(long dyn, long dxn,
|
||||||
|
unsigned char dst[3][dyn][dxn][3],
|
||||||
|
long syn, long sxn,
|
||||||
|
const unsigned char src[syn][sxn][4],
|
||||||
|
long y0, long yn, long x0, long xn) {
|
||||||
|
long y, x;
|
||||||
|
for (y = y0; y < yn; ++y) {
|
||||||
|
for (x = x0; x < xn; ++x) {
|
||||||
|
dst[0][y][x][0] = 0;
|
||||||
|
dst[1][y][x][0] = 0;
|
||||||
|
dst[2][y][x][0] = src[y][x][2];
|
||||||
|
dst[0][y][x][1] = 0;
|
||||||
|
dst[1][y][x][1] = src[y][x][1];
|
||||||
|
dst[2][y][x][1] = 0;
|
||||||
|
dst[0][y][x][2] = src[y][x][0];
|
||||||
|
dst[1][y][x][2] = 0;
|
||||||
|
dst[2][y][x][2] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dst;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Block {
|
||||||
|
char16_t c;
|
||||||
|
unsigned char b[4][2];
|
||||||
|
} kBlocks[] = {
|
||||||
|
{u' ', {{0000, 0000}, {0000, 0000}, {0000, 0000}, {0000, 0000}}}, //
|
||||||
|
{u'░', {{0060, 0060}, {0060, 0060}, {0060, 0060}, {0060, 0060}}}, //
|
||||||
|
{u'▒', {{0140, 0140}, {0140, 0140}, {0140, 0140}, {0140, 0140}}}, //
|
||||||
|
{u'▓', {{0300, 0300}, {0300, 0300}, {0300, 0300}, {0300, 0300}}}, //
|
||||||
|
{u'█', {{0377, 0377}, {0377, 0377}, {0377, 0377}, {0377, 0377}}}, //
|
||||||
|
{u'▄', {{0000, 0000}, {0000, 0000}, {0377, 0377}, {0377, 0377}}}, //
|
||||||
|
{u'▌', {{0377, 0000}, {0377, 0000}, {0377, 0000}, {0377, 0000}}}, //
|
||||||
|
{u'▐', {{0000, 0377}, {0000, 0377}, {0000, 0377}, {0000, 0377}}}, //
|
||||||
|
{u'▀', {{0377, 0377}, {0377, 0377}, {0000, 0000}, {0000, 0000}}}, //
|
||||||
|
};
|
||||||
|
|
||||||
|
static void *Raster(long yn, long xn, unsigned char Y[yn][xn]) {
|
||||||
|
long y, x, i, j, k, s, bi, bs;
|
||||||
|
for (y = 0; y + 4 <= yn; y += 4) {
|
||||||
|
if (y) fputc('\n', stdout);
|
||||||
|
for (x = 0; x + 2 <= xn; x += 2) {
|
||||||
|
bi = 0;
|
||||||
|
bs = LONG_MAX;
|
||||||
|
for (k = 0; k < ARRAYLEN(kBlocks); ++k) {
|
||||||
|
s = 0;
|
||||||
|
for (i = 0; i < 4; ++i) {
|
||||||
|
for (j = 0; j < 2; ++j) {
|
||||||
|
s += SQR(Y[y + i][x + j] - kBlocks[k].b[i][j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (s < bs) {
|
||||||
|
bi = k;
|
||||||
|
bs = s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fputwc(kBlocks[bi].c, stdout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fputc('\n', stdout);
|
||||||
|
return Y;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *Invert(long yn, long xn, unsigned char Y[yn][xn]) {
|
||||||
|
long y, x;
|
||||||
|
if (!g_flags.invert) {
|
||||||
|
for (y = 0; y < yn; ++y) {
|
||||||
|
for (x = 0; x < xn; ++x) {
|
||||||
|
Y[y][x] = 255 - Y[y][x];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Y;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *Grayify(long yn, long xn, unsigned char Y[yn][xn],
|
||||||
|
const unsigned char RGB[3][yn][xn]) {
|
||||||
|
long y, x;
|
||||||
|
for (y = 0; y < yn; ++y) {
|
||||||
|
for (x = 0; x < xn; ++x) {
|
||||||
|
Y[y][x] = RGB[0][y][x] * .299 + RGB[1][y][x] * .587 + RGB[2][y][x] * .114;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Y;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ProcessImage(long yn, long xn, unsigned char RGB[3][yn][xn]) {
|
||||||
|
Raster(yn, xn,
|
||||||
|
Invert(yn, xn, Grayify(yn, xn, gc(memalign(32, yn * xn)), RGB)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void WithImageFile(const char *path,
|
||||||
|
void fn(long yn, long xn, unsigned char RGB[3][yn][xn])) {
|
||||||
|
struct stat st;
|
||||||
|
void *map, *data, *data2;
|
||||||
|
int fd, yn, xn, cn, dyn, dxn, syn, sxn;
|
||||||
|
CHECK_NE(-1, (fd = open(path, O_RDONLY)), "%s", path);
|
||||||
|
CHECK_NE(-1, fstat(fd, &st));
|
||||||
|
CHECK_GT(st.st_size, 0);
|
||||||
|
CHECK_LE(st.st_size, INT_MAX);
|
||||||
|
fadvise(fd, 0, 0, MADV_WILLNEED | MADV_SEQUENTIAL);
|
||||||
|
CHECK_NE(MAP_FAILED,
|
||||||
|
(map = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0)));
|
||||||
|
CHECK_NOTNULL(
|
||||||
|
(data = gc(stbi_load_from_memory(map, st.st_size, &xn, &yn, &cn, 0))),
|
||||||
|
"%s", path);
|
||||||
|
CHECK_NE(-1, munmap(map, st.st_size));
|
||||||
|
CHECK_NE(-1, close(fd));
|
||||||
|
if (g_flags.subpixel) {
|
||||||
|
data = DeblinterlaceSubpixelBgr(yn, xn, gc(memalign(32, yn * xn * 4 * 3)),
|
||||||
|
yn, xn, data, 0, yn, 0, xn);
|
||||||
|
xn *= 3;
|
||||||
|
} else {
|
||||||
|
data = Deblinterlace(yn, xn, gc(memalign(32, yn * xn * 4)), yn, xn, cn,
|
||||||
|
data, 0, yn, 0, xn);
|
||||||
|
cn = 3;
|
||||||
|
}
|
||||||
|
if (g_flags.height && g_flags.width) {
|
||||||
|
syn = yn;
|
||||||
|
sxn = xn;
|
||||||
|
dyn = g_flags.height * 4;
|
||||||
|
dxn = g_flags.width * 2;
|
||||||
|
while (HALF(syn) > dyn || HALF(sxn) > dxn) {
|
||||||
|
if (HALF(sxn) > dxn) {
|
||||||
|
Magikarp2xX(yn, xn, data, syn, sxn);
|
||||||
|
Magikarp2xX(yn, xn, (char *)data + yn * xn, syn, sxn);
|
||||||
|
Magikarp2xX(yn, xn, (char *)data + yn * xn * 2, syn, sxn);
|
||||||
|
sxn = HALF(sxn);
|
||||||
|
}
|
||||||
|
if (HALF(syn) > dyn) {
|
||||||
|
Magikarp2xY(yn, xn, data, syn, sxn);
|
||||||
|
Magikarp2xY(yn, xn, (char *)data + yn * xn, syn, sxn);
|
||||||
|
Magikarp2xY(yn, xn, (char *)data + yn * xn * 2, syn, sxn);
|
||||||
|
syn = HALF(syn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
data = EzGyarados(3, dyn, dxn, gc(memalign(32, dyn * dxn * 3)), cn, yn, xn,
|
||||||
|
data, 0, cn, dyn, dxn, syn, sxn, 0, 0, 0, 0);
|
||||||
|
yn = dyn;
|
||||||
|
xn = dxn;
|
||||||
|
}
|
||||||
|
fn(yn, xn, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
int i;
|
||||||
|
GetOpts(&argc, argv);
|
||||||
|
stbi_set_unpremultiply_on_load(true);
|
||||||
|
for (i = optind; i < argc; ++i) {
|
||||||
|
WithImageFile(argv[i], ProcessImage);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue