mirror of
https://github.com/RGBCube/serenity
synced 2025-05-23 07:35:07 +00:00

Right now we're using the FS segment for our per-CPU struct. On x86_64 there's an instruction to switch between a kernel and usermode GS segment (swapgs) which we could use. This patch doesn't update the rest of the code to use swapgs but it prepares for that by using the GS segment instead of the FS segment.
156 lines
2.6 KiB
C++
156 lines
2.6 KiB
C++
/*
|
|
* Copyright (c) 2018-2021, Andreas Kling <kling@serenityos.org>
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <AK/Types.h>
|
|
|
|
namespace Kernel {
|
|
|
|
ALWAYS_INLINE void cli()
|
|
{
|
|
asm volatile("cli" ::
|
|
: "memory");
|
|
}
|
|
ALWAYS_INLINE void sti()
|
|
{
|
|
asm volatile("sti" ::
|
|
: "memory");
|
|
}
|
|
ALWAYS_INLINE FlatPtr cpu_flags()
|
|
{
|
|
FlatPtr flags;
|
|
asm volatile(
|
|
"pushf\n"
|
|
"pop %0\n"
|
|
: "=rm"(flags)::"memory");
|
|
return flags;
|
|
}
|
|
|
|
#if ARCH(I386)
|
|
ALWAYS_INLINE void set_fs(u16 segment)
|
|
{
|
|
asm volatile(
|
|
"mov %%ax, %%fs" ::"a"(segment)
|
|
: "memory");
|
|
}
|
|
|
|
ALWAYS_INLINE void set_gs(u16 segment)
|
|
{
|
|
asm volatile(
|
|
"mov %%ax, %%gs" ::"a"(segment)
|
|
: "memory");
|
|
}
|
|
|
|
ALWAYS_INLINE u16 get_fs()
|
|
{
|
|
u16 fs;
|
|
asm("mov %%fs, %%eax"
|
|
: "=a"(fs));
|
|
return fs;
|
|
}
|
|
|
|
ALWAYS_INLINE u16 get_gs()
|
|
{
|
|
u16 gs;
|
|
asm("mov %%gs, %%eax"
|
|
: "=a"(gs));
|
|
return gs;
|
|
}
|
|
#endif
|
|
|
|
ALWAYS_INLINE u32 read_gs_u32(u32 offset)
|
|
{
|
|
u32 val;
|
|
asm volatile(
|
|
"movl %%gs:%a[off], %k[val]"
|
|
: [val] "=r"(val)
|
|
: [off] "ir"(offset));
|
|
return val;
|
|
}
|
|
|
|
ALWAYS_INLINE FlatPtr read_gs_ptr(u32 offset)
|
|
{
|
|
return read_gs_u32(offset);
|
|
}
|
|
|
|
ALWAYS_INLINE void write_gs_u32(u32 offset, u32 val)
|
|
{
|
|
asm volatile(
|
|
"movl %k[val], %%gs:%a[off]" ::[off] "ir"(offset), [val] "ir"(val)
|
|
: "memory");
|
|
}
|
|
|
|
ALWAYS_INLINE bool are_interrupts_enabled()
|
|
{
|
|
return cpu_flags() & 0x200;
|
|
}
|
|
|
|
FlatPtr read_cr0();
|
|
FlatPtr read_cr2();
|
|
FlatPtr read_cr3();
|
|
FlatPtr read_cr4();
|
|
u64 read_xcr0();
|
|
|
|
void write_cr0(FlatPtr);
|
|
void write_cr3(FlatPtr);
|
|
void write_cr4(FlatPtr);
|
|
void write_xcr0(u64);
|
|
|
|
void flush_idt();
|
|
|
|
ALWAYS_INLINE void load_task_register(u16 selector)
|
|
{
|
|
asm("ltr %0" ::"r"(selector));
|
|
}
|
|
|
|
FlatPtr read_dr0();
|
|
void write_dr0(FlatPtr);
|
|
FlatPtr read_dr1();
|
|
void write_dr1(FlatPtr);
|
|
FlatPtr read_dr2();
|
|
void write_dr2(FlatPtr);
|
|
FlatPtr read_dr3();
|
|
void write_dr3(FlatPtr);
|
|
FlatPtr read_dr6();
|
|
void write_dr6(FlatPtr);
|
|
FlatPtr read_dr7();
|
|
void write_dr7(FlatPtr);
|
|
|
|
ALWAYS_INLINE static bool is_kernel_mode()
|
|
{
|
|
u16 cs;
|
|
asm volatile(
|
|
"mov %%cs, %[cs] \n"
|
|
: [cs] "=g"(cs));
|
|
return (cs & 3) == 0;
|
|
}
|
|
|
|
ALWAYS_INLINE void read_tsc(u32& lsw, u32& msw)
|
|
{
|
|
asm volatile("rdtsc"
|
|
: "=d"(msw), "=a"(lsw));
|
|
}
|
|
|
|
ALWAYS_INLINE u64 read_tsc()
|
|
{
|
|
u32 lsw;
|
|
u32 msw;
|
|
read_tsc(lsw, msw);
|
|
return ((u64)msw << 32) | lsw;
|
|
}
|
|
|
|
void stac();
|
|
void clac();
|
|
|
|
[[noreturn]] ALWAYS_INLINE void halt_this()
|
|
{
|
|
for (;;) {
|
|
asm volatile("cli; hlt");
|
|
}
|
|
}
|
|
|
|
}
|