mirror of
https://gitlab.com/bztsrc/posix-uefi.git
synced 2024-12-28 06:55:08 +01:00
More examples
This commit is contained in:
parent
81a82cf366
commit
d6ecf787f7
15 changed files with 502 additions and 0 deletions
9
examples/0E_elfload/Makefile
Normal file
9
examples/0E_elfload/Makefile
Normal file
|
@ -0,0 +1,9 @@
|
|||
TARGET = elfload.efi
|
||||
SRCS = elfload.c
|
||||
EXTRA = kernel.elf
|
||||
|
||||
#USE_GCC=1
|
||||
include uefi/Makefile
|
||||
|
||||
kernel.elf:
|
||||
@make -C kernel all USE_GCC=$(USE_GCC)
|
20
examples/0E_elfload/README.md
Normal file
20
examples/0E_elfload/README.md
Normal file
|
@ -0,0 +1,20 @@
|
|||
ELF loader
|
||||
==========
|
||||
|
||||
This is an example ELF loader. Note that UEFI wastes lots and lots of memory, so be sure you link your ELF
|
||||
at an address which isn't used by UEFI. The safest would be 64M, but using 32M looks ok.
|
||||
|
||||
Compilation
|
||||
-----------
|
||||
|
||||
To compile the loader
|
||||
```sh
|
||||
$ make
|
||||
```
|
||||
|
||||
To compile the "kernel":
|
||||
```sh
|
||||
$ make -f Makefile.kernel kernel.elf
|
||||
```
|
||||
First compile the loader, then the kernel. This is tricky because compiling the kernel includes the normal Makefile to
|
||||
get gcc options and flags. Normally you should have the kernel in completely separated repository with its own Makefile.
|
114
examples/0E_elfload/elfload.c
Normal file
114
examples/0E_elfload/elfload.c
Normal file
|
@ -0,0 +1,114 @@
|
|||
#include <uefi.h>
|
||||
|
||||
/*** ELF64 defines and structs ***/
|
||||
#define ELFMAG "\177ELF"
|
||||
#define SELFMAG 4
|
||||
#define EI_CLASS 4 /* File class byte index */
|
||||
#define ELFCLASS64 2 /* 64-bit objects */
|
||||
#define EI_DATA 5 /* Data encoding byte index */
|
||||
#define ELFDATA2LSB 1 /* 2's complement, little endian */
|
||||
#define ET_EXEC 2 /* Executable file */
|
||||
#define PT_LOAD 1 /* Loadable program segment */
|
||||
#ifdef __x86_64__
|
||||
#define EM_MACH 62 /* AMD x86-64 architecture */
|
||||
#endif
|
||||
#ifdef __aarch64__
|
||||
#define EM_MACH 183 /* ARM aarch64 architecture */
|
||||
#endif
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t e_ident[16]; /* Magic number and other info */
|
||||
uint16_t e_type; /* Object file type */
|
||||
uint16_t e_machine; /* Architecture */
|
||||
uint32_t e_version; /* Object file version */
|
||||
uint64_t e_entry; /* Entry point virtual address */
|
||||
uint64_t e_phoff; /* Program header table file offset */
|
||||
uint64_t e_shoff; /* Section header table file offset */
|
||||
uint32_t e_flags; /* Processor-specific flags */
|
||||
uint16_t e_ehsize; /* ELF header size in bytes */
|
||||
uint16_t e_phentsize; /* Program header table entry size */
|
||||
uint16_t e_phnum; /* Program header table entry count */
|
||||
uint16_t e_shentsize; /* Section header table entry size */
|
||||
uint16_t e_shnum; /* Section header table entry count */
|
||||
uint16_t e_shstrndx; /* Section header string table index */
|
||||
} Elf64_Ehdr;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t p_type; /* Segment type */
|
||||
uint32_t p_flags; /* Segment flags */
|
||||
uint64_t p_offset; /* Segment file offset */
|
||||
uint64_t p_vaddr; /* Segment virtual address */
|
||||
uint64_t p_paddr; /* Segment physical address */
|
||||
uint64_t p_filesz; /* Segment size in file */
|
||||
uint64_t p_memsz; /* Segment size in memory */
|
||||
uint64_t p_align; /* Segment alignment */
|
||||
} Elf64_Phdr;
|
||||
|
||||
/**
|
||||
* Load an ELF executable
|
||||
*/
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
FILE *f;
|
||||
char *buff;
|
||||
long int size;
|
||||
Elf64_Ehdr *elf;
|
||||
Elf64_Phdr *phdr;
|
||||
uintptr_t entry;
|
||||
int i, j;
|
||||
|
||||
/* load the file */
|
||||
if((f = fopen("\\0E_elfload\\kernel.elf", "r"))) {
|
||||
fseek(f, 0, SEEK_END);
|
||||
size = ftell(f);
|
||||
fseek(f, 0, SEEK_SET);
|
||||
buff = malloc(size + 1);
|
||||
if(!buff) {
|
||||
fprintf(stderr, "unable to allocate memory\n");
|
||||
return 1;
|
||||
}
|
||||
fread(buff, size, 1, f);
|
||||
fclose(f);
|
||||
} else {
|
||||
fprintf(stderr, "Unable to open file\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* is it a valid ELF executable for this architecture? */
|
||||
elf = (Elf64_Ehdr *)buff;
|
||||
if(!memcmp(elf->e_ident, ELFMAG, SELFMAG) && /* magic match? */
|
||||
elf->e_ident[EI_CLASS] == ELFCLASS64 && /* 64 bit? */
|
||||
elf->e_ident[EI_DATA] == ELFDATA2LSB && /* LSB? */
|
||||
elf->e_type == ET_EXEC && /* executable object? */
|
||||
elf->e_machine == EM_MACH && /* architecture match? */
|
||||
elf->e_phnum > 0) { /* has program headers? */
|
||||
/* load segments */
|
||||
for(phdr = (Elf64_Phdr *)(buff + elf->e_phoff), i = 0;
|
||||
i < elf->e_phnum;
|
||||
i++, phdr = (Elf64_Phdr *)((uint8_t *)phdr + elf->e_phentsize)) {
|
||||
if(phdr->p_type == PT_LOAD) {
|
||||
printf("ELF segment %p %d bytes (bss %d bytes)\n", phdr->p_vaddr, phdr->p_filesz,
|
||||
phdr->p_memsz - phdr->p_filesz);
|
||||
memcpy((void*)phdr->p_vaddr, buff + phdr->p_offset, phdr->p_filesz);
|
||||
memset((void*)(phdr->p_vaddr + phdr->p_filesz), 0, phdr->p_memsz - phdr->p_filesz);
|
||||
}
|
||||
}
|
||||
entry = elf->e_entry;
|
||||
} else {
|
||||
fprintf(stderr, "not a valid ELF executable for this architecture\n");
|
||||
return 0;
|
||||
}
|
||||
/* free resources */
|
||||
free(buff);
|
||||
|
||||
/* execute the "kernel" */
|
||||
printf("ELF entry point %p\n", entry);
|
||||
i = (*((int(* __attribute__((sysv_abi)))(void))(entry)))();
|
||||
printf("ELF returned %d\n", i);
|
||||
|
||||
return 0;
|
||||
}
|
21
examples/0E_elfload/kernel/Makefile
Normal file
21
examples/0E_elfload/kernel/Makefile
Normal file
|
@ -0,0 +1,21 @@
|
|||
ARCH = x86_64
|
||||
TARGET = ../kernel.elf
|
||||
SRCS = kernel.c
|
||||
|
||||
all: $(TARGET)
|
||||
|
||||
ifeq ($(USE_GCC),)
|
||||
CC = clang -target $(ARCH)-elf
|
||||
LD = ld.lld
|
||||
else
|
||||
CC = $(ARCH)-elf-gcc
|
||||
LD = $(ARCH)-elf-ld
|
||||
endif
|
||||
|
||||
# UEFI wastes lots and lots of memory. Link our "kernel" at an address (32M) which isn't used by UEFI
|
||||
$(TARGET): kernel.c
|
||||
$(CC) -ffreestanding -fno-stack-protector -fno-stack-check -D__$(ARCH)__ -I. -c $< -o kernel.o
|
||||
$(LD) -nostdlib -z max-page-size=0x1000 -Ttext=0x01000000 kernel.o -o $(TARGET)
|
||||
|
||||
clean:
|
||||
rm *.o $(TARGET) 2>/dev/null || true
|
7
examples/0E_elfload/kernel/kernel.c
Normal file
7
examples/0E_elfload/kernel/kernel.c
Normal file
|
@ -0,0 +1,7 @@
|
|||
/**
|
||||
* Example "kernel"
|
||||
*/
|
||||
int _start()
|
||||
{
|
||||
return 42;
|
||||
}
|
BIN
examples/0E_elfload/screenshot.png
Normal file
BIN
examples/0E_elfload/screenshot.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.3 KiB |
1
examples/0E_elfload/uefi
Symbolic link
1
examples/0E_elfload/uefi
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../uefi
|
9
examples/0F_exit_bs/Makefile
Normal file
9
examples/0F_exit_bs/Makefile
Normal file
|
@ -0,0 +1,9 @@
|
|||
TARGET = exit_bs.efi
|
||||
SRCS = exit_bs.c
|
||||
EXTRA = kernel.elf
|
||||
|
||||
USE_GCC=1
|
||||
include uefi/Makefile
|
||||
|
||||
kernel.elf:
|
||||
@make -C kernel all USE_GCC=$(USE_GCC)
|
47
examples/0F_exit_bs/elf.h
Normal file
47
examples/0F_exit_bs/elf.h
Normal file
|
@ -0,0 +1,47 @@
|
|||
/*** ELF64 defines and structs ***/
|
||||
#define ELFMAG "\177ELF"
|
||||
#define SELFMAG 4
|
||||
#define EI_CLASS 4 /* File class byte index */
|
||||
#define ELFCLASS64 2 /* 64-bit objects */
|
||||
#define EI_DATA 5 /* Data encoding byte index */
|
||||
#define ELFDATA2LSB 1 /* 2's complement, little endian */
|
||||
#define ET_EXEC 2 /* Executable file */
|
||||
#define PT_LOAD 1 /* Loadable program segment */
|
||||
|
||||
#ifdef __x86_64__
|
||||
#define EM_MACH 62 /* AMD x86-64 architecture */
|
||||
#endif
|
||||
|
||||
#ifdef __aarch64__
|
||||
#define EM_MACH 183 /* ARM aarch64 architecture */
|
||||
#endif
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t e_ident[16]; /* Magic number and other info */
|
||||
uint16_t e_type; /* Object file type */
|
||||
uint16_t e_machine; /* Architecture */
|
||||
uint32_t e_version; /* Object file version */
|
||||
uint64_t e_entry; /* Entry point virtual address */
|
||||
uint64_t e_phoff; /* Program header table file offset */
|
||||
uint64_t e_shoff; /* Section header table file offset */
|
||||
uint32_t e_flags; /* Processor-specific flags */
|
||||
uint16_t e_ehsize; /* ELF header size in bytes */
|
||||
uint16_t e_phentsize; /* Program header table entry size */
|
||||
uint16_t e_phnum; /* Program header table entry count */
|
||||
uint16_t e_shentsize; /* Section header table entry size */
|
||||
uint16_t e_shnum; /* Section header table entry count */
|
||||
uint16_t e_shstrndx; /* Section header string table index */
|
||||
} Elf64_Ehdr;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t p_type; /* Segment type */
|
||||
uint32_t p_flags; /* Segment flags */
|
||||
uint64_t p_offset; /* Segment file offset */
|
||||
uint64_t p_vaddr; /* Segment virtual address */
|
||||
uint64_t p_paddr; /* Segment physical address */
|
||||
uint64_t p_filesz; /* Segment size in file */
|
||||
uint64_t p_memsz; /* Segment size in memory */
|
||||
uint64_t p_align; /* Segment alignment */
|
||||
} Elf64_Phdr;
|
155
examples/0F_exit_bs/exit_bs.c
Normal file
155
examples/0F_exit_bs/exit_bs.c
Normal file
|
@ -0,0 +1,155 @@
|
|||
#include <uefi.h>
|
||||
#include "kernel/bootparam.h"
|
||||
|
||||
/*** ELF64 defines and structs ***/
|
||||
#define ELFMAG "\177ELF"
|
||||
#define SELFMAG 4
|
||||
#define EI_CLASS 4 /* File class byte index */
|
||||
#define ELFCLASS64 2 /* 64-bit objects */
|
||||
#define EI_DATA 5 /* Data encoding byte index */
|
||||
#define ELFDATA2LSB 1 /* 2's complement, little endian */
|
||||
#define ET_EXEC 2 /* Executable file */
|
||||
#define PT_LOAD 1 /* Loadable program segment */
|
||||
#ifdef __x86_64__
|
||||
#define EM_MACH 62 /* AMD x86-64 architecture */
|
||||
#endif
|
||||
#ifdef __aarch64__
|
||||
#define EM_MACH 183 /* ARM aarch64 architecture */
|
||||
#endif
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t e_ident[16]; /* Magic number and other info */
|
||||
uint16_t e_type; /* Object file type */
|
||||
uint16_t e_machine; /* Architecture */
|
||||
uint32_t e_version; /* Object file version */
|
||||
uint64_t e_entry; /* Entry point virtual address */
|
||||
uint64_t e_phoff; /* Program header table file offset */
|
||||
uint64_t e_shoff; /* Section header table file offset */
|
||||
uint32_t e_flags; /* Processor-specific flags */
|
||||
uint16_t e_ehsize; /* ELF header size in bytes */
|
||||
uint16_t e_phentsize; /* Program header table entry size */
|
||||
uint16_t e_phnum; /* Program header table entry count */
|
||||
uint16_t e_shentsize; /* Section header table entry size */
|
||||
uint16_t e_shnum; /* Section header table entry count */
|
||||
uint16_t e_shstrndx; /* Section header string table index */
|
||||
} Elf64_Ehdr;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t p_type; /* Segment type */
|
||||
uint32_t p_flags; /* Segment flags */
|
||||
uint64_t p_offset; /* Segment file offset */
|
||||
uint64_t p_vaddr; /* Segment virtual address */
|
||||
uint64_t p_paddr; /* Segment physical address */
|
||||
uint64_t p_filesz; /* Segment size in file */
|
||||
uint64_t p_memsz; /* Segment size in memory */
|
||||
uint64_t p_align; /* Segment alignment */
|
||||
} Elf64_Phdr;
|
||||
|
||||
/**
|
||||
* Load an ELF executable and pass control over for good
|
||||
*/
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
FILE *f;
|
||||
char *buff;
|
||||
long int size;
|
||||
Elf64_Ehdr *elf;
|
||||
Elf64_Phdr *phdr;
|
||||
uintptr_t entry;
|
||||
bootparam_t bootp;
|
||||
efi_status_t status;
|
||||
efi_guid_t gopGuid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
|
||||
efi_gop_t *gop = NULL;
|
||||
efi_gop_mode_info_t *info = NULL;
|
||||
uintn_t isiz = sizeof(efi_gop_mode_info_t);
|
||||
int i, j;
|
||||
|
||||
/* load the file */
|
||||
if((f = fopen("\\0F_exit_bs\\kernel.elf", "r"))) {
|
||||
fseek(f, 0, SEEK_END);
|
||||
size = ftell(f);
|
||||
fseek(f, 0, SEEK_SET);
|
||||
buff = malloc(size + 1);
|
||||
if(!buff) {
|
||||
fprintf(stderr, "unable to allocate memory\n");
|
||||
return 1;
|
||||
}
|
||||
fread(buff, size, 1, f);
|
||||
fclose(f);
|
||||
} else {
|
||||
fprintf(stderr, "Unable to open file\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* set up boot parameters passed to the "kernel" */
|
||||
memset(&bootp, 0, sizeof(bootparam_t));
|
||||
status = BS->LocateProtocol(&gopGuid, NULL, (void**)&gop);
|
||||
if(!EFI_ERROR(status) && gop) {
|
||||
status = gop->SetMode(gop, 0);
|
||||
ST->ConOut->Reset(ST->ConOut, 0);
|
||||
ST->StdErr->Reset(ST->StdErr, 0);
|
||||
if(EFI_ERROR(status)) {
|
||||
fprintf(stderr, "unable to set video mode\n");
|
||||
return 0;
|
||||
}
|
||||
bootp.framebuffer = (unsigned int*)gop->Mode->FrameBufferBase;
|
||||
bootp.width = gop->Mode->Information->HorizontalResolution;
|
||||
bootp.height = gop->Mode->Information->VerticalResolution;
|
||||
bootp.pitch = sizeof(unsigned int) * gop->Mode->Information->PixelsPerScanLine;
|
||||
} else {
|
||||
fprintf(stderr, "unable to get graphics output protocol\n");
|
||||
return 0;
|
||||
}
|
||||
if(argc > 1) {
|
||||
bootp.argc = argc - 1;
|
||||
bootp.argv = (char**)malloc(argc * sizeof(char*));
|
||||
if(bootp.argv) {
|
||||
for(i = 0; i < bootp.argc; i++)
|
||||
if((bootp.argv[i] = (char*)malloc(strlen(argv[i + 1]) + 1)))
|
||||
strcpy(bootp.argv[i], argv[i + 1]);
|
||||
bootp.argv[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* is it a valid ELF executable for this architecture? */
|
||||
elf = (Elf64_Ehdr *)buff;
|
||||
if(!memcmp(elf->e_ident, ELFMAG, SELFMAG) && /* magic match? */
|
||||
elf->e_ident[EI_CLASS] == ELFCLASS64 && /* 64 bit? */
|
||||
elf->e_ident[EI_DATA] == ELFDATA2LSB && /* LSB? */
|
||||
elf->e_type == ET_EXEC && /* executable object? */
|
||||
elf->e_machine == EM_MACH && /* architecture match? */
|
||||
elf->e_phnum > 0) { /* has program headers? */
|
||||
/* load segments */
|
||||
for(phdr = (Elf64_Phdr *)(buff + elf->e_phoff), i = 0;
|
||||
i < elf->e_phnum;
|
||||
i++, phdr = (Elf64_Phdr *)((uint8_t *)phdr + elf->e_phentsize)) {
|
||||
if(phdr->p_type == PT_LOAD) {
|
||||
memcpy((void*)phdr->p_vaddr, buff + phdr->p_offset, phdr->p_filesz);
|
||||
memset((void*)(phdr->p_vaddr + phdr->p_filesz), 0, phdr->p_memsz - phdr->p_filesz);
|
||||
}
|
||||
}
|
||||
entry = elf->e_entry;
|
||||
} else {
|
||||
fprintf(stderr, "not a valid ELF executable for this architecture\n");
|
||||
return 0;
|
||||
}
|
||||
/* free resources */
|
||||
free(buff);
|
||||
|
||||
/* exit this UEFI bullshit */
|
||||
if(exit_bs()) {
|
||||
fprintf(stderr,
|
||||
"Ph'nglui mglw'nafh Chtulu R'lyeh wgah'nagl fhtagn\n"
|
||||
"(Hastur has a hold on us and won't let us go)\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* execute the "kernel" */
|
||||
(*((void(* __attribute__((sysv_abi)))(bootparam_t *))(entry)))(&bootp);
|
||||
/* failsafe, should never return just in case */
|
||||
while(1);
|
||||
|
||||
return 0;
|
||||
}
|
21
examples/0F_exit_bs/kernel/Makefile
Normal file
21
examples/0F_exit_bs/kernel/Makefile
Normal file
|
@ -0,0 +1,21 @@
|
|||
ARCH = x86_64
|
||||
TARGET = ../kernel.elf
|
||||
SRCS = kernel.c
|
||||
|
||||
all: $(TARGET)
|
||||
|
||||
ifeq ($(USE_GCC),)
|
||||
CC = clang -target $(ARCH)-elf
|
||||
LD = ld.lld
|
||||
else
|
||||
CC = $(ARCH)-elf-gcc
|
||||
LD = $(ARCH)-elf-ld
|
||||
endif
|
||||
|
||||
# UEFI wastes lots and lots of memory. Link our "kernel" at an address (32M) which isn't used by UEFI
|
||||
$(TARGET): kernel.c
|
||||
$(CC) -ffreestanding -fno-stack-protector -fno-stack-check -D__$(ARCH)__ -I. -c $< -o kernel.o
|
||||
$(LD) -nostdlib -z max-page-size=0x1000 -Ttext=0x01000000 kernel.o -o $(TARGET)
|
||||
|
||||
clean:
|
||||
rm *.o $(TARGET) 2>/dev/null || true
|
11
examples/0F_exit_bs/kernel/bootparam.h
Normal file
11
examples/0F_exit_bs/kernel/bootparam.h
Normal file
|
@ -0,0 +1,11 @@
|
|||
/**
|
||||
* Struct passed to the "kernel" from the exit_bs loader
|
||||
*/
|
||||
typedef struct {
|
||||
unsigned int *framebuffer;
|
||||
unsigned int width;
|
||||
unsigned int height;
|
||||
unsigned int pitch;
|
||||
int argc;
|
||||
char **argv;
|
||||
} bootparam_t;
|
86
examples/0F_exit_bs/kernel/kernel.c
Normal file
86
examples/0F_exit_bs/kernel/kernel.c
Normal file
File diff suppressed because one or more lines are too long
BIN
examples/0F_exit_bs/screenshot.png
Normal file
BIN
examples/0F_exit_bs/screenshot.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 560 B |
1
examples/0F_exit_bs/uefi
Symbolic link
1
examples/0F_exit_bs/uefi
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../uefi
|
Loading…
Reference in a new issue