Added UEFI application as loader for the 64bit kernel.

This commit is contained in:
Patrick 2024-01-15 09:48:48 +01:00
parent cd20e87196
commit 474090d4a0
21 changed files with 1101 additions and 495 deletions

7
.gitignore vendored
View File

@ -1,8 +1,13 @@
# Staging Folder
staging/
# Project Folder (at least for now)
.idea
# Compiled Binaries and ISOs
# Compiled Binaries and Images
*.bin
*.efi
*.img
*.iso
# Compile Commands

View File

@ -14,27 +14,13 @@ AddOption(
target = GetOption('target')
env = Environment(tools = ['default', 'compilation_db'])
env.Append(CFLAGS = ['-ffreestanding'])
env.Append(CXXFLAGS = ['-ffreestanding', '-fno-exceptions', '-fno-rtti', '-std=c++20'])
env.Append(LINKFLAGS = ['-T', 'linker.ld', '-ffreestanding', '-nostdlib'])
env.Append(CPPPATH = ['#targets/_any/include', '#bastl/include'])
env.Append(CCFLAGS = ['-g', '-O0'])
env['KERNEL_SOURCES'] = []
env['KERNEL_DEPENDENCIES'] = []
env['ISO_FILES'] = []
env = SConscript('bastl/SConscript', exports = 'env')
env = SConscript('targets/_any/SConscript', exports = 'env')
env = SConscript(f'targets/{target}/SConscript', exports = 'env')
prog_os = env.Program(
target = 'os.bin',
source = env['KERNEL_SOURCES'],
LIBS = ['gcc'],
LINKCOM = env['KERNEL_LINKCOM']
)
env.Depends(prog_os, env['KERNEL_DEPENDENCIES'])
env.Default(prog_os)
comp_db = env.CompilationDatabase(target = '#compile_commands.json')
env.Default(comp_db)

View File

@ -1,42 +1,54 @@
Import('env')
env['AS'] = 'i686-elf-as'
env['CC'] = 'i686-elf-gcc'
env['CXX'] = 'i686-elf-g++'
env['LD'] = 'i686-elf-g++'
kernel_env = env.Clone()
kernel_env['AS'] = 'i686-elf-as'
kernel_env['CC'] = 'i686-elf-gcc'
kernel_env['CXX'] = 'i686-elf-g++'
kernel_env['LD'] = 'i686-elf-g++'
kernel_env.Append(CFLAGS = ['-ffreestanding'])
kernel_env.Append(CXXFLAGS = ['-ffreestanding', '-fno-exceptions', '-fno-rtti', '-std=c++20'])
kernel_env.Append(LINKFLAGS = ['-T', kernel_env.File('linker.ld').abspath, '-ffreestanding', '-nostdlib'])
kernel_env.Append(CPPPATH = ['#targets/_any/include', '#bastl/include'])
def get_crt_object(name: str) -> str:
import subprocess
cmd = [env['CXX']]
cmd.extend(env['CXXFLAGS'])
cmd = [kernel_env['CXX']]
cmd.extend(kernel_env['CXXFLAGS'])
cmd.append(f'-print-file-name={name}')
result = subprocess.run(cmd, stdout=subprocess.PIPE)
return result.stdout.decode('utf-8').strip()
crtbegin_o = get_crt_object('crtbegin.o')
crtend_o = get_crt_object('crtend.o')
crti_o = env.Object('src/crt/crti.s')
crtn_o = env.Object('src/crt/crtn.s')
env['KERNEL_LINKCOM'] = env['LINKCOM'].replace('$_LIBFLAGS', f'{crti_o[0].abspath} {crtbegin_o} $_LIBFLAGS {crtend_o} {crtn_o[0].abspath}')
crti_o = kernel_env.Object('src/crt/crti.s')
crtn_o = kernel_env.Object('src/crt/crtn.s')
kernel_env['LINKCOM'] = env['LINKCOM'].replace('$_LIBFLAGS', f'{crti_o[0].abspath} {crtbegin_o} $_LIBFLAGS {crtend_o} {crtn_o[0].abspath}')
i686_sources = Split('''
kernel_sources = env['KERNEL_SOURCES'] + Split('''
src/kernel/boot.s
src/kernel/startup.cpp
''')
prog_kernel = kernel_env.Program(
target = '#kernel.i686.bin',
source = kernel_sources,
LIBS = ['gcc']
)
kernel_env.Depends(prog_kernel, [crti_o, crtn_o])
kernel_env.Default(prog_kernel)
i686_iso_files = [
{
"source": env.File("boot/grub.cfg"),
"source": kernel_env.File("boot/grub.cfg"),
"target": "boot/grub/grub.cfg"
},
{
"source": env.File("#os.bin"),
"source": kernel_env.File("#os.bin"),
"target": "boot/os.bin"
}
]
env.Append(KERNEL_SOURCES = [env.File(f) for f in i686_sources])
env.Append(KERNEL_DEPENDENCIES = [crti_o, crtn_o])
env.Append(ISO_FILES = i686_iso_files)
Return('env')

View File

@ -1,28 +1,44 @@
Import('env')
env['AS'] = 'x86_64-elf-as'
env['CC'] = 'x86_64-elf-gcc'
env['CXX'] = 'x86_64-elf-g++'
env['LD'] = 'x86_64-elf-g++'
### Kernel
kernel_env = env.Clone()
kernel_env['AS'] = 'x86_64-elf-as'
kernel_env['CC'] = 'x86_64-elf-gcc'
kernel_env['CXX'] = 'x86_64-elf-g++'
kernel_env['LD'] = 'x86_64-elf-g++'
kernel_env.Append(CFLAGS = ['-ffreestanding'])
kernel_env.Append(CXXFLAGS = ['-ffreestanding', '-fno-exceptions', '-fno-rtti', '-std=c++20'])
kernel_env.Append(LINKFLAGS = ['-T', kernel_env.File('linker.ld').abspath, '-ffreestanding', '-nostdlib', '-mcmodel=large', '-mno-red-zone', '-mno-mmx', '-mno-sse', '-mno-sse2'])
kernel_env.Append(CPPPATH = ['#targets/_any/include', '#bastl/include'])
def get_crt_object(name: str) -> str:
import subprocess
cmd = [env['CXX']]
cmd.extend(env['CXXFLAGS'])
cmd = [kernel_env['CXX']]
cmd.extend(kernel_env['CXXFLAGS'])
cmd.append(f'-print-file-name={name}')
result = subprocess.run(cmd, stdout=subprocess.PIPE)
return result.stdout.decode('utf-8').strip()
crtbegin_o = get_crt_object('crtbegin.o')
crtend_o = get_crt_object('crtend.o')
crti_o = env.Object('src/crt/crti.s')
crtn_o = env.Object('src/crt/crtn.s')
crti_o = kernel_env.Object('src/crt/crti.s')
crtn_o = kernel_env.Object('src/crt/crtn.s')
kernel_env['LINKCOM'] = env['LINKCOM'].replace('$_LIBFLAGS', f'{crti_o[0].abspath} {crtbegin_o} $_LIBFLAGS -lgcc {crtend_o} {crtn_o[0].abspath}')
x86_64_sources = Split('''
kernel_sources = env['KERNEL_SOURCES'] + Split('''
src/kernel/boot.s
src/kernel/startup.cpp
''')
env['KERNEL_LINKCOM'] = env['LINKCOM'].replace('$_LIBFLAGS', f'{crti_o[0].abspath} {crtbegin_o} $_LIBFLAGS {crtend_o} {crtn_o[0].abspath}')
kernel_target = kernel_env.File('#kernel.x86_64.bin')
prog_kernel = kernel_env.Program(
target = kernel_target,
source = kernel_sources
)
kernel_env.Depends(prog_kernel, [crti_o, crtn_o])
kernel_env.Default(prog_kernel)
x86_64_iso_files = [
{
@ -39,19 +55,77 @@ x86_64_iso_files = [
}
]
# also compile the loader (as i686-elf)
### UEFI Loader
uefi_env = env.Clone()
uefi_env['AS'] = 'x86_64-w64-mingw32-as'
uefi_env['CC'] = 'x86_64-w64-mingw32-gcc'
uefi_env['CXX'] = 'x86_64-w64-mingw32-g++'
uefi_env['LD'] = 'x86_64-w64-mingw32-g++'
uefi_env.Append(CFLAGS = ['-ffreestanding'])
uefi_env.Append(CXXFLAGS = ['-ffreestanding', '-fno-exceptions', '-fno-rtti', '-std=c++20'])
uefi_env.Append(LINKFLAGS = ['-nostdlib', '-Wl,-dll', '-shared', '-Wl,--subsystem,10', '-e', 'efi_main'])
uefi_env.Append(CPPPATH = ['/usr/include/efi'])
loader_sources = Split('''
src/loader/boot.asm
src/loader/data.c
src/loader/main.cpp
src/loader/minimalloc.cpp
src/loader/miniprintf.cpp
''')
nasm_include_dir = env.Dir('src/loader')
prog_loader = env.Command(
'#loader.bin', 'src/loader/boot.asm', f'nasm -I"{nasm_include_dir.abspath}" "$SOURCE" -f bin -o "$TARGET"'
loader_target = uefi_env.File('#loader.x86_64.efi')
prog_loader = uefi_env.Program(
target = loader_target,
source = loader_sources
)
uefi_env.Default(prog_loader)
### Bootable Image
def runcmd(*args, **kwargs):
from subprocess import run
run(*args, **kwargs, check=True)
def build_img(target, source, env):
fatfile = target[0].abspath
runcmd(['dd', 'if=/dev/zero', f'of={fatfile}', 'bs=1K', 'count=1440'])
runcmd(['mformat', '-i', fatfile, '-f', '1440', '::'])
runcmd(['mmd', '-i', fatfile, '::/EFI'])
runcmd(['mmd', '-i', fatfile, '::/EFI/BOOT'])
runcmd(['mcopy', '-i', fatfile, loader_target.abspath, '::/EFI/BOOT/BOOTX64.EFI'])
runcmd(['mcopy', '-i', fatfile, kernel_target.abspath, '::/kernel.bin'])
img_target = env.File('#boot.x86_64.fat.img')
cmd_image = env.Command(
target = img_target,
source = [prog_kernel, prog_loader],
action = build_img
)
def build_iso(target, source, env):
import os
import shutil
isofile = target[0].abspath
# prepare the staging folder
staging_dir = env.Dir('#staging/x86_64_iso').abspath
shutil.rmtree(staging_dir, ignore_errors=True)
os.makedirs(staging_dir)
# copy files to the staging folder
shutil.copy(img_target.abspath, os.path.join(staging_dir, 'fat.img'))
runcmd(['xorriso', '-as', 'mkisofs', '-R', '-f', '-e', 'fat.img', '-no-emul-boot', '-o', target[0].abspath, staging_dir])
iso_target = env.File('#system.x86_64.iso')
cmd_iso = env.Command(
target = iso_target,
source = [cmd_image],
action = build_iso
)
env.Default(cmd_iso)
# finally update the environment
env.Append(KERNEL_SOURCES = [env.File(f) for f in x86_64_sources])
env.Append(KERNEL_DEPENDENCIES = [crti_o, crtn_o, prog_loader])
env.Append(LINKFLAGS = ['-mcmodel=large', '-mno-red-zone', '-mno-mmx', '-mno-sse', '-mno-sse2'])
env.Append(ISO_FILES = x86_64_iso_files)
Return('env')

61
targets/x86_64/linker.ld Normal file
View File

@ -0,0 +1,61 @@
/* The bootloader will look at this image and start execution at the symbol
designated as the entry point. */
ENTRY(_start)
/* Tell where the various sections of the object files will be put in the final
kernel image. */
SECTIONS
{
/* It used to be universally recommended to use 1M as a start offset,
as it was effectively guaranteed to be available under BIOS systems.
However, UEFI has made things more complicated, and experimental data
strongly suggests that 2M is a safer place to load. In 2016, a new
feature was introduced to the multiboot2 spec to inform bootloaders
that a kernel can be loaded anywhere within a range of addresses and
will be able to relocate itself to run from such a loader-selected
address, in order to give the loader freedom in selecting a span of
memory which is verified to be available by the firmware, in order to
work around this issue. This does not use that feature, so 2M was
chosen as a safer option than the traditional 1M. */
. = 2M;
/* First put the multiboot header, as it is required to be put very early
in the image or the bootloader won't recognize the file format.
Next we'll put the .text section. */
.text BLOCK(4K) : ALIGN(4K)
{
*(.multiboot)
*(.text)
}
/* Read-only data. */
.rodata BLOCK(4K) : ALIGN(4K)
{
start_ctors = .;
*(SORT(.ctors*)) /* Note the "SORT" */
end_ctors = .;
start_dtors = .;
*(SORT(.dtors*))
end_dtors = .;
*(.rodata)
}
/* Read-write data (initialized) */
.data BLOCK(4K) : ALIGN(4K)
{
*(.data)
}
/* Read-write data (uninitialized) and stack */
.bss BLOCK(4K) : ALIGN(4K)
{
*(COMMON)
*(.bss)
}
/* The compiler may produce other sections, by default it will put them in
a segment with the same name. Simply add stuff here as needed. */
gKernelEnd = .;
}

View File

@ -1,10 +1,10 @@
/* x86 crti.s */
/* x86_64 crti.s */
.section .init
.global _init
.type _init, @function
_init:
push %rbp
movl %esp, %ebp
movq %rsp, %rbp
/* gcc will nicely put the contents of crtbegin.o's .init section here. */
.section .fini
@ -12,5 +12,5 @@ _init:
.type _fini, @function
_fini:
push %rbp
movl %esp, %ebp
/* gcc will nicely put the contents of crtbegin.o's .fini section here. */
movq %rsp, %rbp
/* gcc will nicely put the contents of crtbegin.o's .fini section here. */

View File

@ -1,10 +1,10 @@
/* x86 crtn.s */
/* x86_64 crtn.s */
.section .init
/* gcc will nicely put the contents of crtend.o's .init section here. */
pop %rbp
popq %rbp
ret
.section .fini
/* gcc will nicely put the contents of crtend.o's .fini section here. */
pop %rbp
popq %rbp
ret

View File

@ -1,16 +1,3 @@
// constants for the multiboot header
.set ALIGN, 1<<0 /* align loaded modules on page boundaries */
.set MEMINFO, 1<<1 /* provide memory map */
.set FLAGS, ALIGN | MEMINFO /* this is the Multiboot 'flag' field */
.set MAGIC, 0x1BADB002 /* 'magic number' lets bootloader find the header */
.set CHECKSUM, -(MAGIC + FLAGS) /* checksum of above, to prove we are multiboot */
// the actual multiboot header
.section .multiboot
.align 4
.long MAGIC
.long FLAGS
.long CHECKSUM
// stack section
.section .bss
@ -24,34 +11,13 @@ stack_top:
.global _start
.type _start, @function
_start:
/*
The bootloader has loaded us into 32-bit protected mode on a x86
machine. Interrupts are disabled. Paging is disabled. The processor
state is as defined in the multiboot standard. The kernel has full
control of the CPU. The kernel can only make use of hardware features
and any code it provides as part of itself. There's no printf
function, unless the kernel provides its own <stdio.h> header and a
printf implementation. There are no security restrictions, no
safeguards, no debugging mechanisms, only what the kernel provides
itself. It has absolute and complete power over the
machine.
*/
// store the multiboot info
mov %ebx, (gMultibootHeader)
mov %rbx, (gMultibootHeader)
// setup stack
mov $stack_top, %esp
mov $stack_top, %rsp
// call the constructors
mov $start_ctors, %ebx
jmp .ctors_loop_end
.ctors_loop_start:
call *(%ebx)
add 4, %ebx
.ctors_loop_end:
cmp $end_ctors, %ebx
jb .ctors_loop_start
call _init
// enter high-level kernel
call kernel_main

View File

@ -40,6 +40,22 @@ void initHeapFromMultibootHeader(const uint32_t firstEntryAddr, const size_t buf
addr += sizeof(entry.size) + entry.size;
}
}
using initfunc_t = void *();
extern "C" initfunc_t** start_ctors;
extern "C" initfunc_t** end_ctors;
void initGlobals()
{
for (initfunc_t** initFunc = start_ctors; initFunc != end_ctors; ++initFunc)
{
// TODO: this confuses me
if (*initFunc == reinterpret_cast<initfunc_t*>(0xffffffffffffffff)) {
break;
}
(*initFunc)();
}
}
}
extern "C"
@ -52,7 +68,7 @@ void main();
void kernel_main()
{
_init();
initGlobals();
/* Initialize terminal interface */
tty::initialize();
@ -60,8 +76,8 @@ void kernel_main()
std::printf("Kernel End: %p\n", &gKernelEnd);
/* Initialize the heap */
assert(gMultibootHeader->flags & MULTIBOOT_INFO_MEM_MAP);
initHeapFromMultibootHeader(gMultibootHeader->mmap_addr, gMultibootHeader->mmap_length);
// assert(gMultibootHeader->flags & MULTIBOOT_INFO_MEM_MAP);
// initHeapFromMultibootHeader(gMultibootHeader->mmap_addr, gMultibootHeader->mmap_length);
main();

View File

@ -1,37 +0,0 @@
;;; Code
[ORG 0x7c00] ; this is where NASM expects the code to be located (important for offsets and addresses)
jmp start
%include "print.inc"
start:
xor ax, ax ; sets AX to 0
mov ds, ax ; writes the 0 to DS (you can't directly write to DS) DS points to the "data segment"
mov ss, ax ; same as above, but now for the "stack segment"
mov sp, 0x9c00 ; initialize the stack
cld ; clear the direction flag (so lodsb increments si and doesn't decrement it)
mov ax, 0xb800 ; text video memory
mov es, ax ; store inside ES (extended segment), used later by stosw
call clear_screen
mov si, msg ; set the SI (source index) register to our string
call print_string
;;; The end of it
hang:
jmp hang
;;; Data
msg db 'Hello World', 0
terminal_posx db 0 ; X position for writing text
terminal_posy db 0 ; Y position for writing text
;;; Padding and Signature
times 510-($-$$) db 0
; boot signature (so QEMU boots this)
db 0x55
db 0xAA

View File

@ -0,0 +1,218 @@
/*++
Copyright (c) 1998 Intel Corporation
Module Name:
data.c
Abstract:
EFI library global data
Revision History
--*/
#include "lib.h"
//
// LibInitialized - TRUE once InitializeLib() is called for the first time
//
BOOLEAN LibInitialized = FALSE;
//
// ImageHandle - Current ImageHandle, as passed to InitializeLib
//
EFI_HANDLE LibImageHandle;
//
// ST - pointer to the EFI system table
//
EFI_SYSTEM_TABLE *ST;
//
// BS - pointer to the boot services table
//
EFI_BOOT_SERVICES *BS;
//
// Default pool allocation type
//
EFI_MEMORY_TYPE PoolAllocationType = EfiBootServicesData;
//
// Unicode collation functions that are in use
//
EFI_UNICODE_COLLATION_INTERFACE LibStubUnicodeInterface = {
NULL, // LibStubStriCmp,
NULL, // LibStubMetaiMatch,
NULL, // LibStubStrLwrUpr,
NULL, // LibStubStrLwrUpr,
NULL, // FatToStr
NULL, // StrToFat
NULL // SupportedLanguages
};
EFI_UNICODE_COLLATION_INTERFACE *UnicodeInterface = &LibStubUnicodeInterface;
//
// Root device path
//
EFI_DEVICE_PATH RootDevicePath[] = {
{END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE, {END_DEVICE_PATH_LENGTH,0}}
};
EFI_DEVICE_PATH EndDevicePath[] = {
{END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE, {END_DEVICE_PATH_LENGTH, 0}}
};
EFI_DEVICE_PATH EndInstanceDevicePath[] = {
{END_DEVICE_PATH_TYPE, END_INSTANCE_DEVICE_PATH_SUBTYPE, {END_DEVICE_PATH_LENGTH, 0}}
};
//
// EFI IDs
//
EFI_GUID gEfiGlobalVariableGuid = EFI_GLOBAL_VARIABLE;
EFI_GUID NullGuid = { 0,0,0,{0,0,0,0,0,0,0,0} };
//
// Protocol IDs
//
EFI_GUID gEfiDevicePathProtocolGuid = EFI_DEVICE_PATH_PROTOCOL_GUID;
EFI_GUID gEfiDevicePathToTextProtocolGuid = EFI_DEVICE_PATH_TO_TEXT_PROTOCOL_GUID;
EFI_GUID gEfiDevicePathFromTextProtocolGuid = EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL_GUID;
EFI_GUID gEfiDevicePathUtilitiesProtocolGuid = EFI_DEVICE_PATH_UTILITIES_PROTOCOL_GUID;
EFI_GUID gEfiLoadedImageProtocolGuid = EFI_LOADED_IMAGE_PROTOCOL_GUID;
EFI_GUID gEfiSimpleTextInProtocolGuid = EFI_SIMPLE_TEXT_INPUT_PROTOCOL_GUID;
EFI_GUID gEfiSimpleTextOutProtocolGuid = EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL_GUID;
EFI_GUID gEfiBlockIoProtocolGuid = EFI_BLOCK_IO_PROTOCOL_GUID;
EFI_GUID gEfiBlockIo2ProtocolGuid = EFI_BLOCK_IO2_PROTOCOL_GUID;
EFI_GUID gEfiDiskIoProtocolGuid = EFI_DISK_IO_PROTOCOL_GUID;
EFI_GUID gEfiDiskIo2ProtocolGuid = EFI_DISK_IO2_PROTOCOL_GUID;
EFI_GUID gEfiSimpleFileSystemProtocolGuid = EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID;
EFI_GUID gEfiLoadFileProtocolGuid = EFI_LOAD_FILE_PROTOCOL_GUID;
EFI_GUID gEfiDeviceIoProtocolGuid = EFI_DEVICE_IO_PROTOCOL_GUID;
EFI_GUID gEfiUnicodeCollationProtocolGuid = EFI_UNICODE_COLLATION_PROTOCOL_GUID;
EFI_GUID gEfiSerialIoProtocolGuid = EFI_SERIAL_IO_PROTOCOL_GUID;
EFI_GUID gEfiSimpleNetworkProtocolGuid = EFI_SIMPLE_NETWORK_PROTOCOL_GUID;
EFI_GUID gEfiPxeBaseCodeProtocolGuid = EFI_PXE_BASE_CODE_PROTOCOL_GUID;
EFI_GUID gEfiPxeBaseCodeCallbackProtocolGuid = EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL_GUID;
EFI_GUID gEfiNetworkInterfaceIdentifierProtocolGuid = EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL_GUID;
EFI_GUID gEFiUiInterfaceProtocolGuid = EFI_UI_INTERFACE_PROTOCOL_GUID;
EFI_GUID gEfiPciIoProtocolGuid = EFI_PCI_IO_PROTOCOL_GUID;
EFI_GUID gEfiPciRootBridgeIoProtocolGuid = EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_GUID;
EFI_GUID gEfiDriverBindingProtocolGuid = EFI_DRIVER_BINDING_PROTOCOL_GUID;
EFI_GUID gEfiComponentNameProtocolGuid = EFI_COMPONENT_NAME_PROTOCOL_GUID;
EFI_GUID gEfiComponentName2ProtocolGuid = EFI_COMPONENT_NAME2_PROTOCOL_GUID;
EFI_GUID gEfiHashProtocolGuid = EFI_HASH_PROTOCOL_GUID;
EFI_GUID gEfiPlatformDriverOverrideProtocolGuid = EFI_PLATFORM_DRIVER_OVERRIDE_PROTOCOL_GUID;
EFI_GUID gEfiBusSpecificDriverOverrideProtocolGuid = EFI_BUS_SPECIFIC_DRIVER_OVERRIDE_PROTOCOL_GUID;
EFI_GUID gEfiDriverFamilyOverrideProtocolGuid = EFI_DRIVER_FAMILY_OVERRIDE_PROTOCOL_GUID;
EFI_GUID gEfiEbcProtocolGuid = EFI_EBC_PROTOCOL_GUID;
//
// File system information IDs
//
EFI_GUID gEfiFileInfoGuid = EFI_FILE_INFO_ID;
EFI_GUID gEfiFileSystemInfoGuid = EFI_FILE_SYSTEM_INFO_ID;
EFI_GUID gEfiFileSystemVolumeLabelInfoIdGuid = EFI_FILE_SYSTEM_VOLUME_LABEL_ID;
//
// Reference implementation public protocol IDs
//
EFI_GUID InternalShellProtocol = INTERNAL_SHELL_GUID;
EFI_GUID VariableStoreProtocol = VARIABLE_STORE_PROTOCOL;
EFI_GUID LegacyBootProtocol = LEGACY_BOOT_PROTOCOL;
EFI_GUID VgaClassProtocol = VGA_CLASS_DRIVER_PROTOCOL;
EFI_GUID TextOutSpliterProtocol = TEXT_OUT_SPLITER_PROTOCOL;
EFI_GUID ErrorOutSpliterProtocol = ERROR_OUT_SPLITER_PROTOCOL;
EFI_GUID TextInSpliterProtocol = TEXT_IN_SPLITER_PROTOCOL;
/* Added for GOP support */
EFI_GUID gEfiGraphicsOutputProtocolGuid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
EFI_GUID gEfiEdidDiscoveredProtocolGuid = EFI_EDID_DISCOVERED_PROTOCOL_GUID;
EFI_GUID gEfiEdidActiveProtocolGuid = EFI_EDID_ACTIVE_PROTOCOL_GUID;
EFI_GUID gEfiEdidOverrideProtocolGuid = EFI_EDID_OVERRIDE_PROTOCOL_GUID;
EFI_GUID AdapterDebugProtocol = ADAPTER_DEBUG_PROTOCOL;
//
// Device path media protocol IDs
//
EFI_GUID gEfiPcAnsiGuid = EFI_PC_ANSI_GUID;
EFI_GUID gEfiVT100Guid = EFI_VT_100_GUID;
EFI_GUID gEfiVT100PlusGuid = EFI_VT_100_PLUS_GUID;
EFI_GUID gEfiVTUTF8Guid = EFI_VT_UTF8_GUID;
//
// EFI GPT Partition Type GUIDs
//
EFI_GUID EfiPartTypeSystemPartitionGuid = EFI_PART_TYPE_EFI_SYSTEM_PART_GUID;
EFI_GUID EfiPartTypeLegacyMbrGuid = EFI_PART_TYPE_LEGACY_MBR_GUID;
//
// Reference implementation Vendor Device Path Guids
//
EFI_GUID UnknownDevice = UNKNOWN_DEVICE_GUID;
//
// Configuration Table GUIDs
//
EFI_GUID MpsTableGuid = MPS_TABLE_GUID;
EFI_GUID AcpiTableGuid = ACPI_TABLE_GUID;
EFI_GUID SMBIOSTableGuid = SMBIOS_TABLE_GUID;
EFI_GUID SMBIOS3TableGuid = SMBIOS3_TABLE_GUID;
EFI_GUID SalSystemTableGuid = SAL_SYSTEM_TABLE_GUID;
EFI_GUID EfiDtbTableGuid = EFI_DTB_TABLE_GUID;
//
// Network protocol GUIDs
//
EFI_GUID Ip4ServiceBindingProtocol = EFI_IP4_SERVICE_BINDING_PROTOCOL;
EFI_GUID Ip4Protocol = EFI_IP4_PROTOCOL;
EFI_GUID Udp4ServiceBindingProtocol = EFI_UDP4_SERVICE_BINDING_PROTOCOL;
EFI_GUID Udp4Protocol = EFI_UDP4_PROTOCOL;
EFI_GUID Tcp4ServiceBindingProtocol = EFI_TCP4_SERVICE_BINDING_PROTOCOL;
EFI_GUID Tcp4Protocol = EFI_TCP4_PROTOCOL;
//
// Pointer protocol GUIDs
//
EFI_GUID SimplePointerProtocol = EFI_SIMPLE_POINTER_PROTOCOL_GUID;
EFI_GUID AbsolutePointerProtocol = EFI_ABSOLUTE_POINTER_PROTOCOL_GUID;
//
// Debugger protocol GUIDs
//
EFI_GUID gEfiDebugImageInfoTableGuid = EFI_DEBUG_IMAGE_INFO_TABLE_GUID;
EFI_GUID gEfiDebugSupportProtocolGuid = EFI_DEBUG_SUPPORT_PROTOCOL_GUID;
//
// Console extension protocol GUIDs
//
EFI_GUID SimpleTextInputExProtocol = EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID;
//
// Shell protocol GUIDs
//
EFI_GUID ShellProtocolGuid = EFI_SHELL_PROTOCOL_GUID;
EFI_GUID ShellParametersProtocolGuid = EFI_SHELL_PARAMETERS_PROTOCOL_GUID;
EFI_GUID ShellDynamicCommandProtocolGuid = EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL_GUID;

View File

@ -1,20 +0,0 @@
#include <stdint.h>
#include "multiboot.h"
void load_kernel_module(const multiboot_module_t* module)
{
}
void loader_main(const multiboot_info_t* multibootInfo)
{
if (multibootInfo->flags & MULTIBOOT_INFO_MODS)
{
const multiboot_module_t* modules = (multiboot_module_t*) multibootInfo->mods_addr;
for (uint32_t modIdx = 0; modIdx < multibootInfo->mods_count; ++modIdx)
{
load_kernel_module(&modules[modIdx]);
}
}
}

View File

@ -0,0 +1,178 @@
extern "C"
{
#include <efi.h>
#include <efilib.h>
}
#include "miniefi.hpp"
#include "minimalloc.hpp"
#include "miniprintf.hpp"
namespace
{
EFI_STATUS openImageVolume(EFI_HANDLE image, EFI_FILE_HANDLE& outHandle)
{
EFI_LOADED_IMAGE* loadedImage = nullptr;
EFI_GUID lipGuid = EFI_LOADED_IMAGE_PROTOCOL_GUID;
EFI_FILE_IO_INTERFACE* ioVolume = nullptr;
EFI_GUID fsGuid = EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID;
EFI_FILE_HANDLE volume = nullptr;
EFI_STATUS status = BS->HandleProtocol(image, &lipGuid, reinterpret_cast<void**>(&loadedImage));
if (EFI_ERROR(status)) {
return status;
}
status = BS->HandleProtocol(loadedImage->DeviceHandle, &fsGuid, reinterpret_cast<void**>(&ioVolume));
if (EFI_ERROR(status)) {
return status;
}
status = ioVolume->OpenVolume(ioVolume, &volume);
if (EFI_ERROR(status)) {
return status;
}
outHandle = volume;
return EFI_SUCCESS;
}
void print(const CHAR16* text)
{
ST->ConOut->OutputString(ST->ConOut, const_cast<CHAR16*>(text));
}
void putchar(char c)
{
if (c == '\n')
{
print(L"\r\n");
return;
}
CHAR16 buffer[2];
buffer[0] = c;
buffer[1] = L'\0';
print(buffer);
}
void waitForKey()
{
EFI_INPUT_KEY Key;
// reset input buffer to flush previous key strokes
EFI_STATUS status = ST->ConIn->Reset(ST->ConIn, FALSE);
if (EFI_ERROR(status))
{
return;
}
// now wait for a key
while ((status = ST->ConIn->ReadKeyStroke(ST->ConIn, &Key)) == EFI_NOT_READY);
}
void printAndWait(const CHAR16* text)
{
print(text);
waitForKey();
}
EFI_STATUS getEfiFileInfo(EFI_FILE_HANDLE fileHandle, EFI_FILE_INFO*& outFileInfo)
{
static const EFI_GUID GUID = EFI_FILE_INFO_ID;
UINTN size = 0;
EFI_STATUS status = fileHandle->GetInfo(fileHandle, const_cast<EFI_GUID*>(&GUID), &size, nullptr);
if (status != EFI_BUFFER_TOO_SMALL) {
return status;
}
void* buffer = malloc(size);
if (buffer == nullptr) {
return EFI_OUT_OF_RESOURCES;
}
status = fileHandle->GetInfo(fileHandle, const_cast<EFI_GUID*>(&GUID), &size, buffer);
if (EFI_ERROR(status))
{
free(buffer);
return status;
}
outFileInfo = static_cast<EFI_FILE_INFO*>(buffer);
return EFI_SUCCESS;
}
}
#define DIE_ON_ERROR(message) \
if (EFI_ERROR(status)) \
{ \
printAndWait(message L"\r\n"); \
return status; \
}
extern "C" EFI_STATUS efi_main(EFI_HANDLE imageHandle, EFI_SYSTEM_TABLE* systemTable)
{
/* Store the system table for future use in other functions */
ST = systemTable;
BS = systemTable->BootServices;
initMiniMalloc();
initMiniPrintf(&putchar);
ST->ConOut->ClearScreen(ST->ConOut);
EFI_FILE_HANDLE volume;
EFI_STATUS status = openImageVolume(imageHandle, volume);
DIE_ON_ERROR(L"Error opening image volume.");
const CHAR16* fileName = L"kernel.bin";
EFI_FILE_HANDLE fileHandle = nullptr;
status = volume->Open(volume, &fileHandle, const_cast<CHAR16*>(fileName), EFI_FILE_MODE_READ, EFI_FILE_READ_ONLY | EFI_FILE_HIDDEN | EFI_FILE_SYSTEM);
DIE_ON_ERROR(L"Error opening file for reading.");
EFI_FILE_INFO* info = nullptr;
status = getEfiFileInfo(fileHandle, info);
DIE_ON_ERROR(L"Error getting file info.");
printf("File size: %d.\n", static_cast<int>(info->FileSize));
free(info);
Elf64Header header = {};
UINTN bufferSize = sizeof(Elf64Header);
status = fileHandle->Read(fileHandle, &bufferSize, &header);
DIE_ON_ERROR("Error reading EFI64 header.");
printf("headerSize: %d\n", static_cast<int>(header.type));
printf("entry: 0x%X\n", static_cast<unsigned>(header.entry));
for (uint16_t phtEntry = 0; phtEntry < header.phtEntryCount; ++phtEntry)
{
status = fileHandle->SetPosition(fileHandle, header.phtOffset + phtEntry * header.phtEntrySize);
DIE_ON_ERROR("Error seeking in EFI64 file.");
Efi64ProgramHeader programHeader = {};
bufferSize = sizeof(Efi64ProgramHeader);
status = fileHandle->Read(fileHandle, &bufferSize, &programHeader);
DIE_ON_ERROR("Error reading EFI64 program header.");
printf("Program Header %d:\n", phtEntry);
printf(" type: %d\n", static_cast<int>(programHeader.type));
printf(" flags: %d\n", static_cast<int>(programHeader.flags));
printf(" vaddr: 0x%X\n", programHeader.vaddr);
printf(" paddr: 0x%X\n", programHeader.paddr);
printf(" fileSize: %d\n", static_cast<int>(programHeader.fileSize));
printf(" memSize: %d\n", static_cast<int>(programHeader.memSize));
if (programHeader.type != ElfProgramHeaderType::LOAD) {
continue;
}
print(L"Loading segment...\r\n");
status = fileHandle->SetPosition(fileHandle, programHeader.offset);
DIE_ON_ERROR("Error seeking to EFI64 section.");
void* targetAddr = reinterpret_cast<void*>(programHeader.paddr);
bufferSize = programHeader.fileSize;
status = fileHandle->Read(fileHandle, &bufferSize, targetAddr);
DIE_ON_ERROR("Error reading EFI64 section.");
}
// up up and away!
__asm__ __volatile__
(
"jmp %0"
:
: "a"(header.entry)
);
waitForKey();
return EFI_SUCCESS;
}

View File

@ -0,0 +1,110 @@
#pragma once
#if !defined(MINIEFI_HPP_INCLUDED)
#define MINIEFI_HPP_INCLUDED 1
#include <stdint.h>
inline const uint8_t ELF_MAGIC[4] = { 0x7F, 0x45, 0x4c, 0x46 };
enum class ElfClass : uint8_t
{
ELF32 = 1,
ELF64 = 2
};
enum class ElfData : uint8_t
{
LITTLE_ENDIAN = 1,
BIG_ENDIAN = 2
};
enum class ElfOsAbi : uint8_t
{
SYSTEM_V = 0,
HP_UX = 1,
NETBSD = 2,
LINUX = 3,
GNU_HURD = 4,
SOLARIS = 6,
AIX = 7,
IRIX = 8,
FREEBSD = 9,
TRU64 = 10,
NOVELL_MODESTO = 11,
OPENBSD = 12,
OPENVMS = 13,
NONSTOP_KERNEL = 14,
AROS = 15,
FENIXOS = 16,
NUXI_CLOUDABI = 17,
OPENVOS = 18
};
enum class EfiType : uint16_t
{
NONE = 0,
RELOCATABLE = 1,
EXECUTABLE = 2,
SHARED_OBJECT = 3,
CORE = 4
};
enum class EfiMachine : uint16_t
{
// I won't add all of them ...
NONE = 0,
X86 = 3,
X86_64 = 0x3E
};
struct Elf64Header
{
uint8_t magic[4];
ElfClass elfClass;
ElfData data;
uint8_t version;
ElfOsAbi osabi;
uint8_t abiversion;
uint8_t padding__[7];
EfiType type;
uint16_t machine;
uint32_t version2;
uint64_t entry;
uint64_t phtOffset;
uint64_t shtOffset;
uint32_t flags;
uint16_t headerSize;
uint16_t phtEntrySize;
uint16_t phtEntryCount;
uint16_t shtEntrySize;
uint16_t shtEntryCount;
uint16_t shtNameSectionIndex;
} __attribute__((packed));
enum class ElfProgramHeaderType
{
NONE = 0,
LOAD = 1,
DYNAMIC = 2,
INTERP = 3,
NOTE = 4,
SHLIB = 5,
PROGRAM_HEADER_TABLE = 6,
TLS = 7
};
struct Efi64ProgramHeader
{
ElfProgramHeaderType type;
uint32_t flags;
uint64_t offset;
uint64_t vaddr;
uint64_t paddr;
uint64_t fileSize;
uint64_t memSize;
uint64_t align;
} __attribute__((packed));
#endif // MINIEFI_HPP_INCLUDED

View File

@ -0,0 +1,121 @@
#include <stddef.h>
namespace
{
inline const size_t INIT_MALLOC_SPACE_ELEMENTS = 1024;
inline const size_t INIT_MALLOC_SPACE_BYTES = INIT_MALLOC_SPACE_ELEMENTS * sizeof(max_align_t);
max_align_t gInitMallocSpace[INIT_MALLOC_SPACE_ELEMENTS];
struct MallocBlock
{
size_t elements;
MallocBlock* nextBlock;
};
struct AllocInfo
{
size_t elements;
};
static_assert(sizeof(MallocBlock) <= sizeof(max_align_t));
static_assert(sizeof(AllocInfo) <= sizeof(max_align_t));
MallocBlock* gNextBlock;
}
void initMiniMalloc()
{
gNextBlock = reinterpret_cast<MallocBlock*>(gInitMallocSpace);
gNextBlock->elements = INIT_MALLOC_SPACE_ELEMENTS;
gNextBlock->nextBlock = nullptr;
}
extern "C"
{
void* malloc(size_t size) noexcept
{
if (size == 0)
{
return nullptr;
}
const size_t requiredElements = (size + sizeof(max_align_t) - 1) / sizeof(max_align_t) + 1;
MallocBlock* prevBlock = nullptr;
for (MallocBlock* block = gNextBlock; block != nullptr; block = block->nextBlock)
{
if (block->elements >= requiredElements)
{
MallocBlock* newBlock = nullptr;
if (block->elements > requiredElements)
{
newBlock = reinterpret_cast<MallocBlock*>(reinterpret_cast<max_align_t*>(block) + requiredElements);
newBlock->nextBlock = block->nextBlock;
newBlock->elements = block->elements - requiredElements;
} else
{
newBlock = block->nextBlock;
}
if (prevBlock != nullptr)
{
prevBlock->nextBlock = newBlock;
}
AllocInfo* allocInfo = reinterpret_cast<AllocInfo*>(block);
allocInfo->elements = requiredElements;
return reinterpret_cast<max_align_t*>(block) + 1;
}
prevBlock = block;
}
return nullptr;
}
void free(void* memory) noexcept
{
if (memory == nullptr)
{
return;
}
MallocBlock* block = reinterpret_cast<MallocBlock*>(static_cast<max_align_t*>(memory) - 1);
block->nextBlock = gNextBlock;
gNextBlock = block;
}
}
void* operator new(size_t count)
{
if (void* ptr = malloc(count); ptr != nullptr)
{
return ptr;
}
// TODO: some kind of abort
}
void operator delete(void* data) noexcept
{
free(data);
}
void* operator new[](size_t count)
{
if (void* ptr = malloc(count); ptr != nullptr)
{
return ptr;
}
// TODO: some kind of abort
}
void operator delete[](void* data) noexcept
{
free(data);
}
void operator delete(void* data, size_t /* size */) noexcept
{
free(data);
}
void operator delete[](void* data, size_t /* size */) noexcept
{
free(data);
}

View File

@ -0,0 +1,16 @@
#pragma once
#if !defined(MINIMALLOC_HPP_INCLUDED)
#define MINIMALLOC_HPP_INCLUDED 1
#include <stddef.h>
void initMiniMalloc();
extern "C"
{
void* malloc(size_t size) noexcept;
void free(void* memory) noexcept;
}
#endif // MINIMALLOC_HPP_INCLUDED

View File

@ -0,0 +1,226 @@
#include "miniprintf.hpp"
#include <stdint.h>
#include <stdarg.h>
namespace
{
putchar_t putchar;
size_t strlen(const char* str)
{
size_t len = 0;
while (str[len] != '\0') { ++len; }
return len;
}
int printInt(long value)
{
if (value == 0)
{
putchar('0');
return 1;
}
if (value < 0)
{
putchar('-');
return printInt(-value) + 1;
}
char digits[19]; // 9223372036854775807 has 10 digits
char* pos = &digits[0];
while (value > 0)
{
*pos = static_cast<char>('0' + (value % 10));
value /= 10;
++pos;
}
for (char* chr = pos - 1; chr >= digits; --chr)
{
putchar(*chr);
}
return pos - digits;
}
int printUInt(uint64_t value)
{
if (value == 0)
{
putchar('0');
return 1;
}
char digits[20]; // 18,446,744,073,709,551,615 has 20 digits
char* pos = &digits[0];
while (value > 0)
{
*pos = static_cast<char>('0' + (value % 10));
value /= 10;
++pos;
}
for (char* chr = pos - 1; chr >= digits; --chr)
{
putchar(*chr);
}
return pos - digits;
}
int printHexInt(uint64_t value)
{
if (value == 0)
{
putchar('0');
return 1;
}
char digits[16]; // FFFFFFFFFFFFFFFF has 16 digits
char* pos = &digits[0];
while (value > 0)
{
const uint64_t digit = (value % 16);
if (digit < 10)
{
*pos = static_cast<char>('0' + digit);
}
else
{
*pos = static_cast<char>('A' + digit - 10);
}
value /= 16;
++pos;
}
for (char* chr = pos - 1; chr >= digits; --chr)
{
putchar(*chr);
}
return pos - digits;
}
int printPointer(void* ptr)
{
return printHexInt(reinterpret_cast<uint64_t>(ptr));
}
int printString(const char* str)
{
const size_t len = strlen(str);
for (size_t idx = 0; idx < len; ++idx)
{
putchar(str[idx]);
}
return static_cast<int>(len);
}
int printByteSize(size_t bytes)
{
const char* suffixes[] = {
"B", "KiB", "MiB", "GiB", "TiB"
};
int suffixIdx = 0;
for (; suffixIdx < sizeof(suffixes) / sizeof(suffixes[0]); ++suffixIdx)
{
if (bytes < 1024) {
break;
}
bytes /= 1024;
}
return printUInt(bytes) + printString(suffixes[suffixIdx]);
}
}
void initMiniPrintf(putchar_t putcharFn) noexcept
{
putchar = putcharFn;
}
extern "C"
{
int printf(const char* format, ...) noexcept
{
va_list parameters;
va_start(parameters, format);
const int result = vprintf(format, parameters);
va_end(parameters);
return result;
}
int vprintf(const char* format, va_list vlist)
{
int result = 0;
const char* pos = format;
while (*pos != '\0')
{
if (*pos == '%')
{
++pos;
switch (*pos)
{
case '%':
putchar('%');
++result;
break;
case '\0':
// TODO: invalid format string, do something
// assert(!"Invalid format string, ends with %.");
return -1;
case 'b':
result += printByteSize(va_arg(vlist, size_t));
break;
case 'c':
{
const char chr = static_cast<char>(va_arg(vlist, int));
putchar(chr);
++result;
break;
}
case 's':
result += printString(va_arg(vlist, const char*));
break;
case 'd':
result += printInt(va_arg(vlist, int));
break;
case 'p':
result += printPointer(va_arg(vlist, void*));
break;
case 'X':
result += printHexInt(va_arg(vlist, unsigned));
break;
case 'l':
++pos;
switch (*pos)
{
case '\0':
// TODO: invalid format string, do something
// assert(!"Invalid format string, ends with %.");
return -1;
case 'd':
result += printInt(va_arg(vlist, long));
break;
case 'X':
result += printHexInt(va_arg(vlist, long));
break;
default:
return -1;
}
default:
// TODO
// assert(!"Invalid format string, unknown format identifier.");
return -1;
}
}
else
{
putchar(*pos);
}
++pos;
}
++result;
return result;
}
} // extern "C"

View File

@ -0,0 +1,18 @@
#pragma once
#if !defined(MINIPRINTF_HPP_INCLUDED)
#define MINIPRINTF_HPP_INCLUDED 1
#include <stddef.h>
using putchar_t = void (*)(char c);
void initMiniPrintf(putchar_t putcharFn) noexcept;
extern "C"
{
int printf(const char* format, ...) noexcept;
int vprintf(const char* format, va_list vlist);
}
#endif // !defined(MINIPRINTF_HPP_INCLUDED)

View File

@ -1,274 +0,0 @@
/* multiboot.h - Multiboot header file. */
/* Copyright (C) 1999,2003,2007,2008,2009,2010 Free Software Foundation, Inc.
*
* 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 ANY
* DEVELOPER OR DISTRIBUTOR 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.
*/
#ifndef MULTIBOOT_HEADER
#define MULTIBOOT_HEADER 1
/* How many bytes from the start of the file we search for the header. */
#define MULTIBOOT_SEARCH 8192
#define MULTIBOOT_HEADER_ALIGN 4
/* The magic field should contain this. */
#define MULTIBOOT_HEADER_MAGIC 0x1BADB002
/* This should be in %eax. */
#define MULTIBOOT_BOOTLOADER_MAGIC 0x2BADB002
/* Alignment of multiboot modules. */
#define MULTIBOOT_MOD_ALIGN 0x00001000
/* Alignment of the multiboot info structure. */
#define MULTIBOOT_INFO_ALIGN 0x00000004
/* Flags set in the flags member of the multiboot header. */
/* Align all boot modules on i386 page (4KB) boundaries. */
#define MULTIBOOT_PAGE_ALIGN 0x00000001
/* Must pass memory information to OS. */
#define MULTIBOOT_MEMORY_INFO 0x00000002
/* Must pass video information to OS. */
#define MULTIBOOT_VIDEO_MODE 0x00000004
/* This flag indicates the use of the address fields in the header. */
#define MULTIBOOT_AOUT_KLUDGE 0x00010000
/* Flags to be set in the flags member of the multiboot info structure. */
/* is there basic lower/upper memory information? */
#define MULTIBOOT_INFO_MEMORY 0x00000001
/* is there a boot device set? */
#define MULTIBOOT_INFO_BOOTDEV 0x00000002
/* is the command-line defined? */
#define MULTIBOOT_INFO_CMDLINE 0x00000004
/* are there modules to do something with? */
#define MULTIBOOT_INFO_MODS 0x00000008
/* These next two are mutually exclusive */
/* is there a symbol table loaded? */
#define MULTIBOOT_INFO_AOUT_SYMS 0x00000010
/* is there an ELF section header table? */
#define MULTIBOOT_INFO_ELF_SHDR 0X00000020
/* is there a full memory map? */
#define MULTIBOOT_INFO_MEM_MAP 0x00000040
/* Is there drive info? */
#define MULTIBOOT_INFO_DRIVE_INFO 0x00000080
/* Is there a config table? */
#define MULTIBOOT_INFO_CONFIG_TABLE 0x00000100
/* Is there a boot loader name? */
#define MULTIBOOT_INFO_BOOT_LOADER_NAME 0x00000200
/* Is there a APM table? */
#define MULTIBOOT_INFO_APM_TABLE 0x00000400
/* Is there video information? */
#define MULTIBOOT_INFO_VBE_INFO 0x00000800
#define MULTIBOOT_INFO_FRAMEBUFFER_INFO 0x00001000
#ifndef ASM_FILE
typedef unsigned char multiboot_uint8_t;
typedef unsigned short multiboot_uint16_t;
typedef unsigned int multiboot_uint32_t;
typedef unsigned long long multiboot_uint64_t;
struct multiboot_header
{
/* Must be MULTIBOOT_MAGIC - see above. */
multiboot_uint32_t magic;
/* Feature flags. */
multiboot_uint32_t flags;
/* The above fields plus this one must equal 0 mod 2^32. */
multiboot_uint32_t checksum;
/* These are only valid if MULTIBOOT_AOUT_KLUDGE is set. */
multiboot_uint32_t header_addr;
multiboot_uint32_t load_addr;
multiboot_uint32_t load_end_addr;
multiboot_uint32_t bss_end_addr;
multiboot_uint32_t entry_addr;
/* These are only valid if MULTIBOOT_VIDEO_MODE is set. */
multiboot_uint32_t mode_type;
multiboot_uint32_t width;
multiboot_uint32_t height;
multiboot_uint32_t depth;
};
/* The symbol table for a.out. */
struct multiboot_aout_symbol_table
{
multiboot_uint32_t tabsize;
multiboot_uint32_t strsize;
multiboot_uint32_t addr;
multiboot_uint32_t reserved;
};
typedef struct multiboot_aout_symbol_table multiboot_aout_symbol_table_t;
/* The section header table for ELF. */
struct multiboot_elf_section_header_table
{
multiboot_uint32_t num;
multiboot_uint32_t size;
multiboot_uint32_t addr;
multiboot_uint32_t shndx;
};
typedef struct multiboot_elf_section_header_table multiboot_elf_section_header_table_t;
struct multiboot_info
{
/* Multiboot info version number */
multiboot_uint32_t flags;
/* Available memory from BIOS */
multiboot_uint32_t mem_lower;
multiboot_uint32_t mem_upper;
/* "root" partition */
multiboot_uint32_t boot_device;
/* Kernel command line */
multiboot_uint32_t cmdline;
/* Boot-Module list */
multiboot_uint32_t mods_count;
multiboot_uint32_t mods_addr;
union
{
multiboot_aout_symbol_table_t aout_sym;
multiboot_elf_section_header_table_t elf_sec;
} u;
/* Memory Mapping buffer */
multiboot_uint32_t mmap_length;
multiboot_uint32_t mmap_addr;
/* Drive Info buffer */
multiboot_uint32_t drives_length;
multiboot_uint32_t drives_addr;
/* ROM configuration table */
multiboot_uint32_t config_table;
/* Boot Loader Name */
multiboot_uint32_t boot_loader_name;
/* APM table */
multiboot_uint32_t apm_table;
/* Video */
multiboot_uint32_t vbe_control_info;
multiboot_uint32_t vbe_mode_info;
multiboot_uint16_t vbe_mode;
multiboot_uint16_t vbe_interface_seg;
multiboot_uint16_t vbe_interface_off;
multiboot_uint16_t vbe_interface_len;
multiboot_uint64_t framebuffer_addr;
multiboot_uint32_t framebuffer_pitch;
multiboot_uint32_t framebuffer_width;
multiboot_uint32_t framebuffer_height;
multiboot_uint8_t framebuffer_bpp;
#define MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED 0
#define MULTIBOOT_FRAMEBUFFER_TYPE_RGB 1
#define MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT 2
multiboot_uint8_t framebuffer_type;
union
{
struct
{
multiboot_uint32_t framebuffer_palette_addr;
multiboot_uint16_t framebuffer_palette_num_colors;
};
struct
{
multiboot_uint8_t framebuffer_red_field_position;
multiboot_uint8_t framebuffer_red_mask_size;
multiboot_uint8_t framebuffer_green_field_position;
multiboot_uint8_t framebuffer_green_mask_size;
multiboot_uint8_t framebuffer_blue_field_position;
multiboot_uint8_t framebuffer_blue_mask_size;
};
};
};
typedef struct multiboot_info multiboot_info_t;
struct multiboot_color
{
multiboot_uint8_t red;
multiboot_uint8_t green;
multiboot_uint8_t blue;
};
struct multiboot_mmap_entry
{
multiboot_uint32_t size;
multiboot_uint64_t addr;
multiboot_uint64_t len;
#define MULTIBOOT_MEMORY_AVAILABLE 1
#define MULTIBOOT_MEMORY_RESERVED 2
#define MULTIBOOT_MEMORY_ACPI_RECLAIMABLE 3
#define MULTIBOOT_MEMORY_NVS 4
#define MULTIBOOT_MEMORY_BADRAM 5
multiboot_uint32_t type;
} __attribute__((packed));
typedef struct multiboot_mmap_entry multiboot_memory_map_t;
struct multiboot_mod_list
{
/* the memory used goes from bytes mod_start to mod_end-1 inclusive */
multiboot_uint32_t mod_start;
multiboot_uint32_t mod_end;
/* Module command line */
multiboot_uint32_t cmdline;
/* padding to take it to 16 bytes (must be zero) */
multiboot_uint32_t pad;
};
typedef struct multiboot_mod_list multiboot_module_t;
/* APM BIOS info. */
struct multiboot_apm_info
{
multiboot_uint16_t version;
multiboot_uint16_t cseg;
multiboot_uint32_t offset;
multiboot_uint16_t cseg_16;
multiboot_uint16_t dseg;
multiboot_uint16_t flags;
multiboot_uint16_t cseg_len;
multiboot_uint16_t cseg_16_len;
multiboot_uint16_t dseg_len;
};
#endif /* ! ASM_FILE */
#endif /* ! MULTIBOOT_HEADER */

View File

@ -1,70 +0,0 @@
;;; Procedure to print a text on the screen. Takes the address of a 0-terminated string in the SI register.
print_string:
print_string_loop:
lodsb ; load whatever is at SI to AL and increment SI
or al, al ; check if AL is 0
jz print_string_loop_done ; if AL is 0, go to the end
call print_char ; print the character in AL
jmp print_string_loop
print_string_loop_done:
add byte [terminal_posy], 1 ; next row
mov byte [terminal_posx], 0 ; back to the left
ret
;;; Procedure to print a single character. Takes the character in the AL register.
print_char:
mov ah, 0x0F ; set the higher half of AX to white on black color
mov cx, ax ; preserve the content for later
; now calculate the memory offset for the Y position
movzx ax, byte [terminal_posy] ; first load the Y position
mov dx, 160 ; then multiply it with 160 (2 bytes per char, 80 columns)
mul dx ; stores the result in AX
; next calculate the offset for the X position
movzx bx, byte [terminal_posx] ; load the X position
shl bx, 1 ; multiply by 2 (2 bytes per char)
; finally add the two
mov di, 0
add di, ax ; y offset
add di, bx ; x offset
; restore the character and write it
mov ax, cx
stosw
; advance the X position and done
add byte [terminal_posx], 1
ret
;;; Procedure to clear the screen (set everything to 0)
clear_screen:
mov ax, 0
mov di, 0
clear_screen_loop:
stosw ; write the 0 (2 bytes at a time)
cmp di, 2 * 25 * 60 ; check if we cleaned all 80 * 60 * 2 bytes
jne clear_screen_loop ; if not, repeat
mov byte [terminal_posx], 0
mov byte [terminal_posy], 0
ret
; ;;; Procedure to print a text on the using the BIOS. Takes the address to a 0-terminated string in the SI register.
; bios_print:
; bios_print_loop:
; lodsb ; load whatever is at SI to AL and increment SI
; or al, al ; check if AL is 0
; jz bios_print_done ; if AL is 0, go to the end
;
; ; invoke Int 10/AH=0Eh (VIDEO - TELETYPE OUTPUT)
; ; Takes a character from AL, writes it to the screen and advances the cursor.
; mov ah, 0x0E
; mov bh, 0
; int 0x10
; jmp bios_print_loop ; next char
; bios_print_done:
; ret