[kernel] Run global constructors

Look up the global constructor list that the linker outputs, and run
them all. Required creation of the `kutil::no_construct` template for
objects that are constructed before the global constructors are run.

Also split the `memory_initialize` function into two - one for just
those objects that need to happen before the global ctors, and one
after.

Tags: memory c++
This commit is contained in:
Justin C. Miller
2020-05-31 23:58:01 -07:00
parent c6c3a556b3
commit 88b090fe94
17 changed files with 126 additions and 67 deletions

View File

@@ -20,6 +20,12 @@ SECTIONS
*(.rodata) *(.rodata)
} }
.ctors : ALIGN(8) {
__ctors = .;
KEEP(*(.ctors))
__ctors_end = .;
}
.bss ALIGN(4096) : { .bss ALIGN(4096) : {
__bss_start = .; __bss_start = .;
*(.bss) *(.bss)

View File

@@ -1,6 +1,7 @@
#include "kutil/coord.h" #include "kutil/coord.h"
#include "kutil/guid.h" #include "kutil/guid.h"
#include "kutil/memory.h" #include "kutil/memory.h"
#include "kutil/no_construct.h"
#include "kutil/printf.h" #include "kutil/printf.h"
#include "console.h" #include "console.h"
#include "font.h" #include "font.h"
@@ -9,7 +10,9 @@
const char digits[] = "0123456789abcdef"; const char digits[] = "0123456789abcdef";
console g_console;
static kutil::no_construct<console> __g_console_storage;
console &g_console = __g_console_storage.value;
class console::screen_out class console::screen_out

View File

@@ -46,7 +46,7 @@ private:
serial_port *m_serial; serial_port *m_serial;
}; };
extern console g_console; extern console &g_console;
inline console * console::get() { return &g_console; } inline console * console::get() { return &g_console; }

View File

@@ -14,7 +14,7 @@
static const char expected_signature[] = "RSD PTR "; static const char expected_signature[] = "RSD PTR ";
device_manager device_manager::s_instance(nullptr, kutil::allocator::invalid); device_manager device_manager::s_instance;
struct acpi1_rsdp struct acpi1_rsdp
{ {
@@ -59,8 +59,17 @@ void irq4_callback(void *)
} }
device_manager::device_manager(const void *root_table, kutil::allocator &alloc) : device_manager::device_manager() :
m_lapic(nullptr) m_lapic(nullptr)
{
m_irqs.ensure_capacity(32);
m_irqs.set_size(16);
m_irqs[2] = {"Clock interrupt", irq2_callback, nullptr};
m_irqs[4] = {"Serial interrupt", irq4_callback, nullptr};
}
void
device_manager::parse_acpi(const void *root_table)
{ {
kassert(root_table != 0, "ACPI root table pointer is null."); kassert(root_table != 0, "ACPI root table pointer is null.");
@@ -83,11 +92,6 @@ device_manager::device_manager(const void *root_table, kutil::allocator &alloc)
kassert(sum == 0, "ACPI 2.0 RSDP checksum mismatch."); kassert(sum == 0, "ACPI 2.0 RSDP checksum mismatch.");
load_xsdt(reinterpret_cast<const acpi_xsdt *>(acpi2->xsdt_address)); load_xsdt(reinterpret_cast<const acpi_xsdt *>(acpi2->xsdt_address));
m_irqs.ensure_capacity(32);
m_irqs.set_size(16);
m_irqs[2] = {"Clock interrupt", irq2_callback, nullptr};
m_irqs[4] = {"Serial interrupt", irq4_callback, nullptr};
} }
ioapic * ioapic *

View File

@@ -18,9 +18,7 @@ class device_manager
{ {
public: public:
/// Constructor. /// Constructor.
/// \arg root_table Pointer to the ACPI RSDP device_manager();
/// \arg alloc Allocator for device arrays
device_manager(const void *root_table, kutil::allocator &alloc);
/// Get the system global device manager. /// Get the system global device manager.
/// \returns A reference to the system device manager /// \returns A reference to the system device manager
@@ -36,6 +34,10 @@ public:
/// otherwise nullptr. /// otherwise nullptr.
ioapic * get_ioapic(int i); ioapic * get_ioapic(int i);
/// Parse ACPI tables.
/// \arg root_table Pointer to the ACPI RSDP
void parse_acpi(const void *root_table);
/// Intialize drivers for the current device list. /// Intialize drivers for the current device list.
void init_drivers(); void init_drivers();
@@ -122,7 +124,6 @@ private:
static device_manager s_instance; static device_manager s_instance;
device_manager() = delete;
device_manager(const device_manager &) = delete; device_manager(const device_manager &) = delete;
device_manager operator=(const device_manager &) = delete; device_manager operator=(const device_manager &) = delete;
}; };

View File

@@ -6,8 +6,6 @@ using memory::frame_size;
using memory::page_offset; using memory::page_offset;
using frame_block_node = kutil::list_node<frame_block>; using frame_block_node = kutil::list_node<frame_block>;
frame_allocator g_frame_allocator;
int int
frame_block::compare(const frame_block *rhs) const frame_block::compare(const frame_block *rhs) const
{ {

View File

@@ -66,5 +66,3 @@ struct frame_block
int compare(const frame_block *rhs) const; int compare(const frame_block *rhs) const;
}; };
extern frame_allocator g_frame_allocator;

View File

@@ -1,11 +1,16 @@
#include "kutil/memory.h" #include "kutil/memory.h"
#include "kutil/no_construct.h"
#include "console.h" #include "console.h"
#include "log.h" #include "log.h"
#include "scheduler.h" #include "scheduler.h"
static uint8_t log_buffer[0x10000]; static uint8_t log_buffer[0x10000];
static log::logger g_logger(log_buffer, sizeof(log_buffer));
// The logger is initialized _before_ global constructors are called,
// so that we can start log output immediately. Keep its constructor
// from being called here so as to not overwrite the previous initialization.
static kutil::no_construct<log::logger> __g_logger_storage;
static log::logger &g_logger = __g_logger_storage.value;
static const uint8_t level_colors[] = {0x07, 0x07, 0x0f, 0x0b, 0x09}; static const uint8_t level_colors[] = {0x07, 0x07, 0x0f, 0x0b, 0x09};
@@ -50,6 +55,5 @@ logger_task()
void logger_init() void logger_init()
{ {
new (&g_logger) log::logger(log_buffer, sizeof(log_buffer)); new (&g_logger) log::logger(log_buffer, sizeof(log_buffer), output_log);
g_logger.set_immediate(output_log);
} }

View File

@@ -5,7 +5,6 @@
#include "initrd/initrd.h" #include "initrd/initrd.h"
#include "kutil/assert.h" #include "kutil/assert.h"
#include "kutil/heap_allocator.h"
#include "kutil/vm_space.h" #include "kutil/vm_space.h"
#include "apic.h" #include "apic.h"
#include "block_device.h" #include "block_device.h"
@@ -27,12 +26,35 @@
extern "C" { extern "C" {
void kernel_main(kernel::args::header *header); void kernel_main(kernel::args::header *header);
void *__bss_start, *__bss_end; void (*__ctors)(void);
void (*__ctors_end)(void);
} }
void
run_constructors()
{
void (**p)(void) = &__ctors;
while (p < &__ctors_end) {
void (*ctor)(void) = *p++;
ctor();
}
}
class test_ctor
{
public:
test_ctor(int value) : value(value) {}
int value;
};
test_ctor ctor_tester(42);
extern void __kernel_assert(const char *, unsigned, const char *); extern void __kernel_assert(const char *, unsigned, const char *);
extern kutil::heap_allocator g_kernel_heap; /// Bootstrap the memory managers.
void memory_initialize_pre_ctors(kernel::args::header *kargs);
void memory_initialize_post_ctors(kernel::args::header *kargs);
using namespace kernel; using namespace kernel;
class test_observer : class test_observer :
@@ -65,7 +87,6 @@ init_console()
cons->puts("jsix OS "); cons->puts("jsix OS ");
cons->set_color(0x08, 0x00); cons->set_color(0x08, 0x00);
cons->puts(GIT_VERSION " booting...\n"); cons->puts(GIT_VERSION " booting...\n");
logger_init(); logger_init();
} }
@@ -78,13 +99,14 @@ kernel_main(args::header *header)
gdt_init(); gdt_init();
interrupts_init(); interrupts_init();
memory_initialize_pre_ctors(header);
kutil::memset(&ctor_tester, 0, sizeof(ctor_tester));
run_constructors();
memory_initialize_post_ctors(header);
cpu_id cpu; cpu_id cpu;
cpu.validate(); cpu.validate();
memory_initialize(header);
kutil::allocator &heap = g_kernel_heap;
/* /*
if (header->frame_buffer && header->frame_buffer_length) { if (header->frame_buffer && header->frame_buffer_length) {
page_manager::get()->map_offset_pointer( page_manager::get()->map_offset_pointer(
@@ -116,8 +138,8 @@ kernel_main(args::header *header)
page_manager::get()->dump_blocks(true); page_manager::get()->dump_blocks(true);
*/ */
device_manager *devices = device_manager &devices = device_manager::get();
new (&device_manager::get()) device_manager(header->acpi_table, heap); devices.parse_acpi(header->acpi_table);
interrupts_enable(); interrupts_enable();
@@ -130,7 +152,7 @@ kernel_main(args::header *header)
log::info(logs::boot, "cr4: %016x", cr4); log::info(logs::boot, "cr4: %016x", cr4);
*/ */
devices->init_drivers(); devices.init_drivers();
/* /*
block_device *disk = devices->get_block_device(0); block_device *disk = devices->get_block_device(0);
@@ -156,10 +178,10 @@ kernel_main(args::header *header)
} }
*/ */
devices->get_lapic()->calibrate_timer(); devices.get_lapic()->calibrate_timer();
syscall_enable(); syscall_enable();
scheduler *sched = new (&scheduler::get()) scheduler(devices->get_lapic()); scheduler *sched = new (&scheduler::get()) scheduler(devices.get_lapic());
sched->create_kernel_task(-1, logger_task); sched->create_kernel_task(-1, logger_task);

View File

@@ -5,6 +5,7 @@
#include "kutil/assert.h" #include "kutil/assert.h"
#include "kutil/heap_allocator.h" #include "kutil/heap_allocator.h"
#include "kutil/no_construct.h"
#include "kutil/vm_space.h" #include "kutil/vm_space.h"
#include "frame_allocator.h" #include "frame_allocator.h"
@@ -24,7 +25,18 @@ using memory::table_entries;
using namespace kernel; using namespace kernel;
kutil::vm_space g_kernel_space; kutil::vm_space g_kernel_space;
kutil::heap_allocator g_kernel_heap;
// These objects are initialized _before_ global constructors are called,
// so we don't want them to have global constructors at all, lest they
// overwrite the previous initialization.
static kutil::no_construct<kutil::heap_allocator> __g_kernel_heap_storage;
kutil::heap_allocator &g_kernel_heap = __g_kernel_heap_storage.value;
static kutil::no_construct<page_manager> __g_page_manager_storage;
page_manager &g_page_manager = __g_page_manager_storage.value;
static kutil::no_construct<frame_allocator> __g_frame_allocator_storage;
frame_allocator &g_frame_allocator = __g_frame_allocator_storage.value;
void * operator new(size_t size) { return g_kernel_heap.allocate(size); } void * operator new(size_t size) { return g_kernel_heap.allocate(size); }
void * operator new [] (size_t size) { return g_kernel_heap.allocate(size); } void * operator new [] (size_t size) { return g_kernel_heap.allocate(size); }
@@ -74,7 +86,7 @@ void walk_page_table(
} }
void void
memory_initialize(args::header *kargs) memory_initialize_pre_ctors(args::header *kargs)
{ {
args::mem_entry *entries = kargs->mem_map; args::mem_entry *entries = kargs->mem_map;
size_t entry_count = kargs->num_map_entries; size_t entry_count = kargs->num_map_entries;
@@ -82,26 +94,30 @@ memory_initialize(args::header *kargs)
new (&g_kernel_heap) kutil::heap_allocator {heap_start, kernel_max_heap}; new (&g_kernel_heap) kutil::heap_allocator {heap_start, kernel_max_heap};
frame_allocator *fa = new (&g_frame_allocator) frame_allocator; new (&g_frame_allocator) frame_allocator;
for (unsigned i = 0; i < entry_count; ++i) { for (unsigned i = 0; i < entry_count; ++i) {
// TODO: use entry attributes // TODO: use entry attributes
args::mem_entry &e = entries[i]; args::mem_entry &e = entries[i];
if (e.type == args::mem_type::free) if (e.type == args::mem_type::free)
fa->free(e.start, e.pages); g_frame_allocator.free(e.start, e.pages);
} }
// Create the page manager // Create the page manager
page_manager *pm = new (&g_page_manager) page_manager(*fa, kpml4); new (&g_page_manager) page_manager {g_frame_allocator, kpml4};
}
void
memory_initialize_post_ctors(args::header *kargs)
{
new (&g_kernel_space) kutil::vm_space { new (&g_kernel_space) kutil::vm_space {
kernel_offset, kernel_offset,
(page_offset-kernel_offset)}; (page_offset-kernel_offset)};
uintptr_t current_start = 0; uintptr_t current_start = 0;
size_t current_bytes = 0; size_t current_bytes = 0;
// TODO: Should we exclude the top of this area? (eg, buffers, stacks, etc) // TODO: Should we exclude the top of this area? (eg, buffers, stacks, etc)
page_table *kpml4 = reinterpret_cast<page_table*>(kargs->pml4);
for (unsigned i = pml4e_kernel; i < pml4e_offset; ++i) { for (unsigned i = pml4e_kernel; i < pml4e_offset; ++i) {
page_table *pdp = kpml4->get(i); page_table *pdp = kpml4->get(i);
@@ -118,5 +134,7 @@ memory_initialize(args::header *kargs)
g_kernel_space); g_kernel_space);
} }
fa->free(reinterpret_cast<uintptr_t>(kargs->page_table_cache), kargs->num_free_tables); g_frame_allocator.free(
reinterpret_cast<uintptr_t>(kargs->page_table_cache),
kargs->num_free_tables);
} }

View File

@@ -1,11 +1,8 @@
#include "j6/errors.h" #include "j6/errors.h"
#include "j6/signals.h" #include "j6/signals.h"
#include "j6/types.h" #include "j6/types.h"
#include "kutil/heap_allocator.h"
#include "objects/kobject.h" #include "objects/kobject.h"
extern kutil::heap_allocator g_kernel_heap;
// TODO: per-cpu this? // TODO: per-cpu this?
static j6_koid_t next_koid; static j6_koid_t next_koid;

View File

@@ -16,9 +16,6 @@ using memory::page_mappable;
using memory::pml4e_kernel; using memory::pml4e_kernel;
using memory::table_entries; using memory::table_entries;
page_manager g_page_manager(g_frame_allocator, 0);
extern kutil::vm_space g_kernel_space;
// NB: in 4KiB page table entries, bit 7 isn't pagesize but PAT. Currently this // NB: in 4KiB page table entries, bit 7 isn't pagesize but PAT. Currently this
// doesn't matter, becasue in the default PAT table, both 000 and 100 are WB. // doesn't matter, becasue in the default PAT table, both 000 and 100 are WB.
constexpr uint64_t sys_page_flags = 0x183; // global, pagesize, write, present constexpr uint64_t sys_page_flags = 0x183; // global, pagesize, write, present
@@ -321,6 +318,7 @@ page_manager::fault_handler(uintptr_t addr)
if (!addr) if (!addr)
return false; return false;
extern kutil::vm_space g_kernel_space;
bool is_heap = addr >= ::memory::heap_start && bool is_heap = addr >= ::memory::heap_start &&
addr < ::memory::heap_start + ::memory::kernel_max_heap; addr < ::memory::heap_start + ::memory::kernel_max_heap;

View File

@@ -181,7 +181,7 @@ private:
}; };
/// Global page manager. /// Global page manager.
extern page_manager g_page_manager; extern page_manager &g_page_manager;
inline page_manager * page_manager::get() { return &g_page_manager; } inline page_manager * page_manager::get() { return &g_page_manager; }
@@ -206,12 +206,3 @@ page_table_align(T p)
{ {
return ((p - 1) & ~0x1fffffull) + 0x200000; return ((p - 1) & ~0x1fffffull) + 0x200000;
} }
namespace kernel {
namespace args {
struct header;
}
}
/// Bootstrap the memory managers.
void memory_initialize(kernel::args::header *mem_map);

View File

@@ -1,7 +1,7 @@
#include "io.h" #include "io.h"
#include "serial.h" #include "serial.h"
serial_port g_com1; serial_port g_com1(COM1);
serial_port::serial_port() : serial_port::serial_port() :

View File

@@ -18,11 +18,18 @@ enum class level : uint8_t {
class logger class logger
{ {
public: public:
/// Callback type for immediate-mode logging
typedef void (*immediate)(area_t, level, const char *);
/// Default constructor. Creates a logger without a backing store. /// Default constructor. Creates a logger without a backing store.
logger(); /// \arg output Immediate-mode logging output function
logger(immediate output = nullptr);
/// Constructor. Logs are written to the given buffer. /// Constructor. Logs are written to the given buffer.
logger(uint8_t *buffer, size_t size); /// \arg buffer Buffer to which logs are written
/// \arg size Size of `buffer`, in bytes
/// \arg output Immediate-mode logging output function
logger(uint8_t *buffer, size_t size, immediate output = nullptr);
/// Register a log area for future use. /// Register a log area for future use.
/// \arg area The key for the new area /// \arg area The key for the new area
@@ -30,9 +37,6 @@ public:
/// \arg verbosity What level of logs to print for this area /// \arg verbosity What level of logs to print for this area
void register_area(area_t area, const char *name, level verbosity); void register_area(area_t area, const char *name, level verbosity);
/// Callback type for immediate-mode logging
typedef void (*immediate)(area_t, level, const char *);
/// Register an immediate-mode log callback /// Register an immediate-mode log callback
inline void set_immediate(immediate cb) { m_immediate = cb; } inline void set_immediate(immediate cb) { m_immediate = cb; }

View File

@@ -0,0 +1,15 @@
#pragma once
/// \file no_construct.h
/// Tools for creating objects witout running constructors
namespace kutil {
/// Helper template for creating objects witout running constructors
template <typename T>
union no_construct
{
T value;
no_construct() {}
};
} // namespace kutil

View File

@@ -21,9 +21,9 @@ using kutil::memcpy;
logger *logger::s_log = nullptr; logger *logger::s_log = nullptr;
const char *logger::s_level_names[] = {"", "debug", "info", "warn", "error", "fatal"}; const char *logger::s_level_names[] = {"", "debug", "info", "warn", "error", "fatal"};
logger::logger() : logger::logger(logger::immediate output) :
m_buffer(nullptr, 0), m_buffer(nullptr, 0),
m_immediate(nullptr), m_immediate(output),
m_sequence(0) m_sequence(0)
{ {
memset(&m_levels, 0, sizeof(m_levels)); memset(&m_levels, 0, sizeof(m_levels));
@@ -31,9 +31,9 @@ logger::logger() :
s_log = this; s_log = this;
} }
logger::logger(uint8_t *buffer, size_t size) : logger::logger(uint8_t *buffer, size_t size, logger::immediate output) :
m_buffer(buffer, size), m_buffer(buffer, size),
m_immediate(nullptr), m_immediate(output),
m_sequence(0) m_sequence(0)
{ {
memset(&m_levels, 0, sizeof(m_levels)); memset(&m_levels, 0, sizeof(m_levels));