diff --git a/assets/initrd.manifest b/assets/initrd.manifest new file mode 100644 index 0000000..0e1eef6 --- /dev/null +++ b/assets/initrd.manifest @@ -0,0 +1 @@ +assets/fonts/tamsyn8x16r.psf screenfont.psf diff --git a/src/boot/loader.c b/src/boot/loader.c index 22f8deb..45f84a4 100644 --- a/src/boot/loader.c +++ b/src/boot/loader.c @@ -7,7 +7,7 @@ #define PAGE_SIZE 0x1000 static CHAR16 kernel_name[] = KERNEL_FILENAME; -static CHAR16 font_name[] = KERNEL_FONT; +static CHAR16 initrd_name[] = INITRD_FILENAME; EFI_STATUS loader_alloc_pages( @@ -38,7 +38,7 @@ loader_alloc_pages( } EFI_STATUS -loader_load_font( +loader_load_initrd( EFI_BOOT_SERVICES *bootsvc, EFI_FILE_PROTOCOL *root, struct loader_data *data) @@ -46,13 +46,13 @@ loader_load_font( EFI_STATUS status; EFI_FILE_PROTOCOL *file = NULL; - status = root->Open(root, &file, (CHAR16 *)font_name, EFI_FILE_MODE_READ, + status = root->Open(root, &file, (CHAR16 *)initrd_name, EFI_FILE_MODE_READ, EFI_FILE_READ_ONLY | EFI_FILE_HIDDEN | EFI_FILE_SYSTEM); if (status == EFI_NOT_FOUND) return status; - CHECK_EFI_STATUS_OR_RETURN(status, L"Opening file %s", font_name); + CHECK_EFI_STATUS_OR_RETURN(status, L"Opening file %s", initrd_name); char info[sizeof(EFI_FILE_INFO) + 100]; size_t info_length = sizeof(info); @@ -60,16 +60,16 @@ loader_load_font( status = file->GetInfo(file, &guid_file_info, &info_length, info); CHECK_EFI_STATUS_OR_RETURN(status, L"Getting file info"); - data->font_length = ((EFI_FILE_INFO *)info)->FileSize; + data->initrd_length = ((EFI_FILE_INFO *)info)->FileSize; status = loader_alloc_pages( bootsvc, - KERNEL_FONT_MEMTYPE, - &data->font_length, - &data->font); + INITRD_MEMTYPE, + &data->initrd_length, + &data->initrd); CHECK_EFI_STATUS_OR_RETURN(status, L"Allocating pages"); - status = file->Read(file, &data->font_length, data->font); + status = file->Read(file, &data->initrd_length, data->initrd); CHECK_EFI_STATUS_OR_RETURN(status, L"Reading file"); status = file->Close(file); @@ -217,12 +217,12 @@ loader_load_kernel( CHECK_EFI_STATUS_OR_RETURN(status, L"loader_load_elf: %s", kernel_name); - data->font = (void *)((uint64_t)data->kernel + data->kernel_length); - status = loader_load_font(bootsvc, root, data); + data->initrd = (void *)((uint64_t)data->kernel + data->kernel_length); + status = loader_load_initrd(bootsvc, root, data); - CHECK_EFI_STATUS_OR_RETURN(status, L"loader_load_file: %s", font_name); + CHECK_EFI_STATUS_OR_RETURN(status, L"loader_load_file: %s", initrd_name); - data->data = (void *)((uint64_t)data->font + data->font_length); + data->data = (void *)((uint64_t)data->initrd + data->initrd_length); data->data_length += PAGE_SIZE; // extra page for map growth status = loader_alloc_pages( bootsvc, diff --git a/src/boot/loader.h b/src/boot/loader.h index 78021d6..dc12981 100644 --- a/src/boot/loader.h +++ b/src/boot/loader.h @@ -16,24 +16,20 @@ #define KERNEL_MEMTYPE 0x80000000 #endif -#ifndef KERNEL_FONT_MEMTYPE -#define KERNEL_FONT_MEMTYPE 0x80000001 +#ifndef INITRD_MEMTYPE +#define INITRD_MEMTYPE 0x80000001 #endif #ifndef KERNEL_DATA_MEMTYPE #define KERNEL_DATA_MEMTYPE 0x80000002 #endif -#ifndef KERNEL_PT_MEMTYPE -#define KERNEL_PT_MEMTYPE 0x80000004 -#endif - #ifndef KERNEL_FILENAME #define KERNEL_FILENAME L"kernel.elf" #endif -#ifndef KERNEL_FONT -#define KERNEL_FONT L"screenfont.psf" +#ifndef INITRD_FILENAME +#define INITRD_FILENAME L"initrd.img" #endif struct loader_data { @@ -41,8 +37,8 @@ struct loader_data { void *kernel_entry; size_t kernel_length; - void *font; - size_t font_length; + void *initrd; + size_t initrd_length; void *data; size_t data_length; diff --git a/src/boot/main.c b/src/boot/main.c index 5574893..0ce33bd 100644 --- a/src/boot/main.c +++ b/src/boot/main.c @@ -82,9 +82,9 @@ efi_main(EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *system_table) status = loader_load_kernel(bootsvc, &load); CHECK_EFI_STATUS_OR_FAIL(status); - con_printf(L" image bytes at 0x%x : %x\r\n", load.kernel, load.kernel_length); - con_printf(L" font bytes at 0x%x : %x\r\n", load.font, load.font_length); - con_printf(L" data bytes at 0x%x : %x\r\n", load.data, load.data_length); + con_printf(L" %u image bytes at 0x%x\r\n", load.kernel_length, load.kernel); + con_printf(L" %u initrd bytes at 0x%x\r\n", load.initrd_length, load.initrd); + con_printf(L" %u data bytes at 0x%x\r\n", load.data_length, load.data); struct kernel_header *version = (struct kernel_header *)load.kernel; if (version->magic != KERNEL_HEADER_MAGIC) { @@ -111,9 +111,9 @@ efi_main(EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *system_table) data_header->flags = 0; - data_header->font = load.font; - data_header->font_length = load.font_length; - memory_mark_pointer_fixup((void **)&data_header->font); + data_header->initrd = load.initrd; + data_header->initrd_length = load.initrd_length; + memory_mark_pointer_fixup((void **)&data_header->initrd); data_header->data = load.data; data_header->data_length = load.data_length; diff --git a/src/boot/memory.c b/src/boot/memory.c index eb1538e..a06368b 100644 --- a/src/boot/memory.c +++ b/src/boot/memory.c @@ -188,7 +188,7 @@ memory_virtualize(EFI_RUNTIME_SERVICES *runsvc, struct memory_map *map) while (d < end) { switch (d->Type) { case KERNEL_MEMTYPE: - case KERNEL_FONT_MEMTYPE: + case INITRD_MEMTYPE: case KERNEL_DATA_MEMTYPE: d->Attribute |= EFI_MEMORY_RUNTIME; d->VirtualStart = d->PhysicalStart + KERNEL_VIRT_ADDRESS; diff --git a/src/include/kernel_data.h b/src/include/kernel_data.h index c5724cb..2a52867 100644 --- a/src/include/kernel_data.h +++ b/src/include/kernel_data.h @@ -16,8 +16,8 @@ struct popcorn_data { uint32_t _reserved0; uint32_t flags; - void *font; - size_t font_length; + void *initrd; + size_t initrd_length; void *data; size_t data_length; diff --git a/src/kernel/device_manager.cpp b/src/kernel/device_manager.cpp index 6a9165f..a68b8f1 100644 --- a/src/kernel/device_manager.cpp +++ b/src/kernel/device_manager.cpp @@ -41,19 +41,10 @@ struct acpi2_rsdp uint8_t reserved[3]; } __attribute__ ((packed)); -uint8_t -acpi_checksum(const void *p, size_t len, size_t off = 0) -{ - uint8_t sum = 0; - const uint8_t *c = reinterpret_cast(p); - for (int i = off; i < len; ++i) sum += c[i]; - return sum; -} - bool acpi_table_header::validate(uint32_t expected_type) const { - if (acpi_checksum(this, length) != 0) return false; + if (kutil::checksum(this, length) != 0) return false; return !expected_type || (expected_type == type); } @@ -86,7 +77,7 @@ device_manager::device_manager(const void *root_table) : kassert(acpi1->signature[i] == expected_signature[i], "ACPI RSDP table signature mismatch"); - uint8_t sum = acpi_checksum(acpi1, sizeof(acpi1_rsdp), 0); + uint8_t sum = kutil::checksum(acpi1, sizeof(acpi1_rsdp), 0); kassert(sum == 0, "ACPI 1.0 RSDP checksum mismatch."); kassert(acpi1->revision > 1, "ACPI 1.0 not supported."); @@ -94,7 +85,7 @@ device_manager::device_manager(const void *root_table) : const acpi2_rsdp *acpi2 = reinterpret_cast(acpi1); - sum = acpi_checksum(acpi2, sizeof(acpi2_rsdp), sizeof(acpi1_rsdp)); + sum = kutil::checksum(acpi2, sizeof(acpi2_rsdp), sizeof(acpi1_rsdp)); kassert(sum == 0, "ACPI 2.0 RSDP checksum mismatch."); load_xsdt(reinterpret_cast(acpi2->xsdt_address)); diff --git a/src/kernel/main.cpp b/src/kernel/main.cpp index ed99d38..1debf5d 100644 --- a/src/kernel/main.cpp +++ b/src/kernel/main.cpp @@ -1,13 +1,13 @@ #include #include +#include "initrd/initrd.h" #include "kutil/assert.h" #include "kutil/memory.h" #include "block_device.h" #include "console.h" #include "cpu.h" #include "device_manager.h" -#include "font.h" #include "gdt.h" #include "interrupts.h" #include "io.h" @@ -29,23 +29,11 @@ extern "C" { extern void __kernel_assert(const char *, unsigned, const char *); void -init_console(const popcorn_data *header) +init_console() { serial_port *com1 = new (&g_com1) serial_port(COM1); console *cons = new (&g_console) console(com1); - if (header->frame_buffer) { - screen *s = new screen( - header->frame_buffer, - header->hres, - header->vres, - header->rmask, - header->gmask, - header->bmask); - font *f = new font(header->font); - cons->init_screen(s, f); - } - cons->set_color(0x21, 0x00); cons->puts("Popcorn OS "); cons->set_color(0x08, 0x00); @@ -83,16 +71,20 @@ kernel_main(popcorn_data *header) &header->frame_buffer, header->frame_buffer_length); - init_console(header); + init_console(); log::debug(logs::boot, " Popcorn header is at: %016lx", header); log::debug(logs::boot, " Framebuffer is at: %016lx", header->frame_buffer); - log::debug(logs::boot, " Font data is at: %016lx", header->font); log::debug(logs::boot, " Kernel data is at: %016lx", header->data); log::debug(logs::boot, " Memory map is at: %016lx", header->memory_map); log::debug(logs::boot, "ACPI root table is at: %016lx", header->acpi_table); log::debug(logs::boot, "Runtime service is at: %016lx", header->runtime); + initrd::disk ird(header->initrd); + log::info(logs::boot, "initrd loaded with %d files.", ird.files().count()); + for (auto &f : ird.files()) + log::info(logs::boot, " %s (%d bytes).", f.name(), f.size()); + /* pager->dump_pml4(nullptr, 0); pager->dump_blocks(true); diff --git a/src/kernel/wscript b/src/kernel/wscript index f13f81a..097818c 100644 --- a/src/kernel/wscript +++ b/src/kernel/wscript @@ -15,7 +15,7 @@ def build(bld): name = 'kernel', includes = '.', target = bld.env.KERNEL_FILENAME, - use = 'kutil', + use = ['kutil', 'initrd'], linkflags = "-T {}".format(lds), ) diff --git a/src/libraries/initrd/headers.h b/src/libraries/initrd/headers.h new file mode 100644 index 0000000..e89df99 --- /dev/null +++ b/src/libraries/initrd/headers.h @@ -0,0 +1,38 @@ +#pragma once +#include +#include "kutil/enum_bitfields.h" + +namespace initrd { + + +enum class disk_flags : uint16_t +{ +}; + +struct disk_header +{ + uint16_t file_count; + disk_flags flags; + uint32_t length; + uint8_t checksum; + uint8_t reserved[3]; +} __attribute__ ((packed)); + + +enum class file_flags : uint16_t +{ + executable = 0x01 +}; + +struct file_header +{ + uint32_t offset; + uint32_t length; + uint16_t name_offset; + file_flags flags; +} __attribute__ ((packed)); + +} // namepsace initrd + +IS_BITFIELD(initrd::disk_flags); +IS_BITFIELD(initrd::file_flags); diff --git a/src/libraries/initrd/initrd.cpp b/src/libraries/initrd/initrd.cpp new file mode 100644 index 0000000..7e69e72 --- /dev/null +++ b/src/libraries/initrd/initrd.cpp @@ -0,0 +1,41 @@ +#include "initrd/initrd.h" +#include "kutil/assert.h" +#include "kutil/enum_bitfields.h" +#include "headers.h" + +namespace initrd { + +file::file(const file_header *header, const void *start) : + m_header(header) +{ + m_data = kutil::offset_pointer(start, m_header->offset); + auto *name = kutil::offset_pointer(start, m_header->name_offset); + m_name = reinterpret_cast(name); +} + +const char * file::name() const { return m_name; } +const size_t file::size() const { return m_header->length; } +const void * file::data() const { return m_data; } + +bool +file::executable() const { + return bitfield_has(m_header->flags, file_flags::executable); +} + + +disk::disk(const void *start) +{ + auto *header = reinterpret_cast(start); + size_t length = header->length; + uint8_t sum = kutil::checksum(start, length); + kassert(sum == 0, "initrd checksum failed"); + + auto *files = reinterpret_cast(header + 1); + + m_files.ensure_capacity(header->file_count); + for (int i = 0; i < header->file_count; ++i) { + m_files.emplace(&files[i], start); + } +} + +} // namespace initrd diff --git a/src/libraries/initrd/initrd.h b/src/libraries/initrd/initrd.h new file mode 100644 index 0000000..59d1bc8 --- /dev/null +++ b/src/libraries/initrd/initrd.h @@ -0,0 +1,61 @@ +#pragma once +/// \file initrd.h +/// Definitions defining the simple inital ramdisk file format used by the +/// popcorn kernel. + +#include +#include "kutil/vector.h" + +// File format: +// 1x disk_header +// Nx file_header +// filename string data +// file data + +namespace initrd { + +struct disk_header; +struct file_header; + + +/// Encasulates methods for a file on the ramdisk +class file +{ +public: + file(const file_header *header, const void *start); + + /// Get the filename + const char * name() const; + + /// Get the file size + const size_t size() const; + + /// Get a pointer to the file data + const void * data() const; + + /// Whether this file is an executable + bool executable() const; + +private: + const file_header *m_header; + void const *m_data; + char const *m_name; +}; + + +/// Encasulates access methods for the ramdisk +class disk +{ +public: + /// Constructor. + /// \arg start The start of the initrd in memory + disk(const void *start); + + /// Get the vector of files on the disk + const kutil::vector & files() const { return m_files; } + +private: + kutil::vector m_files; +}; + +} // namespace initrd diff --git a/src/libraries/initrd/wscript b/src/libraries/initrd/wscript new file mode 100644 index 0000000..a16ca1b --- /dev/null +++ b/src/libraries/initrd/wscript @@ -0,0 +1,14 @@ + +def configure(ctx): + pass + +def build(bld): + sources = bld.path.ant_glob("**/*.cpp") + + bld.stlib( + source = sources, + name = 'initrd', + target = 'initrd', + ) + +# vim: ft=python et diff --git a/src/libraries/kutil/memory.cpp b/src/libraries/kutil/memory.cpp index 0562d65..71766b0 100644 --- a/src/libraries/kutil/memory.cpp +++ b/src/libraries/kutil/memory.cpp @@ -25,4 +25,13 @@ memcpy(void *dest, void *src, size_t n) return d; } +uint8_t +checksum(const void *p, size_t len, size_t off) +{ + uint8_t sum = 0; + const uint8_t *c = reinterpret_cast(p); + for (int i = off; i < len; ++i) sum += c[i]; + return sum; +} + } // namespace kutil diff --git a/src/libraries/kutil/memory.h b/src/libraries/kutil/memory.h index 5bb4448..72e2237 100644 --- a/src/libraries/kutil/memory.h +++ b/src/libraries/kutil/memory.h @@ -66,4 +66,10 @@ inline T* mask_pointer(T *p, addr_t mask) return reinterpret_cast(reinterpret_cast(p) & ~mask); } +/// Do a simple byte-wise checksum of an area of memory. +/// \arg p The start of the memory region +/// \arg len The number of bytes in the region +/// \arg off An optional offset into the region +uint8_t checksum(const void *p, size_t len, size_t off = 0); + } // namespace kutil diff --git a/src/tools/makerd/entry.cpp b/src/tools/makerd/entry.cpp new file mode 100644 index 0000000..7b2ae2f --- /dev/null +++ b/src/tools/makerd/entry.cpp @@ -0,0 +1,10 @@ +#include "entry.h" + +entry::entry(const std::string &in, const std::string &out) : + m_in(in), m_out(out), m_file(in, std::ios_base::binary) +{ + m_file.seekg(0, std::ios_base::end); + m_size = m_file.tellg(); + m_file.seekg(0); +} + diff --git a/src/tools/makerd/entry.h b/src/tools/makerd/entry.h new file mode 100644 index 0000000..2da7ff0 --- /dev/null +++ b/src/tools/makerd/entry.h @@ -0,0 +1,23 @@ +#pragma once +#include +#include + +class entry +{ +public: + entry(const std::string &in, const std::string &out); + + inline const std::string & in() const { return m_in; } + inline const std::string & out() const { return m_out; } + inline const std::ifstream & file() const { return m_file; } + + inline size_t size() const { return m_size; } + inline bool good() const { return m_file.good(); } + +private: + std::string m_in; + std::string m_out; + std::ifstream m_file; + size_t m_size; +}; + diff --git a/src/tools/makerd/main.cpp b/src/tools/makerd/main.cpp new file mode 100644 index 0000000..911406b --- /dev/null +++ b/src/tools/makerd/main.cpp @@ -0,0 +1,115 @@ +#include +#include +#include +#include +#include +#include "initrd/headers.h" +#include "entry.h" + +int main(int argc, char **argv) +{ + if (argc != 3) { + std::cerr << "Usage: " << argv[0] << " " << std::endl; + return 1; + } + + std::vector entries; + std::ifstream manifest(argv[1]); + + size_t files_size = 0; + size_t names_size = 0; + + while (manifest.good()) { + std::string in, out; + + manifest >> in; + if (in.length() < 1) + continue; + + manifest >> out; + if (in.front() == '#') + continue; + + entries.emplace_back(in, out); + const entry &e = entries.back(); + + if (!e.good()) { + std::cerr << "Error reading file: " << in << std::endl; + return 1; + } + + files_size += e.size(); + names_size += out.length() + 1; + } + + std::fstream out(argv[2], + std::ios_base::binary | + std::ios_base::trunc | + std::ios_base::out | + std::ios_base::in); + + if (!out.good()) { + std::cerr << "Error opening file: " << argv[2] << std::endl; + return 1; + } + + uint32_t total_length = + sizeof(initrd::disk_header) + + sizeof(initrd::file_header) * entries.size() + + names_size + files_size; + + initrd::disk_header dheader; + std::memset(&dheader, 0, sizeof(dheader)); + + dheader.file_count = entries.size(); + dheader.length = total_length; + out.write(reinterpret_cast(&dheader), sizeof(dheader)); + + size_t name_offset = + sizeof(initrd::disk_header) + + sizeof(initrd::file_header) * entries.size(); + + size_t file_offset = name_offset + names_size; + + for (auto &e : entries) { + initrd::file_header fheader; + std::memset(&fheader, 0, sizeof(fheader)); + fheader.offset = file_offset; + fheader.length = e.size(); + fheader.name_offset = name_offset; + + out.write( + reinterpret_cast(&fheader), + sizeof(fheader)); + + name_offset += e.out().length() + 1; + file_offset += e.size(); + } + + for (auto &e : entries) { + out.write(e.out().c_str(), e.out().length() + 1); + } + + for (auto &e : entries) { + out << e.file().rdbuf(); + } + + char buffer[1024]; + uint8_t checksum = 0; + + out.seekg(0); + while (true) { + size_t n = out.readsome(&buffer[0], 1024); + if (n == 0 || out.eof()) break; + + for (size_t i=0; i(buffer[i]); + } + + dheader.checksum = static_cast(0 - checksum); + out.seekp(0); + out.write(reinterpret_cast(&dheader), sizeof(dheader)); + + out.close(); + return 0; +} diff --git a/src/tools/makerd/wscript b/src/tools/makerd/wscript new file mode 100644 index 0000000..3967cbd --- /dev/null +++ b/src/tools/makerd/wscript @@ -0,0 +1,15 @@ + +def configure(ctx): + pass + +def build(bld): + sources = bld.path.ant_glob("**/*.cpp") + + bld.program( + source = sources, + name = 'makerd', + target = 'makerd', + use = 'initrd', + ) + +# vim: ft=python et diff --git a/wscript b/wscript index ddf417f..f6307f1 100644 --- a/wscript +++ b/wscript @@ -2,12 +2,6 @@ top = '.' out = 'build' -from waflib.Build import BuildContext -class TestContext(BuildContext): - cmd = 'test' - variant = 'tests' - - def options(opt): opt.load("nasm clang clang++") @@ -28,29 +22,14 @@ def options(opt): help='Font for the console') -def configure(ctx): - import os - import subprocess +def common_configure(ctx): + from os import listdir from os.path import join, exists + from subprocess import check_output - ctx.find_program("ld", var="LINK_CC") - ctx.env.LINK_CXX = ctx.env.LINK_CC + version = check_output("git describe --always", shell=True).strip() + git_sha = check_output("git rev-parse --short HEAD", shell=True).strip() - ctx.load("nasm clang clang++") - ctx.find_program("objcopy", var="objcopy") - ctx.find_program("objdump", var="objdump") - ctx.find_program("mcopy", var="mcopy") - ctx.find_program("dd", var="dd") - - # Override the gcc/g++ tools setting these assuming LD is gcc/g++ - ctx.env.SHLIB_MARKER = '-Bdynamic' - ctx.env.STLIB_MARKER = '-Bstatic' - ctx.env.LINKFLAGS_cstlib = ['-Bstatic'] - - version = subprocess.check_output("git describe --always", shell=True).strip() - git_sha = subprocess.check_output("git rev-parse --short HEAD", shell=True).strip() - - env = ctx.env major, minor, patch_dirty = version.split(".") dirty = 'dirty' in patch_dirty patch = patch_dirty.split('-')[0] @@ -71,17 +50,66 @@ def configure(ctx): libraries = [] mod_root = join("src", "libraries") - for module in os.listdir(mod_root): + for module in listdir(mod_root): mod_path = join(mod_root, module) if exists(join(mod_path, "wscript")): libraries.append(mod_path) + ctx.env.LIBRARIES = libraries + + tools = [] + mod_root = join("src", "tools") + for module in listdir(mod_root): + mod_path = join(mod_root, module) + if exists(join(mod_path, "wscript")): + tools.append(mod_path) + ctx.env.TOOLS = tools drivers = [] mod_root = join("src", "drivers") - for module in os.listdir(mod_root): + for module in listdir(mod_root): mod_path = join(mod_root, module) if exists(join(mod_path, "wscript")): drivers.append(mod_path) + ctx.env.DRIVERS = drivers + + ctx.env.append_value('DEFINES', [ + 'GIT_VERSION="{}"'.format(version), + 'GIT_VERSION_WIDE=L"{}"'.format(version), + "VERSION_MAJOR={}".format(major), + "VERSION_MINOR={}".format(minor), + "VERSION_PATCH={}".format(patch), + "VERSION_GITSHA=0x{}{}".format({True:1}.get(dirty, 0), git_sha), + ]) + + ctx.env.append_value('QEMUOPTS', [ + '-smp', '1', + '-m', '512', + '-d', 'mmu,int,guest_errors', + '-D', 'popcorn.log', + '-cpu', 'Broadwell', + '-M', 'q35', + '-no-reboot', + '-nographic', + ]) + + if exists('/dev/kvm'): + ctx.env.append_value('QEMUOPTS', ['--enable-kvm']) + + +def configure(ctx): + from os.path import join, exists + + ctx.find_program("ld", var="LINK_CC") + ctx.env.LINK_CXX = ctx.env.LINK_CC + + ctx.load("nasm clang clang++") + ctx.find_program("objcopy", var="objcopy") + ctx.find_program("objdump", var="objdump") + + # Override the gcc/g++ tools setting these assuming LD is gcc/g++ + ctx.env.SHLIB_MARKER = '-Bdynamic' + ctx.env.STLIB_MARKER = '-Bstatic' + ctx.env.LINKFLAGS_cstlib = ['-Bstatic'] baseflags = [ '-nostdlib', @@ -118,15 +146,6 @@ def configure(ctx): 'error' ]] - ctx.env.append_value('DEFINES', [ - 'GIT_VERSION="{}"'.format(version), - 'GIT_VERSION_WIDE=L"{}"'.format(version), - "VERSION_MAJOR={}".format(major), - "VERSION_MINOR={}".format(minor), - "VERSION_PATCH={}".format(patch), - "VERSION_GITSHA=0x{}{}".format({True:1}.get(dirty, 0), git_sha), - ]) - ctx.env.append_value('CFLAGS', baseflags) ctx.env.append_value('CFLAGS', warnflags) ctx.env.append_value('CFLAGS', ['-ggdb', '-std=c11']) @@ -150,66 +169,136 @@ def configure(ctx): '-nostartfiles', ]) - ctx.env.append_value('QEMUOPTS', [ - '-smp', '1', - '-m', '512', - '-d', 'mmu,int,guest_errors', - '-D', 'popcorn.log', - '-cpu', 'Broadwell', - '-M', 'q35', - '-no-reboot', - '-nographic', - ]) - - if os.path.exists('/dev/kvm'): - ctx.env.append_value('QEMUOPTS', ['--enable-kvm']) - - env = ctx.env - ctx.setenv('boot', env=env) + common_configure(ctx) + base_bare = ctx.env + ctx.setenv('boot', env=base_bare) ctx.recurse(join("src", "boot")) - ctx.setenv('kernel', env=env) + ctx.setenv('kernel', env=base_bare) ctx.env.append_value('CFLAGS', ['-mcmodel=large']) ctx.env.append_value('CXXFLAGS', ['-mcmodel=large']) - ctx.env.LIBRARIES = libraries for mod_path in ctx.env.LIBRARIES: ctx.recurse(mod_path) - ctx.env.DRIVERS = drivers for mod_path in ctx.env.DRIVERS: ctx.recurse(mod_path) ctx.recurse(join("src", "kernel")) - ## Testing configuration + ## Tools configuration ## from waflib.ConfigSet import ConfigSet - ctx.setenv('tests', env=ConfigSet()) - ctx.load("clang++") - - ctx.env.append_value('INCLUDES', [ - join(ctx.path.abspath(), "src", "include"), - join(ctx.path.abspath(), "src", "libraries"), - ]) + ctx.setenv('tools', env=ConfigSet()) + ctx.load('clang++') + ctx.find_program("mcopy", var="mcopy") + ctx.find_program("dd", var="dd") + common_configure(ctx) + + ctx.env.CXXFLAGS = ['-g', '-std=c++14', '-fno-rtti'] + ctx.env.LINKFLAGS = ['-g'] + + for mod_path in ctx.env.LIBRARIES: + ctx.recurse(mod_path) + + for mod_path in ctx.env.LIBRARIES: + ctx.recurse(mod_path) + + ## Image configuration + ## + ctx.setenv('image', env=ConfigSet()) + ctx.find_program("mcopy", var="mcopy") + ctx.find_program("dd", var="dd") + common_configure(ctx) + + ## Testing configuration + ## + from waflib.ConfigSet import ConfigSet + ctx.setenv('tests', env=ConfigSet()) + ctx.load('clang++') + common_configure(ctx) ctx.env.CXXFLAGS = ['-g', '-std=c++14', '-fno-rtti'] ctx.env.LINKFLAGS = ['-g'] - ctx.env.LIBRARIES = libraries for mod_path in ctx.env.LIBRARIES: ctx.recurse(mod_path) ctx.recurse(join("src", "tests")) +from waflib.Task import Task +class mcopy(Task): + color = 'YELLOW' + def keyword(self): + return "Updating" + def __str__(self): + node = self.inputs[0] + return node.path_from(node.ctx.launch_node()) + def run(self): + from subprocess import check_call as call + from shutil import copy + copy(self.inputs[0].abspath(), self.outputs[0].abspath()) + args = self.env.mcopy + ["-i", self.outputs[0].abspath(), "-D", "o"] + b_args = args + [self.inputs[1].abspath(), "::/efi/boot/bootx64.efi"] + call(b_args) + for inp in self.inputs[2:]: + call(args + [inp.abspath(), "::/"]) + +class addpart(Task): + color = 'YELLOW' + def keyword(self): + return "Updating" + def __str__(self): + node = self.inputs[0] + return node.path_from(node.ctx.launch_node()) + def run(self): + from subprocess import check_call as call + from shutil import copy + copy(self.inputs[0].abspath(), self.outputs[0].abspath()) + args = self.env.dd + [ + "of={}".format(self.outputs[0].abspath()), + "if={}".format(self.inputs[1].abspath()), + "bs=512", "count=91669", "seek=2048", "conv=notrunc"] + call(args) + +class makerd(Task): + color = 'YELLOW' + def keyword(self): + return "Creating" + def __str__(self): + node = self.outputs[0] + return node.path_from(node.ctx.launch_node()) + def run(self): + from os.path import join + from subprocess import check_call as call + + args = [ + self.inputs[0].abspath(), + self.inputs[1].abspath(), + self.outputs[0].abspath(), + ] + call(args) + + def build(bld): from os.path import join - if not bld.variant: - bld.env = bld.all_envs['boot'] + ## Boot + # + if bld.variant == 'boot': bld.recurse(join("src", "boot")) - bld.env = bld.all_envs['kernel'] + ## Tools + # + elif bld.variant == 'tools': + for mod_path in bld.env.LIBRARIES: + bld.recurse(mod_path) + for mod_path in bld.env.TOOLS: + bld.recurse(mod_path) + + ## Kernel + # + elif bld.variant == 'kernel': for mod_path in bld.env.LIBRARIES: bld.recurse(mod_path) for mod_path in bld.env.DRIVERS: @@ -217,67 +306,44 @@ def build(bld): bld.recurse(join("src", "kernel")) + ## Image + # + elif bld.variant == 'image': src = bld.path - out = bld.path.get_bld() + root = bld.path.get_bld().parent + + out = { + 'boot': root.make_node('boot'), + 'tools': root.make_node('tools'), + 'kernel': root.make_node('kernel'), + } + kernel_name = bld.env.KERNEL_FILENAME - disk = out.make_node("popcorn.img") - disk1 = out.make_node("popcorn.fat") - font = out.make_node("screenfont.psf") + disk = root.make_node("popcorn.img") + disk1 = root.make_node("popcorn.fat") + initrd = root.make_node("initrd.img") bld( source = src.make_node(join("assets", "ovmf", "x64", "OVMF.fd")), - target = out.make_node("flash.img"), + target = root.make_node("flash.img"), rule = "cp ${SRC} ${TGT}", ) - bld( - source = src.make_node(join("assets", "fonts", bld.env.FONT_NAME)), - target = font, - rule = "cp ${SRC} ${TGT}", - ) - - from waflib.Task import Task - class mcopy(Task): - color = 'YELLOW' - def keyword(self): - return "Updating" - def __str__(self): - node = self.inputs[0] - return node.path_from(node.ctx.launch_node()) - def run(self): - from subprocess import check_call as call - from shutil import copy - copy(self.inputs[0].abspath(), self.outputs[0].abspath()) - args = self.env.mcopy + ["-i", self.outputs[0].abspath(), "-D", "o"] - b_args = args + [self.inputs[1].abspath(), "::/efi/boot/bootx64.efi"] - call(b_args) - for inp in self.inputs[2:]: - call(args + [inp.abspath(), "::/"]) - - class addpart(Task): - color = 'YELLOW' - def keyword(self): - return "Updating" - def __str__(self): - node = self.inputs[0] - return node.path_from(node.ctx.launch_node()) - def run(self): - from subprocess import check_call as call - from shutil import copy - copy(self.inputs[0].abspath(), self.outputs[0].abspath()) - args = self.env.dd + [ - "of={}".format(self.outputs[0].abspath()), - "if={}".format(self.inputs[1].abspath()), - "bs=512", "count=91669", "seek=2048", "conv=notrunc"] - call(args) + make_rd = makerd(env = bld.env) + make_rd.set_inputs([ + out['tools'].make_node(join("src", "tools", "makerd", "makerd")), + src.make_node(join("assets", "initrd.manifest")), + ]) + make_rd.set_outputs([initrd]) + bld.add_to_group(make_rd) copy_img = mcopy(env = bld.env) copy_img.set_inputs([ src.make_node(join("assets", "disk.fat")), - out.make_node(join("src", "boot", "boot.efi")), - out.make_node(join("src", "kernel", kernel_name)), - font, + out['boot'].make_node(join("src", "boot", "boot.efi")), + out['kernel'].make_node(join("src", "kernel", kernel_name)), + initrd, ]) copy_img.set_outputs([disk1]) bld.add_to_group(copy_img) @@ -290,11 +356,44 @@ def build(bld): copy_part.set_outputs([disk]) bld.add_to_group(copy_part) - elif bld.variant == 'tests': - for mod_path in bld.env.LIBRARIES: - bld.recurse(mod_path) - bld.recurse(join("src", "tests")) +def test(bld): + from os.path import join + for mod_path in bld.env.LIBRARIES: + bld.recurse(mod_path) + + bld.recurse(join("src", "tests")) + + +def build_all(ctx): + from waflib import Options + Options.commands = ['tools', 'kernel', 'boot', 'image'] + Options.commands + + +from waflib.Build import BuildContext +class TestContext(BuildContext): + cmd = 'test' + variant = 'tests' + +class ToolsContext(BuildContext): + cmd = 'tools' + variant = 'tools' + +class KernelContext(BuildContext): + cmd = 'kernel' + variant = 'kernel' + +class BootContext(BuildContext): + cmd = 'boot' + variant = 'boot' + +class ImageContext(BuildContext): + cmd = 'image' + variant = 'image' + +class BuildAllContext(BuildContext): + cmd = 'build' + fun = 'build_all' class QemuContext(BuildContext):