From bc01a37452674a1c604ec5a8731ad9005fd5d142 Mon Sep 17 00:00:00 2001 From: "Justin C. Miller" Date: Sat, 2 Feb 2019 21:35:39 -0800 Subject: [PATCH] Ninja-based buildsystem now building a running kernel! --- generate_build.py | 14 ++++++++++---- qemu.sh | 22 ++++++++++++++++++++++ scripts/templates/build.ninja.j2 | 8 +++----- scripts/templates/target.host.ninja.j2 | 20 +++++++++++--------- src/arch/x86_64/kernel.ld | 2 +- src/boot/loader.c | 19 ++++++++++++++++++- src/boot/utility.h | 6 ++++++ src/kernel/gdt.s | 8 ++++---- 8 files changed, 75 insertions(+), 24 deletions(-) create mode 100755 qemu.sh diff --git a/generate_build.py b/generate_build.py index ca95643..78b9548 100755 --- a/generate_build.py +++ b/generate_build.py @@ -5,7 +5,7 @@ from collections import namedtuple library = namedtuple('library', ['path', 'deps']) program = namedtuple('program', ['path', 'deps', 'output', 'targets']) source = namedtuple('source', ['name', 'input', 'output', 'action']) -version = namedtuple('version', ['major', 'minor', 'patch', 'sha']) +version = namedtuple('version', ['major', 'minor', 'patch', 'sha', 'dirty']) MODULES = { "elf": library('src/libraries/elf', ['kutil']), @@ -45,7 +45,7 @@ def get_sources(path, srcroot): source( relpath(name, srcroot), abspath(name), - f + ".o", + relpath(abspath(name), path) + ".o", actions[ext])) return sources @@ -53,18 +53,24 @@ def get_sources(path, srcroot): def get_git_version(): from subprocess import run - cp = run(['git', 'describe', '--always'], + cp = run(['git', 'describe', '--dirty', '--abbrev=7'], check=True, capture_output=True) full_version = cp.stdout.decode('utf-8').strip() + dirty = False parts1 = full_version.split('-') + if parts1[-1] == "dirty": + dirty = True + parts1 = parts1[:-1] + parts2 = parts1[0].split('.') return version( parts2[0], parts2[1], parts2[2], - parts1[-1]) + parts1[-1][1:], + dirty) def main(buildroot): diff --git a/qemu.sh b/qemu.sh new file mode 100755 index 0000000..d30652f --- /dev/null +++ b/qemu.sh @@ -0,0 +1,22 @@ +#!/usr/bin/env bash + +build=${1:-"$(dirname $0)/build"} +ninja -C $build + +kvm="" +if [[ -f /dev/kvm ]]; then + kvm="--enable-kvm" +fi + +exec qemu-system-x86_64 \ + -drive "if=pflash,format=raw,file=${build}/flash.img" \ + -drive "format=raw,file=${build}/popcorn.img" \ + -smp 1 \ + -m 512 \ + -d mmu,int,guest_errors \ + -D popcorn.log \ + -cpu Broadwell \ + -M q35 \ + -no-reboot \ + -nographic \ + $kvm diff --git a/scripts/templates/build.ninja.j2 b/scripts/templates/build.ninja.j2 index bbfc9bd..0b56ded 100644 --- a/scripts/templates/build.ninja.j2 +++ b/scripts/templates/build.ninja.j2 @@ -31,15 +31,16 @@ ccflags = $ -DVERSION_MAJOR={{ version.major }} $ -DVERSION_MINOR={{ version.minor }} $ -DVERSION_PATCH={{ version.patch }} $ - -DVERSION_GITSHA=\"{{ version.sha }}\" $ + -DVERSION_GITSHA=0x{% if version.dirty %}1{% else %}0{% endif %}{{ version.sha }} $ -DGIT_VERSION=\"{{ version.major }}.{{ version.minor }}.{{ version.patch }}-{{ version.sha }}\" $ + -DGIT_VERSION_WIDE=L\"{{ version.major }}.{{ version.minor }}.{{ version.patch }}-{{ version.sha }}\" $ $warnflags asflags = $ -DVERSION_MAJOR={{ version.major }} $ -DVERSION_MINOR={{ version.minor }} $ -DVERSION_PATCH={{ version.patch }} $ - -DVERSION_GITSHA=\"{{ version.sha }}\" + -DVERSION_GITSHA=0x{% if version.dirty %}1{% else %}0{% endif %}{{ version.sha }} cflags = -std=c11 cxxflags = -std=c++14 @@ -121,9 +122,6 @@ build $ build $builddir/flash.img : cp $srcroot/assets/ovmf/x64/OVMF.fd name = flash.img -build $builddir/popcorn.fat : cp $srcroot/assets/ovmf/x64/OVMF.fd - name = flash.img - build $builddir/fatroot/popcorn.elf : cp $builddir/host/popcorn.elf name = kernel to FAT image diff --git a/scripts/templates/target.host.ninja.j2 b/scripts/templates/target.host.ninja.j2 index 53e7eba..0c58f08 100644 --- a/scripts/templates/target.host.ninja.j2 +++ b/scripts/templates/target.host.ninja.j2 @@ -11,30 +11,32 @@ objcopy = ${srcroot}/sysroot/bin/x86_64-elf-objcopy {% block variables %} ccflags = $ccflags $ - -D__ELF__ $ - -D__POPCORN__ $ - -nodefaultlibs $ - -nostdinc $ -nostdlib $ -ffreestanding $ + -nodefaultlibs $ + -fno-builtin $ -mno-sse $ -fno-omit-frame-pointer $ -mno-red-zone $ + -g $ -mcmodel=large $ + -D__ELF__ $ + -D__POPCORN__ $ -isystem${srcroot}/sysroot/include $ --sysroot="${srcroot}/sysroot" cxxflags = $cxxflags $ - -nostdlibinc $ - -isystem${srcroot}/sysroot/include/c++/v1 $ -fno-exceptions $ - -fno-rtti + -fno-rtti $ + -isystem${srcroot}/sysroot/include/c++/v1 ldflags = $ldflags $ -g $ -nostdlib $ - -nostartfiles $ -znocombreloc $ - -nostartfiles + -Bsymbolic $ + -nostartfiles $ + -Bstatic {% endblock %} +# vim: et ts=4 sts=4 sw=4 diff --git a/src/arch/x86_64/kernel.ld b/src/arch/x86_64/kernel.ld index a50ff04..af058af 100755 --- a/src/arch/x86_64/kernel.ld +++ b/src/arch/x86_64/kernel.ld @@ -27,7 +27,7 @@ SECTIONS *(.note.*) } - .bss ALIGN(0x1000) : { + .bss ALIGN(16) : { __bss_start = .; *(.bss) __bss_end = .; diff --git a/src/boot/loader.c b/src/boot/loader.c index 45f84a4..51a85cb 100644 --- a/src/boot/loader.c +++ b/src/boot/loader.c @@ -87,6 +87,8 @@ loader_load_elf( { EFI_STATUS status; + con_debug(L"Opening kernel file %s\r\n", (CHAR16 *)kernel_name); + EFI_FILE_PROTOCOL *file = NULL; status = root->Open(root, &file, (CHAR16 *)kernel_name, EFI_FILE_MODE_READ, EFI_FILE_READ_ONLY | EFI_FILE_HIDDEN | EFI_FILE_SYSTEM); @@ -107,6 +109,8 @@ loader_load_elf( status = file->Read(file, &length, &header); CHECK_EFI_STATUS_OR_RETURN(status, L"Reading ELF header"); + con_debug(L"Read %u bytes of ELF header\r\n", length); + if (length < sizeof(struct elf_header)) CHECK_EFI_STATUS_OR_RETURN(EFI_LOAD_ERROR, L"Incomplete read of ELF header"); @@ -131,10 +135,14 @@ loader_load_elf( header.machine != 0x3e) CHECK_EFI_STATUS_OR_RETURN(EFI_LOAD_ERROR, L"ELF load error: wrong machine architecture"); + con_debug(L"ELF is valid, entrypoint %lu\r\n", header.entrypoint); + data->kernel_entry = (void *)header.entrypoint; struct elf_program_header prog_header; for (int i = 0; i < header.ph_num; ++i) { + con_debug(L"Reading ELF program header %d\r\n", i); + status = file->SetPosition(file, header.ph_offset + i * header.ph_entsize); CHECK_EFI_STATUS_OR_RETURN(status, L"Setting ELF file position"); @@ -156,6 +164,8 @@ loader_load_elf( struct elf_section_header sec_header; for (int i = 0; i < header.sh_num; ++i) { + con_debug(L"Reading ELF section header %d ", i); + status = file->SetPosition(file, header.sh_offset + i * header.sh_entsize); CHECK_EFI_STATUS_OR_RETURN(status, L"Setting ELF file position"); @@ -163,11 +173,15 @@ loader_load_elf( status = file->Read(file, &length, &sec_header); CHECK_EFI_STATUS_OR_RETURN(status, L"Reading ELF section header"); - if ((sec_header.flags & ELF_SHF_ALLOC) == 0) continue; + if ((sec_header.flags & ELF_SHF_ALLOC) == 0) { + con_debug(L"SHF_ALLOC section\r\n"); + continue; + } void *addr = (void *)(sec_header.addr - KERNEL_VIRT_ADDRESS); if (sec_header.type == ELF_ST_PROGBITS) { + con_debug(L"PROGBITS section\r\n"); status = file->SetPosition(file, sec_header.offset); CHECK_EFI_STATUS_OR_RETURN(status, L"Setting ELF file position"); @@ -175,7 +189,10 @@ loader_load_elf( status = file->Read(file, &length, addr); CHECK_EFI_STATUS_OR_RETURN(status, L"Reading file"); } else if (sec_header.type == ELF_ST_NOBITS) { + con_debug(L"NOBITS section\r\n"); bootsvc->SetMem(addr, sec_header.size, 0); + } else { + con_debug(L"other section\r\n"); } } diff --git a/src/boot/utility.h b/src/boot/utility.h index c7532e9..eeeba1f 100644 --- a/src/boot/utility.h +++ b/src/boot/utility.h @@ -32,3 +32,9 @@ const CHAR16 *util_error_message(EFI_STATUS status); : "r"((uint64_t)s), "r"((uint64_t)d), "r"((uint64_t)__LINE__) \ : "rax", "rdx", "r8", "r9", "r10"); \ } + +#ifdef BOOTLOADER_DEBUG +#define con_debug(...) con_printf(L"DEBUG: " __VA_ARGS__) +#else +#define con_debug(...) +#endif diff --git a/src/kernel/gdt.s b/src/kernel/gdt.s index 8349f32..ea549e6 100644 --- a/src/kernel/gdt.s +++ b/src/kernel/gdt.s @@ -3,17 +3,17 @@ extern g_gdtr global idt_write idt_write: - lidt [g_idtr] + lidt [rel g_idtr] ret global idt_load idt_load: - sidt [g_idtr] + sidt [rel g_idtr] ret global gdt_write gdt_write: - lgdt [g_gdtr] + lgdt [rel g_gdtr] mov ax, si ; second arg is data segment mov ds, ax mov es, ax @@ -30,6 +30,6 @@ gdt_write: global gdt_load gdt_load: - sgdt [g_gdtr] + sgdt [rel g_gdtr] ret