Compare commits

...

3 commits

9 changed files with 190 additions and 32 deletions

View file

@ -1,6 +1,6 @@
#pragma once
#include "init/acpi.h"
#include "acpi/acpi.h"
#include "memory/pointer.h"
#include "util/number.h"

View file

@ -0,0 +1,19 @@
#pragma once
#include "acpi/madt.h"
#include "util/optional.h"
namespace apic {
struct lapic_timer_calibration_t {
uint64_t tsc_frequency_hz;
};
optional<lapic_timer_calibration_t> calibrateTimer(const acpi::Madt& madt);
// TODO: when dynamic allocation and lists are available
// struct Timer {};
//
// Timer getCoreTimerInstance();
} // namespace apic

View file

@ -0,0 +1,21 @@
#pragma once
#include <cpuid.h>
#include <stdint.h>
#include "util/optional.h"
struct cpuid_result_t {
uint32_t eax;
uint32_t ebx;
uint32_t ecx;
uint32_t edx;
};
inline optional<cpuid_result_t> cpuid(uint32_t leaf, uint32_t subleaf = 0) {
cpuid_result_t result{};
if (__get_cpuid_count(leaf, subleaf, &result.eax, &result.ebx, &result.ecx, &result.edx) == 0) {
return {};
}
return result;
}

View file

@ -1,5 +1,7 @@
#pragma once
#include "util/utility.h"
template<typename... Ts>
struct overloaded : Ts... {
using Ts::operator()...;
@ -7,3 +9,17 @@ struct overloaded : Ts... {
template<typename... Ts>
overloaded(Ts...) -> overloaded<Ts...>;
template<typename Func, typename... BoundArgs>
auto partial(Func func, BoundArgs... bound_args) {
return [func, bound_args...](auto&&... call_args) {
return func(bound_args..., forward<decltype(call_args)>(call_args)...);
};
}
template<typename Type>
auto construct() {
return [](auto&&... args) {
return Type{forward<decltype(args)>(args)...};
};
}

View file

@ -9,6 +9,9 @@
// instead of <utility>. The CrackOS3 value_or_panic() helper is omitted because
// there is no global panic() in this tree yet.
struct nullopt_t {};
inline constexpr nullopt_t nullopt{};
template<typename T>
struct optional {
private:
@ -26,6 +29,7 @@ public:
using value_type = T;
constexpr optional() : initialized(false) {}
constexpr optional(nullopt_t) : initialized(false) {}
optional(const T& value) : initialized(true) {
new (buffer) T(value);
}
@ -135,10 +139,45 @@ public:
return !initialized;
}
template<typename R, typename Func, typename... ArgT>
optional<R> map(Func func, ArgT... args) {
template<typename Func>
auto map(Func&& func) -> optional<decltype(func(value()))> {
if (initialized) {
return func(value(), forward<ArgT>(args)...);
return func(value());
} else {
return {};
}
}
template<typename Func>
auto map(Func&& func) const -> optional<decltype(func(value()))> {
if (initialized) {
return func(value());
} else {
return {};
}
}
template<typename Func>
optional or_else(Func&& func) const {
if (initialized) {
return *this;
}
return func();
}
template<typename Func>
auto bind(Func&& func) -> decltype(func(value())) {
if (initialized) {
return func(value());
} else {
return {};
}
}
template<typename Func>
auto bind(Func&& func) const -> decltype(func(value())) {
if (initialized) {
return func(value());
} else {
return {};
}

View file

@ -18,6 +18,11 @@ struct remove_reference<T&&> {
template<typename T>
using remove_reference_t = typename remove_reference<T>::type;
template<typename T>
inline constexpr bool is_void_v = false;
template<>
inline constexpr bool is_void_v<void> = true;
template<typename T>
constexpr remove_reference_t<T>&& move(T&& value) {
return static_cast<remove_reference_t<T>&&>(value);

55
kernel/src/apic/timer.cpp Normal file
View file

@ -0,0 +1,55 @@
#include "apic/timer.h"
#include "util/cpuid.h"
#include "util/function.h"
namespace {
constexpr uint32_t feature_info_leaf = 0x1;
constexpr uint32_t tsc_crystal_ratio_leaf = 0x15;
constexpr uint32_t processor_frequency_leaf = 0x16;
constexpr uint32_t feature_edx_tsc = 1u << 4;
bool isTscSupported() {
return cpuid(feature_info_leaf)
.map([](const cpuid_result_t& features) {
return (features.edx & feature_edx_tsc) != 0;
})
.value_or(false);
}
optional<uint64_t> tscFrequencyFromCrystalRatio() {
return cpuid(tsc_crystal_ratio_leaf).bind([](const cpuid_result_t& ratio) -> optional<uint64_t> {
uint64_t denominator = ratio.eax;
uint64_t numerator = ratio.ebx;
uint64_t crystal_frequency_hz = ratio.ecx;
if (denominator == 0 || numerator == 0 || crystal_frequency_hz == 0) {
return nullopt;
}
return crystal_frequency_hz * numerator / denominator;
});
}
optional<uint64_t> tscFrequencyFromProcessorBase() {
return cpuid(processor_frequency_leaf).bind([](const cpuid_result_t& frequency_info) -> optional<uint64_t> {
uint64_t base_frequency_mhz = frequency_info.eax & 0xFFFF;
if (base_frequency_mhz == 0) {
return nullopt;
}
return base_frequency_mhz * 1'000'000;
});
}
optional<uint64_t> tscFrequency() {
return tscFrequencyFromCrystalRatio().or_else(tscFrequencyFromProcessorBase);
}
} // namespace
optional<apic::lapic_timer_calibration_t> apic::calibrateTimer(const acpi::Madt&) {
if (!isTscSupported()) {
return {};
}
return tscFrequency().map(construct<lapic_timer_calibration_t>());
}

View file

@ -1,11 +1,12 @@
#include "init/init.h"
#include "init/acpi.h"
#include "init/apic.h"
#include "acpi/acpi.h"
#include "acpi/madt.h"
#include "init/multiboot2.h"
#include "init/print.h"
#include "memory/allocator.h"
#include "memory/pointer.h"
#include "memory/sections.h"
#include "util/utility.h"
[[maybe_unused]] [[noreturn]] __attribute__((used)) static void halt() {
while (true)
@ -18,23 +19,30 @@
}
static int step_depth = 0;
template<typename T>
static void step(const char* name, T&& fn) {
static void print_step_boundary(const char* prefix, const char* name) {
for (int i = 0; i < step_depth; ++i) {
print(" ");
}
print("Starting ");
print(prefix);
print(name);
print("\n");
}
template<typename Fn>
static auto step(const char* name, Fn&& fn) {
print_step_boundary("Starting ", name);
++step_depth;
fn();
--step_depth;
for (int i = 0; i < step_depth; ++i) {
print(" ");
if constexpr (is_void_v<decltype(fn())>) {
fn();
--step_depth;
print_step_boundary("Finished ", name);
} else {
auto result = fn();
--step_depth;
print_step_boundary("Finished ", name);
return result;
}
print("Finished ");
print(name);
print("\n");
}
template<typename Fn>
@ -145,14 +153,9 @@ void PhysicalAllocator::init(const multiboot::tag_mmap* multiboot_info) {
}
static void setupMemory() {
multiboot::visit_all(
overloaded{
[](const multiboot::tag_mmap* mem) {
PhysicalAllocator::init(mem);
},
[](const auto* tag) {}
}
);
multiboot::visit_all(overloaded{[](const multiboot::tag_mmap* mem) {
PhysicalAllocator::init(mem);
}});
}
static paddr_t rsdp_physical_of(const uint8_t* rsdp_payload) {
@ -173,8 +176,7 @@ static acpi::Rsdp findRsdp() {
if (!rsdp.has_value()) {
rsdp = rsdp_physical_of(tag->rsdp);
}
},
[&](const auto* tag) {}
}
}
);
@ -189,18 +191,19 @@ struct AcpiDiscoveryResult {
optional<acpi::Madt> madt;
};
static void setupAcpi() {
auto rsdp = findRsdp();
rsdp.for_each_table(overloaded{[&](const acpi::sdt_header_t* header) {
print(acpi::unfold_signature(header->signature).text);
print("\n");
static AcpiDiscoveryResult setupAcpi() {
AcpiDiscoveryResult res{};
res.rsdp = findRsdp();
res.rsdp->for_each_table(overloaded{[&](const acpi::madt_t* header) {
res.madt = acpi::Madt{header};
}});
return res;
}
[[maybe_unused]] [[noreturn]] __attribute__((used)) void init() {
initFromLow();
print("Reached init\n");
step("memory", setupMemory);
step("acpi", setupAcpi);
auto acpi = step("acpi", setupAcpi);
halt();
}