Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion api/arch/x86/paging.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -317,7 +317,7 @@ class Page_table {
auto* sub = page_dir(&ent);
Expects(sub != nullptr);
if (print) {
printf("%.*s-+<%s> 0x%zx\n", print_lvl * 2, pad,
printf("%.*s-+<%s> %p\n", print_lvl * 2, pad,
util::Byte_r(page_size).to_string().c_str(), (void*)sub->start_addr());
}
sum += sub->summary(print, print_lvl + 1);
Expand Down
31 changes: 23 additions & 8 deletions api/expects
Original file line number Diff line number Diff line change
Expand Up @@ -32,28 +32,43 @@
#endif

#include <os.hpp>
inline void __expect_fail(const char *expr, const char *file, int line, const char *func){
inline void __expect_emit_failure(std::string_view msg, std::string_view panic_text) {
#ifndef UNITTESTS
#ifdef INCLUDEOS_SMP_ENABLE
SMP::global_lock();
#endif
fprintf(stderr, "%s:%i:%s %s \n",file, line, func, expr);
std::fprintf(stderr, "%.*s\n", int(msg.size()), msg.data());
fflush(NULL);
#ifdef INCLUDEOS_SMP_ENABLE
SMP::global_unlock();
#endif
os::panic(expr);
os::panic(std::string(panic_text).c_str());
#else // TEST
(void) panic_text;
// throw here to allow tests to capture the error
#include <stdexcept>
#include <format>
auto msg = std::format("{}:{}:{} {}",file, line, func, expr);
throw std::runtime_error(msg);
throw std::runtime_error(std::string(msg));
#endif
}

#define Expects(x) ((void)((x) || (__expect_fail("Expects failed: "#x, __FILE__, __LINE__, __func__),0)))
#define Ensures(x) ((void)((x) || (__expect_fail("Ensures failed: "#x, __FILE__, __LINE__, __func__),0)))
template <class... Args>
inline void __expect_failf(const char *err_prefix, const char * /*cond*/, const char *file, int line, const char *func, std::format_string<Args...> fmt, Args&&... args){
auto reason_msg = std::format(fmt, std::forward<Args>(args)...);
auto error_msg = std::format("{}:{}:{}: {}: {}", file, line, func, err_prefix, reason_msg);
__expect_emit_failure(error_msg, reason_msg);
}

inline void __expect_failf(const char *err_prefix, const char *cond, const char *file, int line, const char *func){
auto reason_msg = std::format("{}: {}", err_prefix, cond);
auto error_msg = std::format("{}:{}:{}: {}", file, line, func, err_prefix);
__expect_emit_failure(error_msg, reason_msg);
}

#define Expects(cond) ((void)((cond) || (__expect_failf("Expects failed", #cond, __FILE__, __LINE__, __func__),0)))
#define Ensures(cond) ((void)((cond) || (__expect_failf("Ensures failed", #cond, __FILE__, __LINE__, __func__),0)))

#define Expectsf(cond, fmt, ...) ((void)((cond) || (__expect_failf("Expects failed", #cond, __FILE__, __LINE__, __func__, fmt, ##__VA_ARGS__),0)))
#define Ensuresf(cond, fmt, ...) ((void)((cond) || (__expect_failf("Ensures failed", #cond, __FILE__, __LINE__, __func__, fmt, ##__VA_ARGS__),0)))

namespace os {
// parameter for noexcept specifier when bypassing noexcept for testing
Expand Down
2 changes: 1 addition & 1 deletion api/util/elf_binary.inc
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ const typename Elf_binary<Arch>::Section_header& Elf_binary<Arch>::section_heade

template <typename Arch>
const typename Elf_binary<Arch>::Span Elf_binary<Arch>::section_data(const Section_header& sh) const {
return {data_.data() + sh.sh_offset, static_cast<std::ptrdiff_t>(sh.sh_size)};
return {data_.data() + static_cast<std::size_t>(sh.sh_offset), static_cast<std::size_t>(sh.sh_size)};
};

template <typename Arch>
Expand Down
3 changes: 3 additions & 0 deletions cmake/os.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,9 @@ function(os_add_executable TARGET NAME)
endif()
endforeach()

find_package(fmt CONFIG REQUIRED)
target_link_libraries(${ELF_TARGET} fmt::fmt)

# TODO: if not debug strip
if (CMAKE_BUILD_TYPE STREQUAL "Debug")
set(STRIP_LV )
Expand Down
35 changes: 35 additions & 0 deletions deps/libfmt/default.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# note that there is also `<nixpkgs>.fmt`
# so this entire file could just be `{ pkgs }: pkgs.fmt`
{
pkgs,
stdenv ? pkgs.stdenv,
cmake ? pkgs.cmake
}:
let
libfmt = stdenv.mkDerivation rec {
pname = "fmt";
version = "12.0.0";

src = pkgs.fetchFromGitHub {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are we sure there's no way of doing the same without adding another dependency? If we're sure std::fmt absolutely requires futex and fmtlib/fmt doesn't, I'm fine with this. But would much prefer to use the standard if we can.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The extent of what I changed can work just the same without libfmt. That said, libfmt does have some additional quality of life features such as colours and <fmt/compile.h>. Both std::format() and fmt::format() behave the same when it comes to futexes, and both std::format_to() and fmt::format_to() work without it.

If you want I can revert the addition of libfmt. Should be rather trivial.

owner = "fmtlib";
repo = "fmt";
rev = "12.0.0";
hash = "sha256-AZDmIeU1HbadC+K0TIAGogvVnxt0oE9U6ocpawIgl6g=";
};

nativeBuildInputs = [ cmake ];

cmakeFlags = [
"-DCMAKE_TRY_COMPILE_TARGET_TYPE=STATIC_LIBRARY"
"-DBUILD_SHARED_LIBS=OFF"

"-DFMT_TEST=OFF"
"-DFMT_DOC=OFF"
"-DFMT_INSTALL=ON"
];
};
in
libfmt // {
include = "${libfmt}/include";
lib = "${libfmt}/lib";
}
4 changes: 3 additions & 1 deletion develop.nix
Original file line number Diff line number Diff line change
Expand Up @@ -83,11 +83,13 @@ includeos.pkgs.mkShell.override { inherit (includeos) stdenv; } rec {
jq \
--arg libcxx "${includeos.libraries.libcxx.include}" \
--arg libc "${includeos.libraries.libc}" \
--arg localsrc "${toString ./.}" \
--arg libfmt "${includeos.passthru.libfmt.include}" \
--arg localsrc "${toString ./.}" \
'
map(.command |= ( .
+ " -isystem \($libcxx)"
+ " -isystem \($libc)/include"
+ " -I \($libfmt)"
| gsub("(?<a>-I)(?<b>/lib/LiveUpdate/include)"; .a + $localsrc + .b)
))
' "$CCDB" > "$tmp" && mv "$tmp" "$CCDB"
Expand Down
8 changes: 6 additions & 2 deletions overlay.nix
Original file line number Diff line number Diff line change
Expand Up @@ -74,10 +74,12 @@ final: prev: {
stdenv = final.stdenvIncludeOS.includeos_stdenv;

# Deps
uzlib = self.callPackage ./deps/uzlib/default.nix { };
botan2 = self.callPackage ./deps/botan/default.nix { };
s2n-tls = self.callPackage ./deps/s2n/default.nix { };
libfmt = self.callPackage ./deps/libfmt/default.nix { };
http-parser = self.callPackage ./deps/http-parser/default.nix { };
s2n-tls = self.callPackage ./deps/s2n/default.nix { };
uzlib = self.callPackage ./deps/uzlib/default.nix { };

vmbuild = self.callPackage ./vmbuild.nix { };

ccacheWrapper = prev.ccacheWrapper.override {
Expand Down Expand Up @@ -143,6 +145,7 @@ final: prev: {
] ++ prev.lib.optionals withCcache [self.ccacheWrapper ccacheNoticeHook];

buildInputs = [
self.libfmt
self.botan2
self.http-parser
prev.pkgsStatic.openssl
Expand Down Expand Up @@ -191,6 +194,7 @@ final: prev: {
inherit (self) uzlib;
inherit (self) http-parser;
inherit (self) botan2;
inherit (self) libfmt;
#inherit (self) s2n-tls;
inherit (self) cmake;
inherit (self) vmbuild;
Expand Down
5 changes: 5 additions & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ include_directories(
include
)

find_package(fmt CONFIG REQUIRED)
get_target_property(libfmt_include_path fmt::fmt INTERFACE_INCLUDE_DIRECTORIES)
include_directories(${libfmt_include_path})

#TODO move to util and check if needed / can be changed ?..
include_directories(${INCLUDEOS_ROOT}/lib/LiveUpdate/include)

Expand Down Expand Up @@ -66,6 +70,7 @@ FILE(WRITE ${CMAKE_CURRENT_BINARY_DIR}/version.h
include_directories(${CMAKE_CURRENT_BINARY_DIR})

add_library(os STATIC ${SRCS} ${OBJECTS} ${CMAKE_CURRENT_BINARY_DIR}/version.h)
target_link_libraries(os PRIVATE fmt::fmt)

#TODO check if this is almost correct for platform userspace
if (NOT CMAKE_TESTING_ENABLED)
Expand Down
1 change: 1 addition & 0 deletions src/chainload/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
project(chainloader C CXX)

find_package(IncludeOS REQUIRED)
find_package(fmt CONFIG REQUIRED)

set(ARCH i686)
set(PLATFORM nano)
Expand Down
1 change: 1 addition & 0 deletions src/include/kernel.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ namespace kernel {
using namespace util;
constexpr size_t default_max_mem = 2_GiB;
constexpr uintptr_t page_shift = 12;
constexpr size_t kprintf_max_size = 8192;

struct State {
bool running = true;
Expand Down
60 changes: 33 additions & 27 deletions src/kernel/multiboot.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,20 +21,29 @@
#include <kprint>
#include <boot/multiboot.h>
#include <kernel/memory.hpp>
#include <fmt/format.h>

template<class... Args>
static inline void _kfmt(fmt::string_view prefix, fmt::format_string<Args...> fmtstr, Args&&... args) {
fmt::basic_memory_buffer<char, kernel::kprintf_max_size> buf;
fmt::format_to_n(std::back_inserter(buf), buf.capacity(), "%s", prefix);
fmt::format_to_n(std::back_inserter(buf), buf.capacity() - buf.size(), fmtstr, std::forward<Args>(args)...);

kprintf("%.*s", (int)buf.size(), buf.data());
}
#define DEBUG_MULTIBOOT
#if defined(DEBUG_MULTIBOOT)
#undef debug
#define debug(X,...) kprintf(X,##__VA_ARGS__);
#define MYINFO(X,...) kprintf("<Multiboot>" X "\n", ##__VA_ARGS__)
#define debug(fmt, ...) _kfmt("", fmt, ##__VA_ARGS__)
#undef MYINFO
#define MYINFO(fmt, ...) _kfmt("< multiboot >", fmt "\n", ##__VA_ARGS__)
#undef INFO2
#define INFO2(X,...) kprintf("\t" X "\n", ##__VA_ARGS__)
#define INFO2(fmt, ...) _kfmt("\t", fmt "\n", ##__VA_ARGS__)
#else
#define debug(X,...)
#define MYINFO(X,...) INFO("Kernel", X, ##__VA_ARGS__)
#define debug(...) ((void) 0)
#define MYINFO(fmt, ,...) INFO("Kernel", X, ##__VA_ARGS__)
#endif


extern uintptr_t _end;


Expand Down Expand Up @@ -73,11 +82,11 @@ uintptr_t _multiboot_free_begin(uintptr_t boot_addr)
auto* info = bootinfo(boot_addr);
uintptr_t multi_end = reinterpret_cast<uintptr_t>(&_end);

debug("* Multiboot begin: 0x%lx \n", (uintptr_t)info);
debug("* Multiboot begin: {:#x}\n", (uintptr_t)info);
if (info->flags & MULTIBOOT_INFO_CMDLINE
and info->cmdline > multi_end)
{
debug("* Multiboot cmdline @ 0x%x: %s \n", info->cmdline, reinterpret_cast<char*>(info->cmdline));
debug("* Multiboot cmdline @ 0x{:08x}: {}\n", info->cmdline, reinterpret_cast<char*>(info->cmdline));
// We can't use a cmdline that's either insde our ELF or pre-ELF area
Expects(info->cmdline > multi_end
or info->cmdline < 0x100000);
Expand All @@ -89,35 +98,35 @@ uintptr_t _multiboot_free_begin(uintptr_t boot_addr)
}
}

debug("* Multiboot end: 0x%lx \n", multi_end);
debug("* Multiboot end: {:#x}\n", multi_end);
if (info->mods_count == 0)
return multi_end;

auto* mods_list = (multiboot_module_t*) (uintptr_t) info->mods_addr;
debug("* Module list @ %p \n",mods_list);
debug("* Module list @ {}\n", static_cast<const void*>(mods_list));

for (multiboot_module_t* mod = mods_list;
mod < mods_list + info->mods_count;
mod ++) {

debug("\t * Module @ %#x \n", mod->mod_start);
debug("\t * Args: %s \n ", (char*) (uintptr_t) mod->cmdline);
debug("\t * End: %#x \n ", mod->mod_end);
debug("\t * Module @ {:#x}\n", mod->mod_start);
debug("\t * Args: {}\n ", (char*) (uintptr_t) mod->cmdline);
debug("\t * End: {:#x}\n", mod->mod_end);

if (mod->mod_end > multi_end)
multi_end = mod->mod_end;

}

debug("* Multiboot end: 0x%lx \n", multi_end);
debug("* Multiboot end: {} \n", multi_end);
return multi_end;
}

void kernel::multiboot(uint32_t boot_addr)
{
MYINFO("Booted with multiboot");
auto* info = ::bootinfo(boot_addr);
INFO2("* Boot flags: %#x", info->flags);
INFO2("* Boot flags: {:#x}", info->flags);

if (info->flags & MULTIBOOT_INFO_MEMORY) {
uint32_t mem_low_start = 0;
Expand All @@ -127,11 +136,9 @@ void kernel::multiboot(uint32_t boot_addr)
uint32_t mem_high_end = mem_high_start + (info->mem_upper * 1024) - 1;
uint32_t mem_high_kb = info->mem_upper;

INFO2("* Valid memory (%i Kib):", mem_low_kb + mem_high_kb);
INFO2(" 0x%08x - 0x%08x (%i Kib)",
mem_low_start, mem_low_end, mem_low_kb);
INFO2(" 0x%08x - 0x%08x (%i Kib)",
mem_high_start, mem_high_end, mem_high_kb);
INFO2("* Valid memory (%i KiB):", mem_low_kb + mem_high_kb);
INFO2(" 0x{:08x} - 0x{:08x} ({} KiB)", mem_low_start, mem_low_end, mem_low_kb);
INFO2(" 0x{:08x} - 0x{:08x} ({} KiB)", mem_high_start, mem_high_end, mem_high_kb);
INFO2("");
}
else {
Expand All @@ -140,14 +147,14 @@ void kernel::multiboot(uint32_t boot_addr)

if (info->flags & MULTIBOOT_INFO_CMDLINE) {
const auto* cmdline = (const char*) (uintptr_t) info->cmdline;
INFO2("* Booted with parameters @ %p: %s", cmdline, cmdline);
INFO2("* Booted with parameters @ {}: {}", (const void*)(uintptr_t)info->cmdline, cmdline);
kernel::state().cmdline = std::pmr::string(cmdline).data();
}

if (info->flags & MULTIBOOT_INFO_MEM_MAP) {
INFO2("* Multiboot provided memory map (%zu entries @ %p)",
INFO2("* Multiboot provided memory map ({} entries @ {})",
info->mmap_length / sizeof(multiboot_memory_map_t),
(void*) (uintptr_t) info->mmap_addr);
(const void*)(uintptr_t)info->mmap_addr);
std::span<multiboot_memory_map_t> mmap {
reinterpret_cast<multiboot_memory_map_t*>(info->mmap_addr),
static_cast<size_t>(info->mmap_length / sizeof(multiboot_memory_map_t))
Expand All @@ -158,8 +165,7 @@ void kernel::multiboot(uint32_t boot_addr)
const char* str_type = map.type & MULTIBOOT_MEMORY_AVAILABLE ? "FREE" : "RESERVED";
const uintptr_t addr = map.addr;
const uintptr_t size = map.len;
INFO2(" 0x%010zx - 0x%010zx %s (%zu Kb.)",
addr, addr + size - 1, str_type, size / 1024 );
INFO2(" {:#x} - {:#x} {} ({} KiB)", addr, addr + size - 1, str_type, size / 1024);

if (not (map.type & MULTIBOOT_MEMORY_AVAILABLE)) {

Expand All @@ -184,9 +190,9 @@ void kernel::multiboot(uint32_t boot_addr)
auto mods = os::modules();

if (not mods.empty()) {
MYINFO("OS loaded with %zu modules", mods.size());
MYINFO("OS loaded with {} modules", mods.size());
for (auto mod : mods) {
INFO2("* %s @ 0x%x - 0x%x, size: %ib",
INFO2("* {} @ 0x{:08x} - 0x{:08x}, size: {} B",
reinterpret_cast<char*>(mod.params),
mod.mod_start, mod.mod_end, mod.mod_end - mod.mod_start);
}
Expand Down
Loading