Skip to content

Commit

Permalink
feat: load kernel
Browse files Browse the repository at this point in the history
  • Loading branch information
sanchezcarlosjr committed Aug 19, 2022
1 parent 50d3c2d commit 3627184
Show file tree
Hide file tree
Showing 7 changed files with 279 additions and 27 deletions.
3 changes: 2 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
cest.img:
cp /usr/share/edk2-ovmf/x64/OVMF_VARS.fd ./OVMF_VARS.fd
cd src && make && mv cest.efi ../cest.efi
cd src && make && mv cest.efi ../cest.efi && mv kernel.elf ../kernel.elf
mkdir -p EFI/BOOT/
mv cest.efi EFI/BOOT/BOOTX64.efi
mv kernel.elf EFI/BOOT/kernel.elf
dd if=/dev/zero of=cest.img bs=512 count=93750
parted cest.img -s -a minimal mklabel gpt
parted cest.img -s -a minimal mkpart EFI FAT16 2048s 93716s
Expand Down
21 changes: 6 additions & 15 deletions src/Makefile
Original file line number Diff line number Diff line change
@@ -1,18 +1,9 @@
# define which architecture you're targeting
ARCH = x86_64
# define your target file here
TARGET = cest.efi
#define your sources here
SRCS = $(wildcard *.c)
# define your default compiler flags
CFLAGS = -pedantic -Wall -Wextra -Werror --ansi -O2
# define your default linker flags
#LDFLAGS =
# define your additional libraries here
#LIBS = -lm
SRCS = exit_bs.c
ALSO = kernel.elf

# leave the hard work and all the rest to posix-uefi

# set this if you want GNU gcc + ld + objcopy instead of LLVM Clang + Lld
#USE_GCC = 1
#USE_GCC=1
include uefi/Makefile

kernel.elf:
@make -C kernel all USE_GCC=$(USE_GCC)
153 changes: 153 additions & 0 deletions src/exit_bs.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
#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;
int i;

/* load the file */
if((f = fopen("\\EFI\\BOOT\\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;
}
11 changes: 0 additions & 11 deletions src/helloworld.c

This file was deleted.

21 changes: 21 additions & 0 deletions src/kernel/Makefile
Original file line number Diff line number Diff line change
@@ -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 changes: 11 additions & 0 deletions src/kernel/bootparam.h
Original file line number Diff line number Diff line change
@@ -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 changes: 86 additions & 0 deletions src/kernel/kernel.c

Large diffs are not rendered by default.

0 comments on commit 3627184

Please sign in to comment.