Skip to content
Draft
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
11 changes: 9 additions & 2 deletions api/boot/multiboot.h
Original file line number Diff line number Diff line change
Expand Up @@ -195,12 +195,19 @@ typedef struct multiboot_info multiboot_info_t;

struct multiboot_mmap_entry
{
multiboot_uint32_t size;
multiboot_uint32_t size; // size of struct
multiboot_uint64_t addr;
multiboot_uint64_t len;
multiboot_uint64_t len; // bytes available
#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;

[[nodiscard]] constexpr bool is_available() const noexcept {
return type == MULTIBOOT_MEMORY_AVAILABLE;
}
} __attribute__((packed));
typedef struct multiboot_mmap_entry multiboot_memory_map_t;

Expand Down
6 changes: 6 additions & 0 deletions api/kernel/memmap.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,12 @@ class Memory_map {
*/
Fixed_memory_range& assign_range(const Fixed_memory_range::size_type size);

/**
* Removes a memory range previously defined
* Useful to redefine the purpose of a range
*/
void unassign_range(const Fixed_memory_range& range);

/**
* Check if an address is within a range in the map
*
Expand Down
2 changes: 1 addition & 1 deletion api/util/bitops.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,7 @@ inline bool is_aligned(uintptr_t A, uintptr_t ptr) noexcept
return (ptr & (A - 1)) == 0;
}

inline size_t upercent(size_t a, size_t b) noexcept
inline std::size_t upercent(std::size_t a, std::size_t b) noexcept
{
return (100 * a + b / 2) / b;
}
Expand Down
13 changes: 10 additions & 3 deletions example/src/main.cpp
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
#include "kernel/memory.hpp"
#include <os>
#include <service>

void Service::start(const std::string& args){
printf("Args = %s\n", args.c_str());
printf("Try giving the service less memory, eg. 10MB in vm.json\n");
printf("Service done. Shutting down...\n");
std::println("Hello from the example unikernel!");

std::println("Current virtual mappings:");
for (const auto& entry : os::mem::vmmap())
std::println(" {}", entry.second.to_string());

std::println("Tip: Try changing how much memory you give to the service in vm.json");
std::println("Service done. Shutting down...");

os::shutdown();
}
3 changes: 3 additions & 0 deletions example/src/vm.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"mem": 16384
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This is a lot - could we make it smaller?

}
4 changes: 3 additions & 1 deletion src/arch/x86_64/paging.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,8 @@ uintptr_t mem::active_page_size(uintptr_t addr){

void allow_executable()
{
// FIXME: this seems weird. is this only used for tests?
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This is used for the executable part of the IncludeOS service binary


INFO2("* Allowing execute on %p -> %p",
(void*) __exec_begin, (void*)__exec_end);

Expand All @@ -391,7 +393,7 @@ void allow_executable()
m.page_sizes = os::mem::Map::any_size;
m.flags = os::mem::Access::execute | os::mem::Access::read;

os::mem::map(m, "ELF .text");
os::mem::map(m, "Executable");
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Perhaps the text could be "ELF executable"

}

/* TODO: Compiler warning unused
Expand Down
15 changes: 15 additions & 0 deletions src/kernel/memmap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,21 @@ Fixed_memory_range& Memory_map::assign_range(Fixed_memory_range&& rng) {
return new_entry.first->second;
}

///////////////////////////////////////////////////////////////////////////////
void Memory_map::unassign_range(const Fixed_memory_range& range) {
auto it = map_.find(range.addr_start());

if (it != map_.end()) {
if (it->second.addr_end() == range.addr_end()) {
map_.erase(it);
} else {
throw Memory_range_exception{"Range mismatch at address " + std::to_string(range.addr_start())};
}
} else {
throw Memory_range_exception{"No range found to erase at " + std::to_string(range.addr_start())};
}
}

///////////////////////////////////////////////////////////////////////////////
Fixed_memory_range& Memory_map::at(const Key key) {
return const_cast<Fixed_memory_range&>(static_cast<const Memory_map*>(this)->at(key));
Expand Down
97 changes: 72 additions & 25 deletions src/kernel/multiboot.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include <boot/multiboot.h>
#include <kernel/memory.hpp>
#include <fmt/format.h>
#include <ranges>

template<class... Args>
static inline void _kfmt(fmt::string_view prefix, fmt::format_string<Args...> fmtstr, Args&&... args) {
Expand Down Expand Up @@ -122,9 +123,41 @@ uintptr_t _multiboot_free_begin(uintptr_t boot_addr)
return multi_end;
}

constexpr static inline const char* multiboot_memory_type_str(uint32_t type) noexcept {
// TODO: convert multiboot types to enum class
switch (type) {
case MULTIBOOT_MEMORY_AVAILABLE:
return "Available";
case MULTIBOOT_MEMORY_ACPI_RECLAIMABLE:
return "ACPI Reclaimable";
case MULTIBOOT_MEMORY_NVS:
return "ACPI Non-volatile Storage";
case MULTIBOOT_MEMORY_BADRAM:
return "Bad RAM";
case MULTIBOOT_MEMORY_RESERVED:
return "Reserved";
default:
return "UNKNOWN";
}
}


std::span<multiboot_memory_map_t> _multiboot_memory_maps() {
auto* info = kernel::bootinfo();

auto* hardware_map = reinterpret_cast<multiboot_memory_map_t*>(info->mmap_addr);
const size_t entry_count = static_cast<size_t>(info->mmap_length / sizeof(multiboot_memory_map_t));

return std::span<multiboot_memory_map_t> { hardware_map, entry_count };
}

void kernel::multiboot(uint32_t boot_addr)
{
MYINFO("Booted with multiboot");
#if defined(__x86_64)
MYINFO("Booted with multiboot x86_64");
#else
MYINFO("Booted with multiboot x86");
#endif
auto* info = ::bootinfo(boot_addr);
INFO2("* Boot flags: {:#x}", info->flags);

Expand Down Expand Up @@ -152,36 +185,50 @@ void kernel::multiboot(uint32_t boot_addr)
}

if (info->flags & MULTIBOOT_INFO_MEM_MAP) {
INFO2("* Multiboot provided memory map ({} entries @ {})",
info->mmap_length / sizeof(multiboot_memory_map_t),
(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))
};

for (auto map : mmap)
auto* hardware_map = reinterpret_cast<multiboot_memory_map_t*>(info->mmap_addr);
const size_t entry_count = static_cast<size_t>(info->mmap_length / sizeof(multiboot_memory_map_t));

INFO2("* Multiboot provided memory map ({} entries @ {})\n", entry_count, reinterpret_cast<const void*>(hardware_map));

for (auto map : std::span<multiboot_memory_map_t>{ hardware_map, entry_count })
{
const char* str_type = map.type & MULTIBOOT_MEMORY_AVAILABLE ? "FREE" : "RESERVED";
const uintptr_t addr = map.addr;
const uintptr_t start = map.addr;
const uintptr_t size = map.len;
INFO2(" {:#x} - {:#x} {} ({} KiB)", addr, addr + size - 1, str_type, size / 1024);

if (not (map.type & MULTIBOOT_MEMORY_AVAILABLE)) {
const uintptr_t end = start + size - 1;

if (util::bits::is_aligned<4_KiB>(map.addr)) {
os::mem::map({addr, addr, os::mem::Access::read | os::mem::Access::write, size},
"Reserved (Multiboot)");
continue;
}
INFO2(" {:#16x} - {:#16x} ({} KiB): {}", start, end, size / 1024, multiboot_memory_type_str(map.type));

// For non-aligned addresses, assign
os::mem::vmmap().assign_range({addr, addr + size - 1, "Reserved (Multiboot)"});
// os::mem::map() does not accept non-aligned page addresses
if (not util::bits::is_aligned<4_KiB>(map.addr)) {
os::mem::vmmap().assign_range({start, start + size - 1, "UNALIGNED"});
continue;
}
else

os::mem::Map rw_map = { /*.linear=*/start, /*.physical=*/start, /*.fl=*/os::mem::Access::read | os::mem::Access::write, /*.sz=*/size };
switch (map.type)
{
// Map as free memory
//os::mem::map_avail({map.addr, map.addr, {os::mem::Access::read | os::mem::Access::write}, map.len}, "Reserved (Multiboot)");
case MULTIBOOT_MEMORY_ACPI_RECLAIMABLE:
os::mem::map(rw_map, "Multiboot (ACPI Reclaimable)");
break;
case MULTIBOOT_MEMORY_NVS:
os::mem::map(rw_map, "Multiboot (ACPI Non-volatile Storage)");
break;
case MULTIBOOT_MEMORY_BADRAM:
os::mem::map(rw_map, "Multiboot (Bad RAM)");
break;
case MULTIBOOT_MEMORY_RESERVED:
os::mem::map(rw_map, "Multiboot (Reserved)");
break;

case MULTIBOOT_MEMORY_AVAILABLE: {
// these are mapped in src/platform/${platform}/os.cpp
break;
}
default: {
char buf[32]; // libc is not entirely initialized at this point
std::snprintf(buf, sizeof(buf), "Unknown memory map type: %d", map.type);
os::panic(buf);
}
}
}
INFO2("");
Expand Down
1 change: 1 addition & 0 deletions src/musl/common.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ template<typename Fn, typename ...Args>
inline auto strace(Fn func, [[maybe_unused]]const char* name, Args&&... args) {
if (!kernel::state().allow_syscalls) {
fprintf(stderr, "Syscalls not allowed here. Unexpected call to %s - terminating\n", name);
os::halt();
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Instead of halt here it would better to fix the Expect-call so we can get stack traces when this happens after boot (and heap is available)

Expects(kernel::state().allow_syscalls);
}

Expand Down
35 changes: 24 additions & 11 deletions src/platform/x86_pc/os.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ extern uintptr_t _ELF_END_;
// in kernel/os.cpp
extern bool os_default_stdout;

extern std::span<multiboot_memory_map_t> _multiboot_memory_maps();

struct alignas(SMP_ALIGN) OS_CPU {
uint64_t cycles_hlt = 0;
};
Expand Down Expand Up @@ -125,10 +127,6 @@ void kernel::start(uint32_t boot_magic, uint32_t boot_addr)

MYINFO("Total memory detected as %s ", util::Byte_r(kernel::memory_end()).to_string().c_str());

// Give the rest of physical memory to heap
kernel::state().heap_max = kernel::memory_end() - 1;
assert(kernel::heap_begin() != 0x0 and kernel::heap_max() != 0x0);

PROFILE("Memory map");
// Assign memory ranges used by the kernel
auto& memmap = os::mem::vmmap();
Expand All @@ -145,13 +143,28 @@ void kernel::start(uint32_t boot_magic, uint32_t boot_addr)
memmap.assign_range({0x10000, 0x9d3ff, "Stack"});
#endif

// heap (physical) area
uintptr_t span_max = std::numeric_limits<std::ptrdiff_t>::max();
uintptr_t heap_range_max_ = std::min(span_max, kernel::heap_max());
multiboot_memory_map_t heap_map = {0,0,0,0};
for (auto entry : _multiboot_memory_maps())
{
if (not entry.is_available()) continue;

if (entry.len > heap_map.len) {
heap_map = entry;
}
}
uintptr_t end = heap_map.addr + heap_map.len - 1;

if (heap_map.addr < 0x1'000'000) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Could this be solved by adding the LiveUpdate and Syslog ranges to the map statically? Should at least be commented here why there's a check

kernel::state().heap_begin = std::max((uintptr_t)0x1'000'000, (uintptr_t)heap_map.addr);
kernel::state().heap_max = std::min(kernel::heap_max(), end);
} else {
kernel::state().heap_begin = heap_map.addr;
kernel::state().heap_max = end;
}

INFO2("* Assigning heap 0x%zx -> 0x%zx", kernel::heap_begin(), heap_range_max_);
memmap.assign_range({kernel::heap_begin(), heap_range_max_,
"Dynamic memory", kernel::heap_usage });

INFO2("* Assigning heap 0x%lx -> 0x%lx", kernel::heap_begin(), kernel::heap_max());
memmap.assign_range({kernel::heap_begin(), kernel::heap_max(), "Heap", kernel::heap_usage });

MYINFO("Virtual memory map");
for (const auto& entry : memmap)
Expand Down Expand Up @@ -182,7 +195,7 @@ void os::event_loop()
__arch_poweroff();
}


/* legacy boot is used when MULTIBOOT_BOOTLOADER_MAGIC is unset, see x86_pc/kernel_start.cpp */
void kernel::legacy_boot()
{
// Fetch CMOS memory info (unfortunately this is maximally 10^16 kb)
Expand Down