// not, see <https://www.gnu.org/licenses/>.
#include "elf64.hpp"
+#include <assert.hpp>
void os::elf::load_elf(os::process& result, amy::byte* start, amy::size length, const paging::PML4T& original_PML4T) {
- os::assert(length >= amy::byte_size<os::elf::header>(), "Elf file isn't big enough to contain a header: there is an error.");
+ assert(length >= amy::byte_size<os::elf::header>(), "Elf file isn't big enough to contain a header: there is an error.");
// TODO: Check that the elf file sections are all fully inside the file.
// Load test-module elf file:
const os::elf::header elf_header = *(os::elf::header*)start;
// Check if elf is valid:
- os::assert(elf_header.magic[0] == '\x7f', "No elf header.");
- os::assert(elf_header.magic[1] == 'E', "No elf header.");
- os::assert(elf_header.magic[2] == 'L', "No elf header.");
- os::assert(elf_header.magic[3] == 'F', "No elf header.");
- os::assert(elf_header.bitn == 2, "Elf file not 64 bits.");
- os::assert(elf_header.endianness == 1, "Elf file not little endian.");
- os::assert(elf_header.type == 2, "Elf file not executable.");
- os::assert(elf_header.arch == 0x3E, "Elf file not x86_64.");
+ assert(elf_header.magic[0] == '\x7f', "No elf header.");
+ assert(elf_header.magic[1] == 'E', "No elf header.");
+ assert(elf_header.magic[2] == 'L', "No elf header.");
+ assert(elf_header.magic[3] == 'F', "No elf header.");
+ assert(elf_header.bitn == 2, "Elf file not 64 bits.");
+ assert(elf_header.endianness == 1, "Elf file not little endian.");
+ assert(elf_header.type == 2, "Elf file not executable.");
+ assert(elf_header.arch == 0x3E, "Elf file not x86_64.");
constexpr amy::size stack_size = 16 * 0x1000 /* 64KiB */;
amy::byte* const stack = (amy::byte*)0x0000'8000'0000'0000 - stack_size;
const auto page = os::paging::page_allocator.allocate(1);
- os::assert(page.ptr != nullptr, "Not enough memory for elf file loading.");
+ assert(page.ptr != amy::nil, "Not enough memory for elf file loading.");
result.PML4T = phys_ptr<paging::PML4T>(page.ptr.get_phys_addr());
result.rip = amy::u64(elf_header.entry);
result.rsp = amy::u64(stack + stack_size);
continue;
}
os::print("Segment: loadable\n");
- os::assert(0x1000 <= amy::u64(program_header.p_vaddr)
+ assert(0x1000 <= amy::u64(program_header.p_vaddr)
&& amy::u64(program_header.p_vaddr + program_header.p_memsz) < 0x10'0000'0000,
"Program segments must be contained between 0x1000 and 0x10'0000'0000 (i.e. 64GiB).");
amy::size nb_pages = (amy::u64(program_header.p_vaddr) % 0x1000 + program_header.p_memsz + 0x1000 - 1) / 0x1000;
for (amy::size i = 0; i < nb_pages; i++) {
auto const alloc = os::paging::page_allocator.allocate(1);
- os::assert(alloc.ptr != nullptr, "Failed to allocate enough memory for loading of elf binary.");
+ assert(alloc.ptr != nullptr, "Failed to allocate enough memory for loading of elf binary.");
os::paging::map_page(*result.PML4T, (os::paging::page<0>*)(program_header.p_vaddr + i * 0x1000), alloc.ptr, {
.RW = ((program_header.flags & 2) >> 1) != 0,
.US = true, .PWT = false, .PCD = false, .A = false, .D = false, .PAT = false, .G = false, .AVL = 0,
) { // Kernel memory
os::print("Allocating (Ring 0): {}\n", (void*)vaddr);
auto const alloc = os::paging::page_allocator.allocate(1);
- os::assert(alloc.ptr != nullptr, "Out of memory.");
+ assert(alloc.ptr != nullptr, "Out of memory.");
os::paging::map_page(os::paging::global_PML4T, (os::paging::page<0>*)vaddr, alloc.ptr,
{.RW = true, .US = false, .PWT = false, .PCD = false, .A = false, .D = false, .PAT = false, .G = true, .AVL = 0, .NX = true});
return;
) { // Userspace memory
os::print("Allocating (Ring 3): {}\n", (void*)vaddr);
auto const alloc = os::paging::page_allocator.allocate(1);
- os::assert(alloc.ptr != nullptr, "Out of memory.");
+ assert(alloc.ptr != nullptr, "Out of memory.");
os::paging::map_page(*os::get_process(os::current_pid).PML4T, (os::paging::page<0>*)vaddr, alloc.ptr,
{.RW = true, .US = true, .PWT = false, .PCD = false, .A = false, .D = false, .PAT = false, .G = false, .AVL = 0, .NX = true});
return;
#pragma once
#include <types.hpp>
+#include <assert.hpp>
#include "lib/phys_ptr.hpp"
#include "serial.hpp"
#include "utils.hpp"
bool present : 1 = true;
};
-template<typename... Ts>
-void assert(bool cond, const char* format, const Ts&... vs);
-
template<amy::size interrupt_nb>
void enable_interrupts(const isr_info (&ISRs)[interrupt_nb], os::idt<interrupt_nb>& idt) {
- os::assert(is_APIC_builtin(), "No builtin APIC.");
+ assert(is_APIC_builtin(), "No builtin APIC.");
disable_PIC();
set_APIC_reg(0xF0, 0x1FF); // Enable APIC
#include <allocator.hpp>
#include <vector.hpp>
+#include <assert.hpp>
#include "lib/multiboot2.hpp"
#include "paging.hpp"
#include "utils.hpp"
os::hlt();
}
}
- os::assert(magic == 0x36D76289, "Incorrect magic number: wasn't booted with multiboot2.");
+ assert(magic == 0x36D76289, "Incorrect magic number: wasn't booted with multiboot2.");
os::paging::page_allocator.deallocate({
.ptr = os::phys_ptr<os::paging::page<0>>(amy::ptr(&bootstrap_pages_for_memory) & amy::ptr(~0xFFFF'FFFF'8000'0000)),
.size = amy::byte_size<decltype(bootstrap_pages_for_memory)>() / amy::byte_size<decltype(bootstrap_pages_for_memory[0])>()
});
- os::assert(os::cpu_has_msr(), "MSRs aren't supported.");
+ assert(os::cpu_has_msr(), "MSRs aren't supported.");
// Initialise kernel map.
- os::assert(amy::ptr(&_kernel_phys_start) % 4096 == 0, "Kernel isn't page aligned !");
- os::assert(amy::ptr(&_kernel_phys_rw_start) % 4096 == 0, "Kernel isn't page aligned !");
- os::assert(amy::ptr(&_kernel_phys_end) % 4096 == 0, "Kernel isn't page aligned !");
+ assert(amy::ptr(&_kernel_phys_start) % 4096 == 0, "Kernel isn't page aligned !");
+ assert(amy::ptr(&_kernel_phys_rw_start) % 4096 == 0, "Kernel isn't page aligned !");
+ assert(amy::ptr(&_kernel_phys_end) % 4096 == 0, "Kernel isn't page aligned !");
for (amy::size i = amy::ptr(&_kernel_phys_start); i < amy::ptr(&_kernel_phys_rw_start); ) {
if (i % (1024 * 1024 * 1024) == 0 && i + 1024 * 1024 * 1024 < amy::ptr(&_kernel_phys_rw_start)) {
os::paging::map_page<2, 3>(os::paging::global_PML4T, (os::paging::page<2>*)(0xFFFF'FFFF'8000'0000 + i), os::phys_ptr<os::paging::page<2>>(i),
if (e <= 1024 * 1024) { // I'll ignore lower memory for now.
continue;
}
- os::assert(s % 0x1000 == 0, "Memory map unaligned on page boundaries.");
- os::assert(e % 0x1000 == 0, "Memory map unaligned on page boundaries.");
+ assert(s % 0x1000 == 0, "Memory map unaligned on page boundaries.");
+ assert(e % 0x1000 == 0, "Memory map unaligned on page boundaries.");
for (amy::ptr j = s; j < e; ) {
if (j % (1024 * 1024 * 1024) == 0 && j + 1024 * 1024 * 1024 < e) {
os::paging::map_page<2, 3>(
};
amy::stack_allocator<amy::byte_size<ram_range>() * 64, amy::byte_align<ram_range>()> available_ram_allocator;
amy::vector<ram_range, decltype(available_ram_allocator)> available_ram(available_ram_allocator);
- os::assert(!available_ram.construction_failed(), "Failed to create vector.");
+ assert(!available_ram.construction_failed(), "Failed to create vector.");
amy::size available_ram_length = 0;
bool module_specified = false;
if (e.get_phys_addr() <= 1024 * 1024) { // I'll ignore lower memory for now.
continue;
}
- os::assert(available_ram.push_back({.start_address = s, .end_address = e}),
+ assert(available_ram.push_back({.start_address = s, .end_address = e}),
"Too much available RAM sections to initialise correctly. Will fix eventually, probably.");
}
break;
}
}
- os::assert(module_specified, "No modules specified in the multiboot. This is unsupported.");
+ assert(module_specified, "No modules specified in the multiboot. This is unsupported.");
// kernel_start and kernel_end are aligned to 4K by the linker script.
const os::phys_ptr<os::paging::page<0>> kernel_s{amy::ptr(&_kernel_phys_start)};
} else if (available_ram[i].end_address <= kernel_e) {
available_ram[i].end_address = kernel_s - 1; // Since start_address < s, start_address <= new end_address.
} else {
- os::assert(available_ram.push_back(available_ram[i]),
+ assert(available_ram.push_back(available_ram[i]),
"Too much available RAM sections to initialise correctly. Will fix eventually, probably.");
available_ram[i].end_address = kernel_s - 1;
available_ram[available_ram.size() - 1].start_address = kernel_e + 1;
#include <types.hpp>
#include <memory.hpp>
+#include <assert.hpp>
namespace os {
constexpr phys_ptr(amy::nil_t): phys_addr(0xF000'0000'0000'0000) {}
inline void* operator->() const {
+ assert(*this != amy::nil);
return get_virt_addr();
}
inline explicit operator void*() const {
+ assert(*this != amy::nil);
return get_virt_addr();
}
constexpr phys_ptr(amy::nil_t): phys_addr(0xF000'0000'0000'0000) {}
T& operator[](amy::diff i) const {
+ assert(*this != amy::nil);
return get_virt_addr()[i];
}
T& operator*() const {
+ assert(*this != amy::nil);
return *get_virt_addr();
}
T* operator->() const {
+ assert(*this != amy::nil);
return get_virt_addr();
}
explicit operator T*() const {
#pragma once
+#include <assert.hpp>
#include <types.hpp>
+#include "lib/phys_ptr.hpp"
#include "serial.hpp"
#include "utils.hpp"
-#include "lib/phys_ptr.hpp"
namespace os { namespace paging {
return (data & (1 << 0)) != 0;
}
bool is_page() {
- os::assert(is_present(), "Cannot check if a paging_entry is a page if it's not present.");
+ assert(is_present(), "Cannot check if a paging_entry is a page if it's not present.");
return depth == 0 || (data & (1 << 7)) != 0;
}
paging::page_info page_info() {
- os::assert(is_page(), "Cannot access page info for a non-page.");
+ assert(is_page(), "Cannot access page info for a non-page.");
return {
.RW = (data & (1ull << 1)) != 0,
.US = (data & (1ull << 2)) != 0,
};
}
os::phys_ptr<os::paging::page<depth>> page_ptr() {
- os::assert(is_page(), "Cannot access page physical pointer for a non-page.");
+ assert(is_page(), "Cannot access page physical pointer for a non-page.");
amy::ptr addr = data & (depth == 0 ? 0x0000'FFFF'FFFF'F000 : 0x0000'FFFF'FFFF'E000);
return os::phys_ptr<os::paging::page<depth>>(addr | ((addr & 0x0000'8000'0000'0000) != 0 ? 0xFFFF'8000'0000'0000 : 0));
}
void page_ptr(os::phys_ptr<os::paging::page<depth>> page) {
- os::assert(is_page(), "Cannot access page physical pointer for a non-page.");
+ assert(is_page(), "Cannot access page physical pointer for a non-page.");
if (depth == 0) {
data = (data & ~0x0000'FFFF'FFFF'F000) | page.get_phys_addr();
} else {
}
}
paging::paging_table_info paging_table_info() {
- os::assert(!is_page(), "Cannot access paging table info for a page.");
+ assert(!is_page(), "Cannot access paging table info for a page.");
return {
.RW = (data & (1ull << 1)) != 0,
.US = (data & (1ull << 2)) != 0,
};
}
os::phys_ptr<os::paging::paging_table<depth - 1>> paging_table_ptr() {
- os::assert(!is_page(), "Cannot access paging table physical pointer for a page.");
+ assert(!is_page(), "Cannot access paging table physical pointer for a page.");
amy::ptr addr = data & 0x0000'FFFF'FFFF'F000;
return os::phys_ptr<os::paging::paging_table<depth - 1>>(addr | ((addr & 0x0000'8000'0000'0000) != 0 ? 0xFFFF'8000'0000'0000 : 0));
}
void paging_table_ptr(os::phys_ptr<os::paging::paging_table<depth - 1>> table) {
- os::assert(!is_page(), "Cannot access paging table physical pointer for a page.");
+ assert(!is_page(), "Cannot access paging table physical pointer for a page.");
data = (data & ~0x0000'FFFF'FFFF'F000) | table.get_phys_addr();
}
void remove() {
void map_page(paging_table<paging_depth>& paging_table, page<depth> const* vaddr, phys_ptr<page<depth>> paddr, os::paging::page_info page_info) {
amy::size const index = (amy::ptr(vaddr) >> (12 + 9 * paging_depth)) & 0x1FF;
if constexpr (depth == paging_depth) {
- os::assert(!paging_table.contents[index].is_present(), "Virtual address 0x{} is already mapped.", vaddr);
+ assert(!paging_table.contents[index].is_present(), "Virtual address 0x{} is already mapped.", vaddr);
paging_table.contents[index].page_info(page_info);
paging_table.contents[index].page_ptr(paddr);
invlpg(vaddr);
// You should have received a copy of the GNU General Public License along with this program. If
// not, see <https://www.gnu.org/licenses/>.
+#include <assert.hpp>
#include "ring3.hpp"
#include "utils.hpp"
#include "serial.hpp"
// extern "C" int os::syscall_mount_kernel_device(amy::fd wd, char device, char const* path, amy::size path_len, int mount_type);
extern "C" int os::syscall_mount_kernel_device(amy::fd, char, char const*, amy::size, int) {
- os::assert(false, "mount_kernel_device not implemented yet.");
+ assert(false, "mount_kernel_device not implemented yet.");
__builtin_unreachable();
}
// extern "C" amy::fd os::syscall_open(amy::fd wd, char const* path, amy::size path_len, int options);
extern "C" amy::fd os::syscall_open(amy::fd, char const*, amy::size, int) {
- os::assert(false, "open not implemented yet.");
+ assert(false, "open not implemented yet.");
__builtin_unreachable();
}
extern "C" amy::size os::syscall_read(amy::fd file, char* data, amy::size len) {
- os::assert(file == amy::fd(0), "Read isn't really implemented for now.");
- os::assert(len >= 0, "Read expects a positive size.");
+ assert(file == amy::fd(0), "Read isn't really implemented for now.");
+ assert(len >= 0, "Read expects a positive size.");
if (len == 0) {
return 0;
}
}
extern "C" amy::size os::syscall_write(amy::fd file, char const* data, amy::size len) {
- os::assert(file == amy::fd(0), "Write isn't really implemented for now.");
- os::assert(len >= 0, "Write expects a positive size.");
+ assert(file == amy::fd(0), "Write isn't really implemented for now.");
+ assert(len >= 0, "Write expects a positive size.");
if (len == 0) {
return 0;
}
// extern "C" int syscall_close(amy::fd file);
extern "C" int os::syscall_close(amy::fd) {
- os::assert(false, "Close isn't implemented for now.");
+ assert(false, "Close isn't implemented for now.");
__builtin_unreachable();
}
extern "C" void os::syscall_rax_error_handler() {
- os::assert(false, "Incorrect %rax for syscall.");
+ assert(false, "Incorrect %rax for syscall.");
__builtin_unreachable();
}
#include "interrupts.hpp"
#include "serial.hpp"
+void amy::assert_handler(char const* cond, char const* file, int line) {
+ os::print("Assertion error in file '{}', at line {}: {}.\n", file, (unsigned)line, cond);
+ while (true) {
+ os::hlt();
+ }
+}
+
bool os::init_serial_port() {
outb(serial_port + 1, 0x00); // Disable interrupts.
outb(serial_port + 3, 0x80); // Prepare to set baud rate divisor (38400 baud).
write_serial(c);
}
void os::print_formatted(const char* format, const char* val) {
- os::assert(format[0] == '}', "Format string unsupported. TODO.");
+ assert(format[0] == '}', "Format string unsupported. TODO.");
for (amy::size i = 0; val[i] != '\0'; i++) {
os::printc(val[i]);
}
}
void os::print_formatted(const char* format, amy::u64 val) {
- os::assert(format[0] == '}', "Format string unsupported. TODO.");
+ assert(format[0] == '}', "Format string unsupported. TODO.");
char data[20];
char* curr = data + 19;
while (val != 0) {
}
}
void os::print_formatted(const char* format, amy::i64 val) {
- os::assert(format[0] == '}', "Format string unsupported. TODO.");
+ assert(format[0] == '}', "Format string unsupported. TODO.");
if (val < 0) {
os::printc('-');
os::print_formatted(format, amy::u64(-val));
}
}
void os::print_formatted(const char* format, phys_ptr<void> val) {
- os::assert(format[0] == '}', "Format string unsupported. TODO.");
+ assert(format[0] == '}', "Format string unsupported. TODO.");
os::print("0x");
for (int i = 60; i >= 0; i -= 4) {
const int v = (val.get_phys_addr() >> i) & 0xF;
}
}
void os::print_formatted(const char* format, const void* val) {
- os::assert(format[0] == '}', "Format string unsupported. TODO.");
+ assert(format[0] == '}', "Format string unsupported. TODO.");
os::print("0x");
for (int i = 60; i >= 0; i -= 4) {
const int v = (reinterpret_cast<amy::ptr>(val) >> i) & 0xF;
#pragma once
+#include <assert.hpp>
#include "types.hpp"
#include "lib/phys_ptr.hpp"
namespace os {
-template<typename... Ts>
-void assert(bool cond, const char* format, const Ts&... vs);
-
constexpr amy::u16 serial_port{0x3F8};
bool init_serial_port();
for (amy::size i = 0; format[i] != '\0'; i++) {
if (format[i] == '{') {
i++;
- if (format[i] == '\0') {
- os::assert(false, "Error in format string: unterminated '{{}'.");
- } else if (format[i] == '{') {
+ assert(format[i] != '\0', "Error in format string: unterminated '{{}'.");
+ if (format[i] == '{') {
printc('{');
continue;
} else {
amy::size format_spec_end = i;
while (format[format_spec_end] != '}') {
- if (format[format_spec_end++] == '\0') {
- os::assert(false, "Error in format string: unterminated '{{}'.");
- }
+ assert(format[format_spec_end++] != '\0', "Error in format string: unterminated '{{}'.");
}
amy::size n = arg_n;
if ('0' <= format[i] && format[i] <= '9') {
if (arg_n == 0) {
arg_n_is_given = true;
}
- os::assert(arg_n_is_given, "Error in format string: either the arg_id is always given, or never.");
+ assert(arg_n_is_given, "Error in format string: either the arg_id is always given, or never.");
amy::size n_ = 0;
while ('0' <= format[i] && format[i] <= '9') {
n_ = n_ * 10 + (format[i++] - '0');
if (arg_n == 0) {
arg_n_is_given = false;
}
- os::assert(!arg_n_is_given, "Error in format string: either the arg_id is always given, or never.");
+ assert(!arg_n_is_given, "Error in format string: either the arg_id is always given, or never.");
}
if (format[i] == ':') {
i++;
} else {
- os::assert(format[i] == '}', "Error in format string: ':' required before format spec.");
+ assert(format[i] == '}', "Error in format string: ':' required before format spec.");
}
- os::assert(n < amy::size(sizeof...(vs)), "Error in format string: not enough arguments.");
+ assert(n < amy::size(sizeof...(vs)), "Error in format string: not enough arguments.");
(print_nth_helper{n, &format[i]} % ... % get_more_general_type_helper_t<Ts>(vs));
i = format_spec_end;
arg_n++;
}
} else if (format[i] == '}') {
- os::assert(format[i + 1] == '}', "Error in format string: unexpected '}'.");
+ assert(format[i + 1] == '}', "Error in format string: unexpected '}'.");
i++;
printc('}');
} else {
void cli();
void hlt();
-template<typename... Ts>
-void assert(bool cond, const char* format, const Ts&... vs) {
- if (!cond) {
- print("Error: ");
- print(format, vs...);
- printc('\n');
- cli();
- while (true) { hlt(); }
- }
-}
-
} // namespace os
#pragma once
+#include <assert.hpp>
#include <types.hpp>
#include <memory.hpp>
#include "serial.hpp"
return 0 <= index && index < n && elems[index].present;
}
amy::i64 create() {
- os::assert(has_room(), "Too many allocated elems in incrementing_int64_map.");
+ assert(has_room(), "Too many allocated elems in incrementing_int64_map.");
elems[n].present = true;
new(elems[n].buffer) T;
return n++;
}
void remove(amy::i64 index) {
- os::assert(present(index), "Tried removing non-existant element of incrementing_int64_map.");
+ assert(present(index), "Tried removing non-existant element of incrementing_int64_map.");
get(index).~T();
elems[index].present = false;
}
T& get(amy::i64 index) {
- os::assert(present(index), "Tried getting non-existant element of incrementing_int64_map.");
+ assert(present(index), "Tried getting non-existant element of incrementing_int64_map.");
return *amy::launder(reinterpret_cast<T*>(&elems[index].buffer[0]));
}
const T& get(amy::i64 index) const {
- os::assert(present(index), "Tried getting non-existant element of incrementing_int64_map.");
+ assert(present(index), "Tried getting non-existant element of incrementing_int64_map.");
return *amy::launder(reinterpret_cast<T*>(&elems[index].buffer[0]));
}
--- /dev/null
+// Copyright 2023 Amélia COUTARD.
+//
+// This file from the program "voyage au centre des fichiers" is free software: you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by the Free Software Foundation,
+// either version 3 of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+// without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+// PURPOSE. See the GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along with this program. If
+// not, see <https://www.gnu.org/licenses/>.
+
+#pragma once
+
+#define assert(cond, ...) if (!(cond)) amy::assert_handler(#cond ", " #__VA_ARGS__, __FILE__, __LINE__)
+
+namespace amy {
+ void assert_handler(char const* cond, char const* file, int line) __attribute__((noreturn));
+} // namespace amy