1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
|
#include <cstdint>
#pragma once
#include <arch/x86_64/assembly.hpp>
#include <generic/scheduling.hpp>
#include <klibc/string.hpp>
#include <klibc/stdio.hpp>
#include <cstddef>
#include <type_traits>
#include <generic/arch.hpp>
struct cpudata_t {
std::uint64_t user_stack;
std::uint64_t kernel_stack;
std::uint64_t timer_ist_stack;
std::uint32_t cpu;
std::uint64_t tsc_freq;
void* pvclock_buffer;
thread* current_thread;
};
namespace x86_64 {
inline std::uint64_t cpu_data_const = 0;
inline static void init_cpu_data() {
std::uint64_t cpudata = assembly::rdmsr(0xC0000101);
if(!cpudata) {
cpudata = (std::uint64_t)new cpudata_t;
cpu_data_const = cpudata;
klibc::memset((void*)cpudata,0,sizeof(cpudata_t));
assembly::wrmsr(0xC0000101,cpudata);
}
}
inline static void restore_cpu_data() {
assembly::wrmsr(0xC0000101,cpu_data_const);
}
inline static cpudata_t* cpu_data() {
std::uint64_t cpudata = assembly::rdmsr(0xC0000101);
if(!cpudata) {
klibc::printf("cpudata: fdgkldfglfkdfdjnbdff\r\n");
arch::hcf();
}
return (cpudata_t*)cpudata;
}
template <typename T, std::size_t Offset> [[nodiscard]] static inline T cpu_local_read() {
T out;
asm volatile("mov %%gs:%c1, %0" : "=r"(out) : "i"(Offset));
return out;
}
template <typename T, std::size_t Offset, typename V> static inline void cpu_local_write(V&& value) {
static_assert(std::is_same_v<std::remove_cvref_t<V>, std::remove_cv_t<T>>, "member type and value type are not compatible");
T v = static_cast<T>(value);
asm volatile("mov %0, %%gs:%c1" : : "r"(v), "i"(Offset));
}
};
#define CPU_LOCAL_READ(field) x86_64::cpu_local_read<decltype(((cpudata_t*) nullptr)->field), offsetof(cpudata_t, field)>()
#define CPU_LOCAL_WRITE(field, value) x86_64::cpu_local_write<decltype(((cpudata_t*) nullptr)->field), offsetof(cpudata_t, field)>((value))
|