refactor: drop posix-uefi from bootloader
Replace the vendored POSIX-UEFI runtime with a small local EFI entry and header so the bootloader depends only on the UEFI interfaces it actually uses. Made-with: Cursor
This commit is contained in:
@@ -8,35 +8,22 @@ set(UEFI_COMPILE_OPTIONS
|
|||||||
-fno-builtin
|
-fno-builtin
|
||||||
)
|
)
|
||||||
|
|
||||||
set(POSIX_UEFI_SOURCES
|
add_executable(BOOTAA64
|
||||||
Source/uefi/crt_aarch64.c
|
Source/uefi/efi_entry.c
|
||||||
Source/uefi/dirent.c
|
Source/main.c
|
||||||
Source/uefi/qsort.c
|
|
||||||
Source/uefi/stat.c
|
|
||||||
Source/uefi/stdio.c
|
|
||||||
Source/uefi/stdlib.c
|
|
||||||
Source/uefi/string.c
|
|
||||||
Source/uefi/time.c
|
|
||||||
Source/uefi/unistd.c
|
|
||||||
)
|
)
|
||||||
|
|
||||||
add_library(posix_uefi_lib OBJECT ${POSIX_UEFI_SOURCES})
|
|
||||||
target_compile_options(posix_uefi_lib PRIVATE ${UEFI_COMPILE_OPTIONS})
|
|
||||||
target_include_directories(posix_uefi_lib PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/Source/uefi)
|
|
||||||
|
|
||||||
|
|
||||||
add_executable(BOOTAA64 Source/main.c)
|
|
||||||
target_compile_options(BOOTAA64 PRIVATE ${UEFI_COMPILE_OPTIONS})
|
target_compile_options(BOOTAA64 PRIVATE ${UEFI_COMPILE_OPTIONS})
|
||||||
|
target_include_directories(BOOTAA64 PRIVATE
|
||||||
target_link_libraries(BOOTAA64 PRIVATE posix_uefi_lib)
|
${CMAKE_CURRENT_SOURCE_DIR}/Source
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/Source/uefi
|
||||||
|
)
|
||||||
|
|
||||||
target_link_options(BOOTAA64 PRIVATE
|
target_link_options(BOOTAA64 PRIVATE
|
||||||
-fuse-ld=lld
|
-fuse-ld=lld
|
||||||
-target aarch64-unknown-windows-msvc
|
-target aarch64-unknown-windows-msvc
|
||||||
-nostdlib
|
-nostdlib
|
||||||
-Wl,-subsystem:efi_application
|
-Wl,-subsystem:efi_application
|
||||||
-Wl,-include:uefi_init
|
-Wl,-entry:efi_main
|
||||||
-Wl,-entry:uefi_init
|
|
||||||
)
|
)
|
||||||
|
|
||||||
set_target_properties(BOOTAA64 PROPERTIES
|
set_target_properties(BOOTAA64 PROPERTIES
|
||||||
|
|||||||
+173
-107
@@ -1,144 +1,210 @@
|
|||||||
#include "uefi/uefi.h" // IWYU pragma: keep
|
#include "uefi/uefi.h"
|
||||||
#include "../../Common/bootinfo.h"
|
#include "../../Common/bootinfo.h"
|
||||||
|
|
||||||
void print(wchar_t* msg) {
|
#define PAGE_SIZE 0x1000
|
||||||
ST->ConOut->OutputString(ST->ConOut, msg);
|
#define WSTR(str) ((wchar_t*)L##str)
|
||||||
|
|
||||||
|
static wchar_t* kernel_path = WSTR("ksOSKernel.bin");
|
||||||
|
static efi_guid_t dtb_guid = {
|
||||||
|
0xb1b621d5, 0xf19c, 0x41a5, {0x83, 0x0b, 0xd9, 0x15, 0x2c, 0x69, 0xaa, 0xe0}
|
||||||
|
};
|
||||||
|
|
||||||
|
static void print(const wchar_t* msg) {
|
||||||
|
ST->ConOut->OutputString(ST->ConOut, (wchar_t*)msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
static efi_status_t die(void) {
|
||||||
|
while (1) {
|
||||||
|
__asm__ volatile("wfi");
|
||||||
}
|
}
|
||||||
|
|
||||||
efi_status_t die() {
|
|
||||||
while(1) __asm__ volatile("wfi");
|
|
||||||
return EFI_ABORTED;
|
return EFI_ABORTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
int compare_guid(efi_guid_t* a, efi_guid_t* b) {
|
static efi_status_t fail(const wchar_t* msg) {
|
||||||
uint8_t* p1 = (uint8_t*)a;
|
print(msg);
|
||||||
uint8_t* p2 = (uint8_t*)b;
|
return die();
|
||||||
for (int i = 0; i < 16; i++) {
|
|
||||||
if (p1[i] != p2[i]) return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int guid_equal(const efi_guid_t* lhs, const efi_guid_t* rhs) {
|
||||||
|
const uint8_t* lhs_bytes = (const uint8_t*)lhs;
|
||||||
|
const uint8_t* rhs_bytes = (const uint8_t*)rhs;
|
||||||
|
|
||||||
|
for (int i = 0; i < 16; ++i) {
|
||||||
|
if (lhs_bytes[i] != rhs_bytes[i]) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main()
|
static void* find_configuration_table(const efi_guid_t* guid) {
|
||||||
{
|
for (uintn_t i = 0; i < ST->NumberOfTableEntries; ++i) {
|
||||||
efi_gop_t* gop = NULL;
|
if (guid_equal(&ST->ConfigurationTable[i].VendorGuid, guid)) {
|
||||||
efi_guid_t gop_guid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
|
return ST->ConfigurationTable[i].VendorTable;
|
||||||
ST->BootServices->LocateProtocol(&gop_guid, 0, (void**)&gop);
|
|
||||||
|
|
||||||
efi_guid_t dtb_guid = {0xb1b621d5, 0xf19c, 0x41a5, {0x83, 0x0b, 0xd9, 0x15, 0x2c, 0x69, 0xaa, 0xe0}};
|
|
||||||
void* dtbAddress = NULL;
|
|
||||||
|
|
||||||
for (uintn_t i = 0; i < ST->NumberOfTableEntries; i++) {
|
|
||||||
if (compare_guid(&ST->ConfigurationTable[i].VendorGuid, &dtb_guid)) {
|
|
||||||
dtbAddress = ST->ConfigurationTable[i].VendorTable;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!dtbAddress) {
|
return NULL;
|
||||||
print(L"Failed to find DTB!\r\n");
|
|
||||||
return die();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
efi_loaded_image_protocol_t* loaded_image;
|
static efi_status_t open_root_volume(efi_file_handle_t** root) {
|
||||||
efi_guid_t lip_guid = EFI_LOADED_IMAGE_PROTOCOL_GUID;
|
efi_loaded_image_protocol_t* loaded_image = NULL;
|
||||||
gBS->HandleProtocol(IM, &lip_guid, (void**)&loaded_image);
|
efi_guid_t loaded_image_guid = EFI_LOADED_IMAGE_PROTOCOL_GUID;
|
||||||
|
efi_status_t status = gBS->HandleProtocol(IM, &loaded_image_guid, (void**)&loaded_image);
|
||||||
efi_simple_file_system_protocol_t* fs;
|
|
||||||
efi_guid_t sfsp_guid = EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID;
|
|
||||||
gBS->HandleProtocol(loaded_image->DeviceHandle, &sfsp_guid, (void**)&fs);
|
|
||||||
|
|
||||||
efi_file_handle_t* root;
|
|
||||||
fs->OpenVolume(fs, &root);
|
|
||||||
|
|
||||||
efi_file_handle_t* kernel_file;
|
|
||||||
uintn_t kinfo_size = 0;
|
|
||||||
efi_file_info_t* kfile_info = NULL;
|
|
||||||
efi_guid_t fi_guid = EFI_FILE_INFO_GUID;
|
|
||||||
|
|
||||||
efi_status_t status = root->Open(root, &kernel_file, L"ksOSKernel.bin", EFI_FILE_MODE_READ, 0);
|
|
||||||
if (EFI_ERROR(status)) {
|
if (EFI_ERROR(status)) {
|
||||||
print(L"Cant find ksOSKernel.bin\r\n");
|
return status;
|
||||||
return die();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
status = kernel_file->GetInfo(kernel_file, &fi_guid, &kinfo_size, NULL);
|
efi_simple_file_system_protocol_t* fs = NULL;
|
||||||
if (status == EFI_BUFFER_TOO_SMALL) {
|
efi_guid_t filesystem_guid = EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID;
|
||||||
gBS->AllocatePool(EfiLoaderData, kinfo_size, (void**)&kfile_info);
|
status = gBS->HandleProtocol(loaded_image->DeviceHandle, &filesystem_guid, (void**)&fs);
|
||||||
status = kernel_file->GetInfo(kernel_file, &fi_guid, &kinfo_size, kfile_info);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t kernel_size = kfile_info->FileSize;
|
|
||||||
uintn_t kernel_size_read = (uintn_t)kernel_size;
|
|
||||||
|
|
||||||
uintn_t kernel_pages = (kernel_size + 0xFFF) / 0x1000;
|
|
||||||
efi_physical_address_t kernel_addr = 0;
|
|
||||||
|
|
||||||
status = gBS->AllocatePages(AllocateAnyPages, EfiLoaderData, kernel_pages, &kernel_addr);
|
|
||||||
if (EFI_ERROR(status)) {
|
if (EFI_ERROR(status)) {
|
||||||
print(L"Failed to allocate ANY memory for kernel!\r\n");
|
return status;
|
||||||
return die();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
kernel_file->Read(kernel_file, &kernel_size_read, (void*)kernel_addr); \
|
return fs->OpenVolume(fs, root);
|
||||||
printf("Kernel loaded at %p\r\n", (void*)kernel_addr);
|
}
|
||||||
|
|
||||||
Bootinfo* bootInfo = (Bootinfo*)malloc(sizeof(Bootinfo));
|
static efi_status_t read_file_info(efi_file_handle_t* file, efi_file_info_t** file_info) {
|
||||||
bootInfo->magic = BOOTINFO_MAGIC;
|
efi_guid_t file_info_guid = EFI_FILE_INFO_GUID;
|
||||||
|
uintn_t file_info_size = 0;
|
||||||
|
efi_status_t status = file->GetInfo(file, &file_info_guid, &file_info_size, NULL);
|
||||||
|
if (status != EFI_BUFFER_TOO_SMALL) {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
bootInfo->kernelInfo.kernelAddress = (void*)kernel_addr;
|
status = gBS->AllocatePool(EfiLoaderData, file_info_size, (void**)file_info);
|
||||||
bootInfo->kernelInfo.kernelSize = kernel_size;
|
|
||||||
|
|
||||||
bootInfo->framebuffer.base = (BIUInt32*)gop->Mode->FrameBufferBase;
|
|
||||||
bootInfo->framebuffer.baseSize = gop->Mode->FrameBufferSize;
|
|
||||||
bootInfo->framebuffer.height = gop->Mode->Information->VerticalResolution;
|
|
||||||
bootInfo->framebuffer.width = gop->Mode->Information->HorizontalResolution;
|
|
||||||
bootInfo->framebuffer.pitch = gop->Mode->Information->PixelsPerScanLine;
|
|
||||||
|
|
||||||
bootInfo->dtb = dtbAddress;
|
|
||||||
printf("DTB located at: %p\r\n", (void*)dtbAddress);
|
|
||||||
|
|
||||||
uintn_t map_size = 0;
|
|
||||||
efi_memory_descriptor_t *map = NULL;
|
|
||||||
uintn_t map_key;
|
|
||||||
uintn_t desc_size;
|
|
||||||
uint32_t desc_version;
|
|
||||||
|
|
||||||
|
|
||||||
print(L"Almost ready to jump :D. Working with memory map\r\n");
|
|
||||||
|
|
||||||
gBS->GetMemoryMap(&map_size, NULL, &map_key, &desc_size, &desc_version);
|
|
||||||
map_size += 4096;
|
|
||||||
// woah letsgoo
|
|
||||||
status = gBS->AllocatePool(EfiLoaderData, map_size, (void**)&map);
|
|
||||||
if (EFI_ERROR(status)) {
|
if (EFI_ERROR(status)) {
|
||||||
print(L"Failed to allocate pool\r\n");
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
do {
|
return file->GetInfo(file, &file_info_guid, &file_info_size, *file_info);
|
||||||
status = gBS->GetMemoryMap(&map_size, map, &map_key, &desc_size, &desc_version);
|
}
|
||||||
|
|
||||||
|
static efi_status_t load_kernel(efi_file_handle_t* root, efi_physical_address_t* kernel_addr, uint64_t* kernel_size) {
|
||||||
|
efi_file_handle_t* kernel_file = NULL;
|
||||||
|
efi_file_info_t* kernel_info = NULL;
|
||||||
|
efi_status_t status = root->Open(root, &kernel_file, kernel_path, EFI_FILE_MODE_READ, 0);
|
||||||
if (EFI_ERROR(status)) {
|
if (EFI_ERROR(status)) {
|
||||||
break;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
bootInfo->memoryMap.descriptorSize = desc_size;
|
status = read_file_info(kernel_file, &kernel_info);
|
||||||
bootInfo->memoryMap.descriptorVersion = desc_version;
|
if (EFI_ERROR(status)) {
|
||||||
bootInfo->memoryMap.mapSize = map_size;
|
return status;
|
||||||
bootInfo->memoryMap.mapKey = map_key;
|
|
||||||
bootInfo->memoryMap.map = map;
|
|
||||||
|
|
||||||
status = gBS->ExitBootServices(IM, map_key);
|
|
||||||
if (status == EFI_SUCCESS) {
|
|
||||||
break; // FUCK OFF;
|
|
||||||
}
|
}
|
||||||
map_size += 2 * desc_size;
|
|
||||||
} while (EFI_ERROR(status));
|
|
||||||
|
|
||||||
typedef void (__attribute__((sysv_abi)) *kentry)(Bootinfo*);
|
*kernel_size = kernel_info->FileSize;
|
||||||
kentry kmain = (kentry)kernel_addr;
|
|
||||||
|
|
||||||
kmain(bootInfo); // yay! :D
|
uintn_t bytes_to_read = (uintn_t)*kernel_size;
|
||||||
|
uintn_t kernel_pages = (*kernel_size + PAGE_SIZE - 1) / PAGE_SIZE;
|
||||||
|
*kernel_addr = 0;
|
||||||
|
|
||||||
|
status = gBS->AllocatePages(AllocateAnyPages, EfiLoaderData, kernel_pages, kernel_addr);
|
||||||
|
if (EFI_ERROR(status)) {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = kernel_file->Read(kernel_file, &bytes_to_read, (void*)*kernel_addr);
|
||||||
|
if (EFI_ERROR(status) || bytes_to_read != (uintn_t)*kernel_size) {
|
||||||
|
return EFI_LOAD_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
return EFI_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static efi_status_t populate_memory_map(Bootinfo* boot_info) {
|
||||||
|
uintn_t map_size = 0;
|
||||||
|
efi_memory_descriptor_t* map = NULL;
|
||||||
|
uintn_t map_key = 0;
|
||||||
|
uintn_t descriptor_size = 0;
|
||||||
|
uint32_t descriptor_version = 0;
|
||||||
|
|
||||||
|
efi_status_t status = gBS->GetMemoryMap(&map_size, NULL, &map_key, &descriptor_size, &descriptor_version);
|
||||||
|
if (status != EFI_BUFFER_TOO_SMALL) {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
map_size += PAGE_SIZE;
|
||||||
|
status = gBS->AllocatePool(EfiLoaderData, map_size, (void**)&map);
|
||||||
|
if (EFI_ERROR(status)) {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
status = gBS->GetMemoryMap(&map_size, map, &map_key, &descriptor_size, &descriptor_version);
|
||||||
|
if (EFI_ERROR(status)) {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
boot_info->memoryMap.descriptorSize = descriptor_size;
|
||||||
|
boot_info->memoryMap.descriptorVersion = descriptor_version;
|
||||||
|
boot_info->memoryMap.mapSize = map_size;
|
||||||
|
boot_info->memoryMap.mapKey = map_key;
|
||||||
|
boot_info->memoryMap.map = map;
|
||||||
|
|
||||||
|
status = gBS->ExitBootServices(IM, map_key);
|
||||||
|
if (status == EFI_SUCCESS) {
|
||||||
|
return EFI_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
map_size += 2 * descriptor_size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
efi_status_t bootloader_main(void) {
|
||||||
|
efi_gop_t* gop = NULL;
|
||||||
|
efi_guid_t gop_guid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
|
||||||
|
efi_status_t status = ST->BootServices->LocateProtocol(&gop_guid, 0, (void**)&gop);
|
||||||
|
if (EFI_ERROR(status) || gop == NULL) {
|
||||||
|
return fail(WSTR("Failed to locate GOP\r\n"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void* dtb_address = find_configuration_table(&dtb_guid);
|
||||||
|
if (dtb_address == NULL) {
|
||||||
|
return fail(WSTR("Failed to find DTB\r\n"));
|
||||||
|
}
|
||||||
|
|
||||||
|
efi_file_handle_t* root = NULL;
|
||||||
|
status = open_root_volume(&root);
|
||||||
|
if (EFI_ERROR(status)) {
|
||||||
|
return fail(WSTR("Failed to open boot volume\r\n"));
|
||||||
|
}
|
||||||
|
|
||||||
|
efi_physical_address_t kernel_addr = 0;
|
||||||
|
uint64_t kernel_size = 0;
|
||||||
|
status = load_kernel(root, &kernel_addr, &kernel_size);
|
||||||
|
if (EFI_ERROR(status)) {
|
||||||
|
return fail(WSTR("Failed to load ksOSKernel.bin\r\n"));
|
||||||
|
}
|
||||||
|
|
||||||
|
Bootinfo* boot_info = NULL;
|
||||||
|
status = gBS->AllocatePool(EfiLoaderData, sizeof(Bootinfo), (void**)&boot_info);
|
||||||
|
if (EFI_ERROR(status) || boot_info == NULL) {
|
||||||
|
return fail(WSTR("Failed to allocate boot info\r\n"));
|
||||||
|
}
|
||||||
|
|
||||||
|
boot_info->magic = BOOTINFO_MAGIC;
|
||||||
|
boot_info->kernelInfo.kernelAddress = (void*)kernel_addr;
|
||||||
|
boot_info->kernelInfo.kernelSize = kernel_size;
|
||||||
|
boot_info->framebuffer.base = (BIUInt32*)gop->Mode->FrameBufferBase;
|
||||||
|
boot_info->framebuffer.baseSize = gop->Mode->FrameBufferSize;
|
||||||
|
boot_info->framebuffer.height = gop->Mode->Information->VerticalResolution;
|
||||||
|
boot_info->framebuffer.width = gop->Mode->Information->HorizontalResolution;
|
||||||
|
boot_info->framebuffer.pitch = gop->Mode->Information->PixelsPerScanLine;
|
||||||
|
boot_info->dtb = dtb_address;
|
||||||
|
|
||||||
|
print(WSTR("Almost ready to jump. Reading memory map\r\n"));
|
||||||
|
status = populate_memory_map(boot_info);
|
||||||
|
if (EFI_ERROR(status)) {
|
||||||
|
return fail(WSTR("Failed to exit boot services\r\n"));
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef void (*kernel_entry_t)(Bootinfo*);
|
||||||
|
kernel_entry_t kernel_main = (kernel_entry_t)kernel_addr;
|
||||||
|
kernel_main(boot_info);
|
||||||
|
|
||||||
return EFI_SUCCESS;
|
return EFI_SUCCESS;
|
||||||
}
|
}
|
||||||
@@ -1,135 +0,0 @@
|
|||||||
# detect architecture
|
|
||||||
MYARCH = $(shell uname -m | sed s,i[3456789]86,ia32, | sed s,amd,x86_,)
|
|
||||||
ifeq ($(ARCH),)
|
|
||||||
ARCH = $(MYARCH)
|
|
||||||
endif
|
|
||||||
|
|
||||||
# get source files, generate object names
|
|
||||||
ifeq ($(SRCS),)
|
|
||||||
SRCS = $(wildcard *.c) $(wildcard *.S)
|
|
||||||
endif
|
|
||||||
ifeq ($(OBJS),)
|
|
||||||
TMP = $(SRCS:.c=.o)
|
|
||||||
OBJS = $(TMP:.S=.o)
|
|
||||||
endif
|
|
||||||
ifneq ($(OUTDIR),)
|
|
||||||
# OUTDIR is not used with uefi/*.o deliberately
|
|
||||||
OUTDIR:=$(addsuffix /,$(OUTDIR))
|
|
||||||
endif
|
|
||||||
CFLAGS += -fshort-wchar -fno-strict-aliasing -ffreestanding -fno-stack-protector -fno-stack-check -I. -I./uefi \
|
|
||||||
-I/usr/include -I/usr/include/efi -I/usr/include/efi/protocol -I/usr/include/efi/$(ARCH) -D__$(ARCH)__
|
|
||||||
ifeq ($(ARCH),x86_64)
|
|
||||||
CFLAGS += -DHAVE_USE_MS_ABI -mno-red-zone
|
|
||||||
endif
|
|
||||||
|
|
||||||
# for libuefi.a
|
|
||||||
LIBSRCS = $(filter-out $(wildcard crt_*.c),$(wildcard *.c)) $(wildcard *.S)
|
|
||||||
TMP2 = $(LIBSRCS:.c=.o)
|
|
||||||
LIBOBJS = $(TMP2:.S=.o)
|
|
||||||
MAKE ?= make
|
|
||||||
|
|
||||||
# detect toolchain
|
|
||||||
ifeq ($(wildcard /usr/bin/clang)$(wildcard /usr/local/bin/clang)$(wildcard /usr/lib/llvm/*/bin/clang)$(wildcard /gnu/store/*/bin/clang),)
|
|
||||||
USE_GCC = 1
|
|
||||||
endif
|
|
||||||
ifneq ($(USE_GCC),)
|
|
||||||
ifeq ($(ARCH),x86_64)
|
|
||||||
CFLAGS += -maccumulate-outgoing-args
|
|
||||||
endif
|
|
||||||
CFLAGS += -Wno-builtin-declaration-mismatch -fpic -fPIC
|
|
||||||
LDFLAGS += -nostdlib -shared -Bsymbolic -Luefi uefi/crt_$(ARCH).o
|
|
||||||
LIBS += -o $(addprefix $(OUTDIR),$(TARGET).so) -luefi -T uefi/elf_$(ARCH)_efi.lds
|
|
||||||
# see if we're cross-compiling
|
|
||||||
ifneq ($(ARCH),$(MYARCH))
|
|
||||||
CC = $(ARCH)-elf-gcc
|
|
||||||
LD = $(ARCH)-elf-ld
|
|
||||||
OBJCOPY ?= $(ARCH)-elf-objcopy
|
|
||||||
else
|
|
||||||
CC = gcc
|
|
||||||
LD = ld
|
|
||||||
OBJCOPY ?= objcopy
|
|
||||||
endif
|
|
||||||
ifeq ($(ARCH),aarch64)
|
|
||||||
EFIARCH = pei-aarch64-little
|
|
||||||
else
|
|
||||||
ifeq ($(ARCH),riscv64)
|
|
||||||
EFIARCH = pei-riscv64-little
|
|
||||||
else
|
|
||||||
EFIARCH = efi-app-$(ARCH)
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
AR ?= ar
|
|
||||||
else
|
|
||||||
CFLAGS += --target=$(ARCH)-pc-win32-coff -Wno-builtin-requires-header -Wno-incompatible-library-redeclaration -Wno-long-long
|
|
||||||
LDFLAGS += -subsystem:efi_application -nodefaultlib -dll -entry:uefi_init uefi/*.o
|
|
||||||
LIBS = -out:$(addprefix $(OUTDIR),$(TARGET))
|
|
||||||
CC = clang
|
|
||||||
LD = lld -flavor link
|
|
||||||
OBJCOPY = true
|
|
||||||
endif
|
|
||||||
|
|
||||||
# recipies
|
|
||||||
ifeq ($(wildcard uefi/Makefile),)
|
|
||||||
ALLTARGETS = crt_$(ARCH).o libuefi.a buildlib
|
|
||||||
else
|
|
||||||
ALLTARGETS = uefi/crt_$(ARCH).o uefi/libuefi.a $(OBJS) $(TARGET)
|
|
||||||
endif
|
|
||||||
|
|
||||||
all: $(OUTDIR) $(EXTRA) $(ALLTARGETS) $(ALSO)
|
|
||||||
|
|
||||||
ifneq ($(OUTDIR),)
|
|
||||||
$(OUTDIR):
|
|
||||||
@mkdir -p $(OUTDIR)
|
|
||||||
endif
|
|
||||||
|
|
||||||
uefi/libuefi.a:
|
|
||||||
@$(MAKE) --no-print-directory -C uefi libuefi.a USE_GCC=$(USE_GCC) ARCH=$(ARCH)
|
|
||||||
|
|
||||||
libuefi.lib: $(LIBOBJS)
|
|
||||||
|
|
||||||
libuefi.a: $(LIBOBJS)
|
|
||||||
@rm $@ 2>/dev/null || true
|
|
||||||
$(AR) -rsv $@ $(LIBOBJS) >/dev/null
|
|
||||||
|
|
||||||
$(TARGET): $(addprefix $(OUTDIR),$(TARGET).so)
|
|
||||||
ifneq ($(USE_GCC),)
|
|
||||||
$(OBJCOPY) -j .text -j .sdata -j .data -j .dynamic -j .dynsym -j .rel -j .rela -j .rel.* -j .rela.* -j .reloc --target $(EFIARCH) --subsystem=10 $^ $(addprefix $(OUTDIR),$@) || echo target: $(EFIARCH)
|
|
||||||
@rm $(addprefix $(OUTDIR),$(TARGET).so)
|
|
||||||
endif
|
|
||||||
|
|
||||||
$(addprefix $(OUTDIR),$(TARGET).so): $(addprefix $(OUTDIR),$(OBJS)) $(EXTRA)
|
|
||||||
$(LD) $(LDFLAGS) $^ $(LIBS)
|
|
||||||
@rm $(addprefix $(OUTDIR),*.lib) 2>/dev/null || true
|
|
||||||
|
|
||||||
uefi/%.o: uefi/%.c
|
|
||||||
$(CC) $(CFLAGS) -c $< -o $@
|
|
||||||
|
|
||||||
%.o: %.c
|
|
||||||
$(CC) $(CFLAGS) -c $< -o $(addprefix $(OUTDIR),$@)
|
|
||||||
|
|
||||||
%.o: %.S
|
|
||||||
$(CC) $(CFLAGS) -c $< -o $(addprefix $(OUTDIR),$@)
|
|
||||||
|
|
||||||
buildlib:
|
|
||||||
@mkdir ../build ../build/uefi 2>/dev/null || true
|
|
||||||
@cp crt_$(ARCH).o ../build/uefi/crt0.o
|
|
||||||
@cp elf_$(ARCH)_efi.lds ../build/uefi/link.ld
|
|
||||||
ifneq ($(USE_GCC),)
|
|
||||||
@cp libuefi.a uefi.h ../build/uefi
|
|
||||||
else
|
|
||||||
@cp uefi.h ../build/uefi
|
|
||||||
@cp libuefi.a ../build/uefi/libuefi.dll.a
|
|
||||||
endif
|
|
||||||
|
|
||||||
clean:
|
|
||||||
@rm $(addprefix $(OUTDIR),$(TARGET)) *.o *.a *.lib *.elf $(LIBOBJS) 2>/dev/null || true
|
|
||||||
ifneq ($(OUTDIR),)
|
|
||||||
@rm -rf $(OUTDIR)
|
|
||||||
endif
|
|
||||||
|
|
||||||
distclean: clean
|
|
||||||
ifeq ($(wildcard uefi/Makefile),)
|
|
||||||
@rm -rf ../build 2>/dev/null || true
|
|
||||||
else
|
|
||||||
@rm uefi/*.o uefi/libuefi.a 2>/dev/null || true
|
|
||||||
endif
|
|
||||||
@@ -1,239 +0,0 @@
|
|||||||
/*
|
|
||||||
* crt_aarch64.c
|
|
||||||
*
|
|
||||||
* Copyright (C) 2021 bzt (bztsrc@gitlab)
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person
|
|
||||||
* obtaining a copy of this software and associated documentation
|
|
||||||
* files (the "Software"), to deal in the Software without
|
|
||||||
* restriction, including without limitation the rights to use, copy,
|
|
||||||
* modify, merge, publish, distribute, sublicense, and/or sell copies
|
|
||||||
* of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be
|
|
||||||
* included in all copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
||||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
||||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
||||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|
||||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
||||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
||||||
* DEALINGS IN THE SOFTWARE.
|
|
||||||
*
|
|
||||||
* This file is part of the POSIX-UEFI package.
|
|
||||||
* @brief C runtime, bootstraps an EFI application to call standard main()
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <uefi.h>
|
|
||||||
|
|
||||||
/* this is implemented by the application */
|
|
||||||
extern int main(int argc, char_t **argv);
|
|
||||||
|
|
||||||
/* definitions for elf relocations */
|
|
||||||
#ifndef __clang__
|
|
||||||
typedef uint64_t Elf64_Xword;
|
|
||||||
typedef int64_t Elf64_Sxword;
|
|
||||||
typedef uint64_t Elf64_Addr;
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
Elf64_Sxword d_tag; /* Dynamic entry type */
|
|
||||||
union
|
|
||||||
{
|
|
||||||
Elf64_Xword d_val; /* Integer value */
|
|
||||||
Elf64_Addr d_ptr; /* Address value */
|
|
||||||
} d_un;
|
|
||||||
} Elf64_Dyn;
|
|
||||||
#define DT_NULL 0 /* Marks end of dynamic section */
|
|
||||||
#define DT_RELA 7 /* Address of Rela relocs */
|
|
||||||
#define DT_RELASZ 8 /* Total size of Rela relocs */
|
|
||||||
#define DT_RELAENT 9 /* Size of one Rela reloc */
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
Elf64_Addr r_offset; /* Address */
|
|
||||||
Elf64_Xword r_info; /* Relocation type and symbol index */
|
|
||||||
} Elf64_Rel;
|
|
||||||
#define ELF64_R_TYPE(i) ((i) & 0xffffffff)
|
|
||||||
#define R_AARCH64_RELATIVE 1027 /* Adjust by program base */
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* globals to store system table pointers */
|
|
||||||
efi_handle_t IM = NULL;
|
|
||||||
efi_system_table_t *ST = NULL;
|
|
||||||
efi_boot_services_t *BS = NULL;
|
|
||||||
efi_runtime_services_t *RT = NULL;
|
|
||||||
efi_loaded_image_protocol_t *LIP = NULL;
|
|
||||||
#ifndef UEFI_NO_UTF8
|
|
||||||
char *__argvutf8 = NULL;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* we only need one .o file, so use inline Assembly here */
|
|
||||||
void bootstrap(void)
|
|
||||||
{
|
|
||||||
__asm__ __volatile__ (
|
|
||||||
/* call init in C */
|
|
||||||
" .align 4\n"
|
|
||||||
#ifndef __clang__
|
|
||||||
" .globl _start\n"
|
|
||||||
"_start:\n"
|
|
||||||
" ldr x2, =ImageBase\n"
|
|
||||||
" adrp x3, _DYNAMIC\n"
|
|
||||||
" add x3, x3, #:lo12:_DYNAMIC\n"
|
|
||||||
" bl uefi_init\n"
|
|
||||||
" ret\n"
|
|
||||||
|
|
||||||
/* fake a relocation record, so that EFI won't complain */
|
|
||||||
" .data\n"
|
|
||||||
"dummy: .long 0\n"
|
|
||||||
" .section .reloc, \"a\"\n"
|
|
||||||
"label1:\n"
|
|
||||||
" .long dummy-label1\n"
|
|
||||||
" .long 10\n"
|
|
||||||
" .word 0\n"
|
|
||||||
".text\n"
|
|
||||||
#else
|
|
||||||
" .globl __chkstk\n"
|
|
||||||
"__chkstk:\n"
|
|
||||||
" ret\n"
|
|
||||||
#endif
|
|
||||||
);
|
|
||||||
|
|
||||||
/* setjmp and longjmp */
|
|
||||||
__asm__ __volatile__ (
|
|
||||||
" .p2align 3\n"
|
|
||||||
" .globl setjmp\n"
|
|
||||||
"setjmp:\n"
|
|
||||||
" mov x16, sp\n"
|
|
||||||
" stp x19, x20, [x0, #0]\n"
|
|
||||||
" stp x21, x22, [x0, #16]\n"
|
|
||||||
" stp x23, x24, [x0, #32]\n"
|
|
||||||
" stp x25, x26, [x0, #48]\n"
|
|
||||||
" stp x27, x28, [x0, #64]\n"
|
|
||||||
" stp x29, x30, [x0, #80]\n"
|
|
||||||
" str x16, [x0, #96]\n"
|
|
||||||
" stp d8, d9, [x0, #112]\n"
|
|
||||||
" stp d10, d11, [x0, #128]\n"
|
|
||||||
" stp d12, d13, [x0, #144]\n"
|
|
||||||
" stp d14, d15, [x0, #160]\n"
|
|
||||||
" mov w0, #0\n"
|
|
||||||
" ret\n"
|
|
||||||
);
|
|
||||||
__asm__ __volatile__ (
|
|
||||||
" .globl longjmp\n"
|
|
||||||
"longjmp:\n"
|
|
||||||
" ldp x19, x20, [x0, #0]\n"
|
|
||||||
" ldp x21, x22, [x0, #16]\n"
|
|
||||||
" ldp x23, x24, [x0, #32]\n"
|
|
||||||
" ldp x25, x26, [x0, #48]\n"
|
|
||||||
" ldp x27, x28, [x0, #64]\n"
|
|
||||||
" ldp x29, x30, [x0, #80]\n"
|
|
||||||
" ldr x16, [x0, #96]\n"
|
|
||||||
" ldp d8, d9, [x0, #112]\n"
|
|
||||||
" ldp d10, d11, [x0, #128]\n"
|
|
||||||
" ldp d12, d13, [x0, #144]\n"
|
|
||||||
" ldp d14, d15, [x0, #160]\n"
|
|
||||||
" mov sp, x16\n"
|
|
||||||
" cmp w1, #0\n"
|
|
||||||
" mov w0, #1\n"
|
|
||||||
" csel w0, w1, w0, ne\n"
|
|
||||||
" br x30\n"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize POSIX-UEFI and call the application's main() function
|
|
||||||
*/
|
|
||||||
efi_status_t uefi_init (
|
|
||||||
efi_handle_t image, efi_system_table_t *systab
|
|
||||||
#ifndef __clang__
|
|
||||||
, uintptr_t ldbase, Elf64_Dyn *dyn
|
|
||||||
#endif
|
|
||||||
) {
|
|
||||||
efi_guid_t shpGuid = EFI_SHELL_PARAMETERS_PROTOCOL_GUID;
|
|
||||||
efi_shell_parameters_protocol_t *shp = NULL;
|
|
||||||
efi_guid_t shiGuid = SHELL_INTERFACE_PROTOCOL_GUID;
|
|
||||||
efi_shell_interface_protocol_t *shi = NULL;
|
|
||||||
efi_guid_t lipGuid = EFI_LOADED_IMAGE_PROTOCOL_GUID;
|
|
||||||
efi_status_t status;
|
|
||||||
int argc = 0, i, ret;
|
|
||||||
wchar_t **argv = NULL;
|
|
||||||
#ifndef UEFI_NO_UTF8
|
|
||||||
int j;
|
|
||||||
char *s;
|
|
||||||
#endif
|
|
||||||
#ifndef __clang__
|
|
||||||
long relsz = 0, relent = 0;
|
|
||||||
Elf64_Rel *rel = 0;
|
|
||||||
uintptr_t *addr;
|
|
||||||
/* handle relocations */
|
|
||||||
for (i = 0; dyn[i].d_tag != DT_NULL; ++i) {
|
|
||||||
switch (dyn[i].d_tag) {
|
|
||||||
case DT_RELA: rel = (Elf64_Rel*)((unsigned long)dyn[i].d_un.d_ptr + ldbase); break;
|
|
||||||
case DT_RELASZ: relsz = dyn[i].d_un.d_val; break;
|
|
||||||
case DT_RELAENT: relent = dyn[i].d_un.d_val; break;
|
|
||||||
default: break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (rel && relent) {
|
|
||||||
while (relsz > 0) {
|
|
||||||
if(ELF64_R_TYPE (rel->r_info) == R_AARCH64_RELATIVE)
|
|
||||||
{ addr = (unsigned long *)(ldbase + rel->r_offset); *addr += ldbase; }
|
|
||||||
rel = (Elf64_Rel*) ((char *) rel + relent);
|
|
||||||
relsz -= relent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
(void)i;
|
|
||||||
#endif
|
|
||||||
/* failsafes, should never happen */
|
|
||||||
if(!image || !systab || !systab->BootServices || !systab->BootServices->HandleProtocol ||
|
|
||||||
!systab->BootServices->OpenProtocol || !systab->BootServices->AllocatePool || !systab->BootServices->FreePool)
|
|
||||||
return EFI_UNSUPPORTED;
|
|
||||||
/* save EFI pointers and loaded image into globals */
|
|
||||||
IM = image;
|
|
||||||
ST = systab;
|
|
||||||
BS = systab->BootServices;
|
|
||||||
RT = systab->RuntimeServices;
|
|
||||||
BS->HandleProtocol(image, &lipGuid, (void **)&LIP);
|
|
||||||
/* get command line arguments */
|
|
||||||
status = BS->OpenProtocol(image, &shpGuid, (void **)&shp, image, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
|
|
||||||
if(!EFI_ERROR(status) && shp) { argc = (int)shp->Argc; argv = shp->Argv; }
|
|
||||||
else {
|
|
||||||
/* if shell 2.0 failed, fallback to shell 1.0 interface */
|
|
||||||
status = BS->OpenProtocol(image, &shiGuid, (void **)&shi, image, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
|
|
||||||
if(!EFI_ERROR(status) && shi) { argc = (int)shi->Argc; argv = shi->Argv; }
|
|
||||||
}
|
|
||||||
/* call main */
|
|
||||||
#ifndef UEFI_NO_UTF8
|
|
||||||
if(argc && argv) {
|
|
||||||
ret = (argc + 1) * ((int)sizeof(uintptr_t) + 1);
|
|
||||||
for(i = 0; i < argc; i++)
|
|
||||||
for(j = 0; argv[i] && argv[i][j]; j++)
|
|
||||||
ret += argv[i][j] < 0x80 ? 1 : (argv[i][j] < 0x800 ? 2 : 3);
|
|
||||||
status = BS->AllocatePool(LIP ? LIP->ImageDataType : EfiLoaderData, (uintn_t)ret, (void **)&__argvutf8);
|
|
||||||
if(EFI_ERROR(status) || !__argvutf8) { argc = 0; __argvutf8 = NULL; }
|
|
||||||
else {
|
|
||||||
s = __argvutf8 + argc * (int)sizeof(uintptr_t);
|
|
||||||
*((uintptr_t*)s) = (uintptr_t)0; s += sizeof(uintptr_t);
|
|
||||||
for(i = 0; i < argc; i++) {
|
|
||||||
*((uintptr_t*)(__argvutf8 + i * (int)sizeof(uintptr_t))) = (uintptr_t)s;
|
|
||||||
for(j = 0; argv[i] && argv[i][j]; j++) {
|
|
||||||
if(argv[i][j]<0x80) { *s++ = argv[i][j]; } else
|
|
||||||
if(argv[i][j]<0x800) { *s++ = ((argv[i][j]>>6)&0x1F)|0xC0; *s++ = (argv[i][j]&0x3F)|0x80; } else
|
|
||||||
{ *s++ = ((argv[i][j]>>12)&0x0F)|0xE0; *s++ = ((argv[i][j]>>6)&0x3F)|0x80; *s++ = (argv[i][j]&0x3F)|0x80; }
|
|
||||||
}
|
|
||||||
*s++ = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ret = main(argc, (char**)__argvutf8);
|
|
||||||
if(__argvutf8) BS->FreePool(__argvutf8);
|
|
||||||
return ret;
|
|
||||||
#else
|
|
||||||
ret = main(argc, argv);
|
|
||||||
#endif
|
|
||||||
return ret ? EFIERR(ret) : EFI_SUCCESS;
|
|
||||||
}
|
|
||||||
@@ -1,270 +0,0 @@
|
|||||||
/*
|
|
||||||
* crt_riscv64.c
|
|
||||||
*
|
|
||||||
* Copyright (C) 2023 bzt (bztsrc@gitlab)
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person
|
|
||||||
* obtaining a copy of this software and associated documentation
|
|
||||||
* files (the "Software"), to deal in the Software without
|
|
||||||
* restriction, including without limitation the rights to use, copy,
|
|
||||||
* modify, merge, publish, distribute, sublicense, and/or sell copies
|
|
||||||
* of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be
|
|
||||||
* included in all copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
||||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
||||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
||||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|
||||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
||||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
||||||
* DEALINGS IN THE SOFTWARE.
|
|
||||||
*
|
|
||||||
* This file is part of the POSIX-UEFI package.
|
|
||||||
* @brief C runtime, bootstraps an EFI application to call standard main()
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <uefi.h>
|
|
||||||
|
|
||||||
/* this is implemented by the application */
|
|
||||||
extern int main(int argc, char_t **argv);
|
|
||||||
|
|
||||||
/* definitions for elf relocations */
|
|
||||||
#ifndef __clang__
|
|
||||||
typedef uint64_t Elf64_Xword;
|
|
||||||
typedef int64_t Elf64_Sxword;
|
|
||||||
typedef uint64_t Elf64_Addr;
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
Elf64_Sxword d_tag; /* Dynamic entry type */
|
|
||||||
union
|
|
||||||
{
|
|
||||||
Elf64_Xword d_val; /* Integer value */
|
|
||||||
Elf64_Addr d_ptr; /* Address value */
|
|
||||||
} d_un;
|
|
||||||
} Elf64_Dyn;
|
|
||||||
#define DT_NULL 0 /* Marks end of dynamic section */
|
|
||||||
#define DT_RELA 7 /* Address of Rela relocs */
|
|
||||||
#define DT_RELASZ 8 /* Total size of Rela relocs */
|
|
||||||
#define DT_RELAENT 9 /* Size of one Rela reloc */
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
Elf64_Addr r_offset; /* Address */
|
|
||||||
Elf64_Xword r_info; /* Relocation type and symbol index */
|
|
||||||
} Elf64_Rel;
|
|
||||||
#define ELF64_R_TYPE(i) ((i) & 0xffffffff)
|
|
||||||
#define R_RISCV_RELATIVE 3 /* Adjust by program base */
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* globals to store system table pointers */
|
|
||||||
efi_handle_t IM = NULL;
|
|
||||||
efi_system_table_t *ST = NULL;
|
|
||||||
efi_boot_services_t *BS = NULL;
|
|
||||||
efi_runtime_services_t *RT = NULL;
|
|
||||||
efi_loaded_image_protocol_t *LIP = NULL;
|
|
||||||
#ifndef UEFI_NO_UTF8
|
|
||||||
char *__argvutf8 = NULL;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* we only need one .o file, so use inline Assembly here */
|
|
||||||
void bootstrap(void)
|
|
||||||
{
|
|
||||||
__asm__ __volatile__ (
|
|
||||||
/* call init in C */
|
|
||||||
" .align 4\n"
|
|
||||||
#ifndef __clang__
|
|
||||||
" .globl _start\n"
|
|
||||||
"_start:\n"
|
|
||||||
" lla a2, ImageBase\n"
|
|
||||||
" lui a3, %hi(_DYNAMIC)\n"
|
|
||||||
" addi a3, a3, %lo(_DYNAMIC)\n"
|
|
||||||
" call uefi_init\n"
|
|
||||||
" ret\n"
|
|
||||||
|
|
||||||
/* fake a relocation record, so that EFI won't complain */
|
|
||||||
" .data\n"
|
|
||||||
"dummy: .long 0\n"
|
|
||||||
" .section .reloc, \"a\"\n"
|
|
||||||
"label1:\n"
|
|
||||||
" .long dummy-label1\n"
|
|
||||||
" .long 10\n"
|
|
||||||
" .word 0\n"
|
|
||||||
".text\n"
|
|
||||||
#else
|
|
||||||
" .globl __chkstk\n"
|
|
||||||
"__chkstk:\n"
|
|
||||||
" ret\n"
|
|
||||||
#endif
|
|
||||||
);
|
|
||||||
|
|
||||||
/* setjmp and longjmp */
|
|
||||||
__asm__ __volatile__ (
|
|
||||||
" .p2align 3\n"
|
|
||||||
" .globl setjmp\n"
|
|
||||||
"setjmp:\n"
|
|
||||||
" sd ra, 0(a0)\n"
|
|
||||||
" sd sp, 8(a0)\n"
|
|
||||||
" sd s0, 16(a0)\n"
|
|
||||||
" sd s1, 24(a0)\n"
|
|
||||||
" sd s2, 32(a0)\n"
|
|
||||||
" sd s3, 40(a0)\n"
|
|
||||||
" sd s4, 48(a0)\n"
|
|
||||||
" sd s5, 56(a0)\n"
|
|
||||||
" sd s6, 64(a0)\n"
|
|
||||||
" sd s7, 72(a0)\n"
|
|
||||||
" sd s8, 80(a0)\n"
|
|
||||||
" sd s9, 88(a0)\n"
|
|
||||||
" sd s10, 96(a0)\n"
|
|
||||||
" sd s11, 104(a0)\n"
|
|
||||||
#ifndef __riscv_float_abi_soft
|
|
||||||
" fsd fs0, 112(a0)\n"
|
|
||||||
" fsd fs1, 120(a0)\n"
|
|
||||||
" fsd fs2, 128(a0)\n"
|
|
||||||
" fsd fs3, 136(a0)\n"
|
|
||||||
" fsd fs4, 144(a0)\n"
|
|
||||||
" fsd fs5, 152(a0)\n"
|
|
||||||
" fsd fs6, 160(a0)\n"
|
|
||||||
" fsd fs7, 168(a0)\n"
|
|
||||||
" fsd fs8, 176(a0)\n"
|
|
||||||
" fsd fs9, 184(a0)\n"
|
|
||||||
" fsd fs10,192(a0)\n"
|
|
||||||
" fsd fs11,200(a0)\n"
|
|
||||||
#endif
|
|
||||||
" li a0, 0\n"
|
|
||||||
" ret\n"
|
|
||||||
);
|
|
||||||
__asm__ __volatile__ (
|
|
||||||
" .globl longjmp\n"
|
|
||||||
"longjmp:\n"
|
|
||||||
" ld ra, 0(a0)\n"
|
|
||||||
" ld sp, 8(a0)\n"
|
|
||||||
" ld s0, 16(a0)\n"
|
|
||||||
" ld s1, 24(a0)\n"
|
|
||||||
" ld s2, 32(a0)\n"
|
|
||||||
" ld s3, 40(a0)\n"
|
|
||||||
" ld s4, 48(a0)\n"
|
|
||||||
" ld s5, 56(a0)\n"
|
|
||||||
" ld s6, 64(a0)\n"
|
|
||||||
" ld s7, 72(a0)\n"
|
|
||||||
" ld s8, 80(a0)\n"
|
|
||||||
" ld s9, 88(a0)\n"
|
|
||||||
" ld s10, 96(a0)\n"
|
|
||||||
" ld s11, 104(a0)\n"
|
|
||||||
#ifndef __riscv_float_abi_soft
|
|
||||||
" fld fs0, 112(a0)\n"
|
|
||||||
" fld fs1, 120(a0)\n"
|
|
||||||
" fld fs2, 128(a0)\n"
|
|
||||||
" fld fs3, 136(a0)\n"
|
|
||||||
" fld fs4, 144(a0)\n"
|
|
||||||
" fld fs5, 152(a0)\n"
|
|
||||||
" fld fs6, 160(a0)\n"
|
|
||||||
" fld fs7, 168(a0)\n"
|
|
||||||
" fld fs8, 176(a0)\n"
|
|
||||||
" fld fs9, 184(a0)\n"
|
|
||||||
" fld fs10,192(a0)\n"
|
|
||||||
" fld fs11,200(a0)\n"
|
|
||||||
#endif
|
|
||||||
" seqz a0, a1\n"
|
|
||||||
" add a0, a0, a1\n"
|
|
||||||
" ret\n"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize POSIX-UEFI and call the application's main() function
|
|
||||||
*/
|
|
||||||
efi_status_t uefi_init (
|
|
||||||
efi_handle_t image, efi_system_table_t *systab
|
|
||||||
#ifndef __clang__
|
|
||||||
, uintptr_t ldbase, Elf64_Dyn *dyn
|
|
||||||
#endif
|
|
||||||
) {
|
|
||||||
efi_guid_t shpGuid = EFI_SHELL_PARAMETERS_PROTOCOL_GUID;
|
|
||||||
efi_shell_parameters_protocol_t *shp = NULL;
|
|
||||||
efi_guid_t shiGuid = SHELL_INTERFACE_PROTOCOL_GUID;
|
|
||||||
efi_shell_interface_protocol_t *shi = NULL;
|
|
||||||
efi_guid_t lipGuid = EFI_LOADED_IMAGE_PROTOCOL_GUID;
|
|
||||||
efi_status_t status;
|
|
||||||
int argc = 0, i, ret;
|
|
||||||
wchar_t **argv = NULL;
|
|
||||||
#ifndef UEFI_NO_UTF8
|
|
||||||
int j;
|
|
||||||
char *s;
|
|
||||||
#endif
|
|
||||||
#ifndef __clang__
|
|
||||||
long relsz = 0, relent = 0;
|
|
||||||
Elf64_Rel *rel = 0;
|
|
||||||
uintptr_t *addr;
|
|
||||||
/* handle relocations */
|
|
||||||
for (i = 0; dyn[i].d_tag != DT_NULL; ++i) {
|
|
||||||
switch (dyn[i].d_tag) {
|
|
||||||
case DT_RELA: rel = (Elf64_Rel*)((unsigned long)dyn[i].d_un.d_ptr + ldbase); break;
|
|
||||||
case DT_RELASZ: relsz = dyn[i].d_un.d_val; break;
|
|
||||||
case DT_RELAENT: relent = dyn[i].d_un.d_val; break;
|
|
||||||
default: break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (rel && relent) {
|
|
||||||
while (relsz > 0) {
|
|
||||||
if(ELF64_R_TYPE (rel->r_info) == R_RISCV_RELATIVE)
|
|
||||||
{ addr = (unsigned long *)(ldbase + rel->r_offset); *addr += ldbase; }
|
|
||||||
rel = (Elf64_Rel*) ((char *) rel + relent);
|
|
||||||
relsz -= relent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
(void)i;
|
|
||||||
#endif
|
|
||||||
/* failsafes, should never happen */
|
|
||||||
if(!image || !systab || !systab->BootServices || !systab->BootServices->HandleProtocol ||
|
|
||||||
!systab->BootServices->OpenProtocol || !systab->BootServices->AllocatePool || !systab->BootServices->FreePool)
|
|
||||||
return EFI_UNSUPPORTED;
|
|
||||||
/* save EFI pointers and loaded image into globals */
|
|
||||||
IM = image;
|
|
||||||
ST = systab;
|
|
||||||
BS = systab->BootServices;
|
|
||||||
RT = systab->RuntimeServices;
|
|
||||||
BS->HandleProtocol(image, &lipGuid, (void **)&LIP);
|
|
||||||
/* get command line arguments */
|
|
||||||
status = BS->OpenProtocol(image, &shpGuid, (void **)&shp, image, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
|
|
||||||
if(!EFI_ERROR(status) && shp) { argc = (int)shp->Argc; argv = shp->Argv; }
|
|
||||||
else {
|
|
||||||
/* if shell 2.0 failed, fallback to shell 1.0 interface */
|
|
||||||
status = BS->OpenProtocol(image, &shiGuid, (void **)&shi, image, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
|
|
||||||
if(!EFI_ERROR(status) && shi) { argc = (int)shi->Argc; argv = shi->Argv; }
|
|
||||||
}
|
|
||||||
/* call main */
|
|
||||||
#ifndef UEFI_NO_UTF8
|
|
||||||
if(argc && argv) {
|
|
||||||
ret = (argc + 1) * ((int)sizeof(uintptr_t) + 1);
|
|
||||||
for(i = 0; i < argc; i++)
|
|
||||||
for(j = 0; argv[i] && argv[i][j]; j++)
|
|
||||||
ret += argv[i][j] < 0x80 ? 1 : (argv[i][j] < 0x800 ? 2 : 3);
|
|
||||||
status = BS->AllocatePool(LIP ? LIP->ImageDataType : EfiLoaderData, (uintn_t)ret, (void **)&__argvutf8);
|
|
||||||
if(EFI_ERROR(status) || !__argvutf8) { argc = 0; __argvutf8 = NULL; }
|
|
||||||
else {
|
|
||||||
s = __argvutf8 + argc * (int)sizeof(uintptr_t);
|
|
||||||
*((uintptr_t*)s) = (uintptr_t)0; s += sizeof(uintptr_t);
|
|
||||||
for(i = 0; i < argc; i++) {
|
|
||||||
*((uintptr_t*)(__argvutf8 + i * (int)sizeof(uintptr_t))) = (uintptr_t)s;
|
|
||||||
for(j = 0; argv[i] && argv[i][j]; j++) {
|
|
||||||
if(argv[i][j]<0x80) { *s++ = argv[i][j]; } else
|
|
||||||
if(argv[i][j]<0x800) { *s++ = ((argv[i][j]>>6)&0x1F)|0xC0; *s++ = (argv[i][j]&0x3F)|0x80; } else
|
|
||||||
{ *s++ = ((argv[i][j]>>12)&0x0F)|0xE0; *s++ = ((argv[i][j]>>6)&0x3F)|0x80; *s++ = (argv[i][j]&0x3F)|0x80; }
|
|
||||||
}
|
|
||||||
*s++ = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ret = main(argc, (char**)__argvutf8);
|
|
||||||
if(__argvutf8) BS->FreePool(__argvutf8);
|
|
||||||
return ret;
|
|
||||||
#else
|
|
||||||
ret = main(argc, argv);
|
|
||||||
#endif
|
|
||||||
return ret ? EFIERR(ret) : EFI_SUCCESS;
|
|
||||||
}
|
|
||||||
@@ -1,241 +0,0 @@
|
|||||||
/*
|
|
||||||
* crt_x86_64.c
|
|
||||||
*
|
|
||||||
* Copyright (C) 2021 bzt (bztsrc@gitlab)
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person
|
|
||||||
* obtaining a copy of this software and associated documentation
|
|
||||||
* files (the "Software"), to deal in the Software without
|
|
||||||
* restriction, including without limitation the rights to use, copy,
|
|
||||||
* modify, merge, publish, distribute, sublicense, and/or sell copies
|
|
||||||
* of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be
|
|
||||||
* included in all copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
||||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
||||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
||||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|
||||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
||||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
||||||
* DEALINGS IN THE SOFTWARE.
|
|
||||||
*
|
|
||||||
* This file is part of the POSIX-UEFI package.
|
|
||||||
* @brief C runtime, bootstraps an EFI application to call standard main()
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <uefi.h>
|
|
||||||
|
|
||||||
/* this is implemented by the application */
|
|
||||||
extern int main(int argc, char_t **argv);
|
|
||||||
|
|
||||||
/* definitions for elf relocations */
|
|
||||||
#ifndef __clang__
|
|
||||||
typedef uint64_t Elf64_Xword;
|
|
||||||
typedef int64_t Elf64_Sxword;
|
|
||||||
typedef uint64_t Elf64_Addr;
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
Elf64_Sxword d_tag; /* Dynamic entry type */
|
|
||||||
union
|
|
||||||
{
|
|
||||||
Elf64_Xword d_val; /* Integer value */
|
|
||||||
Elf64_Addr d_ptr; /* Address value */
|
|
||||||
} d_un;
|
|
||||||
} Elf64_Dyn;
|
|
||||||
#define DT_NULL 0 /* Marks end of dynamic section */
|
|
||||||
#define DT_RELA 7 /* Address of Rela relocs */
|
|
||||||
#define DT_RELASZ 8 /* Total size of Rela relocs */
|
|
||||||
#define DT_RELAENT 9 /* Size of one Rela reloc */
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
Elf64_Addr r_offset; /* Address */
|
|
||||||
Elf64_Xword r_info; /* Relocation type and symbol index */
|
|
||||||
} Elf64_Rel;
|
|
||||||
#define ELF64_R_TYPE(i) ((i) & 0xffffffff)
|
|
||||||
#define R_X86_64_RELATIVE 8 /* Adjust by program base */
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* globals to store system table pointers */
|
|
||||||
efi_handle_t IM = NULL;
|
|
||||||
efi_system_table_t *ST = NULL;
|
|
||||||
efi_boot_services_t *BS = NULL;
|
|
||||||
efi_runtime_services_t *RT = NULL;
|
|
||||||
efi_loaded_image_protocol_t *LIP = NULL;
|
|
||||||
#ifndef UEFI_NO_UTF8
|
|
||||||
char *__argvutf8 = NULL;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* we only need one .o file, so use inline Assembly here */
|
|
||||||
void bootstrap(void)
|
|
||||||
{
|
|
||||||
__asm__ __volatile__ (
|
|
||||||
/* call init in C */
|
|
||||||
" .align 4\n"
|
|
||||||
#ifndef __clang__
|
|
||||||
" .globl _start\n"
|
|
||||||
"_start:\n"
|
|
||||||
" lea ImageBase(%rip), %rdi\n"
|
|
||||||
" lea _DYNAMIC(%rip), %rsi\n"
|
|
||||||
" call uefi_init\n"
|
|
||||||
" ret\n"
|
|
||||||
|
|
||||||
/* fake a relocation record, so that EFI won't complain */
|
|
||||||
" .data\n"
|
|
||||||
"dummy: .long 0\n"
|
|
||||||
" .section .reloc, \"a\"\n"
|
|
||||||
"label1:\n"
|
|
||||||
" .long dummy-label1\n"
|
|
||||||
" .long 10\n"
|
|
||||||
" .word 0\n"
|
|
||||||
".text\n"
|
|
||||||
#else
|
|
||||||
" .globl __chkstk\n"
|
|
||||||
"__chkstk:\n"
|
|
||||||
" ret\n"
|
|
||||||
#endif
|
|
||||||
);
|
|
||||||
|
|
||||||
/* setjmp and longjmp */
|
|
||||||
__asm__ __volatile__ (
|
|
||||||
" .globl setjmp\n"
|
|
||||||
"setjmp:\n"
|
|
||||||
" pop %rsi\n"
|
|
||||||
" movq %rbx,0x00(%rdi)\n"
|
|
||||||
" movq %rsp,0x08(%rdi)\n"
|
|
||||||
" push %rsi\n"
|
|
||||||
" movq %rbp,0x10(%rdi)\n"
|
|
||||||
" movq %r12,0x18(%rdi)\n"
|
|
||||||
" movq %r13,0x20(%rdi)\n"
|
|
||||||
" movq %r14,0x28(%rdi)\n"
|
|
||||||
" movq %r15,0x30(%rdi)\n"
|
|
||||||
" movq %rsi,0x38(%rdi)\n"
|
|
||||||
" xor %rax,%rax\n"
|
|
||||||
" ret\n"
|
|
||||||
);
|
|
||||||
__asm__ __volatile__ (
|
|
||||||
" .globl longjmp\n"
|
|
||||||
"longjmp:\n"
|
|
||||||
" movl %esi, %eax\n"
|
|
||||||
" movq 0x00(%rdi), %rbx\n"
|
|
||||||
" movq 0x08(%rdi), %rsp\n"
|
|
||||||
" movq 0x10(%rdi), %rbp\n"
|
|
||||||
" movq 0x18(%rdi), %r12\n"
|
|
||||||
" movq 0x20(%rdi), %r13\n"
|
|
||||||
" movq 0x28(%rdi), %r14\n"
|
|
||||||
" movq 0x30(%rdi), %r15\n"
|
|
||||||
" xor %rdx,%rdx\n"
|
|
||||||
" mov $1,%rcx\n"
|
|
||||||
" cmp %rax,%rdx\n"
|
|
||||||
" cmove %rcx,%rax\n"
|
|
||||||
" jmp *0x38(%rdi)\n"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize POSIX-UEFI and call the application's main() function
|
|
||||||
*/
|
|
||||||
efi_status_t uefi_init (
|
|
||||||
#ifndef __clang__
|
|
||||||
uintptr_t ldbase, Elf64_Dyn *dyn, efi_system_table_t *systab, efi_handle_t image
|
|
||||||
#else
|
|
||||||
efi_handle_t image, efi_system_table_t *systab
|
|
||||||
#endif
|
|
||||||
) {
|
|
||||||
efi_guid_t shpGuid = EFI_SHELL_PARAMETERS_PROTOCOL_GUID;
|
|
||||||
efi_shell_parameters_protocol_t *shp = NULL;
|
|
||||||
efi_guid_t shiGuid = SHELL_INTERFACE_PROTOCOL_GUID;
|
|
||||||
efi_shell_interface_protocol_t *shi = NULL;
|
|
||||||
efi_guid_t lipGuid = EFI_LOADED_IMAGE_PROTOCOL_GUID;
|
|
||||||
efi_status_t status;
|
|
||||||
int argc = 0, i, ret;
|
|
||||||
wchar_t **argv = NULL;
|
|
||||||
#ifndef UEFI_NO_UTF8
|
|
||||||
int j;
|
|
||||||
char *s;
|
|
||||||
#endif
|
|
||||||
#ifndef __clang__
|
|
||||||
long relsz = 0, relent = 0;
|
|
||||||
Elf64_Rel *rel = 0;
|
|
||||||
uintptr_t *addr;
|
|
||||||
/* handle relocations */
|
|
||||||
for (i = 0; dyn[i].d_tag != DT_NULL; ++i) {
|
|
||||||
switch (dyn[i].d_tag) {
|
|
||||||
case DT_RELA: rel = (Elf64_Rel*)((unsigned long)dyn[i].d_un.d_ptr + ldbase); break;
|
|
||||||
case DT_RELASZ: relsz = dyn[i].d_un.d_val; break;
|
|
||||||
case DT_RELAENT: relent = dyn[i].d_un.d_val; break;
|
|
||||||
default: break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (rel && relent) {
|
|
||||||
while (relsz > 0) {
|
|
||||||
if(ELF64_R_TYPE (rel->r_info) == R_X86_64_RELATIVE)
|
|
||||||
{ addr = (unsigned long *)(ldbase + rel->r_offset); *addr += ldbase; }
|
|
||||||
rel = (Elf64_Rel*) ((char *) rel + relent);
|
|
||||||
relsz -= relent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
(void)i;
|
|
||||||
#endif
|
|
||||||
/* make sure SSE is enabled, because some say there are buggy firmware in the wild not doing that */
|
|
||||||
__asm__ __volatile__ (
|
|
||||||
" movq %cr0, %rax\n"
|
|
||||||
" andb $0xF1, %al\n"
|
|
||||||
" movq %rax, %cr0\n"
|
|
||||||
" movq %cr4, %rax\n"
|
|
||||||
" orw $3 << 9, %ax\n"
|
|
||||||
" mov %rax, %cr4\n"
|
|
||||||
);
|
|
||||||
/* failsafes, should never happen */
|
|
||||||
if(!image || !systab || !systab->BootServices || !systab->BootServices->HandleProtocol ||
|
|
||||||
!systab->BootServices->OpenProtocol || !systab->BootServices->AllocatePool || !systab->BootServices->FreePool)
|
|
||||||
return EFI_UNSUPPORTED;
|
|
||||||
/* save EFI pointers and loaded image into globals */
|
|
||||||
IM = image;
|
|
||||||
ST = systab;
|
|
||||||
BS = systab->BootServices;
|
|
||||||
RT = systab->RuntimeServices;
|
|
||||||
BS->HandleProtocol(image, &lipGuid, (void **)&LIP);
|
|
||||||
/* get command line arguments */
|
|
||||||
status = BS->OpenProtocol(image, &shpGuid, (void **)&shp, image, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
|
|
||||||
if(!EFI_ERROR(status) && shp) { argc = (int)shp->Argc; argv = shp->Argv; }
|
|
||||||
else {
|
|
||||||
/* if shell 2.0 failed, fallback to shell 1.0 interface */
|
|
||||||
status = BS->OpenProtocol(image, &shiGuid, (void **)&shi, image, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
|
|
||||||
if(!EFI_ERROR(status) && shi) { argc = (int)shi->Argc; argv = shi->Argv; }
|
|
||||||
}
|
|
||||||
/* call main */
|
|
||||||
#ifndef UEFI_NO_UTF8
|
|
||||||
if(argc && argv) {
|
|
||||||
ret = (argc + 1) * ((int)sizeof(uintptr_t) + 1);
|
|
||||||
for(i = 0; i < argc; i++)
|
|
||||||
for(j = 0; argv[i] && argv[i][j]; j++)
|
|
||||||
ret += argv[i][j] < 0x80 ? 1 : (argv[i][j] < 0x800 ? 2 : 3);
|
|
||||||
status = BS->AllocatePool(LIP ? LIP->ImageDataType : EfiLoaderData, (uintn_t)ret, (void **)&__argvutf8);
|
|
||||||
if(EFI_ERROR(status) || !__argvutf8) { argc = 0; __argvutf8 = NULL; }
|
|
||||||
else {
|
|
||||||
s = __argvutf8 + argc * (int)sizeof(uintptr_t);
|
|
||||||
*((uintptr_t*)s) = (uintptr_t)0; s += sizeof(uintptr_t);
|
|
||||||
for(i = 0; i < argc; i++) {
|
|
||||||
*((uintptr_t*)(__argvutf8 + i * (int)sizeof(uintptr_t))) = (uintptr_t)s;
|
|
||||||
for(j = 0; argv[i] && argv[i][j]; j++) {
|
|
||||||
if(argv[i][j]<0x80) { *s++ = argv[i][j]; } else
|
|
||||||
if(argv[i][j]<0x800) { *s++ = ((argv[i][j]>>6)&0x1F)|0xC0; *s++ = (argv[i][j]&0x3F)|0x80; } else
|
|
||||||
{ *s++ = ((argv[i][j]>>12)&0x0F)|0xE0; *s++ = ((argv[i][j]>>6)&0x3F)|0x80; *s++ = (argv[i][j]&0x3F)|0x80; }
|
|
||||||
}
|
|
||||||
*s++ = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ret = main(argc, (char**)__argvutf8);
|
|
||||||
if(__argvutf8) BS->FreePool(__argvutf8);
|
|
||||||
#else
|
|
||||||
ret = main(argc, argv);
|
|
||||||
#endif
|
|
||||||
return ret ? EFIERR(ret) : EFI_SUCCESS;
|
|
||||||
}
|
|
||||||
@@ -1,76 +0,0 @@
|
|||||||
/*
|
|
||||||
* dirent.c
|
|
||||||
*
|
|
||||||
* Copyright (C) 2021 bzt (bztsrc@gitlab)
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person
|
|
||||||
* obtaining a copy of this software and associated documentation
|
|
||||||
* files (the "Software"), to deal in the Software without
|
|
||||||
* restriction, including without limitation the rights to use, copy,
|
|
||||||
* modify, merge, publish, distribute, sublicense, and/or sell copies
|
|
||||||
* of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be
|
|
||||||
* included in all copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
||||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
||||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
||||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|
||||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
||||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
||||||
* DEALINGS IN THE SOFTWARE.
|
|
||||||
*
|
|
||||||
* This file is part of the POSIX-UEFI package.
|
|
||||||
* @brief Implementing functions which are defined in dirent.h
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <uefi.h>
|
|
||||||
|
|
||||||
extern void __stdio_seterrno(efi_status_t status);
|
|
||||||
static struct dirent __dirent;
|
|
||||||
|
|
||||||
DIR *opendir (const char_t *__name)
|
|
||||||
{
|
|
||||||
DIR *dp = (DIR*)fopen(__name, CL("rd"));
|
|
||||||
if(dp) rewinddir(dp);
|
|
||||||
return dp;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct dirent *readdir (DIR *__dirp)
|
|
||||||
{
|
|
||||||
efi_status_t status;
|
|
||||||
efi_file_info_t info;
|
|
||||||
uintn_t bs = sizeof(efi_file_info_t);
|
|
||||||
memset(&__dirent, 0, sizeof(struct dirent));
|
|
||||||
status = __dirp->Read(__dirp, &bs, &info);
|
|
||||||
if(EFI_ERROR(status) || !bs) {
|
|
||||||
if(EFI_ERROR(status)) __stdio_seterrno(status);
|
|
||||||
else errno = 0;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
__dirent.d_type = info.Attribute & EFI_FILE_DIRECTORY ? DT_DIR : DT_REG;
|
|
||||||
#ifndef UEFI_NO_UTF8
|
|
||||||
__dirent.d_reclen = (unsigned short int)wcstombs(__dirent.d_name, info.FileName, FILENAME_MAX - 1);
|
|
||||||
#else
|
|
||||||
__dirent.d_reclen = strlen(info.FileName);
|
|
||||||
strncpy(__dirent.d_name, info.FileName, FILENAME_MAX - 1);
|
|
||||||
#endif
|
|
||||||
return &__dirent;
|
|
||||||
}
|
|
||||||
|
|
||||||
void rewinddir (DIR *__dirp)
|
|
||||||
{
|
|
||||||
if(__dirp)
|
|
||||||
__dirp->SetPosition(__dirp, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
int closedir (DIR *__dirp)
|
|
||||||
{
|
|
||||||
return fclose((FILE*)__dirp);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
#include "uefi.h"
|
||||||
|
|
||||||
|
efi_handle_t IM = NULL;
|
||||||
|
efi_system_table_t* ST = NULL;
|
||||||
|
efi_boot_services_t* BS = NULL;
|
||||||
|
efi_runtime_services_t* RT = NULL;
|
||||||
|
|
||||||
|
efi_status_t bootloader_main(void);
|
||||||
|
|
||||||
|
void __chkstk(void) {}
|
||||||
|
|
||||||
|
efi_status_t EFIAPI efi_main(efi_handle_t image, efi_system_table_t* system_table) {
|
||||||
|
if (image == NULL || system_table == NULL || system_table->BootServices == NULL) {
|
||||||
|
return EFI_UNSUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
IM = image;
|
||||||
|
ST = system_table;
|
||||||
|
BS = system_table->BootServices;
|
||||||
|
RT = system_table->RuntimeServices;
|
||||||
|
|
||||||
|
return bootloader_main();
|
||||||
|
}
|
||||||
@@ -1,63 +0,0 @@
|
|||||||
OUTPUT_FORMAT("elf64-littleaarch64", "elf64-littleaarch64", "elf64-littleaarch64")
|
|
||||||
OUTPUT_ARCH(aarch64)
|
|
||||||
ENTRY(_start)
|
|
||||||
SECTIONS
|
|
||||||
{
|
|
||||||
.text 0x0 : {
|
|
||||||
_text = .;
|
|
||||||
*(.text.head)
|
|
||||||
*(.text)
|
|
||||||
*(.text.*)
|
|
||||||
*(.gnu.linkonce.t.*)
|
|
||||||
*(.srodata)
|
|
||||||
*(.rodata*)
|
|
||||||
. = ALIGN(16);
|
|
||||||
}
|
|
||||||
_etext = .;
|
|
||||||
_text_size = . - _text;
|
|
||||||
.dynamic : { *(.dynamic) }
|
|
||||||
.data : ALIGN(4096)
|
|
||||||
{
|
|
||||||
_data = .;
|
|
||||||
*(.sdata)
|
|
||||||
*(.data)
|
|
||||||
*(.data1)
|
|
||||||
*(.data.*)
|
|
||||||
*(.got.plt)
|
|
||||||
*(.got)
|
|
||||||
|
|
||||||
/* the EFI loader doesn't seem to like a .bss section, so we stick
|
|
||||||
it all into .data: */
|
|
||||||
. = ALIGN(16);
|
|
||||||
_bss = .;
|
|
||||||
*(.sbss)
|
|
||||||
*(.scommon)
|
|
||||||
*(.dynbss)
|
|
||||||
*(.bss)
|
|
||||||
*(COMMON)
|
|
||||||
. = ALIGN(16);
|
|
||||||
_bss_end = .;
|
|
||||||
}
|
|
||||||
|
|
||||||
.rela.dyn : { *(.rela.dyn) }
|
|
||||||
.rela.plt : { *(.rela.plt) }
|
|
||||||
.rela.got : { *(.rela.got) }
|
|
||||||
.rela.data : { *(.rela.data) *(.rela.data*) }
|
|
||||||
. = ALIGN(512);
|
|
||||||
_edata = .;
|
|
||||||
_data_size = . - _data;
|
|
||||||
|
|
||||||
. = ALIGN(4096);
|
|
||||||
.dynsym : { *(.dynsym) }
|
|
||||||
. = ALIGN(4096);
|
|
||||||
.dynstr : { *(.dynstr) }
|
|
||||||
. = ALIGN(4096);
|
|
||||||
.note.gnu.build-id : { *(.note.gnu.build-id) }
|
|
||||||
/DISCARD/ :
|
|
||||||
{
|
|
||||||
*(.rel.reloc)
|
|
||||||
*(.eh_frame)
|
|
||||||
*(.note.GNU-stack)
|
|
||||||
}
|
|
||||||
.comment 0 : { *(.comment) }
|
|
||||||
}
|
|
||||||
@@ -1,64 +0,0 @@
|
|||||||
OUTPUT_FORMAT("elf64-littleriscv", "elf64-littleriscv", "elf64-littleriscv")
|
|
||||||
OUTPUT_ARCH(riscv)
|
|
||||||
ENTRY(_start)
|
|
||||||
SECTIONS
|
|
||||||
{
|
|
||||||
.text 0x0 : {
|
|
||||||
_text = .;
|
|
||||||
*(.text.head)
|
|
||||||
*(.text)
|
|
||||||
*(.text.*)
|
|
||||||
*(.gnu.linkonce.t.*)
|
|
||||||
*(.srodata)
|
|
||||||
*(.rodata*)
|
|
||||||
. = ALIGN(16);
|
|
||||||
}
|
|
||||||
_etext = .;
|
|
||||||
_text_size = . - _text;
|
|
||||||
.dynamic : { *(.dynamic) }
|
|
||||||
.data : ALIGN(4096)
|
|
||||||
{
|
|
||||||
_data = .;
|
|
||||||
*(.sdata)
|
|
||||||
*(.data)
|
|
||||||
*(.data1)
|
|
||||||
*(.data.*)
|
|
||||||
*(.got.plt)
|
|
||||||
*(.got)
|
|
||||||
|
|
||||||
/* the EFI loader doesn't seem to like a .bss section, so we stick
|
|
||||||
it all into .data: */
|
|
||||||
. = ALIGN(16);
|
|
||||||
_bss = .;
|
|
||||||
*(.sbss)
|
|
||||||
*(.scommon)
|
|
||||||
*(.dynbss)
|
|
||||||
*(.bss)
|
|
||||||
*(COMMON)
|
|
||||||
. = ALIGN(16);
|
|
||||||
_bss_end = .;
|
|
||||||
}
|
|
||||||
|
|
||||||
.rela.text : { *(.rela.text) *(.rela.text*) }
|
|
||||||
.rela.dyn : { *(.rela.dyn) }
|
|
||||||
.rela.plt : { *(.rela.plt) }
|
|
||||||
.rela.got : { *(.rela.got) }
|
|
||||||
.rela.data : { *(.rela.data) *(.rela.data*) }
|
|
||||||
. = ALIGN(512);
|
|
||||||
_edata = .;
|
|
||||||
_data_size = . - _data;
|
|
||||||
|
|
||||||
. = ALIGN(4096);
|
|
||||||
.dynsym : { *(.dynsym) }
|
|
||||||
. = ALIGN(4096);
|
|
||||||
.dynstr : { *(.dynstr) }
|
|
||||||
. = ALIGN(4096);
|
|
||||||
.note.gnu.build-id : { *(.note.gnu.build-id) }
|
|
||||||
/DISCARD/ :
|
|
||||||
{
|
|
||||||
*(.rel.reloc)
|
|
||||||
*(.eh_frame)
|
|
||||||
*(.note.GNU-stack)
|
|
||||||
}
|
|
||||||
.comment 0 : { *(.comment) }
|
|
||||||
}
|
|
||||||
@@ -1,76 +0,0 @@
|
|||||||
/* Same as elf_x86_64_fbsd_efi.lds, except for OUTPUT_FORMAT below - KEEP IN SYNC */
|
|
||||||
OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64")
|
|
||||||
OUTPUT_ARCH(i386:x86-64)
|
|
||||||
ENTRY(_start)
|
|
||||||
SECTIONS
|
|
||||||
{
|
|
||||||
. = 0;
|
|
||||||
ImageBase = .;
|
|
||||||
/* .hash and/or .gnu.hash MUST come first! */
|
|
||||||
.hash : { *(.hash) }
|
|
||||||
.gnu.hash : { *(.gnu.hash) }
|
|
||||||
. = ALIGN(4096);
|
|
||||||
.eh_frame :
|
|
||||||
{
|
|
||||||
*(.eh_frame)
|
|
||||||
}
|
|
||||||
. = ALIGN(4096);
|
|
||||||
.text :
|
|
||||||
{
|
|
||||||
_text = .;
|
|
||||||
*(.text)
|
|
||||||
*(.text.*)
|
|
||||||
*(.gnu.linkonce.t.*)
|
|
||||||
. = ALIGN(16);
|
|
||||||
}
|
|
||||||
_etext = .;
|
|
||||||
_text_size = . - _text;
|
|
||||||
. = ALIGN(4096);
|
|
||||||
.reloc :
|
|
||||||
{
|
|
||||||
*(.reloc)
|
|
||||||
}
|
|
||||||
. = ALIGN(4096);
|
|
||||||
.data :
|
|
||||||
{
|
|
||||||
_data = .;
|
|
||||||
*(.rodata*)
|
|
||||||
*(.got.plt)
|
|
||||||
*(.got)
|
|
||||||
*(.data*)
|
|
||||||
*(.sdata)
|
|
||||||
/* the EFI loader doesn't seem to like a .bss section, so we stick
|
|
||||||
it all into .data: */
|
|
||||||
*(.sbss)
|
|
||||||
*(.scommon)
|
|
||||||
*(.dynbss)
|
|
||||||
*(.bss)
|
|
||||||
*(COMMON)
|
|
||||||
*(.rel.local)
|
|
||||||
}
|
|
||||||
.note.gnu.build-id : { *(.note.gnu.build-id) }
|
|
||||||
|
|
||||||
_edata = .;
|
|
||||||
_data_size = . - _etext;
|
|
||||||
. = ALIGN(4096);
|
|
||||||
.dynamic : { *(.dynamic) }
|
|
||||||
. = ALIGN(4096);
|
|
||||||
.rela :
|
|
||||||
{
|
|
||||||
*(.rela.data*)
|
|
||||||
*(.rela.got)
|
|
||||||
*(.rela.stab)
|
|
||||||
}
|
|
||||||
. = ALIGN(4096);
|
|
||||||
.dynsym : { *(.dynsym) }
|
|
||||||
. = ALIGN(4096);
|
|
||||||
.dynstr : { *(.dynstr) }
|
|
||||||
. = ALIGN(4096);
|
|
||||||
.ignored.reloc :
|
|
||||||
{
|
|
||||||
*(.rela.reloc)
|
|
||||||
*(.eh_frame)
|
|
||||||
*(.note.GNU-stack)
|
|
||||||
}
|
|
||||||
.comment 0 : { *(.comment) }
|
|
||||||
}
|
|
||||||
@@ -1,154 +0,0 @@
|
|||||||
/*
|
|
||||||
* qsort.c
|
|
||||||
*
|
|
||||||
* @brief from OpenBSD
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* $OpenBSD: qsort.c,v 1.10 2005/08/08 08:05:37 espie Exp $ */
|
|
||||||
/*-
|
|
||||||
* Copyright (c) 1992, 1993
|
|
||||||
* The Regents of the University of California. All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions
|
|
||||||
* are met:
|
|
||||||
* 1. Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
* 3. Neither the name of the University nor the names of its contributors
|
|
||||||
* may be used to endorse or promote products derived from this software
|
|
||||||
* without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
|
||||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
||||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
|
||||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
||||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
||||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
||||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
||||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
||||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
||||||
* SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
#include <uefi.h>
|
|
||||||
|
|
||||||
static __inline char *med3(char *, char *, char *, __compar_fn_t cmp);
|
|
||||||
static __inline void swapfunc(char *, char *, int, int);
|
|
||||||
/*
|
|
||||||
* Qsort routine from Bentley & McIlroy's "Engineering a Sort Function".
|
|
||||||
*/
|
|
||||||
#define swapcode(TYPE, parmi, parmj, n) { \
|
|
||||||
long i = (n) / sizeof (TYPE); \
|
|
||||||
TYPE *pi = (TYPE *) (parmi); \
|
|
||||||
TYPE *pj = (TYPE *) (parmj); \
|
|
||||||
do { \
|
|
||||||
TYPE t = *pi; \
|
|
||||||
*pi++ = *pj; \
|
|
||||||
*pj++ = t; \
|
|
||||||
} while (--i > 0); \
|
|
||||||
}
|
|
||||||
#define SWAPINIT(a, es) swaptype = ((char *)a - (char *)0) % sizeof(long) || \
|
|
||||||
es % sizeof(long) ? 2 : es == sizeof(long)? 0 : 1;
|
|
||||||
static __inline void
|
|
||||||
swapfunc(char *a, char *b, int n, int swaptype)
|
|
||||||
{
|
|
||||||
if (swaptype <= 1)
|
|
||||||
swapcode(long, a, b, n)
|
|
||||||
else
|
|
||||||
swapcode(char, a, b, n)
|
|
||||||
}
|
|
||||||
#define swap(a, b) \
|
|
||||||
if (swaptype == 0) { \
|
|
||||||
long t = *(long *)(a); \
|
|
||||||
*(long *)(a) = *(long *)(b); \
|
|
||||||
*(long *)(b) = t; \
|
|
||||||
} else \
|
|
||||||
swapfunc(a, b, es, swaptype)
|
|
||||||
#define vecswap(a, b, n) if ((n) > 0) swapfunc(a, b, n, swaptype)
|
|
||||||
static __inline char *
|
|
||||||
med3(char *a, char *b, char *c, __compar_fn_t cmp)
|
|
||||||
{
|
|
||||||
return cmp(a, b) < 0 ?
|
|
||||||
(cmp(b, c) < 0 ? b : (cmp(a, c) < 0 ? c : a ))
|
|
||||||
:(cmp(b, c) > 0 ? b : (cmp(a, c) < 0 ? a : c ));
|
|
||||||
}
|
|
||||||
|
|
||||||
void qsort(void *aa, size_t n, size_t es, __compar_fn_t cmp)
|
|
||||||
{
|
|
||||||
char *pa, *pb, *pc, *pd, *pl, *pm, *pn;
|
|
||||||
int d, r, swaptype, swap_cnt;
|
|
||||||
char *a = aa;
|
|
||||||
loop: SWAPINIT(a, es);
|
|
||||||
swap_cnt = 0;
|
|
||||||
if (n < 7) {
|
|
||||||
for (pm = (char *)a + es; pm < (char *) a + n * es; pm += es)
|
|
||||||
for (pl = pm; pl > (char *) a && cmp(pl - es, pl) > 0;
|
|
||||||
pl -= es)
|
|
||||||
swap(pl, pl - es);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
pm = (char *)a + (n / 2) * es;
|
|
||||||
if (n > 7) {
|
|
||||||
pl = (char *)a;
|
|
||||||
pn = (char *)a + (n - 1) * es;
|
|
||||||
if (n > 40) {
|
|
||||||
d = (n / 8) * es;
|
|
||||||
pl = med3(pl, pl + d, pl + 2 * d, cmp);
|
|
||||||
pm = med3(pm - d, pm, pm + d, cmp);
|
|
||||||
pn = med3(pn - 2 * d, pn - d, pn, cmp);
|
|
||||||
}
|
|
||||||
pm = med3(pl, pm, pn, cmp);
|
|
||||||
}
|
|
||||||
swap(a, pm);
|
|
||||||
pa = pb = (char *)a + es;
|
|
||||||
|
|
||||||
pc = pd = (char *)a + (n - 1) * es;
|
|
||||||
for (;;) {
|
|
||||||
while (pb <= pc && (r = cmp(pb, a)) <= 0) {
|
|
||||||
if (r == 0) {
|
|
||||||
swap_cnt = 1;
|
|
||||||
swap(pa, pb);
|
|
||||||
pa += es;
|
|
||||||
}
|
|
||||||
pb += es;
|
|
||||||
}
|
|
||||||
while (pb <= pc && (r = cmp(pc, a)) >= 0) {
|
|
||||||
if (r == 0) {
|
|
||||||
swap_cnt = 1;
|
|
||||||
swap(pc, pd);
|
|
||||||
pd -= es;
|
|
||||||
}
|
|
||||||
pc -= es;
|
|
||||||
}
|
|
||||||
if (pb > pc)
|
|
||||||
break;
|
|
||||||
swap(pb, pc);
|
|
||||||
swap_cnt = 1;
|
|
||||||
pb += es;
|
|
||||||
pc -= es;
|
|
||||||
}
|
|
||||||
if (swap_cnt == 0) { /* Switch to insertion sort */
|
|
||||||
for (pm = (char *) a + es; pm < (char *) a + n * es; pm += es)
|
|
||||||
for (pl = pm; pl > (char *) a && cmp(pl - es, pl) > 0;
|
|
||||||
pl -= es)
|
|
||||||
swap(pl, pl - es);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
pn = (char *)a + n * es;
|
|
||||||
r = min(pa - (char *)a, pb - pa);
|
|
||||||
vecswap(a, pb - r, r);
|
|
||||||
r = min(pd - pc, pn - pd - (int)es);
|
|
||||||
vecswap(pb, pn - r, r);
|
|
||||||
if ((r = pb - pa) > (int)es)
|
|
||||||
qsort(a, r / es, es, cmp);
|
|
||||||
if ((r = pd - pc) > (int)es) {
|
|
||||||
/* Iterate rather than recurse to save stack space */
|
|
||||||
a = pn - r;
|
|
||||||
n = r / es;
|
|
||||||
goto loop;
|
|
||||||
}
|
|
||||||
/* qsort(pn - r, r / es, es, cmp);*/
|
|
||||||
}
|
|
||||||
@@ -1,68 +0,0 @@
|
|||||||
/*
|
|
||||||
* stat.c
|
|
||||||
*
|
|
||||||
* Copyright (C) 2021 bzt (bztsrc@gitlab)
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person
|
|
||||||
* obtaining a copy of this software and associated documentation
|
|
||||||
* files (the "Software"), to deal in the Software without
|
|
||||||
* restriction, including without limitation the rights to use, copy,
|
|
||||||
* modify, merge, publish, distribute, sublicense, and/or sell copies
|
|
||||||
* of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be
|
|
||||||
* included in all copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
||||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
||||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
||||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|
||||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
||||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
||||||
* DEALINGS IN THE SOFTWARE.
|
|
||||||
*
|
|
||||||
* This file is part of the POSIX-UEFI package.
|
|
||||||
* @brief Implementing functions which are defined in sys/stat.h
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <uefi.h>
|
|
||||||
|
|
||||||
/* fstat is in stdio.c because we can't access static variables otherwise... */
|
|
||||||
|
|
||||||
int stat (const char_t *__file, struct stat *__buf)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
FILE *f;
|
|
||||||
|
|
||||||
if(!__file || !*__file || !__buf) {
|
|
||||||
errno = EINVAL;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
f = fopen(__file, CL("*"));
|
|
||||||
if(!f) {
|
|
||||||
memset(__buf, 0, sizeof(struct stat));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
ret = fstat(f, __buf);
|
|
||||||
fclose(f);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
extern int mkdir (const char_t *__path, mode_t __mode)
|
|
||||||
{
|
|
||||||
FILE *f;
|
|
||||||
(void)__mode;
|
|
||||||
if(!__path || !*__path) {
|
|
||||||
errno = EINVAL;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
f = fopen(__path, CL("wd"));
|
|
||||||
if(!f) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
fclose(f);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@@ -1,817 +0,0 @@
|
|||||||
/*
|
|
||||||
* stdio.c
|
|
||||||
*
|
|
||||||
* Copyright (C) 2021 bzt (bztsrc@gitlab)
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person
|
|
||||||
* obtaining a copy of this software and associated documentation
|
|
||||||
* files (the "Software"), to deal in the Software without
|
|
||||||
* restriction, including without limitation the rights to use, copy,
|
|
||||||
* modify, merge, publish, distribute, sublicense, and/or sell copies
|
|
||||||
* of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be
|
|
||||||
* included in all copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
||||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
||||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
||||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|
||||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
||||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
||||||
* DEALINGS IN THE SOFTWARE.
|
|
||||||
*
|
|
||||||
* This file is part of the POSIX-UEFI package.
|
|
||||||
* @brief Implementing functions which are defined in stdio.h
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <uefi.h>
|
|
||||||
|
|
||||||
static efi_file_handle_t *__root_dir = NULL;
|
|
||||||
static efi_serial_io_protocol_t *__ser = NULL;
|
|
||||||
static block_file_t *__blk_devs = NULL;
|
|
||||||
static uintn_t __blk_ndevs = 0;
|
|
||||||
extern time_t __mktime_efi(efi_time_t *t);
|
|
||||||
void __stdio_cleanup(void);
|
|
||||||
void __stdio_seterrno(efi_status_t status);
|
|
||||||
int __remove (const char_t *__filename, int isdir);
|
|
||||||
|
|
||||||
void __stdio_cleanup(void)
|
|
||||||
{
|
|
||||||
#ifndef UEFI_NO_UTF8
|
|
||||||
if(__argvutf8)
|
|
||||||
BS->FreePool(__argvutf8);
|
|
||||||
#endif
|
|
||||||
if(__blk_devs) {
|
|
||||||
free(__blk_devs);
|
|
||||||
__blk_devs = NULL;
|
|
||||||
__blk_ndevs = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void __stdio_seterrno(efi_status_t status)
|
|
||||||
{
|
|
||||||
switch((int)(status & 0xffff)) {
|
|
||||||
case EFI_WRITE_PROTECTED & 0xffff: errno = EROFS; break;
|
|
||||||
case EFI_ACCESS_DENIED & 0xffff: errno = EACCES; break;
|
|
||||||
case EFI_VOLUME_FULL & 0xffff: errno = ENOSPC; break;
|
|
||||||
case EFI_NOT_FOUND & 0xffff: errno = ENOENT; break;
|
|
||||||
case EFI_INVALID_PARAMETER & 0xffff: errno = EINVAL; break;
|
|
||||||
default: errno = EIO; break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int fstat (FILE *__f, struct stat *__buf)
|
|
||||||
{
|
|
||||||
efi_guid_t infGuid = EFI_FILE_INFO_GUID;
|
|
||||||
efi_file_info_t info;
|
|
||||||
uintn_t fsiz = (uintn_t)sizeof(efi_file_info_t);
|
|
||||||
efi_status_t status;
|
|
||||||
uintn_t i;
|
|
||||||
|
|
||||||
if(!__f || !__buf) {
|
|
||||||
errno = EINVAL;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
memset(__buf, 0, sizeof(struct stat));
|
|
||||||
if(__f == stdin) {
|
|
||||||
__buf->st_mode = S_IREAD | S_IFIFO;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if(__f == stdout || __f == stderr) {
|
|
||||||
__buf->st_mode = S_IWRITE | S_IFIFO;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if(__ser && __f == (FILE*)__ser) {
|
|
||||||
__buf->st_mode = S_IREAD | S_IWRITE | S_IFCHR;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
for(i = 0; i < __blk_ndevs; i++)
|
|
||||||
if(__f == (FILE*)__blk_devs[i].bio) {
|
|
||||||
__buf->st_mode = S_IREAD | S_IWRITE | S_IFBLK;
|
|
||||||
__buf->st_size = (off_t)__blk_devs[i].bio->Media->BlockSize * ((off_t)__blk_devs[i].bio->Media->LastBlock + 1);
|
|
||||||
__buf->st_blocks = __blk_devs[i].bio->Media->LastBlock + 1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
status = __f->GetInfo(__f, &infGuid, &fsiz, &info);
|
|
||||||
if(EFI_ERROR(status)) {
|
|
||||||
__stdio_seterrno(status);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
__buf->st_mode = S_IREAD |
|
|
||||||
(info.Attribute & EFI_FILE_READ_ONLY ? 0 : S_IWRITE) |
|
|
||||||
(info.Attribute & EFI_FILE_DIRECTORY ? S_IFDIR : S_IFREG);
|
|
||||||
__buf->st_size = (off_t)info.FileSize;
|
|
||||||
__buf->st_blocks = (blkcnt_t)info.PhysicalSize;
|
|
||||||
__buf->st_atime = __mktime_efi(&info.LastAccessTime);
|
|
||||||
__buf->st_mtime = __mktime_efi(&info.ModificationTime);
|
|
||||||
__buf->st_ctime = __mktime_efi(&info.CreateTime);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int fclose (FILE *__stream)
|
|
||||||
{
|
|
||||||
efi_status_t status = EFI_SUCCESS;
|
|
||||||
uintn_t i;
|
|
||||||
if(!__stream) {
|
|
||||||
errno = EINVAL;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if(__stream == stdin || __stream == stdout || __stream == stderr || (__ser && __stream == (FILE*)__ser)) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
for(i = 0; i < __blk_ndevs; i++)
|
|
||||||
if(__stream == (FILE*)__blk_devs[i].bio)
|
|
||||||
return 1;
|
|
||||||
status = __stream->Close(__stream);
|
|
||||||
free(__stream);
|
|
||||||
return !EFI_ERROR(status);
|
|
||||||
}
|
|
||||||
|
|
||||||
int fflush (FILE *__stream)
|
|
||||||
{
|
|
||||||
efi_status_t status = EFI_SUCCESS;
|
|
||||||
uintn_t i;
|
|
||||||
if(!__stream) {
|
|
||||||
errno = EINVAL;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if(__stream == stdin || __stream == stdout || __stream == stderr || (__ser && __stream == (FILE*)__ser)) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
for(i = 0; i < __blk_ndevs; i++)
|
|
||||||
if(__stream == (FILE*)__blk_devs[i].bio) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
status = __stream->Flush(__stream);
|
|
||||||
return !EFI_ERROR(status);
|
|
||||||
}
|
|
||||||
|
|
||||||
int __remove (const char_t *__filename, int isdir)
|
|
||||||
{
|
|
||||||
efi_status_t status;
|
|
||||||
efi_guid_t infGuid = EFI_FILE_INFO_GUID;
|
|
||||||
efi_file_info_t info;
|
|
||||||
uintn_t fsiz = (uintn_t)sizeof(efi_file_info_t), i;
|
|
||||||
/* little hack to support read and write mode for Delete() and stat() without create mode or checks */
|
|
||||||
FILE *f = fopen(__filename, CL("*"));
|
|
||||||
if(errno)
|
|
||||||
return 1;
|
|
||||||
if(!f || f == stdin || f == stdout || f == stderr || (__ser && f == (FILE*)__ser)) {
|
|
||||||
errno = EBADF;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
for(i = 0; i < __blk_ndevs; i++)
|
|
||||||
if(f == (FILE*)__blk_devs[i].bio) {
|
|
||||||
errno = EBADF;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if(isdir != -1) {
|
|
||||||
status = f->GetInfo(f, &infGuid, &fsiz, &info);
|
|
||||||
if(EFI_ERROR(status)) goto err;
|
|
||||||
if(isdir == 0 && (info.Attribute & EFI_FILE_DIRECTORY)) {
|
|
||||||
fclose(f); errno = EISDIR;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if(isdir == 1 && !(info.Attribute & EFI_FILE_DIRECTORY)) {
|
|
||||||
fclose(f); errno = ENOTDIR;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
status = f->Delete(f);
|
|
||||||
if(EFI_ERROR(status)) {
|
|
||||||
err: __stdio_seterrno(status);
|
|
||||||
fclose(f);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
/* no need for fclose(f); */
|
|
||||||
free(f);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int remove (const char_t *__filename)
|
|
||||||
{
|
|
||||||
return __remove(__filename, -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
FILE *fopen (const char_t *__filename, const char_t *__modes)
|
|
||||||
{
|
|
||||||
FILE *ret;
|
|
||||||
efi_status_t status;
|
|
||||||
efi_guid_t sfsGuid = EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID;
|
|
||||||
efi_simple_file_system_protocol_t *sfs = NULL;
|
|
||||||
efi_guid_t infGuid = EFI_FILE_INFO_GUID;
|
|
||||||
efi_file_info_t info;
|
|
||||||
uintn_t fsiz = (uintn_t)sizeof(efi_file_info_t), par, i;
|
|
||||||
#ifndef UEFI_NO_UTF8
|
|
||||||
wchar_t wcname[BUFSIZ];
|
|
||||||
#endif
|
|
||||||
errno = 0;
|
|
||||||
if(!__filename || !*__filename || !__modes || (__modes[0] != CL('r') && __modes[0] != CL('w') && __modes[0] != CL('a') &&
|
|
||||||
__modes[0] != CL('*')) || (__modes[1] != 0 && __modes[1] != CL('d') && __modes[1] != CL('+'))) {
|
|
||||||
errno = EINVAL;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
/* fake some device names. UEFI has no concept of device files */
|
|
||||||
if(!strcmp(__filename, CL("/dev/stdin"))) {
|
|
||||||
if(__modes[0] == CL('w') || __modes[0] == CL('a')) { errno = EPERM; return NULL; }
|
|
||||||
return stdin;
|
|
||||||
}
|
|
||||||
if(!strcmp(__filename, CL("/dev/stdout"))) {
|
|
||||||
if(__modes[0] == CL('r')) { errno = EPERM; return NULL; }
|
|
||||||
return stdout;
|
|
||||||
}
|
|
||||||
if(!strcmp(__filename, CL("/dev/stderr"))) {
|
|
||||||
if(__modes[0] == CL('r')) { errno = EPERM; return NULL; }
|
|
||||||
return stderr;
|
|
||||||
}
|
|
||||||
if(!memcmp(__filename, CL("/dev/serial"), 11 * sizeof(char_t))) {
|
|
||||||
par = (uintn_t)atol(__filename + 11);
|
|
||||||
if(!__ser) {
|
|
||||||
efi_guid_t serGuid = EFI_SERIAL_IO_PROTOCOL_GUID;
|
|
||||||
status = BS->LocateProtocol(&serGuid, NULL, (void**)&__ser);
|
|
||||||
if(EFI_ERROR(status) || !__ser) { errno = ENOENT; return NULL; }
|
|
||||||
}
|
|
||||||
__ser->SetAttributes(__ser, par > 9600 ? par : 115200, 0, 1000, NoParity, 8, OneStopBit);
|
|
||||||
return (FILE*)__ser;
|
|
||||||
}
|
|
||||||
if(!memcmp(__filename, CL("/dev/disk"), 9 * sizeof(char_t))) {
|
|
||||||
par = (uintn_t)atol(__filename + 9);
|
|
||||||
if(!__blk_ndevs) {
|
|
||||||
efi_guid_t bioGuid = EFI_BLOCK_IO_PROTOCOL_GUID;
|
|
||||||
efi_handle_t handles[128];
|
|
||||||
uintn_t handle_size = sizeof(handles);
|
|
||||||
status = BS->LocateHandle(ByProtocol, &bioGuid, NULL, &handle_size, (efi_handle_t*)&handles);
|
|
||||||
if(!EFI_ERROR(status)) {
|
|
||||||
handle_size /= (uintn_t)sizeof(efi_handle_t);
|
|
||||||
/* workaround a bug in TianoCore, it reports zero size even though the data is in the buffer */
|
|
||||||
if(handle_size < 1)
|
|
||||||
handle_size = (uintn_t)sizeof(handles) / sizeof(efi_handle_t);
|
|
||||||
__blk_devs = (block_file_t*)malloc(handle_size * sizeof(block_file_t));
|
|
||||||
if(__blk_devs) {
|
|
||||||
memset(__blk_devs, 0, handle_size * sizeof(block_file_t));
|
|
||||||
for(i = __blk_ndevs = 0; i < handle_size; i++)
|
|
||||||
if(handles[i] && !EFI_ERROR(BS->HandleProtocol(handles[i], &bioGuid, (void **) &__blk_devs[__blk_ndevs].bio)) &&
|
|
||||||
__blk_devs[__blk_ndevs].bio && __blk_devs[__blk_ndevs].bio->Media &&
|
|
||||||
__blk_devs[__blk_ndevs].bio->Media->BlockSize > 0)
|
|
||||||
__blk_ndevs++;
|
|
||||||
} else
|
|
||||||
__blk_ndevs = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(__blk_ndevs && par < __blk_ndevs)
|
|
||||||
return (FILE*)__blk_devs[par].bio;
|
|
||||||
errno = ENOENT;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
if(!__root_dir && LIP) {
|
|
||||||
status = BS->HandleProtocol(LIP->DeviceHandle, &sfsGuid, (void **)&sfs);
|
|
||||||
if(!EFI_ERROR(status))
|
|
||||||
status = sfs->OpenVolume(sfs, &__root_dir);
|
|
||||||
}
|
|
||||||
if(!__root_dir) {
|
|
||||||
errno = ENODEV;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
ret = (FILE*)malloc(sizeof(FILE));
|
|
||||||
if(!ret) return NULL;
|
|
||||||
/* normally write means read,write,create. But for remove (internal '*' mode), we need read,write without create
|
|
||||||
* also mode 'w' in POSIX means write-only (without read), but that's not working on certain firmware, we must
|
|
||||||
* pass read too. This poses a problem of truncating a write-only file, see issue #26, we have to do that manually */
|
|
||||||
#ifndef UEFI_NO_UTF8
|
|
||||||
mbstowcs((wchar_t*)&wcname, __filename, BUFSIZ - 1);
|
|
||||||
status = __root_dir->Open(__root_dir, &ret, (wchar_t*)&wcname,
|
|
||||||
#else
|
|
||||||
status = __root_dir->Open(__root_dir, &ret, (wchar_t*)__filename,
|
|
||||||
#endif
|
|
||||||
__modes[0] == CL('w') || __modes[0] == CL('a') ? (EFI_FILE_MODE_WRITE | EFI_FILE_MODE_READ | EFI_FILE_MODE_CREATE) :
|
|
||||||
EFI_FILE_MODE_READ | (__modes[0] == CL('*') || __modes[1] == CL('+') ? EFI_FILE_MODE_WRITE : 0),
|
|
||||||
__modes[1] == CL('d') ? EFI_FILE_DIRECTORY : 0);
|
|
||||||
if(EFI_ERROR(status)) {
|
|
||||||
err: __stdio_seterrno(status);
|
|
||||||
free(ret); return NULL;
|
|
||||||
}
|
|
||||||
if(__modes[0] == CL('*')) return ret;
|
|
||||||
status = ret->GetInfo(ret, &infGuid, &fsiz, &info);
|
|
||||||
if(EFI_ERROR(status)) goto err;
|
|
||||||
if(__modes[1] == CL('d') && !(info.Attribute & EFI_FILE_DIRECTORY)) {
|
|
||||||
ret->Close(ret); free(ret); errno = ENOTDIR; return NULL;
|
|
||||||
}
|
|
||||||
if(__modes[1] != CL('d') && (info.Attribute & EFI_FILE_DIRECTORY)) {
|
|
||||||
ret->Close(ret); free(ret); errno = EISDIR; return NULL;
|
|
||||||
}
|
|
||||||
if(__modes[0] == CL('a')) fseek(ret, 0, SEEK_END);
|
|
||||||
if(__modes[0] == CL('w')) {
|
|
||||||
/* manually truncate file size
|
|
||||||
* See https://github.com/tianocore/edk2/blob/master/MdePkg/Library/UefiFileHandleLib/UefiFileHandleLib.c
|
|
||||||
* function FileHandleSetSize */
|
|
||||||
info.FileSize = 0;
|
|
||||||
ret->SetInfo(ret, &infGuid, fsiz, &info);
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t fread (void *__ptr, size_t __size, size_t __n, FILE *__stream)
|
|
||||||
{
|
|
||||||
uintn_t bs = __size * __n, i, n;
|
|
||||||
efi_status_t status;
|
|
||||||
if(!__ptr || __size < 1 || __n < 1 || !__stream) {
|
|
||||||
errno = EINVAL;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if(__stream == stdin || __stream == stdout || __stream == stderr) {
|
|
||||||
errno = ESPIPE;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if(__ser && __stream == (FILE*)__ser) {
|
|
||||||
status = __ser->Read(__ser, &bs, __ptr);
|
|
||||||
} else {
|
|
||||||
for(i = 0; i < __blk_ndevs; i++)
|
|
||||||
if(__stream == (FILE*)__blk_devs[i].bio) {
|
|
||||||
n = __blk_devs[i].offset / __blk_devs[i].bio->Media->BlockSize;
|
|
||||||
bs = (bs / __blk_devs[i].bio->Media->BlockSize) * __blk_devs[i].bio->Media->BlockSize;
|
|
||||||
status = __blk_devs[i].bio->ReadBlocks(__blk_devs[i].bio, __blk_devs[i].bio->Media->MediaId, n, bs, __ptr);
|
|
||||||
if(EFI_ERROR(status)) {
|
|
||||||
__stdio_seterrno(status);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
__blk_devs[i].offset += bs;
|
|
||||||
return bs / __size;
|
|
||||||
}
|
|
||||||
status = __stream->Read(__stream, &bs, __ptr);
|
|
||||||
}
|
|
||||||
if(EFI_ERROR(status)) {
|
|
||||||
__stdio_seterrno(status);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return bs / __size;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t fwrite (const void *__ptr, size_t __size, size_t __n, FILE *__stream)
|
|
||||||
{
|
|
||||||
uintn_t bs = __size * __n, n, i;
|
|
||||||
efi_status_t status;
|
|
||||||
if(!__ptr || __size < 1 || __n < 1 || !__stream) {
|
|
||||||
errno = EINVAL;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if(__stream == stdin || __stream == stdout || __stream == stderr) {
|
|
||||||
errno = ESPIPE;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if(__ser && __stream == (FILE*)__ser) {
|
|
||||||
status = __ser->Write(__ser, &bs, (void*)__ptr);
|
|
||||||
} else {
|
|
||||||
for(i = 0; i < __blk_ndevs; i++)
|
|
||||||
if(__stream == (FILE*)__blk_devs[i].bio) {
|
|
||||||
n = __blk_devs[i].offset / __blk_devs[i].bio->Media->BlockSize;
|
|
||||||
bs = (bs / __blk_devs[i].bio->Media->BlockSize) * __blk_devs[i].bio->Media->BlockSize;
|
|
||||||
status = __blk_devs[i].bio->WriteBlocks(__blk_devs[i].bio, __blk_devs[i].bio->Media->MediaId, n, bs, (void*)__ptr);
|
|
||||||
if(EFI_ERROR(status)) {
|
|
||||||
__stdio_seterrno(status);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
__blk_devs[i].offset += bs;
|
|
||||||
return bs / __size;
|
|
||||||
}
|
|
||||||
status = __stream->Write(__stream, &bs, (void *)__ptr);
|
|
||||||
}
|
|
||||||
if(EFI_ERROR(status)) {
|
|
||||||
__stdio_seterrno(status);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return bs / __size;
|
|
||||||
}
|
|
||||||
|
|
||||||
int fseek (FILE *__stream, long int __off, int __whence)
|
|
||||||
{
|
|
||||||
off_t off = 0;
|
|
||||||
efi_status_t status;
|
|
||||||
efi_guid_t infoGuid = EFI_FILE_INFO_GUID;
|
|
||||||
efi_file_info_t info;
|
|
||||||
uintn_t fsiz = sizeof(efi_file_info_t), i;
|
|
||||||
if(!__stream || (__whence != SEEK_SET && __whence != SEEK_CUR && __whence != SEEK_END)) {
|
|
||||||
errno = EINVAL;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if(__stream == stdin || __stream == stdout || __stream == stderr) {
|
|
||||||
errno = ESPIPE;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if(__ser && __stream == (FILE*)__ser) {
|
|
||||||
errno = EBADF;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
for(i = 0; i < __blk_ndevs; i++)
|
|
||||||
if(__stream == (FILE*)__blk_devs[i].bio) {
|
|
||||||
off = (uint64_t)__blk_devs[i].bio->Media->BlockSize * (uint64_t)__blk_devs[i].bio->Media->LastBlock;
|
|
||||||
switch(__whence) {
|
|
||||||
case SEEK_END:
|
|
||||||
__blk_devs[i].offset = off + __off;
|
|
||||||
break;
|
|
||||||
case SEEK_CUR:
|
|
||||||
__blk_devs[i].offset += __off;
|
|
||||||
break;
|
|
||||||
case SEEK_SET:
|
|
||||||
__blk_devs[i].offset = __off;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if(__blk_devs[i].offset < 0) __blk_devs[i].offset = 0;
|
|
||||||
if(__blk_devs[i].offset > off) __blk_devs[i].offset = off;
|
|
||||||
__blk_devs[i].offset = (__blk_devs[i].offset / __blk_devs[i].bio->Media->BlockSize) *
|
|
||||||
__blk_devs[i].bio->Media->BlockSize;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
switch(__whence) {
|
|
||||||
case SEEK_END:
|
|
||||||
status = __stream->GetInfo(__stream, &infoGuid, &fsiz, &info);
|
|
||||||
if(!EFI_ERROR(status)) {
|
|
||||||
off = info.FileSize + __off;
|
|
||||||
status = __stream->SetPosition(__stream, off);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case SEEK_CUR:
|
|
||||||
status = __stream->GetPosition(__stream, &off);
|
|
||||||
if(!EFI_ERROR(status)) {
|
|
||||||
off += __off;
|
|
||||||
status = __stream->SetPosition(__stream, off);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
status = __stream->SetPosition(__stream, __off);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return EFI_ERROR(status) ? -1 : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
long int ftell (FILE *__stream)
|
|
||||||
{
|
|
||||||
uint64_t off = 0;
|
|
||||||
uintn_t i;
|
|
||||||
efi_status_t status;
|
|
||||||
if(!__stream) {
|
|
||||||
errno = EINVAL;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if(__stream == stdin || __stream == stdout || __stream == stderr) {
|
|
||||||
errno = ESPIPE;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if(__ser && __stream == (FILE*)__ser) {
|
|
||||||
errno = EBADF;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
for(i = 0; i < __blk_ndevs; i++)
|
|
||||||
if(__stream == (FILE*)__blk_devs[i].bio) {
|
|
||||||
return (long int)__blk_devs[i].offset;
|
|
||||||
}
|
|
||||||
status = __stream->GetPosition(__stream, &off);
|
|
||||||
return EFI_ERROR(status) ? -1 : (long int)off;
|
|
||||||
}
|
|
||||||
|
|
||||||
int feof (FILE *__stream)
|
|
||||||
{
|
|
||||||
uint64_t off = 0;
|
|
||||||
efi_guid_t infGuid = EFI_FILE_INFO_GUID;
|
|
||||||
efi_file_info_t info;
|
|
||||||
uintn_t fsiz = (uintn_t)sizeof(efi_file_info_t), i;
|
|
||||||
efi_status_t status;
|
|
||||||
if(!__stream) {
|
|
||||||
errno = EINVAL;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if(__stream == stdin || __stream == stdout || __stream == stderr) {
|
|
||||||
errno = ESPIPE;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if(__ser && __stream == (FILE*)__ser) {
|
|
||||||
errno = EBADF;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
for(i = 0; i < __blk_ndevs; i++)
|
|
||||||
if(__stream == (FILE*)__blk_devs[i].bio) {
|
|
||||||
errno = EBADF;
|
|
||||||
return __blk_devs[i].offset == (off_t)__blk_devs[i].bio->Media->BlockSize * (off_t)__blk_devs[i].bio->Media->LastBlock;
|
|
||||||
}
|
|
||||||
status = __stream->GetPosition(__stream, &off);
|
|
||||||
if(EFI_ERROR(status)) {
|
|
||||||
err: __stdio_seterrno(status);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
status = __stream->GetInfo(__stream, &infGuid, &fsiz, &info);
|
|
||||||
if(EFI_ERROR(status)) goto err;
|
|
||||||
__stream->SetPosition(__stream, off);
|
|
||||||
return info.FileSize == off;
|
|
||||||
}
|
|
||||||
|
|
||||||
int vsnprintf(char_t *dst, size_t maxlen, const char_t *fmt, __builtin_va_list args)
|
|
||||||
{
|
|
||||||
#define needsescape(a) (a==CL('\"') || a==CL('\\') || a==CL('\a') || a==CL('\b') || a==CL('\033') || a==CL('\f') || \
|
|
||||||
a==CL('\r') || a==CL('\n') || a==CL('\t') || a==CL('\v'))
|
|
||||||
efi_physical_address_t m;
|
|
||||||
uint8_t *mem;
|
|
||||||
uint64_t arg;
|
|
||||||
int64_t iarg;
|
|
||||||
int len, sign, i, j;
|
|
||||||
char_t *p, *orig=dst, *end = dst + maxlen - 1, tmpstr[24], pad, n;
|
|
||||||
#ifdef UEFI_NO_UTF8
|
|
||||||
char *c;
|
|
||||||
#endif
|
|
||||||
if(dst==NULL || fmt==NULL)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
arg = 0;
|
|
||||||
while(*fmt && dst < end) {
|
|
||||||
if(*fmt==CL('%')) {
|
|
||||||
fmt++;
|
|
||||||
if(*fmt==CL('%')) goto put;
|
|
||||||
len=0; pad=CL(' ');
|
|
||||||
if(*fmt==CL('0')) pad=CL('0');
|
|
||||||
while(*fmt>=CL('0') && *fmt<=CL('9')) {
|
|
||||||
len *= 10;
|
|
||||||
len += *fmt-CL('0');
|
|
||||||
fmt++;
|
|
||||||
}
|
|
||||||
if(*fmt==CL('l')) fmt++;
|
|
||||||
if(*fmt==CL('c')) {
|
|
||||||
arg = __builtin_va_arg(args, uint32_t);
|
|
||||||
#ifndef UEFI_NO_UTF8
|
|
||||||
if(arg<0x80) { *dst++ = arg; } else
|
|
||||||
if(arg<0x800) { *dst++ = ((arg>>6)&0x1F)|0xC0; *dst++ = (arg&0x3F)|0x80; } else
|
|
||||||
{ *dst++ = ((arg>>12)&0x0F)|0xE0; *dst++ = ((arg>>6)&0x3F)|0x80; *dst++ = (arg&0x3F)|0x80; }
|
|
||||||
#else
|
|
||||||
*dst++ = (wchar_t)(arg & 0xffff);
|
|
||||||
#endif
|
|
||||||
fmt++;
|
|
||||||
continue;
|
|
||||||
} else
|
|
||||||
if(*fmt==CL('d') || *fmt==CL('i') || *fmt==CL('u')) {
|
|
||||||
iarg = __builtin_va_arg(args, int64_t);
|
|
||||||
sign=0;
|
|
||||||
if(*fmt!=CL('u') && iarg<0) {
|
|
||||||
arg=-iarg;
|
|
||||||
sign++;
|
|
||||||
} else arg=(uint64_t)iarg;
|
|
||||||
i=23;
|
|
||||||
tmpstr[i]=0;
|
|
||||||
do {
|
|
||||||
tmpstr[--i]=CL('0')+(arg%10);
|
|
||||||
arg/=10;
|
|
||||||
} while(arg!=0 && i>0);
|
|
||||||
if(sign) {
|
|
||||||
tmpstr[--i]=CL('-');
|
|
||||||
}
|
|
||||||
if(len>0 && len<23) {
|
|
||||||
while(i && i>23-len) {
|
|
||||||
tmpstr[--i]=pad;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
p=&tmpstr[i];
|
|
||||||
goto copystring;
|
|
||||||
} else
|
|
||||||
if(*fmt==CL('p')) {
|
|
||||||
arg = __builtin_va_arg(args, uint64_t);
|
|
||||||
len = 16; pad = CL('0'); goto hex;
|
|
||||||
} else
|
|
||||||
if(*fmt==CL('x') || *fmt==CL('X')) {
|
|
||||||
arg = __builtin_va_arg(args, uint64_t);
|
|
||||||
hex: i=16;
|
|
||||||
tmpstr[i]=0;
|
|
||||||
do {
|
|
||||||
n=arg & 0xf;
|
|
||||||
/* 0-9 => '0'-'9', 10-15 => 'A'-'F' */
|
|
||||||
tmpstr[--i]=n+(n>9?(*fmt==CL('X')?0x37:0x57):0x30);
|
|
||||||
arg>>=4;
|
|
||||||
} while(arg!=0 && i>0);
|
|
||||||
/* padding, only leading zeros */
|
|
||||||
if(len>0 && len<=16) {
|
|
||||||
while(i>16-len) {
|
|
||||||
tmpstr[--i]=CL('0');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
p=&tmpstr[i];
|
|
||||||
goto copystring;
|
|
||||||
} else
|
|
||||||
if(*fmt==CL('s') || *fmt==CL('q')) {
|
|
||||||
p = __builtin_va_arg(args, char_t*);
|
|
||||||
copystring: if(p==NULL) {
|
|
||||||
p=CL("(null)");
|
|
||||||
}
|
|
||||||
while(*p && dst + 2 < end) {
|
|
||||||
if(*fmt==CL('q') && needsescape(*p)) {
|
|
||||||
*dst++ = CL('\\');
|
|
||||||
switch(*p) {
|
|
||||||
case CL('\a'): *dst++ = CL('a'); break;
|
|
||||||
case CL('\b'): *dst++ = CL('b'); break;
|
|
||||||
case 27: *dst++ = CL('e'); break; /* gcc 10.2 doesn't like CL('\e') in ansi mode */
|
|
||||||
case CL('\f'): *dst++ = CL('f'); break;
|
|
||||||
case CL('\n'): *dst++ = CL('n'); break;
|
|
||||||
case CL('\r'): *dst++ = CL('r'); break;
|
|
||||||
case CL('\t'): *dst++ = CL('t'); break;
|
|
||||||
case CL('\v'): *dst++ = CL('v'); break;
|
|
||||||
default: *dst++ = *p++; break;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if(*p == CL('\n') && (orig == dst || *(dst - 1) != CL('\r'))) *dst++ = CL('\r');
|
|
||||||
*dst++ = *p++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
#ifdef UEFI_NO_UTF8
|
|
||||||
if(*fmt==L'S' || *fmt==L'Q') {
|
|
||||||
c = __builtin_va_arg(args, char*);
|
|
||||||
if(c==NULL) goto copystring;
|
|
||||||
while(*p && dst + 2 < end) {
|
|
||||||
arg = *c;
|
|
||||||
if((*c & 128) != 0) {
|
|
||||||
if((*c & 32) == 0 ) {
|
|
||||||
arg = ((*c & 0x1F)<<6)|(*(c+1) & 0x3F);
|
|
||||||
c += 1;
|
|
||||||
} else
|
|
||||||
if((*c & 16) == 0 ) {
|
|
||||||
arg = ((*c & 0xF)<<12)|((*(c+1) & 0x3F)<<6)|(*(c+2) & 0x3F);
|
|
||||||
c += 2;
|
|
||||||
} else
|
|
||||||
if((*c & 8) == 0 ) {
|
|
||||||
arg = ((*c & 0x7)<<18)|((*(c+1) & 0x3F)<<12)|((*(c+2) & 0x3F)<<6)|(*(c+3) & 0x3F);
|
|
||||||
c += 3;
|
|
||||||
} else
|
|
||||||
arg = L'?';
|
|
||||||
}
|
|
||||||
if(!arg) break;
|
|
||||||
if(*fmt==L'Q' && needsescape(arg)) {
|
|
||||||
*dst++ = L'\\';
|
|
||||||
switch(arg) {
|
|
||||||
case L'\a': *dst++ = L'a'; break;
|
|
||||||
case L'\b': *dst++ = L'b'; break;
|
|
||||||
case 27: *dst++ = L'e'; break; /* gcc 10.2 doesn't like L'\e' in ansi mode */
|
|
||||||
case L'\f': *dst++ = L'f'; break;
|
|
||||||
case L'\n': *dst++ = L'n'; break;
|
|
||||||
case L'\r': *dst++ = L'r'; break;
|
|
||||||
case L'\t': *dst++ = L't'; break;
|
|
||||||
case L'\v': *dst++ = L'v'; break;
|
|
||||||
default: *dst++ = arg; break;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if(arg == L'\n') *dst++ = L'\r';
|
|
||||||
*dst++ = (wchar_t)(arg & 0xffff);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
#endif
|
|
||||||
if(*fmt==CL('D')) {
|
|
||||||
m = __builtin_va_arg(args, efi_physical_address_t);
|
|
||||||
for(j = 0; j < (len < 1 ? 1 : (len > 16 ? 16 : len)); j++) {
|
|
||||||
for(i = 44; i >= 0; i -= 4) {
|
|
||||||
n = (m >> i) & 15; *dst++ = n + (n>9?0x37:0x30);
|
|
||||||
if(dst >= end) goto zro;
|
|
||||||
}
|
|
||||||
*dst++ = CL(':'); if(dst >= end) goto zro;
|
|
||||||
*dst++ = CL(' '); if(dst >= end) goto zro;
|
|
||||||
mem = (uint8_t*)m;
|
|
||||||
for(i = 0; i < 16; i++) {
|
|
||||||
n = (mem[i] >> 4) & 15; *dst++ = n + (n>9?0x37:0x30); if(dst >= end) goto zro;
|
|
||||||
n = mem[i] & 15; *dst++ = n + (n>9?0x37:0x30); if(dst >= end) goto zro;
|
|
||||||
*dst++ = CL(' ');if(dst >= end) goto zro;
|
|
||||||
}
|
|
||||||
*dst++ = CL(' '); if(dst >= end) goto zro;
|
|
||||||
for(i = 0; i < 16; i++) {
|
|
||||||
*dst++ = (mem[i] < 32 || mem[i] >= 127 ? CL('.') : (char_t)mem[i]);
|
|
||||||
if(dst >= end) goto zro;
|
|
||||||
}
|
|
||||||
*dst++ = CL('\r'); if(dst >= end) goto zro;
|
|
||||||
*dst++ = CL('\n'); if(dst >= end) goto zro;
|
|
||||||
m += 16;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
put: if(*fmt == CL('\n') && (orig == dst || *(dst - 1) != CL('\r'))) *dst++ = CL('\r');
|
|
||||||
*dst++ = *fmt;
|
|
||||||
}
|
|
||||||
fmt++;
|
|
||||||
}
|
|
||||||
zro:*dst=0;
|
|
||||||
return (int)(dst-orig);
|
|
||||||
#undef needsescape
|
|
||||||
}
|
|
||||||
|
|
||||||
int vsprintf(char_t *dst, const char_t *fmt, __builtin_va_list args)
|
|
||||||
{
|
|
||||||
return vsnprintf(dst, BUFSIZ, fmt, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
int sprintf(char_t *dst, const char_t* fmt, ...)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
__builtin_va_list args;
|
|
||||||
__builtin_va_start(args, fmt);
|
|
||||||
ret = vsnprintf(dst, BUFSIZ, fmt, args);
|
|
||||||
__builtin_va_end(args);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
int snprintf(char_t *dst, size_t maxlen, const char_t* fmt, ...)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
__builtin_va_list args;
|
|
||||||
__builtin_va_start(args, fmt);
|
|
||||||
ret = vsnprintf(dst, maxlen, fmt, args);
|
|
||||||
__builtin_va_end(args);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
int vprintf(const char_t* fmt, __builtin_va_list args)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
wchar_t dst[BUFSIZ];
|
|
||||||
#ifndef UEFI_NO_UTF8
|
|
||||||
char_t tmp[BUFSIZ];
|
|
||||||
ret = vsnprintf(tmp, BUFSIZ, fmt, args);
|
|
||||||
mbstowcs(dst, tmp, BUFSIZ - 1);
|
|
||||||
#else
|
|
||||||
ret = vsnprintf(dst, BUFSIZ, fmt, args);
|
|
||||||
#endif
|
|
||||||
ST->ConOut->OutputString(ST->ConOut, (wchar_t *)&dst);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
int printf(const char_t* fmt, ...)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
__builtin_va_list args;
|
|
||||||
__builtin_va_start(args, fmt);
|
|
||||||
ret = vprintf(fmt, args);
|
|
||||||
__builtin_va_end(args);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
int vfprintf (FILE *__stream, const char_t *__format, __builtin_va_list args)
|
|
||||||
{
|
|
||||||
wchar_t dst[BUFSIZ];
|
|
||||||
char_t tmp[BUFSIZ];
|
|
||||||
uintn_t ret, i;
|
|
||||||
#ifndef UEFI_NO_UTF8
|
|
||||||
ret = (uintn_t)vsnprintf(tmp, BUFSIZ, __format, args);
|
|
||||||
ret = mbstowcs(dst, tmp, BUFSIZ - 1);
|
|
||||||
#else
|
|
||||||
ret = vsnprintf(dst, BUFSIZ, __format, args);
|
|
||||||
#endif
|
|
||||||
if(ret < 1 || !__stream || __stream == stdin) return 0;
|
|
||||||
for(i = 0; i < __blk_ndevs; i++)
|
|
||||||
if(__stream == (FILE*)__blk_devs[i].bio) {
|
|
||||||
errno = EBADF;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if(__stream == stdout)
|
|
||||||
ST->ConOut->OutputString(ST->ConOut, (wchar_t*)&dst);
|
|
||||||
else if(__stream == stderr)
|
|
||||||
ST->StdErr->OutputString(ST->StdErr, (wchar_t*)&dst);
|
|
||||||
else if(__ser && __stream == (FILE*)__ser) {
|
|
||||||
#ifdef UEFI_NO_UTF8
|
|
||||||
wcstombs((char*)&tmp, dst, BUFSIZ - 1);
|
|
||||||
#endif
|
|
||||||
__ser->Write(__ser, &ret, (void*)&tmp);
|
|
||||||
} else
|
|
||||||
#ifndef UEFI_NO_UTF8
|
|
||||||
__stream->Write(__stream, &ret, (void*)&tmp);
|
|
||||||
#else
|
|
||||||
__stream->Write(__stream, &ret, (void*)&dst);
|
|
||||||
#endif
|
|
||||||
return (int)ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
int fprintf (FILE *__stream, const char_t *__format, ...)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
__builtin_va_list args;
|
|
||||||
__builtin_va_start(args, __format);
|
|
||||||
ret = vfprintf(__stream, __format, args);
|
|
||||||
__builtin_va_end(args);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
int getchar_ifany (void)
|
|
||||||
{
|
|
||||||
efi_input_key_t key = { 0 };
|
|
||||||
efi_status_t status = ST->ConIn->ReadKeyStroke(ST->ConIn, &key);
|
|
||||||
return EFI_ERROR(status) ? 0 : key.UnicodeChar;
|
|
||||||
}
|
|
||||||
|
|
||||||
int getchar (void)
|
|
||||||
{
|
|
||||||
uintn_t idx;
|
|
||||||
BS->WaitForEvent(1, &ST->ConIn->WaitForKey, &idx);
|
|
||||||
return getchar_ifany();
|
|
||||||
}
|
|
||||||
|
|
||||||
int putchar (int __c)
|
|
||||||
{
|
|
||||||
wchar_t tmp[2];
|
|
||||||
tmp[0] = (wchar_t)__c;
|
|
||||||
tmp[1] = 0;
|
|
||||||
ST->ConOut->OutputString(ST->ConOut, (__c == L'\n' ? (wchar_t*)L"\r\n" : (wchar_t*)&tmp));
|
|
||||||
return (int)tmp[0];
|
|
||||||
}
|
|
||||||
@@ -1,365 +0,0 @@
|
|||||||
/*
|
|
||||||
* stdlib.c
|
|
||||||
*
|
|
||||||
* Copyright (C) 2021 bzt (bztsrc@gitlab)
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person
|
|
||||||
* obtaining a copy of this software and associated documentation
|
|
||||||
* files (the "Software"), to deal in the Software without
|
|
||||||
* restriction, including without limitation the rights to use, copy,
|
|
||||||
* modify, merge, publish, distribute, sublicense, and/or sell copies
|
|
||||||
* of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be
|
|
||||||
* included in all copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
||||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
||||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
||||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|
||||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
||||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
||||||
* DEALINGS IN THE SOFTWARE.
|
|
||||||
*
|
|
||||||
* This file is part of the POSIX-UEFI package.
|
|
||||||
* @brief Implementing functions which are defined in stdlib.h
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <uefi.h>
|
|
||||||
|
|
||||||
int errno = 0;
|
|
||||||
static uint64_t __srand_seed = 6364136223846793005ULL;
|
|
||||||
extern void __stdio_cleanup(void);
|
|
||||||
#ifndef UEFI_NO_TRACK_ALLOC
|
|
||||||
static uintptr_t *__stdlib_allocs = NULL;
|
|
||||||
static uintn_t __stdlib_numallocs = 0;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int atoi(const char_t *s)
|
|
||||||
{
|
|
||||||
return (int)atol(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
int64_t atol(const char_t *s)
|
|
||||||
{
|
|
||||||
int64_t sign = 1;
|
|
||||||
if(!s || !*s) return 0;
|
|
||||||
if(*s == CL('-')) { sign = -1; s++; }
|
|
||||||
if(s[0] == CL('0')) {
|
|
||||||
if(s[1] == CL('x'))
|
|
||||||
return strtol(s + 2, NULL, 16) * sign;
|
|
||||||
if(s[1] >= CL('0') && s[1] <= CL('7'))
|
|
||||||
return strtol(s, NULL, 8) * sign;
|
|
||||||
}
|
|
||||||
return strtol(s, NULL, 10) * sign;
|
|
||||||
}
|
|
||||||
|
|
||||||
int64_t strtol (const char_t *s, char_t **__endptr, int __base)
|
|
||||||
{
|
|
||||||
int64_t v=0, sign = 1;
|
|
||||||
if(!s || !*s) return 0;
|
|
||||||
if(*s == CL('-')) { sign = -1; s++; }
|
|
||||||
while(!(*s < CL('0') || (__base < 10 && *s >= __base + CL('0')) || (__base >= 10 && ((*s > CL('9') && *s < CL('A')) ||
|
|
||||||
(*s > CL('F') && *s < CL('a')) || *s > CL('f'))))) {
|
|
||||||
v *= __base;
|
|
||||||
if(*s >= CL('0') && *s <= (__base < 10 ? __base + CL('0') : CL('9')))
|
|
||||||
v += (*s)-CL('0');
|
|
||||||
else if(__base == 16 && *s >= CL('a') && *s <= CL('f'))
|
|
||||||
v += (*s)-CL('a')+10;
|
|
||||||
else if(__base == 16 && *s >= CL('A') && *s <= CL('F'))
|
|
||||||
v += (*s)-CL('A')+10;
|
|
||||||
s++;
|
|
||||||
}
|
|
||||||
if(__endptr) *__endptr = (char_t*)s;
|
|
||||||
return v * sign;
|
|
||||||
}
|
|
||||||
|
|
||||||
void *malloc (size_t __size)
|
|
||||||
{
|
|
||||||
void *ret = NULL;
|
|
||||||
efi_status_t status;
|
|
||||||
#ifndef UEFI_NO_TRACK_ALLOC
|
|
||||||
uintn_t i;
|
|
||||||
for(i = 0; i < __stdlib_numallocs && __stdlib_allocs[i] != 0; i += 2);
|
|
||||||
if(i == __stdlib_numallocs) {
|
|
||||||
/* no free slots found, (re)allocate the housekeeping array */
|
|
||||||
status = BS->AllocatePool(LIP ? LIP->ImageDataType : EfiLoaderData, (__stdlib_numallocs + 2) * sizeof(uintptr_t), &ret);
|
|
||||||
if(EFI_ERROR(status) || !ret) { errno = ENOMEM; return NULL; }
|
|
||||||
if(__stdlib_allocs) memcpy(ret, __stdlib_allocs, __stdlib_numallocs * sizeof(uintptr_t));
|
|
||||||
__stdlib_allocs = (uintptr_t*)ret;
|
|
||||||
__stdlib_allocs[i] = __stdlib_allocs[i + 1] = 0;
|
|
||||||
__stdlib_numallocs += 2;
|
|
||||||
ret = NULL;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
status = BS->AllocatePool(LIP ? LIP->ImageDataType : EfiLoaderData, __size, &ret);
|
|
||||||
if(EFI_ERROR(status) || !ret) { errno = ENOMEM; ret = NULL; }
|
|
||||||
#ifndef UEFI_NO_TRACK_ALLOC
|
|
||||||
__stdlib_allocs[i] = (uintptr_t)ret;
|
|
||||||
__stdlib_allocs[i + 1] = (uintptr_t)__size;
|
|
||||||
#endif
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void *calloc (size_t __nmemb, size_t __size)
|
|
||||||
{
|
|
||||||
void *ret = malloc(__nmemb * __size);
|
|
||||||
if(ret) memset(ret, 0, __nmemb * __size);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void *realloc (void *__ptr, size_t __size)
|
|
||||||
{
|
|
||||||
void *ret = NULL;
|
|
||||||
efi_status_t status;
|
|
||||||
#ifndef UEFI_NO_TRACK_ALLOC
|
|
||||||
uintn_t i;
|
|
||||||
#endif
|
|
||||||
if(!__ptr) return malloc(__size);
|
|
||||||
if(!__size) { free(__ptr); return NULL; }
|
|
||||||
#ifndef UEFI_NO_TRACK_ALLOC
|
|
||||||
/* get the slot which stores the old size for this buffer */
|
|
||||||
for(i = 0; i < __stdlib_numallocs && __stdlib_allocs[i] != (uintptr_t)__ptr; i += 2);
|
|
||||||
if(i == __stdlib_numallocs) { errno = ENOMEM; return NULL; }
|
|
||||||
/* allocate a new buffer and copy data from old buffer */
|
|
||||||
status = BS->AllocatePool(LIP ? LIP->ImageDataType : EfiLoaderData, __size, &ret);
|
|
||||||
if(EFI_ERROR(status) || !ret) { errno = ENOMEM; ret = NULL; }
|
|
||||||
else {
|
|
||||||
memcpy(ret, (void*)__stdlib_allocs[i], __stdlib_allocs[i + 1] < __size ? __stdlib_allocs[i + 1] : __size);
|
|
||||||
if(__size > __stdlib_allocs[i + 1]) memset((uint8_t*)ret + __stdlib_allocs[i + 1], 0, __size - __stdlib_allocs[i + 1]);
|
|
||||||
/* free old buffer and store new buffer in slot */
|
|
||||||
BS->FreePool((void*)__stdlib_allocs[i]);
|
|
||||||
__stdlib_allocs[i] = (uintptr_t)ret;
|
|
||||||
__stdlib_allocs[i + 1] = (uintptr_t)__size;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
status = BS->AllocatePool(LIP ? LIP->ImageDataType : EfiLoaderData, __size, &ret);
|
|
||||||
if(EFI_ERROR(status) || !ret) { errno = ENOMEM; return NULL; }
|
|
||||||
/* this means out of bounds read, but fine with POSIX as the end of new buffer supposed to be left uninitialized) */
|
|
||||||
memcpy(ret, (void*)__ptr, __size);
|
|
||||||
BS->FreePool((void*)__ptr);
|
|
||||||
#endif
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void free (void *__ptr)
|
|
||||||
{
|
|
||||||
efi_status_t status;
|
|
||||||
#ifndef UEFI_NO_TRACK_ALLOC
|
|
||||||
uintn_t i;
|
|
||||||
#endif
|
|
||||||
if(!__ptr) { errno = ENOMEM; return; }
|
|
||||||
#ifndef UEFI_NO_TRACK_ALLOC
|
|
||||||
/* find and clear the slot */
|
|
||||||
for(i = 0; i < __stdlib_numallocs && __stdlib_allocs[i] != (uintptr_t)__ptr; i += 2);
|
|
||||||
if(i == __stdlib_numallocs) { errno = ENOMEM; return; }
|
|
||||||
__stdlib_allocs[i] = 0;
|
|
||||||
__stdlib_allocs[i + 1] = 0;
|
|
||||||
/* if there are only empty slots, free the housekeeping array too */
|
|
||||||
for(i = 0; i < __stdlib_numallocs && __stdlib_allocs[i] == 0; i += 2);
|
|
||||||
if(i == __stdlib_numallocs) { BS->FreePool(__stdlib_allocs); __stdlib_allocs = NULL; __stdlib_numallocs = 0; }
|
|
||||||
#endif
|
|
||||||
status = BS->FreePool(__ptr);
|
|
||||||
if(EFI_ERROR(status)) errno = ENOMEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
void abort ()
|
|
||||||
{
|
|
||||||
#ifndef UEFI_NO_TRACK_ALLOC
|
|
||||||
if(__stdlib_allocs)
|
|
||||||
BS->FreePool(__stdlib_allocs);
|
|
||||||
__stdlib_allocs = NULL;
|
|
||||||
__stdlib_numallocs = 0;
|
|
||||||
#endif
|
|
||||||
__stdio_cleanup();
|
|
||||||
BS->Exit(IM, EFI_ABORTED, 0, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
void exit (int __status)
|
|
||||||
{
|
|
||||||
#ifndef UEFI_NO_TRACK_ALLOC
|
|
||||||
if(__stdlib_allocs)
|
|
||||||
BS->FreePool(__stdlib_allocs);
|
|
||||||
__stdlib_allocs = NULL;
|
|
||||||
__stdlib_numallocs = 0;
|
|
||||||
#endif
|
|
||||||
__stdio_cleanup();
|
|
||||||
BS->Exit(IM, !__status ? 0 : (__status < 0 ? EFIERR(-__status) : EFIERR(__status)), 0, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
int exit_bs()
|
|
||||||
{
|
|
||||||
efi_status_t status = 0;
|
|
||||||
efi_memory_descriptor_t *memory_map = NULL;
|
|
||||||
uintn_t cnt = 3, memory_map_size=0, map_key=0, desc_size=0;
|
|
||||||
#ifndef UEFI_NO_TRACK_ALLOC
|
|
||||||
if(__stdlib_allocs)
|
|
||||||
BS->FreePool(__stdlib_allocs);
|
|
||||||
__stdlib_allocs = NULL;
|
|
||||||
__stdlib_numallocs = 0;
|
|
||||||
#endif
|
|
||||||
__stdio_cleanup();
|
|
||||||
while(cnt--) {
|
|
||||||
status = BS->GetMemoryMap(&memory_map_size, memory_map, &map_key, &desc_size, NULL);
|
|
||||||
if (status!=EFI_BUFFER_TOO_SMALL) break;
|
|
||||||
status = BS->ExitBootServices(IM, map_key);
|
|
||||||
if(!EFI_ERROR(status)) return 0;
|
|
||||||
}
|
|
||||||
return (int)(status & 0xffff);
|
|
||||||
}
|
|
||||||
|
|
||||||
void *bsearch(const void *key, const void *base, size_t nmemb, size_t size, __compar_fn_t cmp)
|
|
||||||
{
|
|
||||||
uint64_t s=0, e=nmemb, m;
|
|
||||||
int ret;
|
|
||||||
while (s < e) {
|
|
||||||
m = s + (e-s)/2;
|
|
||||||
ret = cmp(key, (uint8_t*)base + m*size);
|
|
||||||
if (ret < 0) e = m; else
|
|
||||||
if (ret > 0) s = m+1; else
|
|
||||||
return (void *)((uint8_t*)base + m*size);
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
int mblen(const char *s, size_t n)
|
|
||||||
{
|
|
||||||
const char *e = s+n;
|
|
||||||
int c = 0;
|
|
||||||
if(s) {
|
|
||||||
while(s < e && *s) {
|
|
||||||
if((*s & 128) != 0) {
|
|
||||||
if((*s & 32) == 0 ) s++; else
|
|
||||||
if((*s & 16) == 0 ) s+=2; else
|
|
||||||
if((*s & 8) == 0 ) s+=3;
|
|
||||||
}
|
|
||||||
c++;
|
|
||||||
s++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
|
|
||||||
int mbtowc (wchar_t * __pwc, const char *s, size_t n)
|
|
||||||
{
|
|
||||||
wchar_t arg;
|
|
||||||
int ret = 1;
|
|
||||||
if(!s || !*s) return 0;
|
|
||||||
arg = (wchar_t)*s;
|
|
||||||
if((*s & 128) != 0) {
|
|
||||||
if((*s & 32) == 0 && n > 0) { arg = ((*s & 0x1F)<<6)|(*(s+1) & 0x3F); ret = 2; } else
|
|
||||||
if((*s & 16) == 0 && n > 1) { arg = ((*s & 0xF)<<12)|((*(s+1) & 0x3F)<<6)|(*(s+2) & 0x3F); ret = 3; } else
|
|
||||||
if((*s & 8) == 0 && n > 2) { arg = ((*s & 0x7)<<18)|((*(s+1) & 0x3F)<<12)|((*(s+2) & 0x3F)<<6)|(*(s+3) & 0x3F); ret = 4; }
|
|
||||||
else return -1;
|
|
||||||
}
|
|
||||||
if(__pwc) *__pwc = arg;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
int wctomb (char *s, wchar_t u)
|
|
||||||
{
|
|
||||||
int ret = 0;
|
|
||||||
if(u<0x80) {
|
|
||||||
*s = u;
|
|
||||||
ret = 1;
|
|
||||||
} else if(u<0x800) {
|
|
||||||
*(s+0)=((u>>6)&0x1F)|0xC0;
|
|
||||||
*(s+1)=(u&0x3F)|0x80;
|
|
||||||
ret = 2;
|
|
||||||
} else {
|
|
||||||
*(s+0)=((u>>12)&0x0F)|0xE0;
|
|
||||||
*(s+1)=((u>>6)&0x3F)|0x80;
|
|
||||||
*(s+2)=(u&0x3F)|0x80;
|
|
||||||
ret = 3;
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t mbstowcs (wchar_t *__pwcs, const char *__s, size_t __n)
|
|
||||||
{
|
|
||||||
int r;
|
|
||||||
wchar_t *orig = __pwcs;
|
|
||||||
if(!__s || !*__s) return 0;
|
|
||||||
while(*__s) {
|
|
||||||
r = mbtowc(__pwcs, __s, __n - (size_t)(__pwcs - orig));
|
|
||||||
if(r < 0) return (size_t)-1;
|
|
||||||
__pwcs++;
|
|
||||||
__s += r;
|
|
||||||
}
|
|
||||||
*__pwcs = 0;
|
|
||||||
return (size_t)(__pwcs - orig);
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t wcstombs (char *__s, const wchar_t *__pwcs, size_t __n)
|
|
||||||
{
|
|
||||||
int r;
|
|
||||||
char *orig = __s;
|
|
||||||
if(!__s || !__pwcs || !*__pwcs) return 0;
|
|
||||||
while(*__pwcs && ((size_t)(__s - orig + 4) < __n)) {
|
|
||||||
r = wctomb(__s, *__pwcs);
|
|
||||||
if(r < 0) return (size_t)-1;
|
|
||||||
__pwcs++;
|
|
||||||
__s += r;
|
|
||||||
}
|
|
||||||
*__s = 0;
|
|
||||||
return (size_t)(__s - orig);
|
|
||||||
}
|
|
||||||
|
|
||||||
void srand(unsigned int __seed)
|
|
||||||
{
|
|
||||||
__srand_seed = __seed - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int rand()
|
|
||||||
{
|
|
||||||
efi_guid_t rngGuid = EFI_RNG_PROTOCOL_GUID;
|
|
||||||
efi_rng_protocol_t *rng = NULL;
|
|
||||||
efi_status_t status;
|
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
__srand_seed = 6364136223846793005ULL*__srand_seed + 1;
|
|
||||||
status = BS->LocateProtocol(&rngGuid, NULL, (void**)&rng);
|
|
||||||
if(!EFI_ERROR(status) && rng)
|
|
||||||
rng->GetRNG(rng, NULL, (uintn_t)sizeof(int), (uint8_t*)&ret);
|
|
||||||
ret ^= (int)(__srand_seed>>33);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t *getenv(char_t *name, uintn_t *len)
|
|
||||||
{
|
|
||||||
efi_guid_t globGuid = EFI_GLOBAL_VARIABLE;
|
|
||||||
uint8_t tmp[EFI_MAXIMUM_VARIABLE_SIZE], *ret;
|
|
||||||
uint32_t attr;
|
|
||||||
efi_status_t status;
|
|
||||||
#ifndef UEFI_NO_UTF8
|
|
||||||
wchar_t wcname[256];
|
|
||||||
mbstowcs((wchar_t*)&wcname, name, 256);
|
|
||||||
status = RT->GetVariable((wchar_t*)&wcname, &globGuid, &attr, len, &tmp);
|
|
||||||
#else
|
|
||||||
status = RT->GetVariable(name, &globGuid, &attr, len, &tmp);
|
|
||||||
#endif
|
|
||||||
if(EFI_ERROR(status) || *len < 1 || !(ret = malloc((*len) + 1))) {
|
|
||||||
*len = 0;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
memcpy(ret, tmp, *len);
|
|
||||||
ret[*len] = 0;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
int setenv(char_t *name, uintn_t len, uint8_t *data)
|
|
||||||
{
|
|
||||||
efi_guid_t globGuid = EFI_GLOBAL_VARIABLE;
|
|
||||||
efi_status_t status;
|
|
||||||
#ifndef UEFI_NO_UTF8
|
|
||||||
wchar_t wcname[256];
|
|
||||||
mbstowcs((wchar_t*)&wcname, name, 256);
|
|
||||||
status = RT->SetVariable(wcname, &globGuid, 0, len, data);
|
|
||||||
#else
|
|
||||||
status = RT->SetVariable(name, &globGuid, 0, len, data);
|
|
||||||
#endif
|
|
||||||
return !EFI_ERROR(status);
|
|
||||||
}
|
|
||||||
@@ -1,262 +0,0 @@
|
|||||||
/*
|
|
||||||
* string.c
|
|
||||||
*
|
|
||||||
* Copyright (C) 2021 bzt (bztsrc@gitlab)
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person
|
|
||||||
* obtaining a copy of this software and associated documentation
|
|
||||||
* files (the "Software"), to deal in the Software without
|
|
||||||
* restriction, including without limitation the rights to use, copy,
|
|
||||||
* modify, merge, publish, distribute, sublicense, and/or sell copies
|
|
||||||
* of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be
|
|
||||||
* included in all copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
||||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
||||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
||||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|
||||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
||||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
||||||
* DEALINGS IN THE SOFTWARE.
|
|
||||||
*
|
|
||||||
* This file is part of the POSIX-UEFI package.
|
|
||||||
* @brief Implementing functions which are defined in string.h
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <uefi.h>
|
|
||||||
|
|
||||||
void *memcpy(void *dst, const void *src, size_t n)
|
|
||||||
{
|
|
||||||
uint8_t *a=(uint8_t*)dst,*b=(uint8_t*)src;
|
|
||||||
if(src && dst && src != dst && n>0) {
|
|
||||||
while(n--) *a++ = *b++;
|
|
||||||
}
|
|
||||||
return dst;
|
|
||||||
}
|
|
||||||
|
|
||||||
void *memmove(void *dst, const void *src, size_t n)
|
|
||||||
{
|
|
||||||
uint8_t *a=(uint8_t*)dst,*b=(uint8_t*)src;
|
|
||||||
if(src && dst && src != dst && n>0) {
|
|
||||||
if(a>b && a<b+n) {
|
|
||||||
a+=n-1; b+=n-1; while(n-->0) *a--=*b--;
|
|
||||||
} else {
|
|
||||||
while(n--) *a++ = *b++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return dst;
|
|
||||||
}
|
|
||||||
|
|
||||||
void *memset(void *s, int c, size_t n)
|
|
||||||
{
|
|
||||||
uint8_t *p=(uint8_t*)s;
|
|
||||||
if(s && n>0) {
|
|
||||||
while(n--) *p++ = (uint8_t)c;
|
|
||||||
}
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
int memcmp(const void *s1, const void *s2, size_t n)
|
|
||||||
{
|
|
||||||
uint8_t *a=(uint8_t*)s1,*b=(uint8_t*)s2;
|
|
||||||
if(s1 && s2 && s1 != s2 && n>0) {
|
|
||||||
while(n--) {
|
|
||||||
if(*a != *b) return *a - *b;
|
|
||||||
a++; b++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void *memchr(const void *s, int c, size_t n)
|
|
||||||
{
|
|
||||||
uint8_t *e, *p=(uint8_t*)s;
|
|
||||||
if(s && n>0) {
|
|
||||||
for(e=p+n; p<e; p++) if(*p==(uint8_t)c) return p;
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void *memrchr(const void *s, int c, size_t n)
|
|
||||||
{
|
|
||||||
uint8_t *e, *p=(uint8_t*)s;
|
|
||||||
if(s && n>0) {
|
|
||||||
for(e=p+n; p<e; --e) if(*e==(uint8_t)c) return e;
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void *memmem(const void *haystack, size_t hl, const void *needle, size_t nl)
|
|
||||||
{
|
|
||||||
uint8_t *c = (uint8_t*)haystack;
|
|
||||||
if(!haystack || !needle || !hl || !nl || nl > hl) return NULL;
|
|
||||||
hl -= nl - 1;
|
|
||||||
while(hl) {
|
|
||||||
if(!memcmp(c, needle, nl)) return c;
|
|
||||||
c++; hl--;
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void *memrmem(const void *haystack, size_t hl, const void *needle, size_t nl)
|
|
||||||
{
|
|
||||||
uint8_t *c = (uint8_t*)haystack;
|
|
||||||
if(!haystack || !needle || !hl || !nl || nl > hl) return NULL;
|
|
||||||
hl -= nl;
|
|
||||||
c += hl;
|
|
||||||
while(hl) {
|
|
||||||
if(!memcmp(c, needle, nl)) return c;
|
|
||||||
c--; hl--;
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
char_t *strcpy(char_t *dst, const char_t *src)
|
|
||||||
{
|
|
||||||
char_t *s = dst;
|
|
||||||
if(src && dst && src != dst) {
|
|
||||||
while(*src) {*dst++=*src++;} *dst=0;
|
|
||||||
}
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
char_t *strncpy(char_t *dst, const char_t *src, size_t n)
|
|
||||||
{
|
|
||||||
char_t *s = dst;
|
|
||||||
const char_t *e = src+n;
|
|
||||||
if(src && dst && src != dst && n>0) {
|
|
||||||
while(*src && src<e) {*dst++=*src++;} *dst=0;
|
|
||||||
}
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
char_t *strcat(char_t *dst, const char_t *src)
|
|
||||||
{
|
|
||||||
char_t *s = dst;
|
|
||||||
if(src && dst) {
|
|
||||||
dst += strlen(dst);
|
|
||||||
while(*src) {*dst++=*src++;} *dst=0;
|
|
||||||
}
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
int strcmp(const char_t *s1, const char_t *s2)
|
|
||||||
{
|
|
||||||
if(s1 && s2 && s1!=s2) {
|
|
||||||
while(*s1 && *s1==*s2){s1++;s2++;}
|
|
||||||
return *s1-*s2;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
char_t *strncat(char_t *dst, const char_t *src, size_t n)
|
|
||||||
{
|
|
||||||
char_t *s = dst;
|
|
||||||
const char_t *e = src+n;
|
|
||||||
if(src && dst && n>0) {
|
|
||||||
dst += strlen(dst);
|
|
||||||
while(*src && src<e) {*dst++=*src++;} *dst=0;
|
|
||||||
}
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
int strncmp(const char_t *s1, const char_t *s2, size_t n)
|
|
||||||
{
|
|
||||||
const char_t *e = s1+n-1;
|
|
||||||
if(s1 && s2 && s1!=s2 && n>0) {
|
|
||||||
while(s1<e && *s1 && *s1==*s2){s1++;s2++;}
|
|
||||||
return *s1-*s2;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
char_t *strdup(const char_t *s)
|
|
||||||
{
|
|
||||||
size_t i = (strlen(s)+1) * sizeof(char_t);
|
|
||||||
char_t *s2 = (char_t *)malloc(i);
|
|
||||||
if(s2 != NULL) memcpy(s2, (const void*)s, i);
|
|
||||||
return s2;
|
|
||||||
}
|
|
||||||
|
|
||||||
char_t *strchr(const char_t *s, int c)
|
|
||||||
{
|
|
||||||
if(s) {
|
|
||||||
while(*s) {
|
|
||||||
if(*s == (char_t)c) return (char_t*)s;
|
|
||||||
s++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
char_t *strrchr(const char_t *s, int c)
|
|
||||||
{
|
|
||||||
char_t *e;
|
|
||||||
if(s) {
|
|
||||||
e = (char_t*)s + strlen(s) - 1;
|
|
||||||
while(s <= e) {
|
|
||||||
if(*e == (char_t)c) return e;
|
|
||||||
e--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
char_t *strstr(const char_t *haystack, const char_t *needle)
|
|
||||||
{
|
|
||||||
return memmem(haystack, strlen(haystack) * sizeof(char_t), needle, strlen(needle) * sizeof(char_t));
|
|
||||||
}
|
|
||||||
|
|
||||||
static char_t *_strtok_r(char_t *s, const char_t *d, char_t **p)
|
|
||||||
{
|
|
||||||
int c, sc;
|
|
||||||
char_t *tok, *sp;
|
|
||||||
|
|
||||||
if(d == NULL || (s == NULL && (s=*p) == NULL)) return NULL;
|
|
||||||
again:
|
|
||||||
c = *s++;
|
|
||||||
for(sp = (char_t *)d; (sc=*sp++)!=0;) {
|
|
||||||
if(c == sc) goto again;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (c == 0) { *p=NULL; return NULL; }
|
|
||||||
tok = s-1;
|
|
||||||
while(1) {
|
|
||||||
c = *s++;
|
|
||||||
sp = (char_t *)d;
|
|
||||||
do {
|
|
||||||
if((sc=*sp++) == c) {
|
|
||||||
if(c == 0) s = NULL;
|
|
||||||
else *(s-1) = 0;
|
|
||||||
*p = s;
|
|
||||||
return tok;
|
|
||||||
}
|
|
||||||
} while(sc != 0);
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
char_t *strtok(char_t *s, const char_t *delim)
|
|
||||||
{
|
|
||||||
static char_t *p;
|
|
||||||
return _strtok_r (s, delim, &p);
|
|
||||||
}
|
|
||||||
|
|
||||||
char_t *strtok_r(char_t *s, const char_t *delim, char_t **ptr)
|
|
||||||
{
|
|
||||||
return _strtok_r (s, delim, ptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t strlen (const char_t *__s)
|
|
||||||
{
|
|
||||||
size_t ret;
|
|
||||||
|
|
||||||
if(!__s) return 0;
|
|
||||||
for(ret = 0; __s[ret]; ret++);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
@@ -1,146 +0,0 @@
|
|||||||
/*
|
|
||||||
* time.c
|
|
||||||
*
|
|
||||||
* Copyright (C) 2021 bzt (bztsrc@gitlab)
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person
|
|
||||||
* obtaining a copy of this software and associated documentation
|
|
||||||
* files (the "Software"), to deal in the Software without
|
|
||||||
* restriction, including without limitation the rights to use, copy,
|
|
||||||
* modify, merge, publish, distribute, sublicense, and/or sell copies
|
|
||||||
* of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be
|
|
||||||
* included in all copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
||||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
||||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
||||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|
||||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
||||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
||||||
* DEALINGS IN THE SOFTWARE.
|
|
||||||
*
|
|
||||||
* This file is part of the POSIX-UEFI package.
|
|
||||||
* @brief Implementing functions which are defined in time.h
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <uefi.h>
|
|
||||||
|
|
||||||
static struct tm __tm;
|
|
||||||
time_t __mktime_efi(efi_time_t *t);
|
|
||||||
|
|
||||||
/* from musl */
|
|
||||||
static uint64_t __year_to_secs(uint64_t year, int *is_leap)
|
|
||||||
{
|
|
||||||
int y, cycles, centuries, leaps, rem;
|
|
||||||
|
|
||||||
if (year-2ULL <= 136) {
|
|
||||||
y = (int)year;
|
|
||||||
leaps = (y-68)>>2;
|
|
||||||
if (!((y-68)&3)) {
|
|
||||||
leaps--;
|
|
||||||
if (is_leap) *is_leap = 1;
|
|
||||||
} else if (is_leap) *is_leap = 0;
|
|
||||||
return 31536000ULL*(uint64_t)(y-70) + 86400ULL*(uint64_t)leaps;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!is_leap) is_leap = &(int){0};
|
|
||||||
cycles = (int)((year-100) / 400);
|
|
||||||
rem = (year-100) % 400;
|
|
||||||
if (rem < 0) {
|
|
||||||
cycles--;
|
|
||||||
rem += 400;
|
|
||||||
}
|
|
||||||
if (!rem) {
|
|
||||||
*is_leap = 1;
|
|
||||||
centuries = 0;
|
|
||||||
leaps = 0;
|
|
||||||
} else {
|
|
||||||
if (rem >= 200) {
|
|
||||||
if (rem >= 300) { centuries = 3; rem -= 300; }
|
|
||||||
else { centuries = 2; rem -= 200; }
|
|
||||||
} else {
|
|
||||||
if (rem >= 100) { centuries = 1; rem -= 100; }
|
|
||||||
else centuries = 0;
|
|
||||||
}
|
|
||||||
if (!rem) {
|
|
||||||
*is_leap = 0;
|
|
||||||
leaps = 0;
|
|
||||||
} else {
|
|
||||||
leaps = rem / 4;
|
|
||||||
rem %= 4;
|
|
||||||
*is_leap = !rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
leaps += 97*cycles + 24*centuries - *is_leap;
|
|
||||||
|
|
||||||
return (uint64_t)(year-100) * 31536000ULL + (uint64_t)leaps * 86400ULL + 946684800ULL + 86400ULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
time_t __mktime_efi(efi_time_t *t)
|
|
||||||
{
|
|
||||||
__tm.tm_year = t->Year + (/* workaround some buggy firmware*/ t->Year > 2000 ? -1900 : 98);
|
|
||||||
__tm.tm_mon = t->Month - 1;
|
|
||||||
__tm.tm_mday = t->Day;
|
|
||||||
__tm.tm_hour = t->Hour;
|
|
||||||
__tm.tm_min = t->Minute;
|
|
||||||
__tm.tm_sec = t->Second;
|
|
||||||
__tm.tm_isdst = t->Daylight;
|
|
||||||
return mktime(&__tm);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This isn't POSIX, no arguments. Just returns the current time in struct tm
|
|
||||||
*/
|
|
||||||
struct tm *localtime (const time_t *__timer)
|
|
||||||
{
|
|
||||||
efi_time_t t = {0};
|
|
||||||
(void)__timer;
|
|
||||||
ST->RuntimeServices->GetTime(&t, NULL);
|
|
||||||
__mktime_efi(&t);
|
|
||||||
return &__tm;
|
|
||||||
}
|
|
||||||
|
|
||||||
time_t mktime(const struct tm *tm)
|
|
||||||
{
|
|
||||||
static const uint64_t secs_through_month[] = {
|
|
||||||
0, 31*86400, 59*86400, 90*86400,
|
|
||||||
120*86400, 151*86400, 181*86400, 212*86400,
|
|
||||||
243*86400, 273*86400, 304*86400, 334*86400 };
|
|
||||||
int is_leap;
|
|
||||||
uint64_t year = (uint64_t)tm->tm_year, t, adj;
|
|
||||||
int month = tm->tm_mon;
|
|
||||||
if (month >= 12 || month < 0) {
|
|
||||||
adj = (uint64_t)month / 12;
|
|
||||||
month %= 12;
|
|
||||||
if (month < 0) {
|
|
||||||
adj--;
|
|
||||||
month += 12;
|
|
||||||
}
|
|
||||||
year += adj;
|
|
||||||
}
|
|
||||||
t = __year_to_secs(year, &is_leap);
|
|
||||||
t += secs_through_month[month];
|
|
||||||
if (is_leap && month >= 2) t += 86400;
|
|
||||||
t += 86400ULL * (uint64_t)(tm->tm_mday-1);
|
|
||||||
t += 3600ULL * (uint64_t)tm->tm_hour;
|
|
||||||
t += 60ULL * (uint64_t)tm->tm_min;
|
|
||||||
t += (uint64_t)tm->tm_sec;
|
|
||||||
return (time_t)t;
|
|
||||||
}
|
|
||||||
|
|
||||||
time_t time(time_t *__timer)
|
|
||||||
{
|
|
||||||
time_t ret;
|
|
||||||
efi_time_t t = {0};
|
|
||||||
ST->RuntimeServices->GetTime(&t, NULL);
|
|
||||||
ret = __mktime_efi(&t);
|
|
||||||
if(__timer) *__timer = ret;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
+172
-1220
File diff suppressed because it is too large
Load Diff
@@ -1,65 +0,0 @@
|
|||||||
/*
|
|
||||||
* unistd.c
|
|
||||||
*
|
|
||||||
* Copyright (C) 2021 bzt (bztsrc@gitlab)
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person
|
|
||||||
* obtaining a copy of this software and associated documentation
|
|
||||||
* files (the "Software"), to deal in the Software without
|
|
||||||
* restriction, including without limitation the rights to use, copy,
|
|
||||||
* modify, merge, publish, distribute, sublicense, and/or sell copies
|
|
||||||
* of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be
|
|
||||||
* included in all copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
||||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
||||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
||||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|
||||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
||||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
||||||
* DEALINGS IN THE SOFTWARE.
|
|
||||||
*
|
|
||||||
* This file is part of the POSIX-UEFI package.
|
|
||||||
* @brief Implementing functions which are defined in unistd.h
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <uefi.h>
|
|
||||||
|
|
||||||
int __remove(const wchar_t *__filename, int isdir);
|
|
||||||
|
|
||||||
int usleep (unsigned long int __useconds)
|
|
||||||
{
|
|
||||||
BS->Stall(__useconds);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int sleep (unsigned int __seconds)
|
|
||||||
{
|
|
||||||
/* Issue 56: some real firmware is buggy and Stall doesn't work for large delays, so use a timer instead */
|
|
||||||
uint64_t usec = (uint64_t)__seconds * 1000000UL;
|
|
||||||
uintn_t index = 0;
|
|
||||||
efi_event_t timer_event;
|
|
||||||
efi_status_t status = status = BS->CreateEvent(EVT_TIMER, 0, NULL, NULL, &timer_event);
|
|
||||||
if(!EFI_ERROR(status)) {
|
|
||||||
BS->SetTimer(timer_event, TimerRelative, usec * 10UL);
|
|
||||||
BS->WaitForEvent(1, &timer_event, &index);
|
|
||||||
BS->CloseEvent(timer_event);
|
|
||||||
} else
|
|
||||||
BS->Stall(usec);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int unlink (const wchar_t *__filename)
|
|
||||||
{
|
|
||||||
return __remove(__filename, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
int rmdir (const wchar_t *__filename)
|
|
||||||
{
|
|
||||||
return __remove(__filename, 1);
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user