[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

@@ -1,6 +1,7 @@
#include "kutil/coord.h"
#include "kutil/guid.h"
#include "kutil/memory.h"
#include "kutil/no_construct.h"
#include "kutil/printf.h"
#include "console.h"
#include "font.h"
@@ -9,7 +10,9 @@
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

View File

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

View File

@@ -14,7 +14,7 @@
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
{
@@ -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_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.");
@@ -83,11 +92,6 @@ device_manager::device_manager(const void *root_table, kutil::allocator &alloc)
kassert(sum == 0, "ACPI 2.0 RSDP checksum mismatch.");
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 *

View File

@@ -18,9 +18,7 @@ class device_manager
{
public:
/// Constructor.
/// \arg root_table Pointer to the ACPI RSDP
/// \arg alloc Allocator for device arrays
device_manager(const void *root_table, kutil::allocator &alloc);
device_manager();
/// Get the system global device manager.
/// \returns A reference to the system device manager
@@ -36,6 +34,10 @@ public:
/// otherwise nullptr.
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.
void init_drivers();
@@ -122,7 +124,6 @@ private:
static device_manager s_instance;
device_manager() = delete;
device_manager(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 frame_block_node = kutil::list_node<frame_block>;
frame_allocator g_frame_allocator;
int
frame_block::compare(const frame_block *rhs) const
{

View File

@@ -66,5 +66,3 @@ struct frame_block
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/no_construct.h"
#include "console.h"
#include "log.h"
#include "scheduler.h"
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};
@@ -50,6 +55,5 @@ logger_task()
void logger_init()
{
new (&g_logger) log::logger(log_buffer, sizeof(log_buffer));
g_logger.set_immediate(output_log);
new (&g_logger) log::logger(log_buffer, sizeof(log_buffer), output_log);
}

View File

@@ -5,7 +5,6 @@
#include "initrd/initrd.h"
#include "kutil/assert.h"
#include "kutil/heap_allocator.h"
#include "kutil/vm_space.h"
#include "apic.h"
#include "block_device.h"
@@ -27,12 +26,35 @@
extern "C" {
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 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;
class test_observer :
@@ -65,7 +87,6 @@ init_console()
cons->puts("jsix OS ");
cons->set_color(0x08, 0x00);
cons->puts(GIT_VERSION " booting...\n");
logger_init();
}
@@ -78,13 +99,14 @@ kernel_main(args::header *header)
gdt_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.validate();
memory_initialize(header);
kutil::allocator &heap = g_kernel_heap;
/*
if (header->frame_buffer && header->frame_buffer_length) {
page_manager::get()->map_offset_pointer(
@@ -116,8 +138,8 @@ kernel_main(args::header *header)
page_manager::get()->dump_blocks(true);
*/
device_manager *devices =
new (&device_manager::get()) device_manager(header->acpi_table, heap);
device_manager &devices = device_manager::get();
devices.parse_acpi(header->acpi_table);
interrupts_enable();
@@ -130,7 +152,7 @@ kernel_main(args::header *header)
log::info(logs::boot, "cr4: %016x", cr4);
*/
devices->init_drivers();
devices.init_drivers();
/*
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();
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);

View File

@@ -5,6 +5,7 @@
#include "kutil/assert.h"
#include "kutil/heap_allocator.h"
#include "kutil/no_construct.h"
#include "kutil/vm_space.h"
#include "frame_allocator.h"
@@ -24,7 +25,18 @@ using memory::table_entries;
using namespace kernel;
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); }
@@ -74,7 +86,7 @@ void walk_page_table(
}
void
memory_initialize(args::header *kargs)
memory_initialize_pre_ctors(args::header *kargs)
{
args::mem_entry *entries = kargs->mem_map;
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};
frame_allocator *fa = new (&g_frame_allocator) frame_allocator;
new (&g_frame_allocator) frame_allocator;
for (unsigned i = 0; i < entry_count; ++i) {
// TODO: use entry attributes
args::mem_entry &e = entries[i];
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
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 {
kernel_offset,
(page_offset-kernel_offset)};
uintptr_t current_start = 0;
size_t current_bytes = 0;
// 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) {
page_table *pdp = kpml4->get(i);
@@ -118,5 +134,7 @@ memory_initialize(args::header *kargs)
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/signals.h"
#include "j6/types.h"
#include "kutil/heap_allocator.h"
#include "objects/kobject.h"
extern kutil::heap_allocator g_kernel_heap;
// TODO: per-cpu this?
static j6_koid_t next_koid;

View File

@@ -16,9 +16,6 @@ using memory::page_mappable;
using memory::pml4e_kernel;
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
// 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
@@ -321,6 +318,7 @@ page_manager::fault_handler(uintptr_t addr)
if (!addr)
return false;
extern kutil::vm_space g_kernel_space;
bool is_heap = addr >= ::memory::heap_start &&
addr < ::memory::heap_start + ::memory::kernel_max_heap;

View File

@@ -181,7 +181,7 @@ private:
};
/// 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; }
@@ -206,12 +206,3 @@ page_table_align(T p)
{
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 "serial.h"
serial_port g_com1;
serial_port g_com1(COM1);
serial_port::serial_port() :