This is the first of two rather big changes to clean up includes throughout the project. In this commit, the implicit semi-dependency on libc that bonnibel adds to every module is removed. Previously, I was sloppy with includes of libc headers and include directory order. Now, the freestanding headers from libc are split out into libc_free, and an implicit real dependency is added onto this module, unless `no_libc` is set to `True`. The full libc needs to be explicitly specified as a dependency to be used. Several things needed to change in order to do this: - Many places use `memset` or `memcpy` that cannot depend on libc. The kernel has basic implementations of them itself for this reason. Now those functions are moved into the lower-level `j6/memutils.h`, and libc merely references them. Other modules are now free to reference those functions from libj6 instead. - The kernel's `assert.h` was renamed kassert.h (matching its `kassert` function) so that the new `util/assert.h` can use `__has_include` to detect it and make sure the `assert` macro is usable in libutil code. - Several implementation header files under `__libj6/` also moved under the new libc_free. - A new `include_phase` property has been added to modules for Bonnibel, which can be "normal" (default) or "late" which uses `-idirafter` instead of `-I` for includes. - Since `<utility>` and `<new>` are not freestanding, implementations of `remove_reference`, `forward`, `move`, and `swap` were added to the `util` namespace to replace those from `std`, and `util/new.h` was added to declare `operator new` and `operator delete`.
169 lines
4.6 KiB
C++
169 lines
4.6 KiB
C++
#include <j6/memutils.h>
|
|
#include <util/no_construct.h>
|
|
|
|
#include "kassert.h"
|
|
#include "cpu.h"
|
|
#include "gdt.h"
|
|
#include "logger.h"
|
|
#include "tss.h"
|
|
|
|
extern "C" void gdt_write(const void *gdt_ptr, uint16_t cs, uint16_t ds, uint16_t tr);
|
|
|
|
static constexpr uint8_t kern_cs_index = 1;
|
|
static constexpr uint8_t kern_ss_index = 2;
|
|
static constexpr uint8_t user_cs32_index = 3;
|
|
static constexpr uint8_t user_ss_index = 4;
|
|
static constexpr uint8_t user_cs64_index = 5;
|
|
static constexpr uint8_t tss_index = 6; // Note that this takes TWO GDT entries
|
|
|
|
// The BSP's GDT is initialized _before_ global constructors are called,
|
|
// so we don't want it to have a global constructor, lest it overwrite
|
|
// the previous initialization.
|
|
static util::no_construct<GDT> __g_bsp_gdt_storage;
|
|
GDT &g_bsp_gdt = __g_bsp_gdt_storage.value;
|
|
|
|
|
|
GDT::GDT(TSS *tss) :
|
|
m_tss(tss)
|
|
{
|
|
memset(this, 0, sizeof(GDT));
|
|
|
|
m_ptr.limit = sizeof(m_entries) - 1;
|
|
m_ptr.base = &m_entries[0];
|
|
|
|
// Kernel CS/SS - always 64bit
|
|
set(kern_cs_index, 0, 0xfffff, true, type::read_write | type::execute);
|
|
set(kern_ss_index, 0, 0xfffff, true, type::read_write);
|
|
|
|
// User CS32/SS/CS64 - layout expected by SYSRET
|
|
set(user_cs32_index, 0, 0xfffff, false, type::ring3 | type::read_write | type::execute);
|
|
set(user_ss_index, 0, 0xfffff, true, type::ring3 | type::read_write);
|
|
set(user_cs64_index, 0, 0xfffff, true, type::ring3 | type::read_write | type::execute);
|
|
|
|
set_tss(tss);
|
|
}
|
|
|
|
GDT &
|
|
GDT::current()
|
|
{
|
|
cpu_data &cpu = current_cpu();
|
|
return *cpu.gdt;
|
|
}
|
|
|
|
void
|
|
GDT::install() const
|
|
{
|
|
gdt_write(
|
|
static_cast<const void*>(&m_ptr),
|
|
kern_cs_index << 3,
|
|
kern_ss_index << 3,
|
|
tss_index << 3);
|
|
}
|
|
|
|
void
|
|
GDT::set(uint8_t i, uint32_t base, uint64_t limit, bool is64, type t)
|
|
{
|
|
m_entries[i].limit_low = limit & 0xffff;
|
|
m_entries[i].size = (limit >> 16) & 0xf;
|
|
m_entries[i].size |= (is64 ? 0xa0 : 0xc0);
|
|
|
|
m_entries[i].base_low = base & 0xffff;
|
|
m_entries[i].base_mid = (base >> 16) & 0xff;
|
|
m_entries[i].base_high = (base >> 24) & 0xff;
|
|
|
|
m_entries[i].type = t | type::system | type::present;
|
|
}
|
|
|
|
struct tss_descriptor
|
|
{
|
|
uint16_t limit_low;
|
|
uint16_t base_00;
|
|
uint8_t base_16;
|
|
GDT::type type;
|
|
uint8_t size;
|
|
uint8_t base_24;
|
|
uint32_t base_32;
|
|
uint32_t reserved;
|
|
} __attribute__ ((packed));
|
|
|
|
void
|
|
GDT::set_tss(TSS *tss)
|
|
{
|
|
tss_descriptor tssd;
|
|
|
|
size_t limit = sizeof(TSS);
|
|
tssd.limit_low = limit & 0xffff;
|
|
tssd.size = (limit >> 16) & 0xf;
|
|
|
|
uintptr_t base = reinterpret_cast<uintptr_t>(tss);
|
|
tssd.base_00 = base & 0xffff;
|
|
tssd.base_16 = (base >> 16) & 0xff;
|
|
tssd.base_24 = (base >> 24) & 0xff;
|
|
tssd.base_32 = (base >> 32) & 0xffffffff;
|
|
tssd.reserved = 0;
|
|
|
|
tssd.type =
|
|
type::accessed |
|
|
type::execute |
|
|
type::ring3 |
|
|
type::present;
|
|
|
|
memcpy(&m_entries[tss_index], &tssd, sizeof(tss_descriptor));
|
|
}
|
|
|
|
/*
|
|
void
|
|
GDT::dump(unsigned index) const
|
|
{
|
|
console *cons = console::get();
|
|
|
|
unsigned start = 0;
|
|
unsigned count = (m_ptr.limit + 1) / sizeof(descriptor);
|
|
if (index != -1) {
|
|
start = index;
|
|
count = 1;
|
|
} else {
|
|
cons->printf(" GDT: loc:%lx size:%d\n", m_ptr.base, m_ptr.limit+1);
|
|
}
|
|
|
|
const descriptor *gdt =
|
|
reinterpret_cast<const descriptor *>(m_ptr.base);
|
|
|
|
for (int i = start; i < start+count; ++i) {
|
|
uint32_t base =
|
|
(gdt[i].base_high << 24) |
|
|
(gdt[i].base_mid << 16) |
|
|
gdt[i].base_low;
|
|
|
|
uint32_t limit =
|
|
static_cast<uint32_t>(gdt[i].size & 0x0f) << 16 |
|
|
gdt[i].limit_low;
|
|
|
|
cons->printf(" %02d:", i);
|
|
if (! (gdt[i].type && type::present)) {
|
|
cons->puts(" Not Present\n");
|
|
continue;
|
|
}
|
|
|
|
cons->printf(" Base %08x limit %05x ", base, limit);
|
|
|
|
switch (gdt[i].type & type::ring3) {
|
|
case type::ring3: cons->puts("ring3"); break;
|
|
case type::ring2: cons->puts("ring2"); break;
|
|
case type::ring1: cons->puts("ring1"); break;
|
|
default: cons->puts("ring0"); break;
|
|
}
|
|
|
|
cons->printf(" %s %s %s %s %s %s %s\n",
|
|
(gdt[i].type && type::accessed) ? "A" : " ",
|
|
(gdt[i].type && type::read_write) ? "RW" : " ",
|
|
(gdt[i].type && type::conforming) ? "C" : " ",
|
|
(gdt[i].type && type::execute) ? "EX" : " ",
|
|
(gdt[i].type && type::system) ? "S" : " ",
|
|
(gdt[i].size & 0x80) ? "KB" : " B",
|
|
(gdt[i].size & 0x60) == 0x20 ? "64" :
|
|
(gdt[i].size & 0x60) == 0x40 ? "32" : "16");
|
|
}
|
|
}
|
|
*/
|