diff --git a/modules.yaml b/modules.yaml index ceff427..75bc913 100644 --- a/modules.yaml +++ b/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 diff --git a/src/boot/console.cpp b/src/boot/console.cpp index b679735..02c9181 100644 --- a/src/boot/console.cpp +++ b/src/boot/console.cpp @@ -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"); } diff --git a/src/boot/main.cpp b/src/boot/main.cpp index 3f74ee4..f48e3b8 100644 --- a/src/boot/main.cpp +++ b/src/boot/main.cpp @@ -8,6 +8,7 @@ #include #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); diff --git a/src/boot/memory.cpp b/src/boot/memory.cpp index e283ed9..92bafa5 100644 --- a/src/boot/memory.cpp +++ b/src/boot/memory.cpp @@ -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(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; } diff --git a/src/boot/paging.cpp b/src/boot/paging.cpp index 21f693d..b1423fb 100644 --- a/src/boot/paging.cpp +++ b/src/boot/paging.cpp @@ -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(addr); + + args->pml4 = pml4; args->table_count = tables_needed - 1; args->page_tables = offset_ptr(addr, page_size); - page_table *pml4 = reinterpret_cast(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); diff --git a/src/drivers/fb/main.cpp b/src/drivers/fb/main.cpp index 2f02053..efedc50 100644 --- a/src/drivers/fb/main.cpp +++ b/src/drivers/fb/main.cpp @@ -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; } } diff --git a/src/drivers/fb/screen.cpp b/src/drivers/fb/screen.cpp index a01823b..d7862f9 100644 --- a/src/drivers/fb/screen.cpp +++ b/src/drivers/fb/screen.cpp @@ -1,3 +1,5 @@ +#include +#include #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(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)); } diff --git a/src/drivers/fb/screen.h b/src/drivers/fb/screen.h index a9766ec..8d338ce 100644 --- a/src/drivers/fb/screen.h +++ b/src/drivers/fb/screen.h @@ -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; diff --git a/src/kernel/cpu.cpp b/src/kernel/cpu.cpp index 7e6c25b..4b0720e 100644 --- a/src/kernel/cpu.cpp +++ b/src/kernel/cpu.cpp @@ -1,116 +1,31 @@ #include +#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(&m_vendor_id[0]), - reinterpret_cast(&m_vendor_id[8]), - reinterpret_cast(&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(&m_brand_name[0]), - reinterpret_cast(&m_brand_name[4]), - reinterpret_cast(&m_brand_name[8]), - reinterpret_cast(&m_brand_name[12])); - __cpuid(cpuid_extended + 3, 0, - reinterpret_cast(&m_brand_name[16]), - reinterpret_cast(&m_brand_name[20]), - reinterpret_cast(&m_brand_name[24]), - reinterpret_cast(&m_brand_name[28])); - __cpuid(cpuid_extended + 4, 0, - reinterpret_cast(&m_brand_name[32]), - reinterpret_cast(&m_brand_name[36]), - reinterpret_cast(&m_brand_name[40]), - reinterpret_cast(&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(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(feat))) != 0; } diff --git a/src/kernel/cpu.h b/src/kernel/cpu.h index 84108fd..ed5722d 100644 --- a/src/kernel/cpu.h +++ b/src/kernel/cpu.h @@ -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(); diff --git a/src/kernel/main.cpp b/src/kernel/main.cpp index 6cd52f2..e872f1d 100644 --- a/src/kernel/main.cpp +++ b/src/kernel/main.cpp @@ -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(reinterpret_cast(&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(reinterpret_cast(&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(); /* diff --git a/src/kernel/memory_bootstrap.cpp b/src/kernel/memory_bootstrap.cpp index 114a5ce..df8d726 100644 --- a/src/kernel/memory_bootstrap.cpp +++ b/src/kernel/memory_bootstrap.cpp @@ -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) { diff --git a/src/kernel/msr.cpp b/src/kernel/msr.cpp index d43c1fc..4efb175 100644 --- a/src/kernel/msr.cpp +++ b/src/kernel/msr.cpp @@ -1,5 +1,11 @@ #include "msr.h" +msr +find_mtrr(msr type, unsigned index) +{ + return static_cast(static_cast(type) + (2 * index)); +} + uint64_t rdmsr(msr addr) { diff --git a/src/kernel/msr.h b/src/kernel/msr.h index 4d26425..ee02d45 100644 --- a/src/kernel/msr.h +++ b/src/kernel/msr.h @@ -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); diff --git a/src/kernel/objects/vm_area.h b/src/kernel/objects/vm_area.h index e8b34c2..dbeb18d 100644 --- a/src/kernel/objects/vm_area.h +++ b/src/kernel/objects/vm_area.h @@ -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 }; diff --git a/src/kernel/page_table.cpp b/src/kernel/page_table.cpp index 5753e09..915493d 100644 --- a/src/kernel/page_table.cpp +++ b/src/kernel/page_table.cpp @@ -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); } diff --git a/src/kernel/page_table.h b/src/kernel/page_table.h index 5e3f010..8114f36 100644 --- a/src/kernel/page_table.h +++ b/src/kernel/page_table.h @@ -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 diff --git a/src/kernel/scheduler.cpp b/src/kernel/scheduler.cpp index b8e203f..6ce2183 100644 --- a/src/kernel/scheduler.cpp +++ b/src/kernel/scheduler.cpp @@ -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)); } diff --git a/src/kernel/vm_space.cpp b/src/kernel/vm_space.cpp index fd14f30..98fd6c9 100644 --- a/src/kernel/vm_space.cpp +++ b/src/kernel/vm_space.cpp @@ -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}; diff --git a/src/libraries/cpu/cpu.cpp b/src/libraries/cpu/cpu.cpp new file mode 100644 index 0000000..98395e5 --- /dev/null +++ b/src/libraries/cpu/cpu.cpp @@ -0,0 +1,97 @@ +#include +#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(&m_vendor_id[0]), + reinterpret_cast(&m_vendor_id[8]), + reinterpret_cast(&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(&m_brand_name[0]), + reinterpret_cast(&m_brand_name[4]), + reinterpret_cast(&m_brand_name[8]), + reinterpret_cast(&m_brand_name[12])); + __cpuid(cpuid_extended + 3, 0, + reinterpret_cast(&m_brand_name[16]), + reinterpret_cast(&m_brand_name[20]), + reinterpret_cast(&m_brand_name[24]), + reinterpret_cast(&m_brand_name[28])); + __cpuid(cpuid_extended + 4, 0, + reinterpret_cast(&m_brand_name[32]), + reinterpret_cast(&m_brand_name[36]), + reinterpret_cast(&m_brand_name[40]), + reinterpret_cast(&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(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(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(feat))) != 0; +} + +} diff --git a/src/libraries/cpu/include/cpu/cpu.h b/src/libraries/cpu/include/cpu/cpu.h new file mode 100644 index 0000000..ceace0f --- /dev/null +++ b/src/libraries/cpu/include/cpu/cpu.h @@ -0,0 +1,81 @@ +#pragma once +/// \file cpu.h Definition of required cpu features for jsix + +#include + +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]; +}; + +} diff --git a/src/kernel/cpu_features.inc b/src/libraries/cpu/include/cpu/features.inc similarity index 89% rename from src/kernel/cpu_features.inc rename to src/libraries/cpu/include/cpu/features.inc index b455f53..34d3f54 100644 --- a/src/kernel/cpu_features.inc +++ b/src/libraries/cpu/include/cpu/features.inc @@ -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) diff --git a/src/libraries/libc/string/memcpy.c b/src/libraries/libc/string/memcpy.c index 981d3c6..ed1cda9 100644 --- a/src/libraries/libc/string/memcpy.c +++ b/src/libraries/libc/string/memcpy.c @@ -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; }