- TARGET = kernel.efi
+ ARCH = x86_64
+ EFIARCH = efi-app-$(ARCH)
+ TARGET = BOOTX64.EFI
+
+OVMF = /usr/share/qemu/OVMF.fd
- #OVMF = /usr/share/edk2-ovmf/OVMF_CODE.fd
+
- include uefi/Makefile
+ CC = gcc
+ LD = ld
+ OBJCOPY = objcopy
+ AR = ar
+
+ CFLAGS = \
+ -fshort-wchar \
+ -fno-strict-aliasing \
+ -ffreestanding \
+ -fno-stack-protector \
+ -fno-stack-check \
+ -mno-red-zone \
+ -maccumulate-outgoing-args \
+ -Wno-builtin-declaration-mismatch \
+ -fpic \
+ -fPIC
+
+ CPPFLAGS = \
+ -I./core/ \
+ -I./uefi \
+ -I/usr/include \
+ -D__$(ARCH)__ \
+ -DHAVE_USE_MS_ABI
+
+ LDFLAGS = \
+ -nostdlib \
+ -shared \
+ -Bsymbolic \
+ -Luefi
+
+ LIBS = \
+ -o $(TARGET).so \
+ -T uefi/elf_$(ARCH)_efi.lds
- .PHONY: all run clean
+ # get source files, generate object names
+ SRCS = $(wildcard core/*.c uefi/*.c)
+ OBJS = $(SRCS:.c=.o)
- all: boot.img
+ .PHONY: all clean run
+
+ all: $(TARGET)
clean:
find -name '*.o' -delete
#define FONT_HEIGHT 16
extern uint8_t Font[];
- struct Video {
- uint32_t* buffer;
- uint32_t stride;
- };
-
- extern struct Video Video;
-
- void Video_Init(void);
--void Video_PutGlyph(int x, int y, char c);
--
static inline void Video_PutPixel(int x, int y, uint32_t pixel)
{
- int offset = (sizeof(pixel) * Video.stride * y) + (sizeof(pixel) * x);
- *(Video.buffer + offset) = pixel;
+ Video.buffer[Video.stride * y + x] = pixel;
}
+ /*
+ Terminal/Console Driver
+ */
++void Term_Init(void);
void Term_Clear(void);
void Term_PutChar(int c);
void Term_PutString(char* s);
--- /dev/null
-// BS->Stall(1000000);
+ #include <platform.h>
++#include <kernel.h>
+
+ int main (int argc, char** argv)
+ {
++ Term_Init();
+
+ /* loop forever */
+ for (;;)
+ {
++ Term_PutString("foo\n");
++ sleep(250);
++ Term_PutString("bar\n");
++ sleep(250);
++ Term_PutString("baz\n");
++ sleep(250);
+ }
+
+ return 0;
+ }
- #include <uefi.h>
+ #include <platform.h>
+ #include <kernel.h>
+
++#define MAX_COLS 240
++#define MAX_ROWS 75
+
static char* Digits = "0123456789abcdef";
- (x * FONT_WIDTH) + col,
- (y * FONT_HEIGHT) + row,
++struct {
++ int cols;
++ int rows;
++ int cursor;
++ char cells[MAX_ROWS * MAX_COLS];
++} Term = { 0 };
++
+ static void PutGlyph(int x, int y, char c)
+ {
+ char* glyph = &Font[c * FONT_HEIGHT];
+ for (int row = 0; row < 16; row++)
+ {
+ char piece = glyph[row];
+ for (int col = 0; col < 8; col++, piece <<= 1)
+ {
+ Video_PutPixel(
++ x + col,
++ y + row,
+ (piece & 0x80) ? 0xFFFFFFFF : 0x00000000);
+ }
+ }
+ }
+
++static void PutCell(int c)
++{
++ int max = Term.rows * Term.cols;
++ /* check if we need to scroll and do it */
++ if (Term.cursor >= max)
++ {
++ int dst = 0;
++ int src = Term.cols;
++ Term.cursor = (Term.rows - 1) * Term.cols;
++ while (src < max)
++ {
++ PutGlyph((dst % Term.cols) * 8, (dst / Term.rows) * 16, Term.cells[src]);
++ Term.cells[dst++] = Term.cells[src++];
++ }
++ for (int i = Term.cursor; i < Term.cols; i++)
++ {
++ PutGlyph((i % Term.cols) * 8, (i / Term.rows) * 16, ' ');
++ Term.cells[i] = ' ';
++ }
++ }
++ /* now place the new glyph */
++ Term.cells[Term.cursor] = c;
++ int row = (Term.cursor / Term.cols);
++ int col = (Term.cursor % Term.cols);
++ PutGlyph(col * 8, row * 16, c);
++ Term.cursor++;
++}
++
++void Term_Init(void)
++{
++ Term.cols = min(Video.width / FONT_WIDTH, MAX_COLS);
++ Term.rows = min(Video.height / FONT_HEIGHT, MAX_ROWS);
++}
+
void Term_PutChar(int c)
{
- wchar_t tmp[2] = { (wchar_t)c, 0 };
- ST->ConOut->OutputString(ST->ConOut, (c == '\n' ? (wchar_t*)L"\r\n" : tmp));
-// wchar_t tmp[2] = { (wchar_t)c, 0 };
-// ST->ConOut->OutputString(ST->ConOut, (c == '\n' ? (wchar_t*)L"\r\n" : tmp));
++ switch (c)
++ {
++ case '\r':
++ Term.cursor = (Term.cursor / Term.cols) * Term.cols;
++ break;
++
++ case '\n':
++ Term.cursor = (Term.cursor / Term.cols) * Term.cols;
++ Term.cursor += Term.cols;
++ break;
++
++ default:
++ PutCell(c);
++ break;
++ }
}
void Term_PutString(char* s)
+ #include <platform.h>
+ #include <uefi.h>
+
+ /* this is implemented by the application */
+ extern int main(void);
+
+ /* globals to store system table pointers */
+ static efi_handle_t IM = NULL;
+ static efi_system_table_t *ST = NULL;
+ static efi_boot_services_t *BS = NULL;
+ static efi_runtime_services_t *RT = NULL;
+ static efi_loaded_image_protocol_t *LIP = NULL;
+
+ /* platform specific globals */
+ VideoConfig Video = {0};
+
++void sleep(int ms)
++{
++ BS->Stall(ms * 1000);
++}
++
+ static void video_init(void)
+ {
+ /* get a handle to the graphics protocol */
+ efi_gop_t *gop = NULL;
+ efi_guid_t gopGuid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
+ BS->LocateProtocol(&gopGuid, NULL, (void**)&gop);
+
+ /* query mode 0 to see if mode needs to be set first */
+ uintn_t info_size = 0;
+ efi_gop_mode_info_t *info = NULL;
+ uintn_t status = gop->QueryMode(gop, 0, &info_size, &info);
+
+ /* some machines need mode set explicitly first */
+ if (status == EFI_NOT_STARTED)
+ {
+ status = gop->SetMode(gop, 0);
+ }
+
+ /*
+ OK, now we have real info for possible modes, pick the max mode.
+ We assume this one is the best resolution.
+ */
+ if (status == EFI_SUCCESS)
+ {
+ status = gop->SetMode(gop, 17); /* pick a smaller resolution for QEMU */
+ // status = gop->SetMode(gop, gop->Mode->MaxMode-1);
+ }
+
+ /*
+ Now let's save off the info we need to draw pixels and glyphs.
+ The code in this file assumes 32 bits per pixel.
+ */
+ Video.buffer = (uint32_t*)(gop->Mode->FrameBufferBase);
+ Video.stride = gop->Mode->Information->PixelsPerScanLine;
++ Video.width = gop->Mode->Information->HorizontalResolution;
++ Video.height = gop->Mode->Information->VerticalResolution;
+ }
+
/*
- * crt_x86_64.c
+ * crt_x86_64.c : bootstrap() and uefi_init()
*
* Copyright (C) 2021 bzt (bztsrc@gitlab)
*
--- /dev/null
-extern VideoConfig Video;
+ /* define standard type definitions */
+ typedef char int8_t;
+ typedef unsigned char uint8_t;
+ typedef short int16_t;
+ typedef unsigned short uint16_t;
+ typedef int int32_t;
+ typedef unsigned int uint32_t;
+ typedef long long int64_t;
+ typedef unsigned long long uint64_t;
+ typedef long long intptr_t;
+ typedef unsigned long long uintptr_t;
+
+ /* sanity check type definitions */
+ extern char check_u16[sizeof(uint16_t) == 2 ? 1 : -1];
+ extern char check_u32[sizeof(uint32_t) == 4 ? 1 : -1];
+ extern char check_u64[sizeof(uint64_t) == 8 ? 1 : -1];
+ extern char check_uptr[sizeof(uintptr_t) == 8 ? 1 : -1];
+
+ #define NULL ((void*)0)
+ #define abs(x) ((x)<0?-(x):(x))
+ #define min(x,y) ((x)<(y)?(x):(y))
+ #define max(x,y) ((x)>(y)?(x):(y))
+
+ /* video memory configuration info */
+ typedef struct {
+ uint32_t* buffer;
+ uint32_t stride;
+ uint32_t width;
+ uint32_t height;
+ } VideoConfig;
+
++extern VideoConfig Video;
++
++void sleep(int ms);