Merge branch 'real-hardware' into fb-driver

This commit is contained in:
Justin C. Miller
2021-01-18 13:38:51 -08:00
23 changed files with 447 additions and 211 deletions

View File

@@ -6,6 +6,7 @@ modules:
output: jsix.elf output: jsix.elf
target: host target: host
deps: deps:
- cpu
- kutil - kutil
includes: includes:
- src/kernel - src/kernel
@@ -62,6 +63,8 @@ modules:
kind: exe kind: exe
target: boot target: boot
output: boot.efi output: boot.efi
deps:
- cpu
source: source:
- src/boot/main.cpp - src/boot/main.cpp
- src/boot/console.cpp - src/boot/console.cpp
@@ -110,6 +113,14 @@ modules:
- src/libraries/kutil/memory.cpp - src/libraries/kutil/memory.cpp
- src/libraries/kutil/printf.c - src/libraries/kutil/printf.c
cpu:
kind: lib
output: libcpu.a
includes:
- src/libraries/cpu/include
source:
- src/libraries/cpu/cpu.cpp
libc: libc:
kind: lib kind: lib

View File

@@ -70,8 +70,8 @@ console::console(uefi::boot_services *bs, uefi::protos::simple_text_output *out)
type = L"unknown"; type = L"unknown";
} }
printf(L"Found framebuffer: %dx%d type %s @0x%x\r\n", printf(L"Found framebuffer: %dx%d[%d] type %s @0x%x\r\n",
m_fb.horizontal, m_fb.vertical, type, m_fb.phys_addr); m_fb.horizontal, m_fb.vertical, m_fb.scanline, type, m_fb.phys_addr);
} else { } else {
printf(L"No framebuffer found.\r\n"); printf(L"No framebuffer found.\r\n");
} }

View File

@@ -8,6 +8,7 @@
#include <stdint.h> #include <stdint.h>
#include "console.h" #include "console.h"
#include "cpu/cpu.h"
#include "error.h" #include "error.h"
#include "fs.h" #include "fs.h"
#include "hardware.h" #include "hardware.h"
@@ -94,6 +95,28 @@ add_module(args::header *args, args::mod_type type, buffer &data)
m.size = data.size; 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 /// 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 /// UEFI is still in control of the machine. (ie, while the loader still
/// has access to boot services. /// has access to boot services.
@@ -160,6 +183,7 @@ efi_main(uefi::handle image, uefi::system_table *st)
{ {
using namespace boot; using namespace boot;
console con(st->boot_services, st->con_out); console con(st->boot_services, st->con_out);
check_cpu_supported();
args::header *args = uefi_preboot(image, st); args::header *args = uefi_preboot(image, st);
memory::efi_mem_map map = uefi_exit(args, image, st->boot_services); memory::efi_mem_map map = uefi_exit(args, image, st->boot_services);

View File

@@ -36,6 +36,15 @@ static const wchar_t *memory_type_names[] = {
L"persistent memory" 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 * static const wchar_t *
memory_type_name(uefi::memory_type t) memory_type_name(uefi::memory_type t)
{ {
@@ -45,6 +54,12 @@ memory_type_name(uefi::memory_type t)
return L"Bad Type Value"; 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 void
update_marked_addresses(uefi::event, void *context) 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; bool first = true;
for (auto desc : map) { for (auto desc : map) {
/* /*
// EFI map dump
console::print(L" Range %lx (%lx) %x(%s) [%lu]\r\n", 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); 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: case uefi::memory_type::loader_data:
type = mem_type::pending; type = mem_type::pending;
break;
case uefi::memory_type::runtime_services_code: case uefi::memory_type::runtime_services_code:
case uefi::memory_type::runtime_services_data: 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->mem_map = kernel_map;
args->map_count = i; 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; return map;
} }

View File

@@ -28,7 +28,7 @@ using ::memory::table_entries;
/// Page table entry flags for entries pointing at a page /// Page table entry flags for entries pointing at a page
constexpr uint16_t page_flags = 0x103; 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 // | IGN | | | | | | | | +- Present
// | | | | | | | | +--- Writeable // | | | | | | | | +--- Writeable
// | | | | | | | +----- Supervisor only // | | | | | | | +----- 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); 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->table_count = tables_needed - 1;
args->page_tables = offset_ptr<void>(addr, page_size); 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_kernel_pds(pml4, args->page_tables, args->table_count);
add_offset_mappings(pml4, args->page_tables, args->table_count); add_offset_mappings(pml4, args->page_tables, args->table_count);

View File

@@ -60,6 +60,7 @@ main(int argc, const char **argv)
screen::pixel_t fg = scr.color(0xb0, 0xb0, 0xb0); screen::pixel_t fg = scr.color(0xb0, 0xb0, 0xb0);
screen::pixel_t bg = scr.color(49, 79, 128); screen::pixel_t bg = scr.color(49, 79, 128);
scr.fill(bg); scr.fill(bg);
scr.update();
constexpr int margin = 2; constexpr int margin = 2;
const unsigned xstride = (margin + fnt.width()); const unsigned xstride = (margin + fnt.width());
@@ -85,11 +86,13 @@ main(int argc, const char **argv)
scroll.add_line(e->message, eom); scroll.add_line(e->message, eom);
if (++pending > pending_threshold) { if (++pending > pending_threshold) {
scroll.render(scr, fnt); scroll.render(scr, fnt);
scr.update();
pending = 0; pending = 0;
} }
} else { } else {
if (pending) { if (pending) {
scroll.render(scr, fnt); scroll.render(scr, fnt);
scr.update();
pending = 0; pending = 0;
} }
} }

View File

@@ -1,3 +1,5 @@
#include <stdlib.h>
#include <string.h>
#include "screen.h" #include "screen.h"
screen::screen(void *addr, unsigned hres, unsigned vres, pixel_order order) : 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_resx(hres),
m_resy(vres) m_resy(vres)
{ {
m_back = reinterpret_cast<pixel_t*>(malloc(hres*vres*sizeof(pixel_t)));
} }
screen::pixel_t screen::pixel_t
@@ -31,11 +34,17 @@ screen::fill(pixel_t color)
{ {
const size_t len = m_resx * m_resy; const size_t len = m_resx * m_resy;
for (size_t i = 0; i < len; ++i) for (size_t i = 0; i < len; ++i)
m_fb[i] = color; m_back[i] = color;
} }
void void
screen::draw_pixel(unsigned x, unsigned y, pixel_t color) 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));
} }

View File

@@ -19,8 +19,10 @@ public:
void fill(pixel_t color); void fill(pixel_t color);
void draw_pixel(unsigned x, unsigned y, pixel_t color); void draw_pixel(unsigned x, unsigned y, pixel_t color);
void update();
private: private:
pixel_t *m_fb; pixel_t *m_fb, *m_back;
pixel_order m_order; pixel_order m_order;
unsigned m_resx, m_resy; unsigned m_resx, m_resy;

View File

@@ -1,116 +1,31 @@
#include <stdint.h> #include <stdint.h>
#include "kutil/assert.h"
#include "kutil/memory.h" #include "kutil/memory.h"
#include "cpu.h" #include "cpu.h"
#include "cpu/cpu.h"
#include "log.h" #include "log.h"
cpu_data bsp_cpu_data; 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 void
cpu_id::validate() cpu_validate()
{ {
bool fail = false; cpu::cpu_id cpu;
uint32_t leaf = 0;
uint32_t sub = 0;
regs r;
log::info(logs::boot, "CPU: %s", brand_name()); log::info(logs::boot, "CPU: %s", cpu.brand_name());
log::debug(logs::boot, " Vendor is %s", vendor_id()); 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 basic CPUID: 0x%02x", cpu.highest_basic());
log::debug(logs::boot, " Higest ext CPUID: 0x%02x", highest_ext() & ~cpuid_extended); 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) \ #define CPU_FEATURE_OPT(name, ...) \
if (leaf != feat_leaf || sub != feat_sub) { \ log::debug(logs::boot, " Supports %9s: %s", #name, cpu.has_feature(cpu::feature::name) ? "yes" : "no");
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_REQ(name, feat_leaf, feat_sub, regname, bit) \ #define CPU_FEATURE_REQ(name, feat_leaf, feat_sub, regname, bit) \
CPU_FEATURE_OPT(name, feat_leaf, feat_sub, regname, bit); \ CPU_FEATURE_OPT(name, feat_leaf, feat_sub, regname, bit); \
if ((r.regname & (1ull << bit)) == 0) { \ kassert(cpu.has_feature(cpu::feature::name), "Missing required CPU feature " #name );
log::error(logs::boot, "CPU missing required feature " #name); \
fail = true; \
}
#include "cpu_features.inc" #include "cpu/features.inc"
#undef CPU_FEATURE_OPT #undef CPU_FEATURE_OPT
#undef CPU_FEATURE_REQ #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;
} }

View File

@@ -27,69 +27,6 @@ struct cpu_data
extern cpu_data bsp_cpu_data; extern cpu_data bsp_cpu_data;
/// Enum of the cpu features jsix cares about // We already validated the required options in the bootloader,
enum class cpu_feature { // but iterate the options and log about them.
#define CPU_FEATURE_REQ(name, ...) name, void cpu_validate();
#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;
};

View File

@@ -33,19 +33,10 @@ extern "C" {
void (*__ctors_end)(void); 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 *); extern void __kernel_assert(const char *, unsigned, const char *);
/// Bootstrap the memory managers. /// Bootstrap the memory managers.
void setup_pat();
void memory_initialize_pre_ctors(kernel::args::header *kargs); void memory_initialize_pre_ctors(kernel::args::header *kargs);
void memory_initialize_post_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"); 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; channel *std_out = nullptr;
void void
@@ -110,9 +111,23 @@ void
kernel_main(args::header *header) kernel_main(args::header *header)
{ {
kutil::assert_set_callback(__kernel_assert); kutil::assert_set_callback(__kernel_assert);
init_console(); init_console();
logger_init(); 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(); gdt_init();
interrupts_init(); interrupts_init();
@@ -120,8 +135,7 @@ kernel_main(args::header *header)
run_constructors(); run_constructors();
memory_initialize_post_ctors(header); memory_initialize_post_ctors(header);
cpu_id cpu; cpu_validate();
cpu.validate();
for (size_t i = 0; i < header->num_modules; ++i) { for (size_t i = 0; i < header->num_modules; ++i) {
args::module &mod = header->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, " jsix header is at: %016lx", header);
log::debug(logs::boot, " Memory map is at: %016lx", header->mem_map); 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); log::debug(logs::boot, "ACPI root table is at: %016lx", header->acpi_table);
@@ -152,7 +159,6 @@ kernel_main(args::header *header)
interrupts_enable(); interrupts_enable();
devices.init_drivers(); devices.init_drivers();
devices.get_lapic()->calibrate_timer(); devices.get_lapic()->calibrate_timer();
/* /*

View File

@@ -9,6 +9,7 @@
#include "frame_allocator.h" #include "frame_allocator.h"
#include "io.h" #include "io.h"
#include "log.h" #include "log.h"
#include "msr.h"
#include "objects/process.h" #include "objects/process.h"
#include "objects/vm_area.h" #include "objects/vm_area.h"
#include "vm_space.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 void
memory_initialize_pre_ctors(args::header *kargs) memory_initialize_pre_ctors(args::header *kargs)
{ {

View File

@@ -1,5 +1,11 @@
#include "msr.h" #include "msr.h"
msr
find_mtrr(msr type, unsigned index)
{
return static_cast<msr>(static_cast<uint32_t>(type) + (2 * index));
}
uint64_t uint64_t
rdmsr(msr addr) rdmsr(msr addr)
{ {

View File

@@ -6,6 +6,27 @@
enum class msr : uint32_t enum class msr : uint32_t
{ {
ia32_mtrrcap = 0x000000fe,
ia32_mtrrdeftype = 0x000002ff,
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_efer = 0xc0000080,
ia32_star = 0xc0000081, ia32_star = 0xc0000081,
ia32_lstar = 0xc0000082, ia32_lstar = 0xc0000082,
@@ -15,6 +36,9 @@ enum class msr : uint32_t
ia32_kernel_gs_base = 0xc0000102 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 /// Read the value of a MSR
/// \arg addr The MSR address /// \arg addr The MSR address
/// \returns The current value of the MSR /// \returns The current value of the MSR

View File

@@ -29,6 +29,7 @@ enum class vm_flags : uint32_t
huge_pages = 0x00000200, huge_pages = 0x00000200,
mmio = 0x00010000, mmio = 0x00010000,
write_combine = 0x00020000,
user_mask = 0x0000ffff ///< flags allowed via syscall user_mask = 0x0000ffff ///< flags allowed via syscall
}; };

View File

@@ -181,6 +181,7 @@ page_table::get_table_page()
s_page_cache = s_page_cache->next; s_page_cache = s_page_cache->next;
--s_cache_count; --s_cache_count;
kutil::memset(page, 0, memory::frame_size);
return reinterpret_cast<page_table*>(page); return reinterpret_cast<page_table*>(page);
} }

View File

@@ -21,14 +21,21 @@ struct page_table
present = 0x0001, /// Entry is present in the table present = 0x0001, /// Entry is present in the table
write = 0x0002, /// Section may be written write = 0x0002, /// Section may be written
user = 0x0004, /// User-accessible user = 0x0004, /// User-accessible
mtrr0 = 0x0008, /// MTRR selector bit 0 pat0 = 0x0008, /// PAT selector bit 0
mtrr1 = 0x0010, /// MTRR selector bit 1 pat1 = 0x0010, /// PAT selector bit 1
accessed = 0x0020, /// Entry has been accessed accessed = 0x0020, /// Entry has been accessed
dirty = 0x0040, /// Page has been written to dirty = 0x0040, /// Page has been written to
page = 0x0080, /// Entry is a large page 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 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 /// Helper for getting the next level value

View File

@@ -141,7 +141,7 @@ load_process_image(uintptr_t phys, uintptr_t virt, size_t bytes, TCB *tcb)
// Crazypants framebuffer part // Crazypants framebuffer part
if (fb) { 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); space.add(0x100000000, vma);
vma->commit(fb->phys_addr, 0, memory::page_count(fb->size)); vma->commit(fb->phys_addr, 0, memory::page_count(fb->size));
} }

View File

@@ -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 flags =
page_table::flag::present | page_table::flag::present |
(m_kernel ? page_table::flag::none : page_table::flag::user) | (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}; page_table::iterator it {virt, m_pml4};

97
src/libraries/cpu/cpu.cpp Normal file
View 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;
}
}

View 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];
};
}

View File

@@ -7,8 +7,9 @@ CPU_FEATURE_REQ(pse, 0x00000001, 0, edx, 3)
CPU_FEATURE_OPT(tsc, 0x00000001, 0, edx, 4) CPU_FEATURE_OPT(tsc, 0x00000001, 0, edx, 4)
CPU_FEATURE_REQ(msr, 0x00000001, 0, edx, 5) CPU_FEATURE_REQ(msr, 0x00000001, 0, edx, 5)
CPU_FEATURE_REQ(apic, 0x00000001, 0, edx, 9) 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_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_REQ(fxsr, 0x00000001, 0, edx, 24)
CPU_FEATURE_OPT(fsgsbase, 0x00000007, 0, ebx, 0) CPU_FEATURE_OPT(fsgsbase, 0x00000007, 0, ebx, 0)

View File

@@ -10,9 +10,24 @@ void * memcpy( void * restrict s1, const void * restrict s2, size_t n )
{ {
char * dest = (char *) s1; char * dest = (char *) s1;
const char * src = (const char *) s2; 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++; *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; return s1;
} }