mirror of
https://github.com/justinian/jsix.git
synced 2025-12-09 16:04:32 -08:00
Merge branch 'real-hardware' into fb-driver
This commit is contained in:
11
modules.yaml
11
modules.yaml
@@ -6,6 +6,7 @@ modules:
|
||||
output: jsix.elf
|
||||
target: host
|
||||
deps:
|
||||
- cpu
|
||||
- kutil
|
||||
includes:
|
||||
- src/kernel
|
||||
@@ -62,6 +63,8 @@ modules:
|
||||
kind: exe
|
||||
target: boot
|
||||
output: boot.efi
|
||||
deps:
|
||||
- cpu
|
||||
source:
|
||||
- src/boot/main.cpp
|
||||
- src/boot/console.cpp
|
||||
@@ -110,6 +113,14 @@ modules:
|
||||
- src/libraries/kutil/memory.cpp
|
||||
- src/libraries/kutil/printf.c
|
||||
|
||||
cpu:
|
||||
kind: lib
|
||||
output: libcpu.a
|
||||
includes:
|
||||
- src/libraries/cpu/include
|
||||
source:
|
||||
- src/libraries/cpu/cpu.cpp
|
||||
|
||||
|
||||
libc:
|
||||
kind: lib
|
||||
|
||||
@@ -70,8 +70,8 @@ console::console(uefi::boot_services *bs, uefi::protos::simple_text_output *out)
|
||||
type = L"unknown";
|
||||
}
|
||||
|
||||
printf(L"Found framebuffer: %dx%d type %s @0x%x\r\n",
|
||||
m_fb.horizontal, m_fb.vertical, type, m_fb.phys_addr);
|
||||
printf(L"Found framebuffer: %dx%d[%d] type %s @0x%x\r\n",
|
||||
m_fb.horizontal, m_fb.vertical, m_fb.scanline, type, m_fb.phys_addr);
|
||||
} else {
|
||||
printf(L"No framebuffer found.\r\n");
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#include "console.h"
|
||||
#include "cpu/cpu.h"
|
||||
#include "error.h"
|
||||
#include "fs.h"
|
||||
#include "hardware.h"
|
||||
@@ -94,6 +95,28 @@ add_module(args::header *args, args::mod_type type, buffer &data)
|
||||
m.size = data.size;
|
||||
}
|
||||
|
||||
/// Check that all required cpu features are supported
|
||||
void
|
||||
check_cpu_supported()
|
||||
{
|
||||
status_line status {L"Checking CPU features"};
|
||||
|
||||
cpu::cpu_id cpu;
|
||||
uint64_t missing = cpu.missing();
|
||||
if (missing) {
|
||||
#define CPU_FEATURE_OPT(...)
|
||||
#define CPU_FEATURE_REQ(name, ...) \
|
||||
if (!cpu.has_feature(cpu::feature::name)) { \
|
||||
status::fail(L"CPU required feature " L ## #name, uefi::status::unsupported); \
|
||||
}
|
||||
#include "cpu/features.inc"
|
||||
#undef CPU_FEATURE_REQ
|
||||
#undef CPU_FEATURE_OPT
|
||||
|
||||
error::raise(uefi::status::unsupported, L"CPU not supported");
|
||||
}
|
||||
}
|
||||
|
||||
/// The main procedure for the portion of the loader that runs while
|
||||
/// UEFI is still in control of the machine. (ie, while the loader still
|
||||
/// has access to boot services.
|
||||
@@ -160,6 +183,7 @@ efi_main(uefi::handle image, uefi::system_table *st)
|
||||
{
|
||||
using namespace boot;
|
||||
console con(st->boot_services, st->con_out);
|
||||
check_cpu_supported();
|
||||
|
||||
args::header *args = uefi_preboot(image, st);
|
||||
memory::efi_mem_map map = uefi_exit(args, image, st->boot_services);
|
||||
|
||||
@@ -36,6 +36,15 @@ static const wchar_t *memory_type_names[] = {
|
||||
L"persistent memory"
|
||||
};
|
||||
|
||||
static const wchar_t *kernel_memory_type_names[] = {
|
||||
L"free",
|
||||
L"pending",
|
||||
L"acpi",
|
||||
L"uefi_runtime",
|
||||
L"mmio",
|
||||
L"persistent"
|
||||
};
|
||||
|
||||
static const wchar_t *
|
||||
memory_type_name(uefi::memory_type t)
|
||||
{
|
||||
@@ -45,6 +54,12 @@ memory_type_name(uefi::memory_type t)
|
||||
return L"Bad Type Value";
|
||||
}
|
||||
|
||||
static const wchar_t *
|
||||
kernel_memory_type_name(kernel::args::mem_type t)
|
||||
{
|
||||
return kernel_memory_type_names[static_cast<uint32_t>(t)];
|
||||
}
|
||||
|
||||
void
|
||||
update_marked_addresses(uefi::event, void *context)
|
||||
{
|
||||
@@ -144,6 +159,7 @@ build_kernel_mem_map(kernel::args::header *args, uefi::boot_services *bs)
|
||||
bool first = true;
|
||||
for (auto desc : map) {
|
||||
/*
|
||||
// EFI map dump
|
||||
console::print(L" Range %lx (%lx) %x(%s) [%lu]\r\n",
|
||||
desc->physical_start, desc->attribute, desc->type, memory_type_name(desc->type), desc->number_of_pages);
|
||||
*/
|
||||
@@ -165,6 +181,7 @@ build_kernel_mem_map(kernel::args::header *args, uefi::boot_services *bs)
|
||||
|
||||
case uefi::memory_type::loader_data:
|
||||
type = mem_type::pending;
|
||||
break;
|
||||
|
||||
case uefi::memory_type::runtime_services_code:
|
||||
case uefi::memory_type::runtime_services_data:
|
||||
@@ -216,6 +233,15 @@ build_kernel_mem_map(kernel::args::header *args, uefi::boot_services *bs)
|
||||
args->mem_map = kernel_map;
|
||||
args->map_count = i;
|
||||
|
||||
/*
|
||||
// kernel map dump
|
||||
for (unsigned i = 0; i < args->map_count; ++i) {
|
||||
const kernel::args::mem_entry &e = kernel_map[i];
|
||||
console::print(L" Range %lx (%lx) %x(%s) [%lu]\r\n",
|
||||
e.start, e.attr, e.type, kernel_memory_type_name(e.type), e.pages);
|
||||
}
|
||||
*/
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ using ::memory::table_entries;
|
||||
/// Page table entry flags for entries pointing at a page
|
||||
constexpr uint16_t page_flags = 0x103;
|
||||
|
||||
// Flags: 0 0 0 0 1 1 0 0 0 0 0 1 1 = 0x0183
|
||||
// Flags: 0 0 0 0 1 1 0 0 0 1 0 1 1 = 0x018b
|
||||
// | IGN | | | | | | | | +- Present
|
||||
// | | | | | | | | +--- Writeable
|
||||
// | | | | | | | +----- Supervisor only
|
||||
@@ -209,11 +209,14 @@ allocate_tables(kernel::args::header *args, uefi::boot_services *bs)
|
||||
|
||||
bs->set_mem(addr, tables_needed*page_size, 0);
|
||||
|
||||
args->pml4 = addr;
|
||||
page_table *pml4 = reinterpret_cast<page_table*>(addr);
|
||||
|
||||
args->pml4 = pml4;
|
||||
args->table_count = tables_needed - 1;
|
||||
args->page_tables = offset_ptr<void>(addr, page_size);
|
||||
|
||||
page_table *pml4 = reinterpret_cast<page_table*>(addr);
|
||||
console::print(L" First page (pml4) at: 0x%lx\r\n", pml4);
|
||||
|
||||
add_kernel_pds(pml4, args->page_tables, args->table_count);
|
||||
add_offset_mappings(pml4, args->page_tables, args->table_count);
|
||||
|
||||
|
||||
@@ -60,6 +60,7 @@ main(int argc, const char **argv)
|
||||
screen::pixel_t fg = scr.color(0xb0, 0xb0, 0xb0);
|
||||
screen::pixel_t bg = scr.color(49, 79, 128);
|
||||
scr.fill(bg);
|
||||
scr.update();
|
||||
|
||||
constexpr int margin = 2;
|
||||
const unsigned xstride = (margin + fnt.width());
|
||||
@@ -85,11 +86,13 @@ main(int argc, const char **argv)
|
||||
scroll.add_line(e->message, eom);
|
||||
if (++pending > pending_threshold) {
|
||||
scroll.render(scr, fnt);
|
||||
scr.update();
|
||||
pending = 0;
|
||||
}
|
||||
} else {
|
||||
if (pending) {
|
||||
scroll.render(scr, fnt);
|
||||
scr.update();
|
||||
pending = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "screen.h"
|
||||
|
||||
screen::screen(void *addr, unsigned hres, unsigned vres, pixel_order order) :
|
||||
@@ -6,6 +8,7 @@ screen::screen(void *addr, unsigned hres, unsigned vres, pixel_order order) :
|
||||
m_resx(hres),
|
||||
m_resy(vres)
|
||||
{
|
||||
m_back = reinterpret_cast<pixel_t*>(malloc(hres*vres*sizeof(pixel_t)));
|
||||
}
|
||||
|
||||
screen::pixel_t
|
||||
@@ -31,11 +34,17 @@ screen::fill(pixel_t color)
|
||||
{
|
||||
const size_t len = m_resx * m_resy;
|
||||
for (size_t i = 0; i < len; ++i)
|
||||
m_fb[i] = color;
|
||||
m_back[i] = color;
|
||||
}
|
||||
|
||||
void
|
||||
screen::draw_pixel(unsigned x, unsigned y, pixel_t color)
|
||||
{
|
||||
m_fb[x + y * m_resx] = color;
|
||||
m_back[x + y * m_resx] = color;
|
||||
}
|
||||
|
||||
void
|
||||
screen::update()
|
||||
{
|
||||
memcpy(m_fb, m_back, m_resx*m_resy*sizeof(pixel_t));
|
||||
}
|
||||
|
||||
@@ -19,8 +19,10 @@ public:
|
||||
void fill(pixel_t color);
|
||||
void draw_pixel(unsigned x, unsigned y, pixel_t color);
|
||||
|
||||
void update();
|
||||
|
||||
private:
|
||||
pixel_t *m_fb;
|
||||
pixel_t *m_fb, *m_back;
|
||||
pixel_order m_order;
|
||||
unsigned m_resx, m_resy;
|
||||
|
||||
|
||||
@@ -1,116 +1,31 @@
|
||||
#include <stdint.h>
|
||||
#include "kutil/assert.h"
|
||||
#include "kutil/memory.h"
|
||||
#include "cpu.h"
|
||||
#include "cpu/cpu.h"
|
||||
#include "log.h"
|
||||
|
||||
cpu_data bsp_cpu_data;
|
||||
|
||||
static constexpr uint32_t cpuid_extended = 0x80000000;
|
||||
|
||||
|
||||
inline static void
|
||||
__cpuid(
|
||||
uint32_t leaf,
|
||||
uint32_t subleaf,
|
||||
uint32_t *eax,
|
||||
uint32_t *ebx = nullptr,
|
||||
uint32_t *ecx = nullptr,
|
||||
uint32_t *edx = nullptr)
|
||||
{
|
||||
uint32_t a, b, c, d;
|
||||
__asm__ __volatile__ ( "cpuid"
|
||||
: "=a"(a), "=b"(b), "=c"(c), "=d"(d)
|
||||
: "a"(leaf), "c"(subleaf)
|
||||
);
|
||||
if (eax) *eax = a;
|
||||
if (ebx) *ebx = b;
|
||||
if (ecx) *ecx = c;
|
||||
if (edx) *edx = d;
|
||||
}
|
||||
|
||||
cpu_id::cpu_id() :
|
||||
m_features(0)
|
||||
{
|
||||
__cpuid(0, 0,
|
||||
&m_high_basic,
|
||||
reinterpret_cast<uint32_t *>(&m_vendor_id[0]),
|
||||
reinterpret_cast<uint32_t *>(&m_vendor_id[8]),
|
||||
reinterpret_cast<uint32_t *>(&m_vendor_id[4]));
|
||||
|
||||
__cpuid(cpuid_extended, 0, &m_high_ext);
|
||||
|
||||
if (m_high_ext >= cpuid_extended + 4) {
|
||||
__cpuid(cpuid_extended + 2, 0,
|
||||
reinterpret_cast<uint32_t *>(&m_brand_name[0]),
|
||||
reinterpret_cast<uint32_t *>(&m_brand_name[4]),
|
||||
reinterpret_cast<uint32_t *>(&m_brand_name[8]),
|
||||
reinterpret_cast<uint32_t *>(&m_brand_name[12]));
|
||||
__cpuid(cpuid_extended + 3, 0,
|
||||
reinterpret_cast<uint32_t *>(&m_brand_name[16]),
|
||||
reinterpret_cast<uint32_t *>(&m_brand_name[20]),
|
||||
reinterpret_cast<uint32_t *>(&m_brand_name[24]),
|
||||
reinterpret_cast<uint32_t *>(&m_brand_name[28]));
|
||||
__cpuid(cpuid_extended + 4, 0,
|
||||
reinterpret_cast<uint32_t *>(&m_brand_name[32]),
|
||||
reinterpret_cast<uint32_t *>(&m_brand_name[36]),
|
||||
reinterpret_cast<uint32_t *>(&m_brand_name[40]),
|
||||
reinterpret_cast<uint32_t *>(&m_brand_name[44]));
|
||||
} else {
|
||||
m_brand_name[0] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
cpu_id::regs
|
||||
cpu_id::get(uint32_t leaf, uint32_t sub) const
|
||||
{
|
||||
regs ret {0, 0, 0, 0};
|
||||
|
||||
if ((leaf & cpuid_extended) == 0 && leaf > m_high_basic) return ret;
|
||||
if ((leaf & cpuid_extended) != 0 && leaf > m_high_ext) return ret;
|
||||
|
||||
__cpuid(leaf, sub, &ret.eax, &ret.ebx, &ret.ecx, &ret.edx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
cpu_id::validate()
|
||||
cpu_validate()
|
||||
{
|
||||
bool fail = false;
|
||||
uint32_t leaf = 0;
|
||||
uint32_t sub = 0;
|
||||
regs r;
|
||||
cpu::cpu_id cpu;
|
||||
|
||||
log::info(logs::boot, "CPU: %s", brand_name());
|
||||
log::debug(logs::boot, " Vendor is %s", vendor_id());
|
||||
log::info(logs::boot, "CPU: %s", cpu.brand_name());
|
||||
log::debug(logs::boot, " Vendor is %s", cpu.vendor_id());
|
||||
|
||||
log::debug(logs::boot, " Higest basic CPUID: 0x%02x", highest_basic());
|
||||
log::debug(logs::boot, " Higest ext CPUID: 0x%02x", highest_ext() & ~cpuid_extended);
|
||||
log::debug(logs::boot, " Higest basic CPUID: 0x%02x", cpu.highest_basic());
|
||||
log::debug(logs::boot, " Higest ext CPUID: 0x%02x", cpu.highest_ext() & ~cpu::cpu_id::cpuid_extended);
|
||||
|
||||
#define CPU_FEATURE_OPT(name, feat_leaf, feat_sub, regname, bit) \
|
||||
if (leaf != feat_leaf || sub != feat_sub) { \
|
||||
leaf = feat_leaf; sub = feat_sub; r = get(leaf, sub); \
|
||||
} \
|
||||
if (r.regname & (1ull << bit)) \
|
||||
m_features |= (1ull << static_cast<uint64_t>(cpu_feature::name)); \
|
||||
log::debug(logs::boot, " Supports %9s: %s", #name, (r.regname & (1ull << bit)) ? "yes" : "no");
|
||||
#define CPU_FEATURE_OPT(name, ...) \
|
||||
log::debug(logs::boot, " Supports %9s: %s", #name, cpu.has_feature(cpu::feature::name) ? "yes" : "no");
|
||||
|
||||
#define CPU_FEATURE_REQ(name, feat_leaf, feat_sub, regname, bit) \
|
||||
CPU_FEATURE_OPT(name, feat_leaf, feat_sub, regname, bit); \
|
||||
if ((r.regname & (1ull << bit)) == 0) { \
|
||||
log::error(logs::boot, "CPU missing required feature " #name); \
|
||||
fail = true; \
|
||||
}
|
||||
kassert(cpu.has_feature(cpu::feature::name), "Missing required CPU feature " #name );
|
||||
|
||||
#include "cpu_features.inc"
|
||||
#include "cpu/features.inc"
|
||||
#undef CPU_FEATURE_OPT
|
||||
#undef CPU_FEATURE_REQ
|
||||
|
||||
if (fail)
|
||||
log::fatal(logs::boot, "CPU not supported.");
|
||||
}
|
||||
|
||||
bool
|
||||
cpu_id::has_feature(cpu_feature feat)
|
||||
{
|
||||
return (m_features & (1 << static_cast<uint64_t>(feat))) != 0;
|
||||
}
|
||||
|
||||
@@ -27,69 +27,6 @@ struct cpu_data
|
||||
|
||||
extern cpu_data bsp_cpu_data;
|
||||
|
||||
/// Enum of the cpu features jsix cares about
|
||||
enum class cpu_feature {
|
||||
#define CPU_FEATURE_REQ(name, ...) name,
|
||||
#define CPU_FEATURE_OPT(name, ...) name,
|
||||
#include "cpu_features.inc"
|
||||
#undef CPU_FEATURE_OPT
|
||||
#undef CPU_FEATURE_REQ
|
||||
max
|
||||
};
|
||||
|
||||
class cpu_id
|
||||
{
|
||||
public:
|
||||
/// CPUID result register values
|
||||
struct regs {
|
||||
union {
|
||||
uint32_t reg[4];
|
||||
uint32_t eax, ebx, ecx, edx;
|
||||
};
|
||||
|
||||
/// Return true if bit |bit| of EAX is set
|
||||
bool eax_bit(unsigned bit) { return (eax >> bit) & 0x1; }
|
||||
|
||||
/// Return true if bit |bit| of EBX is set
|
||||
bool ebx_bit(unsigned bit) { return (ebx >> bit) & 0x1; }
|
||||
|
||||
/// Return true if bit |bit| of ECX is set
|
||||
bool ecx_bit(unsigned bit) { return (ecx >> bit) & 0x1; }
|
||||
|
||||
/// Return true if bit |bit| of EDX is set
|
||||
bool edx_bit(unsigned bit) { return (edx >> bit) & 0x1; }
|
||||
};
|
||||
|
||||
cpu_id();
|
||||
|
||||
/// The the result of a given CPUID leaf/subleaf
|
||||
/// \arg leaf The leaf selector (initial EAX)
|
||||
/// \arg subleaf The subleaf selector (initial ECX)
|
||||
/// \returns A |regs| struct of the values retuned
|
||||
regs get(uint32_t leaf, uint32_t sub = 0) const;
|
||||
|
||||
/// Get the name of the cpu vendor (eg, "GenuineIntel")
|
||||
inline const char * vendor_id() const { return m_vendor_id; }
|
||||
|
||||
/// Get the brand name of this processor model
|
||||
inline const char * brand_name() const { return m_brand_name; }
|
||||
|
||||
/// Get the highest basic CPUID leaf supported
|
||||
inline uint32_t highest_basic() const { return m_high_basic; }
|
||||
|
||||
/// Get the highest extended CPUID leaf supported
|
||||
inline uint32_t highest_ext() const { return m_high_ext; }
|
||||
|
||||
/// Validate the CPU supports the necessary options for jsix
|
||||
void validate();
|
||||
|
||||
/// Return true if the CPU claims to support the given feature
|
||||
bool has_feature(cpu_feature feat);
|
||||
|
||||
private:
|
||||
uint32_t m_high_basic;
|
||||
uint32_t m_high_ext;
|
||||
char m_vendor_id[13];
|
||||
char m_brand_name[48];
|
||||
uint64_t m_features;
|
||||
};
|
||||
// We already validated the required options in the bootloader,
|
||||
// but iterate the options and log about them.
|
||||
void cpu_validate();
|
||||
|
||||
@@ -33,19 +33,10 @@ extern "C" {
|
||||
void (*__ctors_end)(void);
|
||||
}
|
||||
|
||||
void
|
||||
run_constructors()
|
||||
{
|
||||
void (**p)(void) = &__ctors;
|
||||
while (p < &__ctors_end) {
|
||||
void (*ctor)(void) = *p++;
|
||||
ctor();
|
||||
}
|
||||
}
|
||||
|
||||
extern void __kernel_assert(const char *, unsigned, const char *);
|
||||
|
||||
/// Bootstrap the memory managers.
|
||||
void setup_pat();
|
||||
void memory_initialize_pre_ctors(kernel::args::header *kargs);
|
||||
void memory_initialize_post_ctors(kernel::args::header *kargs);
|
||||
|
||||
@@ -66,6 +57,16 @@ init_console()
|
||||
cons->puts(GIT_VERSION " booting...\n");
|
||||
}
|
||||
|
||||
void
|
||||
run_constructors()
|
||||
{
|
||||
void (**p)(void) = &__ctors;
|
||||
while (p < &__ctors_end) {
|
||||
void (*ctor)(void) = *p++;
|
||||
ctor();
|
||||
}
|
||||
}
|
||||
|
||||
channel *std_out = nullptr;
|
||||
|
||||
void
|
||||
@@ -110,9 +111,23 @@ void
|
||||
kernel_main(args::header *header)
|
||||
{
|
||||
kutil::assert_set_callback(__kernel_assert);
|
||||
|
||||
init_console();
|
||||
logger_init();
|
||||
|
||||
setup_pat();
|
||||
|
||||
bool has_video = false;
|
||||
if (header->video.size > 0) {
|
||||
has_video = true;
|
||||
fb = memory::to_virtual<args::framebuffer>(reinterpret_cast<uintptr_t>(&header->video));
|
||||
|
||||
const args::framebuffer &video = header->video;
|
||||
log::debug(logs::boot, "Framebuffer: %dx%d[%d] type %s @ %016llx",
|
||||
video.horizontal, video.vertical, video.scanline, video.type, video.phys_addr);
|
||||
logger_clear_immediate();
|
||||
}
|
||||
|
||||
gdt_init();
|
||||
interrupts_init();
|
||||
|
||||
@@ -120,8 +135,7 @@ kernel_main(args::header *header)
|
||||
run_constructors();
|
||||
memory_initialize_post_ctors(header);
|
||||
|
||||
cpu_id cpu;
|
||||
cpu.validate();
|
||||
cpu_validate();
|
||||
|
||||
for (size_t i = 0; i < header->num_modules; ++i) {
|
||||
args::module &mod = header->modules[i];
|
||||
@@ -135,13 +149,6 @@ kernel_main(args::header *header)
|
||||
}
|
||||
}
|
||||
|
||||
bool has_video = false;
|
||||
if (header->video.size > 0) {
|
||||
fb = memory::to_virtual<args::framebuffer>(reinterpret_cast<uintptr_t>(&header->video));
|
||||
has_video = true;
|
||||
logger_clear_immediate();
|
||||
}
|
||||
|
||||
log::debug(logs::boot, " jsix header is at: %016lx", header);
|
||||
log::debug(logs::boot, " Memory map is at: %016lx", header->mem_map);
|
||||
log::debug(logs::boot, "ACPI root table is at: %016lx", header->acpi_table);
|
||||
@@ -152,7 +159,6 @@ kernel_main(args::header *header)
|
||||
|
||||
interrupts_enable();
|
||||
devices.init_drivers();
|
||||
|
||||
devices.get_lapic()->calibrate_timer();
|
||||
|
||||
/*
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "frame_allocator.h"
|
||||
#include "io.h"
|
||||
#include "log.h"
|
||||
#include "msr.h"
|
||||
#include "objects/process.h"
|
||||
#include "objects/vm_area.h"
|
||||
#include "vm_space.h"
|
||||
@@ -100,6 +101,71 @@ void walk_page_table(
|
||||
}
|
||||
*/
|
||||
|
||||
static void
|
||||
log_mtrrs()
|
||||
{
|
||||
uint64_t mtrrcap = rdmsr(msr::ia32_mtrrcap);
|
||||
uint64_t mtrrdeftype = rdmsr(msr::ia32_mtrrdeftype);
|
||||
unsigned vcap = mtrrcap & 0xff;
|
||||
log::debug(logs::boot, "MTRRs: vcap=%d %s %s def=%02x %s %s",
|
||||
vcap,
|
||||
(mtrrcap & (1<< 8)) ? "fix" : "",
|
||||
(mtrrcap & (1<<10)) ? "wc" : "",
|
||||
mtrrdeftype & 0xff,
|
||||
(mtrrdeftype & (1<<10)) ? "fe" : "",
|
||||
(mtrrdeftype & (1<<11)) ? "enabled" : ""
|
||||
);
|
||||
|
||||
for (unsigned i = 0; i < vcap; ++i) {
|
||||
uint64_t base = rdmsr(find_mtrr(msr::ia32_mtrrphysbase, i));
|
||||
uint64_t mask = rdmsr(find_mtrr(msr::ia32_mtrrphysmask, i));
|
||||
log::debug(logs::boot, " vcap[%2d] base:%016llx mask:%016llx type:%02x %s", i,
|
||||
(base & ~0xfffull),
|
||||
(mask & ~0xfffull),
|
||||
(base & 0xff),
|
||||
(mask & (1<<11)) ? "valid" : "");
|
||||
}
|
||||
|
||||
msr mtrr_fixed[] = {
|
||||
msr::ia32_mtrrfix64k_00000,
|
||||
msr::ia32_mtrrfix16k_80000,
|
||||
msr::ia32_mtrrfix16k_a0000,
|
||||
msr::ia32_mtrrfix4k_c0000,
|
||||
msr::ia32_mtrrfix4k_c8000,
|
||||
msr::ia32_mtrrfix4k_d0000,
|
||||
msr::ia32_mtrrfix4k_d8000,
|
||||
msr::ia32_mtrrfix4k_e0000,
|
||||
msr::ia32_mtrrfix4k_e8000,
|
||||
msr::ia32_mtrrfix4k_f0000,
|
||||
msr::ia32_mtrrfix4k_f8000,
|
||||
};
|
||||
|
||||
for (int i = 0; i < 11; ++i) {
|
||||
uint64_t v = rdmsr(mtrr_fixed[i]);
|
||||
log::debug(logs::boot, " fixed[%2d] %02x %02x %02x %02x %02x %02x %02x %02x", i,
|
||||
((v << 0) & 0xff), ((v << 8) & 0xff), ((v << 16) & 0xff), ((v << 24) & 0xff),
|
||||
((v << 32) & 0xff), ((v << 40) & 0xff), ((v << 48) & 0xff), ((v << 56) & 0xff));
|
||||
}
|
||||
|
||||
uint64_t pat = rdmsr(msr::ia32_pat);
|
||||
static const char *pat_names[] = {"UC ","WC ","XX ","XX ","WT ","WP ","WB ","UC-"};
|
||||
log::debug(logs::boot, " PAT: 0:%s 1:%s 2:%s 3:%s 4:%s 5:%s 6:%s 7:%s",
|
||||
pat_names[(pat >> (0*8)) & 7], pat_names[(pat >> (1*8)) & 7],
|
||||
pat_names[(pat >> (2*8)) & 7], pat_names[(pat >> (3*8)) & 7],
|
||||
pat_names[(pat >> (4*8)) & 7], pat_names[(pat >> (5*8)) & 7],
|
||||
pat_names[(pat >> (6*8)) & 7], pat_names[(pat >> (7*8)) & 7]);
|
||||
}
|
||||
|
||||
void
|
||||
setup_pat()
|
||||
{
|
||||
uint64_t pat = rdmsr(msr::ia32_pat);
|
||||
pat = (pat & 0x00ffffffffffffffull) | (0x01ull << 56); // set PAT 7 to WC
|
||||
wrmsr(msr::ia32_pat, pat);
|
||||
log_mtrrs();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
memory_initialize_pre_ctors(args::header *kargs)
|
||||
{
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
#include "msr.h"
|
||||
|
||||
msr
|
||||
find_mtrr(msr type, unsigned index)
|
||||
{
|
||||
return static_cast<msr>(static_cast<uint32_t>(type) + (2 * index));
|
||||
}
|
||||
|
||||
uint64_t
|
||||
rdmsr(msr addr)
|
||||
{
|
||||
|
||||
@@ -6,22 +6,46 @@
|
||||
|
||||
enum class msr : uint32_t
|
||||
{
|
||||
ia32_efer = 0xc0000080,
|
||||
ia32_star = 0xc0000081,
|
||||
ia32_lstar = 0xc0000082,
|
||||
ia32_fmask = 0xc0000084,
|
||||
ia32_mtrrcap = 0x000000fe,
|
||||
ia32_mtrrdeftype = 0x000002ff,
|
||||
|
||||
ia32_gs_base = 0xc0000101,
|
||||
ia32_kernel_gs_base = 0xc0000102
|
||||
ia32_mtrrphysbase = 0x00000200,
|
||||
ia32_mtrrphysmask = 0x00000201,
|
||||
|
||||
ia32_mtrrfix64k_00000 = 0x00000250,
|
||||
|
||||
ia32_mtrrfix16k_80000 = 0x00000258,
|
||||
ia32_mtrrfix16k_a0000 = 0x00000259,
|
||||
|
||||
ia32_mtrrfix4k_c0000 = 0x00000268,
|
||||
ia32_mtrrfix4k_c8000 = 0x00000269,
|
||||
ia32_mtrrfix4k_d0000 = 0x0000026A,
|
||||
ia32_mtrrfix4k_d8000 = 0x0000026B,
|
||||
ia32_mtrrfix4k_e0000 = 0x0000026C,
|
||||
ia32_mtrrfix4k_e8000 = 0x0000026D,
|
||||
ia32_mtrrfix4k_f0000 = 0x0000026E,
|
||||
ia32_mtrrfix4k_f8000 = 0x0000026F,
|
||||
|
||||
ia32_pat = 0x00000277,
|
||||
ia32_efer = 0xc0000080,
|
||||
ia32_star = 0xc0000081,
|
||||
ia32_lstar = 0xc0000082,
|
||||
ia32_fmask = 0xc0000084,
|
||||
|
||||
ia32_gs_base = 0xc0000101,
|
||||
ia32_kernel_gs_base = 0xc0000102
|
||||
};
|
||||
|
||||
/// Find the msr for MTRR physical base or mask
|
||||
msr find_mtrr(msr type, unsigned index);
|
||||
|
||||
/// Read the value of a MSR
|
||||
/// \arg addr The MSR address
|
||||
/// \returns The current value of the MSR
|
||||
/// \arg addr The MSR address
|
||||
/// \returns The current value of the MSR
|
||||
uint64_t rdmsr(msr addr);
|
||||
|
||||
/// Write to a MSR
|
||||
/// \arg addr The MSR address
|
||||
/// \arg value The value to write
|
||||
/// \arg addr The MSR address
|
||||
/// \arg value The value to write
|
||||
void wrmsr(msr addr, uint64_t value);
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ enum class vm_flags : uint32_t
|
||||
huge_pages = 0x00000200,
|
||||
|
||||
mmio = 0x00010000,
|
||||
write_combine = 0x00020000,
|
||||
|
||||
user_mask = 0x0000ffff ///< flags allowed via syscall
|
||||
};
|
||||
|
||||
@@ -181,6 +181,7 @@ page_table::get_table_page()
|
||||
s_page_cache = s_page_cache->next;
|
||||
--s_cache_count;
|
||||
|
||||
kutil::memset(page, 0, memory::frame_size);
|
||||
return reinterpret_cast<page_table*>(page);
|
||||
}
|
||||
|
||||
|
||||
@@ -21,14 +21,21 @@ struct page_table
|
||||
present = 0x0001, /// Entry is present in the table
|
||||
write = 0x0002, /// Section may be written
|
||||
user = 0x0004, /// User-accessible
|
||||
mtrr0 = 0x0008, /// MTRR selector bit 0
|
||||
mtrr1 = 0x0010, /// MTRR selector bit 1
|
||||
pat0 = 0x0008, /// PAT selector bit 0
|
||||
pat1 = 0x0010, /// PAT selector bit 1
|
||||
accessed = 0x0020, /// Entry has been accessed
|
||||
dirty = 0x0040, /// Page has been written to
|
||||
page = 0x0080, /// Entry is a large page
|
||||
pte_mtrr2 = 0x0080, /// MTRR selector bit 2 on PT entries
|
||||
pat2 = 0x0080, /// PAT selector bit 2 on PT entries
|
||||
global = 0x0100, /// Entry is not PCID-specific
|
||||
mtrr2 = 0x1000 /// MTRR selector bit 2 on PD and PDP entries
|
||||
pat2_lg = 0x1000, /// PAT selector bit 2 on large/huge pages
|
||||
|
||||
wb = none,
|
||||
wt = pat0,
|
||||
uc_ = pat1,
|
||||
uc = pat0 | pat1,
|
||||
wc = pat0 | pat1 | pat2,
|
||||
wc_lg = pat0 | pat1 | pat2_lg,
|
||||
};
|
||||
|
||||
/// Helper for getting the next level value
|
||||
|
||||
@@ -141,7 +141,7 @@ load_process_image(uintptr_t phys, uintptr_t virt, size_t bytes, TCB *tcb)
|
||||
|
||||
// Crazypants framebuffer part
|
||||
if (fb) {
|
||||
vma = new vm_area_open(fb->size, space, vm_flags::write|vm_flags::mmio);
|
||||
vma = new vm_area_open(fb->size, space, vm_flags::write|vm_flags::mmio|vm_flags::write_combine);
|
||||
space.add(0x100000000, vma);
|
||||
vma->commit(fb->phys_addr, 0, memory::page_count(fb->size));
|
||||
}
|
||||
|
||||
@@ -170,7 +170,8 @@ vm_space::page_in(const vm_area &vma, uintptr_t offset, uintptr_t phys, size_t c
|
||||
page_table::flag flags =
|
||||
page_table::flag::present |
|
||||
(m_kernel ? page_table::flag::none : page_table::flag::user) |
|
||||
((vma.flags() && vm_flags::write) ? page_table::flag::write : page_table::flag::none);
|
||||
((vma.flags() && vm_flags::write) ? page_table::flag::write : page_table::flag::none) |
|
||||
((vma.flags() && vm_flags::write_combine) ? page_table::flag::wc : page_table::flag::none);
|
||||
|
||||
page_table::iterator it {virt, m_pml4};
|
||||
|
||||
|
||||
97
src/libraries/cpu/cpu.cpp
Normal file
97
src/libraries/cpu/cpu.cpp
Normal file
@@ -0,0 +1,97 @@
|
||||
#include <stdint.h>
|
||||
#include "cpu/cpu.h"
|
||||
|
||||
namespace cpu {
|
||||
|
||||
inline static void
|
||||
__cpuid(
|
||||
uint32_t leaf,
|
||||
uint32_t subleaf,
|
||||
uint32_t *eax,
|
||||
uint32_t *ebx = nullptr,
|
||||
uint32_t *ecx = nullptr,
|
||||
uint32_t *edx = nullptr)
|
||||
{
|
||||
uint32_t a, b, c, d;
|
||||
__asm__ __volatile__ ( "cpuid"
|
||||
: "=a"(a), "=b"(b), "=c"(c), "=d"(d)
|
||||
: "a"(leaf), "c"(subleaf)
|
||||
);
|
||||
if (eax) *eax = a;
|
||||
if (ebx) *ebx = b;
|
||||
if (ecx) *ecx = c;
|
||||
if (edx) *edx = d;
|
||||
}
|
||||
|
||||
cpu_id::cpu_id() :
|
||||
m_features {0},
|
||||
m_missing {0}
|
||||
{
|
||||
__cpuid(0, 0,
|
||||
&m_high_basic,
|
||||
reinterpret_cast<uint32_t *>(&m_vendor_id[0]),
|
||||
reinterpret_cast<uint32_t *>(&m_vendor_id[8]),
|
||||
reinterpret_cast<uint32_t *>(&m_vendor_id[4]));
|
||||
|
||||
__cpuid(cpuid_extended, 0, &m_high_ext);
|
||||
|
||||
if (m_high_ext >= cpuid_extended + 4) {
|
||||
__cpuid(cpuid_extended + 2, 0,
|
||||
reinterpret_cast<uint32_t *>(&m_brand_name[0]),
|
||||
reinterpret_cast<uint32_t *>(&m_brand_name[4]),
|
||||
reinterpret_cast<uint32_t *>(&m_brand_name[8]),
|
||||
reinterpret_cast<uint32_t *>(&m_brand_name[12]));
|
||||
__cpuid(cpuid_extended + 3, 0,
|
||||
reinterpret_cast<uint32_t *>(&m_brand_name[16]),
|
||||
reinterpret_cast<uint32_t *>(&m_brand_name[20]),
|
||||
reinterpret_cast<uint32_t *>(&m_brand_name[24]),
|
||||
reinterpret_cast<uint32_t *>(&m_brand_name[28]));
|
||||
__cpuid(cpuid_extended + 4, 0,
|
||||
reinterpret_cast<uint32_t *>(&m_brand_name[32]),
|
||||
reinterpret_cast<uint32_t *>(&m_brand_name[36]),
|
||||
reinterpret_cast<uint32_t *>(&m_brand_name[40]),
|
||||
reinterpret_cast<uint32_t *>(&m_brand_name[44]));
|
||||
} else {
|
||||
m_brand_name[0] = 0;
|
||||
}
|
||||
|
||||
uint32_t leaf = -1u;
|
||||
uint32_t sub = -1u;
|
||||
regs r;
|
||||
#define CPU_FEATURE_OPT(name, feat_leaf, feat_sub, regname, bit) \
|
||||
if (leaf != feat_leaf || sub != feat_sub) { \
|
||||
leaf = feat_leaf; sub = feat_sub; r = get(leaf, sub); \
|
||||
} \
|
||||
if (r.regname & (1ull << bit)) \
|
||||
m_features |= (1ull << static_cast<uint64_t>(feature::name)); \
|
||||
|
||||
#define CPU_FEATURE_REQ(name, feat_leaf, feat_sub, regname, bit) \
|
||||
CPU_FEATURE_OPT(name, feat_leaf, feat_sub, regname, bit); \
|
||||
if ((r.regname & (1ull << bit)) == 0) { \
|
||||
m_missing |= (1ull << static_cast<uint64_t>(feature::name)); \
|
||||
}
|
||||
|
||||
#include "cpu/features.inc"
|
||||
#undef CPU_FEATURE_OPT
|
||||
#undef CPU_FEATURE_REQ
|
||||
}
|
||||
|
||||
cpu_id::regs
|
||||
cpu_id::get(uint32_t leaf, uint32_t sub) const
|
||||
{
|
||||
regs ret {0, 0, 0, 0};
|
||||
|
||||
if ((leaf & cpuid_extended) == 0 && leaf > m_high_basic) return ret;
|
||||
if ((leaf & cpuid_extended) != 0 && leaf > m_high_ext) return ret;
|
||||
|
||||
__cpuid(leaf, sub, &ret.eax, &ret.ebx, &ret.ecx, &ret.edx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool
|
||||
cpu_id::has_feature(feature feat)
|
||||
{
|
||||
return (m_features & (1 << static_cast<uint64_t>(feat))) != 0;
|
||||
}
|
||||
|
||||
}
|
||||
81
src/libraries/cpu/include/cpu/cpu.h
Normal file
81
src/libraries/cpu/include/cpu/cpu.h
Normal file
@@ -0,0 +1,81 @@
|
||||
#pragma once
|
||||
/// \file cpu.h Definition of required cpu features for jsix
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace cpu {
|
||||
|
||||
/// Enum of the cpu features jsix cares about
|
||||
enum class feature {
|
||||
#define CPU_FEATURE_REQ(name, ...) name,
|
||||
#define CPU_FEATURE_OPT(name, ...) name,
|
||||
#include "cpu/features.inc"
|
||||
#undef CPU_FEATURE_OPT
|
||||
#undef CPU_FEATURE_REQ
|
||||
max
|
||||
};
|
||||
|
||||
class cpu_id
|
||||
{
|
||||
public:
|
||||
static constexpr uint32_t cpuid_extended = 0x80000000;
|
||||
|
||||
/// CPUID result register values
|
||||
struct regs {
|
||||
union {
|
||||
uint32_t reg[4];
|
||||
uint32_t eax, ebx, ecx, edx;
|
||||
};
|
||||
|
||||
/// Return true if bit |bit| of EAX is set
|
||||
bool eax_bit(unsigned bit) { return (eax >> bit) & 0x1; }
|
||||
|
||||
/// Return true if bit |bit| of EBX is set
|
||||
bool ebx_bit(unsigned bit) { return (ebx >> bit) & 0x1; }
|
||||
|
||||
/// Return true if bit |bit| of ECX is set
|
||||
bool ecx_bit(unsigned bit) { return (ecx >> bit) & 0x1; }
|
||||
|
||||
/// Return true if bit |bit| of EDX is set
|
||||
bool edx_bit(unsigned bit) { return (edx >> bit) & 0x1; }
|
||||
};
|
||||
|
||||
cpu_id();
|
||||
|
||||
/// The the result of a given CPUID leaf/subleaf
|
||||
/// \arg leaf The leaf selector (initial EAX)
|
||||
/// \arg subleaf The subleaf selector (initial ECX)
|
||||
/// \returns A |regs| struct of the values retuned
|
||||
regs get(uint32_t leaf, uint32_t sub = 0) const;
|
||||
|
||||
/// Get the name of the cpu vendor (eg, "GenuineIntel")
|
||||
inline const char * vendor_id() const { return m_vendor_id; }
|
||||
|
||||
/// Get the brand name of this processor model
|
||||
inline const char * brand_name() const { return m_brand_name; }
|
||||
|
||||
/// Get the highest basic CPUID leaf supported
|
||||
inline uint32_t highest_basic() const { return m_high_basic; }
|
||||
|
||||
/// Get the highest extended CPUID leaf supported
|
||||
inline uint32_t highest_ext() const { return m_high_ext; }
|
||||
|
||||
/// Get which required options are missing as flags
|
||||
inline uint64_t missing() const { return m_missing; }
|
||||
|
||||
/// Validate the CPU supports the necessary options for jsix
|
||||
inline bool supported() const { return m_missing; }
|
||||
|
||||
/// Return true if the CPU claims to support the given feature
|
||||
bool has_feature(feature feat);
|
||||
|
||||
private:
|
||||
uint32_t m_high_basic;
|
||||
uint32_t m_high_ext;
|
||||
uint64_t m_features;
|
||||
uint64_t m_missing;
|
||||
char m_vendor_id[13];
|
||||
char m_brand_name[48];
|
||||
};
|
||||
|
||||
}
|
||||
@@ -7,8 +7,9 @@ CPU_FEATURE_REQ(pse, 0x00000001, 0, edx, 3)
|
||||
CPU_FEATURE_OPT(tsc, 0x00000001, 0, edx, 4)
|
||||
CPU_FEATURE_REQ(msr, 0x00000001, 0, edx, 5)
|
||||
CPU_FEATURE_REQ(apic, 0x00000001, 0, edx, 9)
|
||||
CPU_FEATURE_REQ(mtrr, 0x00000001, 0, edx, 12)
|
||||
CPU_FEATURE_REQ(pge, 0x00000001, 0, edx, 13)
|
||||
CPU_FEATURE_OPT(pat, 0x00000001, 0, edx, 16)
|
||||
CPU_FEATURE_REQ(pat, 0x00000001, 0, edx, 16)
|
||||
CPU_FEATURE_REQ(fxsr, 0x00000001, 0, edx, 24)
|
||||
|
||||
CPU_FEATURE_OPT(fsgsbase, 0x00000007, 0, ebx, 0)
|
||||
@@ -10,9 +10,24 @@ void * memcpy( void * restrict s1, const void * restrict s2, size_t n )
|
||||
{
|
||||
char * dest = (char *) s1;
|
||||
const char * src = (const char *) s2;
|
||||
while ( n-- )
|
||||
{
|
||||
|
||||
if (((uintptr_t)src & 7) == ((uintptr_t)dest & 7)) {
|
||||
while (((uintptr_t)src & 7) && n--)
|
||||
*dest++ = *src++;
|
||||
|
||||
const uint64_t *srcq = (const uint64_t*)src;
|
||||
uint64_t *destq = (uint64_t*)dest;
|
||||
while (n >= 8) {
|
||||
*destq++ = *srcq++;
|
||||
n -= 8;
|
||||
}
|
||||
|
||||
src = (const char*)srcq;
|
||||
dest = (char*)destq;
|
||||
}
|
||||
|
||||
while (n--)
|
||||
*dest++ = *src++;
|
||||
}
|
||||
|
||||
return s1;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user