[kernel] Move more from kutil to kernel
The moving of kernel-only code out of kutil continues. (See 042f061)
This commit moves the following:
- The heap allocator code
- memory.cpp/h which means:
- letting string.h be the right header for memset and memcpy, still
including an implementation of it for the kernel though, since
we're not linking libc to the kernel
- Changing calls to kalloc/kfree to new/delete in kutil containers
that aren't going to be merged into the kernel
- Fixing a problem with stdalign.h from libc, which was causing issues
for type_traits.
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
#include "kutil/memory.h"
|
||||
#include "kutil/no_construct.h"
|
||||
#include "printf/printf.h"
|
||||
|
||||
#include "console.h"
|
||||
#include "serial.h"
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include <stdint.h>
|
||||
#include "kutil/assert.h"
|
||||
#include "kutil/memory.h"
|
||||
|
||||
#include "cpu.h"
|
||||
#include "cpu/cpu_id.h"
|
||||
#include "device_manager.h"
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#include "kutil/assert.h"
|
||||
#include "kutil/memory.h"
|
||||
|
||||
#include "acpi_tables.h"
|
||||
#include "apic.h"
|
||||
#include "clock.h"
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "interrupts.h"
|
||||
#include "kernel_memory.h"
|
||||
#include "log.h"
|
||||
#include "memory.h"
|
||||
#include "objects/endpoint.h"
|
||||
#include "serial.h"
|
||||
|
||||
@@ -47,7 +48,7 @@ struct acpi2_rsdp
|
||||
bool
|
||||
acpi_table_header::validate(uint32_t expected_type) const
|
||||
{
|
||||
if (kutil::checksum(this, length) != 0) return false;
|
||||
if (::checksum(this, length) != 0) return false;
|
||||
return !expected_type || (expected_type == type);
|
||||
}
|
||||
|
||||
@@ -82,7 +83,7 @@ device_manager::parse_acpi(const void *root_table)
|
||||
kassert(acpi1->signature[i] == expected_signature[i],
|
||||
"ACPI RSDP table signature mismatch");
|
||||
|
||||
uint8_t sum = kutil::checksum(acpi1, sizeof(acpi1_rsdp), 0);
|
||||
uint8_t sum = checksum(acpi1, sizeof(acpi1_rsdp), 0);
|
||||
kassert(sum == 0, "ACPI 1.0 RSDP checksum mismatch.");
|
||||
|
||||
kassert(acpi1->revision > 1, "ACPI 1.0 not supported.");
|
||||
@@ -90,7 +91,7 @@ device_manager::parse_acpi(const void *root_table)
|
||||
const acpi2_rsdp *acpi2 =
|
||||
reinterpret_cast<const acpi2_rsdp *>(acpi1);
|
||||
|
||||
sum = kutil::checksum(acpi2, sizeof(acpi2_rsdp), sizeof(acpi1_rsdp));
|
||||
sum = checksum(acpi2, sizeof(acpi2_rsdp), sizeof(acpi1_rsdp));
|
||||
kassert(sum == 0, "ACPI 2.0 RSDP checksum mismatch.");
|
||||
|
||||
load_xsdt(memory::to_virtual(acpi2->xsdt_address));
|
||||
@@ -212,8 +213,8 @@ device_manager::load_apic(const acpi_table_header *header)
|
||||
|
||||
switch (type) {
|
||||
case 0: { // Local APIC
|
||||
uint8_t uid = kutil::read_from<uint8_t>(p+2);
|
||||
uint8_t id = kutil::read_from<uint8_t>(p+3);
|
||||
uint8_t uid = read_from<uint8_t>(p+2);
|
||||
uint8_t id = read_from<uint8_t>(p+3);
|
||||
m_apic_ids.append(id);
|
||||
|
||||
log::debug(logs::device, " Local APIC uid %x id %x", uid, id);
|
||||
@@ -221,8 +222,8 @@ device_manager::load_apic(const acpi_table_header *header)
|
||||
break;
|
||||
|
||||
case 1: { // I/O APIC
|
||||
uintptr_t base = kutil::read_from<uint32_t>(p+4);
|
||||
uint32_t base_gsi = kutil::read_from<uint32_t>(p+8);
|
||||
uintptr_t base = read_from<uint32_t>(p+4);
|
||||
uint32_t base_gsi = read_from<uint32_t>(p+8);
|
||||
m_ioapics.emplace(base, base_gsi);
|
||||
|
||||
log::debug(logs::device, " IO APIC gsi %x base %x", base_gsi, base);
|
||||
@@ -231,9 +232,9 @@ device_manager::load_apic(const acpi_table_header *header)
|
||||
|
||||
case 2: { // Interrupt source override
|
||||
irq_override o;
|
||||
o.source = kutil::read_from<uint8_t>(p+3);
|
||||
o.gsi = kutil::read_from<uint32_t>(p+4);
|
||||
o.flags = kutil::read_from<uint16_t>(p+8);
|
||||
o.source = read_from<uint8_t>(p+3);
|
||||
o.gsi = read_from<uint32_t>(p+4);
|
||||
o.flags = read_from<uint16_t>(p+8);
|
||||
m_overrides.append(o);
|
||||
|
||||
log::debug(logs::device, " Intr source override IRQ %d -> %d Pol %d Tri %d",
|
||||
@@ -243,9 +244,9 @@ device_manager::load_apic(const acpi_table_header *header)
|
||||
|
||||
case 4: {// LAPIC NMI
|
||||
apic_nmi nmi;
|
||||
nmi.cpu = kutil::read_from<uint8_t>(p + 2);
|
||||
nmi.lint = kutil::read_from<uint8_t>(p + 5);
|
||||
nmi.flags = kutil::read_from<uint16_t>(p + 3);
|
||||
nmi.cpu = read_from<uint8_t>(p + 2);
|
||||
nmi.lint = read_from<uint8_t>(p + 5);
|
||||
nmi.flags = read_from<uint16_t>(p + 3);
|
||||
m_nmis.append(nmi);
|
||||
|
||||
log::debug(logs::device, " LAPIC NMI Proc %02x LINT%d Pol %d Tri %d",
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#include "kutil/assert.h"
|
||||
#include "kutil/memory.h"
|
||||
|
||||
#include "frame_allocator.h"
|
||||
#include "kernel_args.h"
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "kutil/assert.h"
|
||||
#include "kutil/memory.h"
|
||||
#include "kutil/no_construct.h"
|
||||
|
||||
#include "console.h"
|
||||
#include "cpu.h"
|
||||
#include "gdt.h"
|
||||
@@ -28,7 +29,7 @@ GDT &g_bsp_gdt = __g_bsp_gdt_storage.value;
|
||||
GDT::GDT(TSS *tss) :
|
||||
m_tss(tss)
|
||||
{
|
||||
kutil::memset(this, 0, sizeof(GDT));
|
||||
memset(this, 0, sizeof(GDT));
|
||||
|
||||
m_ptr.limit = sizeof(m_entries) - 1;
|
||||
m_ptr.base = &m_entries[0];
|
||||
@@ -110,7 +111,7 @@ GDT::set_tss(TSS *tss)
|
||||
type::ring3 |
|
||||
type::present;
|
||||
|
||||
kutil::memcpy(&m_entries[tss_index], &tssd, sizeof(tss_descriptor));
|
||||
memcpy(&m_entries[tss_index], &tssd, sizeof(tss_descriptor));
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
177
src/kernel/heap_allocator.cpp
Normal file
177
src/kernel/heap_allocator.cpp
Normal file
@@ -0,0 +1,177 @@
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include "kutil/assert.h"
|
||||
#include "kutil/util.h"
|
||||
|
||||
#include "heap_allocator.h"
|
||||
#include "memory.h"
|
||||
|
||||
struct heap_allocator::mem_header
|
||||
{
|
||||
mem_header(mem_header *prev, mem_header *next, uint8_t order) :
|
||||
m_prev(prev), m_next(next)
|
||||
{
|
||||
set_order(order);
|
||||
}
|
||||
|
||||
inline void set_order(uint8_t order) {
|
||||
m_prev = reinterpret_cast<mem_header *>(
|
||||
reinterpret_cast<uintptr_t>(prev()) | (order & 0x3f));
|
||||
}
|
||||
|
||||
inline void set_used(bool used) {
|
||||
m_next = reinterpret_cast<mem_header *>(
|
||||
reinterpret_cast<uintptr_t>(next()) | (used ? 1 : 0));
|
||||
}
|
||||
|
||||
inline void set_next(mem_header *next) {
|
||||
bool u = used();
|
||||
m_next = next;
|
||||
set_used(u);
|
||||
}
|
||||
|
||||
inline void set_prev(mem_header *prev) {
|
||||
uint8_t s = order();
|
||||
m_prev = prev;
|
||||
set_order(s);
|
||||
}
|
||||
|
||||
void remove() {
|
||||
if (next()) next()->set_prev(prev());
|
||||
if (prev()) prev()->set_next(next());
|
||||
set_prev(nullptr);
|
||||
set_next(nullptr);
|
||||
}
|
||||
|
||||
inline mem_header * next() { return mask_pointer(m_next, 0x3f); }
|
||||
inline mem_header * prev() { return mask_pointer(m_prev, 0x3f); }
|
||||
|
||||
inline mem_header * buddy() const {
|
||||
return reinterpret_cast<mem_header *>(
|
||||
reinterpret_cast<uintptr_t>(this) ^ (1 << order()));
|
||||
}
|
||||
|
||||
inline bool eldest() const { return this < buddy(); }
|
||||
|
||||
inline uint8_t order() const { return reinterpret_cast<uintptr_t>(m_prev) & 0x3f; }
|
||||
inline bool used() const { return reinterpret_cast<uintptr_t>(m_next) & 0x1; }
|
||||
|
||||
private:
|
||||
mem_header *m_prev;
|
||||
mem_header *m_next;
|
||||
};
|
||||
|
||||
|
||||
heap_allocator::heap_allocator() : m_start {0}, m_end {0} {}
|
||||
|
||||
heap_allocator::heap_allocator(uintptr_t start, size_t size) :
|
||||
m_start {start},
|
||||
m_end {start+size},
|
||||
m_blocks {0},
|
||||
m_allocated_size {0}
|
||||
{
|
||||
memset(m_free, 0, sizeof(m_free));
|
||||
}
|
||||
|
||||
void *
|
||||
heap_allocator::allocate(size_t length)
|
||||
{
|
||||
size_t total = length + sizeof(mem_header);
|
||||
|
||||
if (length == 0)
|
||||
return nullptr;
|
||||
|
||||
unsigned order = kutil::log2(total);
|
||||
if (order < min_order)
|
||||
order = min_order;
|
||||
|
||||
kassert(order <= max_order, "Tried to allocate a block bigger than max_order");
|
||||
if (order > max_order)
|
||||
return nullptr;
|
||||
|
||||
kutil::scoped_lock lock {m_lock};
|
||||
|
||||
mem_header *header = pop_free(order);
|
||||
header->set_used(true);
|
||||
m_allocated_size += (1 << order);
|
||||
return header + 1;
|
||||
}
|
||||
|
||||
void
|
||||
heap_allocator::free(void *p)
|
||||
{
|
||||
if (!p) return;
|
||||
|
||||
uintptr_t addr = reinterpret_cast<uintptr_t>(p);
|
||||
kassert(addr >= m_start && addr < m_end,
|
||||
"Attempt to free non-heap pointer");
|
||||
|
||||
kutil::scoped_lock lock {m_lock};
|
||||
|
||||
mem_header *header = reinterpret_cast<mem_header *>(p);
|
||||
header -= 1; // p points after the header
|
||||
header->set_used(false);
|
||||
m_allocated_size -= (1 << header->order());
|
||||
|
||||
while (header->order() != max_order) {
|
||||
auto order = header->order();
|
||||
|
||||
mem_header *buddy = header->buddy();
|
||||
if (buddy->used() || buddy->order() != order)
|
||||
break;
|
||||
|
||||
if (get_free(order) == buddy)
|
||||
get_free(order) = buddy->next();
|
||||
|
||||
buddy->remove();
|
||||
|
||||
header = header->eldest() ? header : buddy;
|
||||
header->set_order(order + 1);
|
||||
}
|
||||
|
||||
uint8_t order = header->order();
|
||||
header->set_next(get_free(order));
|
||||
get_free(order) = header;
|
||||
if (header->next())
|
||||
header->next()->set_prev(header);
|
||||
}
|
||||
|
||||
void
|
||||
heap_allocator::ensure_block(unsigned order)
|
||||
{
|
||||
if (get_free(order) != nullptr)
|
||||
return;
|
||||
|
||||
if (order == max_order) {
|
||||
size_t bytes = (1 << max_order);
|
||||
uintptr_t next = m_start + m_blocks * bytes;
|
||||
if (next + bytes <= m_end) {
|
||||
mem_header *nextp = reinterpret_cast<mem_header *>(next);
|
||||
new (nextp) mem_header(nullptr, nullptr, order);
|
||||
get_free(order) = nextp;
|
||||
++m_blocks;
|
||||
}
|
||||
} else {
|
||||
mem_header *orig = pop_free(order + 1);
|
||||
if (orig) {
|
||||
mem_header *next = offset_pointer(orig, 1 << order);
|
||||
new (next) mem_header(orig, nullptr, order);
|
||||
|
||||
orig->set_next(next);
|
||||
orig->set_order(order);
|
||||
get_free(order) = orig;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
heap_allocator::mem_header *
|
||||
heap_allocator::pop_free(unsigned order)
|
||||
{
|
||||
ensure_block(order);
|
||||
mem_header *block = get_free(order);
|
||||
if (block) {
|
||||
get_free(order) = block->next();
|
||||
block->remove();
|
||||
}
|
||||
return block;
|
||||
}
|
||||
62
src/kernel/heap_allocator.h
Normal file
62
src/kernel/heap_allocator.h
Normal file
@@ -0,0 +1,62 @@
|
||||
#pragma once
|
||||
/// \file heap_allocator.h
|
||||
/// A buddy allocator for a memory heap
|
||||
|
||||
#include <stddef.h>
|
||||
#include "kutil/spinlock.h"
|
||||
|
||||
|
||||
/// Allocator for a given heap range
|
||||
class heap_allocator
|
||||
{
|
||||
public:
|
||||
/// Default constructor creates a valid but empty heap.
|
||||
heap_allocator();
|
||||
|
||||
/// Constructor. The given memory area must already have been reserved.
|
||||
/// \arg start Starting address of the heap
|
||||
/// \arg size Size of the heap in bytes
|
||||
heap_allocator(uintptr_t start, size_t size);
|
||||
|
||||
/// Allocate memory from the area managed.
|
||||
/// \arg length The amount of memory to allocate, in bytes
|
||||
/// \returns A pointer to the allocated memory, or nullptr if
|
||||
/// allocation failed.
|
||||
void * allocate(size_t length);
|
||||
|
||||
/// Free a previous allocation.
|
||||
/// \arg p A pointer previously retuned by allocate()
|
||||
void free(void *p);
|
||||
|
||||
/// Minimum block size is (2^min_order). Must be at least 6.
|
||||
static const unsigned min_order = 6;
|
||||
|
||||
/// Maximum block size is (2^max_order). Must be less than 64.
|
||||
static const unsigned max_order = 22;
|
||||
|
||||
protected:
|
||||
class mem_header;
|
||||
|
||||
/// Ensure there is a block of a given order, recursively splitting
|
||||
/// \arg order Order (2^N) of the block we want
|
||||
void ensure_block(unsigned order);
|
||||
|
||||
/// Helper accessor for the list of blocks of a given order
|
||||
/// \arg order Order (2^N) of the block we want
|
||||
/// \returns A mutable reference to the head of the list
|
||||
mem_header *& get_free(unsigned order) { return m_free[order - min_order]; }
|
||||
|
||||
/// Helper to get a block of the given order, growing if necessary
|
||||
/// \arg order Order (2^N) of the block we want
|
||||
/// \returns A detached block of the given order
|
||||
mem_header * pop_free(unsigned order);
|
||||
|
||||
uintptr_t m_start, m_end;
|
||||
size_t m_blocks;
|
||||
mem_header *m_free[max_order - min_order + 1];
|
||||
size_t m_allocated_size;
|
||||
|
||||
kutil::spinlock m_lock;
|
||||
|
||||
heap_allocator(const heap_allocator &) = delete;
|
||||
};
|
||||
@@ -1,5 +1,7 @@
|
||||
#include "kutil/memory.h"
|
||||
#include <string.h>
|
||||
|
||||
#include "kutil/no_construct.h"
|
||||
|
||||
#include "cpu.h"
|
||||
#include "idt.h"
|
||||
#include "log.h"
|
||||
@@ -33,7 +35,7 @@ IDT::set_nmi_handler(uintptr_t address)
|
||||
|
||||
IDT::IDT()
|
||||
{
|
||||
kutil::memset(this, 0, sizeof(IDT));
|
||||
memset(this, 0, sizeof(IDT));
|
||||
m_ptr.limit = sizeof(m_entries) - 1;
|
||||
m_ptr.base = &m_entries[0];
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ kernel = module("kernel",
|
||||
"frame_allocator.cpp",
|
||||
"gdt.cpp",
|
||||
"gdtidt.s",
|
||||
"heap_allocator.cpp",
|
||||
"hpet.cpp",
|
||||
"idt.cpp",
|
||||
"interrupts.cpp",
|
||||
@@ -27,6 +28,7 @@ kernel = module("kernel",
|
||||
"io.cpp",
|
||||
"log.cpp",
|
||||
"logger.cpp",
|
||||
"memory.cpp",
|
||||
"memory_bootstrap.cpp",
|
||||
"msr.cpp",
|
||||
"objects/channel.cpp",
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
#include "j6/signals.h"
|
||||
#include "kutil/memory.h"
|
||||
#include "kutil/no_construct.h"
|
||||
|
||||
#include "console.h"
|
||||
#include "log.h"
|
||||
#include "memory.h"
|
||||
#include "objects/system.h"
|
||||
#include "objects/thread.h"
|
||||
|
||||
@@ -57,8 +58,8 @@ logger_task()
|
||||
size_t size = g_logger.get_entry(buffer, buffer_size);
|
||||
if (size > buffer_size) {
|
||||
while (size > buffer_size) buffer_size *= 2;
|
||||
kutil::kfree(buffer);
|
||||
buffer = reinterpret_cast<uint8_t*>(kutil::kalloc(buffer_size));
|
||||
kfree(buffer);
|
||||
buffer = reinterpret_cast<uint8_t*>(kalloc(buffer_size));
|
||||
kassert(buffer, "Could not allocate logger task buffer");
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "kutil/assert.h"
|
||||
#include "kutil/constexpr_hash.h"
|
||||
#include "kutil/memory.h"
|
||||
#include "printf/printf.h"
|
||||
|
||||
#include "logger.h"
|
||||
@@ -15,9 +16,6 @@ namespace logs {
|
||||
|
||||
namespace log {
|
||||
|
||||
using kutil::memset;
|
||||
using kutil::memcpy;
|
||||
|
||||
logger *logger::s_log = nullptr;
|
||||
const char *logger::s_level_names[] = {"", "debug", "info", "warn", "error", "fatal"};
|
||||
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "j6/signals.h"
|
||||
|
||||
#include "kernel_args.h"
|
||||
#include "kernel_memory.h"
|
||||
#include "kutil/assert.h"
|
||||
|
||||
#include "apic.h"
|
||||
#include "block_device.h"
|
||||
#include "clock.h"
|
||||
@@ -14,8 +17,6 @@
|
||||
#include "idt.h"
|
||||
#include "interrupts.h"
|
||||
#include "io.h"
|
||||
#include "kernel_args.h"
|
||||
#include "kernel_memory.h"
|
||||
#include "log.h"
|
||||
#include "msr.h"
|
||||
#include "objects/channel.h"
|
||||
@@ -28,6 +29,7 @@
|
||||
#include "tss.h"
|
||||
#include "vm_space.h"
|
||||
|
||||
|
||||
#ifndef GIT_VERSION
|
||||
#define GIT_VERSION
|
||||
#endif
|
||||
@@ -96,7 +98,7 @@ kernel_main(init::args *args)
|
||||
extern uintptr_t idle_stack_end;
|
||||
|
||||
cpu_data *cpu = &g_bsp_cpu_data;
|
||||
kutil::memset(cpu, 0, sizeof(cpu_data));
|
||||
memset(cpu, 0, sizeof(cpu_data));
|
||||
|
||||
cpu->self = cpu;
|
||||
cpu->idt = new (&g_bsp_idt) IDT;
|
||||
@@ -158,7 +160,7 @@ kernel_main(init::args *args)
|
||||
if (disk) {
|
||||
for (int i=0; i<1; ++i) {
|
||||
uint8_t buf[512];
|
||||
kutil::memset(buf, 0, 512);
|
||||
memset(buf, 0, 512);
|
||||
|
||||
kassert(disk->read(0x200, sizeof(buf), buf),
|
||||
"Disk read returned 0");
|
||||
@@ -214,7 +216,7 @@ start_aps(lapic &apic, const kutil::vector<uint8_t> &ids, void *kpml4)
|
||||
uint8_t vector = addr >> 12;
|
||||
vm_area *vma = new vm_area_fixed(addr, 0x1000, vm_flags::write);
|
||||
vm_space::kernel_space().add(addr, vma);
|
||||
kutil::memcpy(
|
||||
memcpy(
|
||||
reinterpret_cast<void*>(addr),
|
||||
reinterpret_cast<void*>(&ap_startup),
|
||||
ap_startup_code_size);
|
||||
@@ -241,7 +243,7 @@ start_aps(lapic &apic, const kutil::vector<uint8_t> &ids, void *kpml4)
|
||||
TSS *tss = new TSS;
|
||||
GDT *gdt = new GDT {tss};
|
||||
cpu_data *cpu = new cpu_data;
|
||||
kutil::memset(cpu, 0, sizeof(cpu_data));
|
||||
memset(cpu, 0, sizeof(cpu_data));
|
||||
|
||||
cpu->self = cpu;
|
||||
cpu->id = id;
|
||||
|
||||
37
src/kernel/memory.cpp
Normal file
37
src/kernel/memory.cpp
Normal file
@@ -0,0 +1,37 @@
|
||||
#include "memory.h"
|
||||
|
||||
namespace std {
|
||||
enum class __attribute__ ((__type_visibility("default"))) align_val_t : size_t { };
|
||||
}
|
||||
|
||||
// Implementation of memset and memcpy because we're not
|
||||
// linking libc into the kernel
|
||||
extern "C" {
|
||||
|
||||
void *
|
||||
memset(void *s, uint8_t v, size_t n)
|
||||
{
|
||||
uint8_t *p = reinterpret_cast<uint8_t *>(s);
|
||||
for (size_t i = 0; i < n; ++i) p[i] = v;
|
||||
return s;
|
||||
}
|
||||
|
||||
void *
|
||||
memcpy(void *dest, const void *src, size_t n)
|
||||
{
|
||||
const uint8_t *s = reinterpret_cast<const uint8_t *>(src);
|
||||
uint8_t *d = reinterpret_cast<uint8_t *>(dest);
|
||||
for (size_t i = 0; i < n; ++i) d[i] = s[i];
|
||||
return d;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
uint8_t
|
||||
checksum(const void *p, size_t len, size_t off)
|
||||
{
|
||||
uint8_t sum = 0;
|
||||
const uint8_t *c = reinterpret_cast<const uint8_t *>(p);
|
||||
for (int i = off; i < len; ++i) sum += c[i];
|
||||
return sum;
|
||||
}
|
||||
52
src/kernel/memory.h
Normal file
52
src/kernel/memory.h
Normal file
@@ -0,0 +1,52 @@
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
void * operator new (size_t, void *p) noexcept;
|
||||
|
||||
/// Allocate from the default allocator.
|
||||
/// \arg size The size in bytes requested
|
||||
/// \returns A pointer to the newly allocated memory,
|
||||
/// or nullptr on error
|
||||
void * kalloc(size_t size);
|
||||
|
||||
/// Free memory allocated by `kalloc`.
|
||||
/// \arg p Pointer that was returned from a `kalloc` call
|
||||
void kfree(void *p);
|
||||
|
||||
/// Read a value of type T from a location in memory
|
||||
/// \arg p The location in memory to read
|
||||
/// \returns The value at the given location cast to T
|
||||
template <typename T>
|
||||
inline T read_from(const void *p)
|
||||
{
|
||||
return *reinterpret_cast<const T *>(p);
|
||||
}
|
||||
|
||||
/// Get a pointer that's offset from another pointer
|
||||
/// \arg p The base pointer
|
||||
/// \arg n The offset in bytes
|
||||
/// \returns The offset pointer
|
||||
template <typename T>
|
||||
inline T * offset_pointer(T *p, ptrdiff_t n)
|
||||
{
|
||||
return reinterpret_cast<T *>(reinterpret_cast<uintptr_t>(p) + n);
|
||||
}
|
||||
|
||||
/// Return a pointer with the given bits masked out
|
||||
/// \arg p The original pointer
|
||||
/// \arg mask A bitmask of bits to clear from p
|
||||
/// \returns The masked pointer
|
||||
template <typename T>
|
||||
inline T* mask_pointer(T *p, uintptr_t mask)
|
||||
{
|
||||
return reinterpret_cast<T *>(reinterpret_cast<uintptr_t>(p) & ~mask);
|
||||
}
|
||||
|
||||
/// Do a simple byte-wise checksum of an area of memory.
|
||||
/// \arg p The start of the memory region
|
||||
/// \arg len The number of bytes in the region
|
||||
/// \arg off An optional offset into the region
|
||||
uint8_t checksum(const void *p, size_t len, size_t off = 0);
|
||||
@@ -5,12 +5,12 @@
|
||||
|
||||
#include "enum_bitfields.h"
|
||||
#include "kutil/assert.h"
|
||||
#include "kutil/heap_allocator.h"
|
||||
#include "kutil/no_construct.h"
|
||||
|
||||
#include "device_manager.h"
|
||||
#include "frame_allocator.h"
|
||||
#include "gdt.h"
|
||||
#include "heap_allocator.h"
|
||||
#include "io.h"
|
||||
#include "log.h"
|
||||
#include "msr.h"
|
||||
@@ -39,8 +39,8 @@ extern "C" uintptr_t initialize_main_user_stack();
|
||||
// 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<heap_allocator> __g_kernel_heap_storage;
|
||||
heap_allocator &g_kernel_heap = __g_kernel_heap_storage.value;
|
||||
|
||||
static kutil::no_construct<frame_allocator> __g_frame_allocator_storage;
|
||||
frame_allocator &g_frame_allocator = __g_frame_allocator_storage.value;
|
||||
@@ -62,10 +62,8 @@ void * operator new [] (size_t size) { return g_kernel_heap.allocate(size)
|
||||
void operator delete (void *p) noexcept { return g_kernel_heap.free(p); }
|
||||
void operator delete [] (void *p) noexcept { return g_kernel_heap.free(p); }
|
||||
|
||||
namespace kutil {
|
||||
void * kalloc(size_t size) { return g_kernel_heap.allocate(size); }
|
||||
void kfree(void *p) { return g_kernel_heap.free(p); }
|
||||
}
|
||||
void * kalloc(size_t size) { return g_kernel_heap.allocate(size); }
|
||||
void kfree(void *p) { return g_kernel_heap.free(p); }
|
||||
|
||||
template <typename T>
|
||||
uintptr_t
|
||||
@@ -80,7 +78,7 @@ memory_initialize_pre_ctors(init::args &kargs)
|
||||
|
||||
page_table *kpml4 = static_cast<page_table*>(kargs.pml4);
|
||||
|
||||
new (&g_kernel_heap) kutil::heap_allocator {heap_start, kernel_max_heap};
|
||||
new (&g_kernel_heap) heap_allocator {heap_start, kernel_max_heap};
|
||||
|
||||
frame_block *blocks = reinterpret_cast<frame_block*>(memory::bitmap_start);
|
||||
new (&g_frame_allocator) frame_allocator {blocks, kargs.frame_blocks.count};
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#include <string.h>
|
||||
#include "kutil/assert.h"
|
||||
|
||||
#include "kernel_memory.h"
|
||||
@@ -38,7 +39,7 @@ channel::enqueue(size_t *len, const void *data)
|
||||
size_t avail = m_buffer.reserve(*len, &buffer);
|
||||
*len = *len > avail ? avail : *len;
|
||||
|
||||
kutil::memcpy(buffer, data, *len);
|
||||
memcpy(buffer, data, *len);
|
||||
m_buffer.commit(*len);
|
||||
|
||||
assert_signal(j6_signal_channel_can_recv);
|
||||
@@ -65,7 +66,7 @@ channel::dequeue(size_t *len, void *data)
|
||||
size_t avail = m_buffer.get_block(&buffer);
|
||||
*len = *len > avail ? avail : *len;
|
||||
|
||||
kutil::memcpy(data, buffer, *len);
|
||||
memcpy(data, buffer, *len);
|
||||
m_buffer.consume(*len);
|
||||
|
||||
assert_signal(j6_signal_channel_can_send);
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#include "j6/signals.h"
|
||||
|
||||
#include "cpu.h"
|
||||
#include "log.h"
|
||||
#include "memory.h"
|
||||
#include "objects/thread.h"
|
||||
#include "objects/process.h"
|
||||
#include "objects/vm_area.h"
|
||||
@@ -40,7 +42,7 @@ thread::from_tcb(TCB *tcb)
|
||||
{
|
||||
static ptrdiff_t offset =
|
||||
-1 * static_cast<ptrdiff_t>(offsetof(thread, m_tcb));
|
||||
return reinterpret_cast<thread*>(kutil::offset_pointer(tcb, offset));
|
||||
return reinterpret_cast<thread*>(offset_pointer(tcb, offset));
|
||||
}
|
||||
|
||||
thread & thread::current() { return *current_cpu().thread; }
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "kutil/assert.h"
|
||||
#include "kutil/memory.h"
|
||||
|
||||
#include "console.h"
|
||||
#include "frame_allocator.h"
|
||||
#include "kernel_memory.h"
|
||||
#include "memory.h"
|
||||
#include "page_table.h"
|
||||
|
||||
using memory::page_offset;
|
||||
@@ -28,8 +31,8 @@ page_table::iterator::iterator(uintptr_t virt, page_table *pml4) :
|
||||
|
||||
page_table::iterator::iterator(const page_table::iterator &o)
|
||||
{
|
||||
kutil::memcpy(&m_table, &o.m_table, sizeof(m_table));
|
||||
kutil::memcpy(&m_index, &o.m_index, sizeof(m_index));
|
||||
memcpy(&m_table, &o.m_table, sizeof(m_table));
|
||||
memcpy(&m_index, &o.m_index, sizeof(m_index));
|
||||
}
|
||||
|
||||
inline static level to_lv(unsigned i) { return static_cast<level>(i); }
|
||||
@@ -190,7 +193,7 @@ page_table::get_table_page()
|
||||
--s_cache_count;
|
||||
}
|
||||
|
||||
kutil::memset(page, 0, memory::frame_size);
|
||||
memset(page, 0, memory::frame_size);
|
||||
return reinterpret_cast<page_table*>(page);
|
||||
}
|
||||
|
||||
@@ -220,11 +223,11 @@ page_table::fill_table_page_cache()
|
||||
memory::to_virtual<free_page_header>(phys);
|
||||
|
||||
for (int i = 0; i < n - 1; ++i)
|
||||
kutil::offset_pointer(start, i * memory::frame_size)
|
||||
->next = kutil::offset_pointer(start, (i+1) * memory::frame_size);
|
||||
offset_pointer(start, i * memory::frame_size)
|
||||
->next = offset_pointer(start, (i+1) * memory::frame_size);
|
||||
|
||||
free_page_header *end =
|
||||
kutil::offset_pointer(start, (n-1) * memory::frame_size);
|
||||
offset_pointer(start, (n-1) * memory::frame_size);
|
||||
|
||||
end->next = s_page_cache;
|
||||
s_page_cache = start;
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "kutil/assert.h"
|
||||
#include "kutil/memory.h"
|
||||
|
||||
#include "frame_allocator.h"
|
||||
#include "kernel_memory.h"
|
||||
#include "page_tree.h"
|
||||
@@ -33,7 +35,7 @@ page_tree::page_tree(uint64_t base, uint8_t level) :
|
||||
m_base {base & level_mask(level)},
|
||||
m_level {level}
|
||||
{
|
||||
kutil::memset(m_entries, 0, sizeof(m_entries));
|
||||
memset(m_entries, 0, sizeof(m_entries));
|
||||
}
|
||||
|
||||
page_tree::~page_tree()
|
||||
|
||||
@@ -106,7 +106,7 @@ pci_device::pci_device(pci_group &group, uint8_t bus, uint8_t device, uint8_t fu
|
||||
// Walk the extended capabilities list
|
||||
uint8_t next = m_base[13] & 0xff;
|
||||
while (next) {
|
||||
pci_cap *cap = reinterpret_cast<pci_cap *>(kutil::offset_pointer(m_base, next));
|
||||
pci_cap *cap = reinterpret_cast<pci_cap *>(offset_pointer(m_base, next));
|
||||
next = cap->next;
|
||||
log::debug(logs::device, " - found PCI cap type %02x", cap->id);
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
/// PCI devices and groups
|
||||
|
||||
#include <stdint.h>
|
||||
#include "kutil/memory.h"
|
||||
#include "memory.h"
|
||||
|
||||
struct pci_group;
|
||||
enum class isr : uint8_t;
|
||||
@@ -126,7 +126,7 @@ struct pci_group
|
||||
/// \returns A pointer to the memory-mapped configuration registers
|
||||
inline uint32_t * base_for(uint8_t bus, uint8_t device, uint8_t func)
|
||||
{
|
||||
return kutil::offset_pointer(base,
|
||||
return offset_pointer(base,
|
||||
pci_device::bus_addr(bus, device, func) << 12);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include <string.h>
|
||||
#include "kutil/assert.h"
|
||||
#include "kutil/memory.h"
|
||||
#include "kutil/no_construct.h"
|
||||
|
||||
#include "interrupts.h"
|
||||
#include "io.h"
|
||||
#include "serial.h"
|
||||
@@ -121,7 +122,7 @@ serial_port::do_write()
|
||||
if (n > fifo_size)
|
||||
n = fifo_size;
|
||||
|
||||
kutil::memcpy(tmp, data, n);
|
||||
memcpy(tmp, data, n);
|
||||
m_out_buffer.consume(n);
|
||||
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// vim: ft=cpp
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "kutil/memory.h"
|
||||
|
||||
#include "console.h"
|
||||
#include "debug.h"
|
||||
@@ -38,7 +38,7 @@ syscall_invalid(uint64_t call)
|
||||
void
|
||||
syscall_initialize()
|
||||
{
|
||||
kutil::memset(&syscall_registry, 0, sizeof(syscall_registry));
|
||||
memset(&syscall_registry, 0, sizeof(syscall_registry));
|
||||
|
||||
/*[[[cog code generation
|
||||
for id, scope, method in syscalls.methods:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#include <string.h>
|
||||
#include "kutil/assert.h"
|
||||
#include "kutil/memory.h"
|
||||
#include "kutil/no_construct.h"
|
||||
|
||||
#include "cpu.h"
|
||||
@@ -17,7 +17,7 @@ TSS &g_bsp_tss = __g_bsp_tss_storage.value;
|
||||
|
||||
TSS::TSS()
|
||||
{
|
||||
kutil::memset(this, 0, sizeof(TSS));
|
||||
memset(this, 0, sizeof(TSS));
|
||||
m_iomap_offset = sizeof(TSS);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "frame_allocator.h"
|
||||
#include "kernel_memory.h"
|
||||
#include "log.h"
|
||||
@@ -38,7 +40,7 @@ vm_space::vm_space() :
|
||||
m_pml4 = page_table::get_table_page();
|
||||
page_table *kpml4 = kernel_space().m_pml4;
|
||||
|
||||
kutil::memset(m_pml4, 0, memory::frame_size/2);
|
||||
memset(m_pml4, 0, memory::frame_size/2);
|
||||
for (unsigned i = memory::pml4e_kernel; i < memory::table_entries; ++i)
|
||||
m_pml4->entries[i] = kpml4->entries[i];
|
||||
}
|
||||
@@ -295,7 +297,7 @@ vm_space::copy(vm_space &source, vm_space &dest, const void *from, void *to, siz
|
||||
|
||||
// TODO: iterate page mappings and continue copying. For now i'm blindly
|
||||
// assuming both buffers are fully contained within single pages
|
||||
kutil::memcpy(
|
||||
memcpy(
|
||||
memory::to_virtual<void>((*dit & ~0xfffull) | (ito & 0xffful)),
|
||||
memory::to_virtual<void>((*sit & ~0xfffull) | (ifrom & 0xffful)),
|
||||
length);
|
||||
|
||||
Reference in New Issue
Block a user