mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-12-04 05:20:30 +00:00
022f7790db
This is quite nice, although I wish [[gnu::always_inline]] implied inline. Also "gnu::" is kind of a wart, but whatcha gonna do.
295 lines
6.2 KiB
C++
295 lines
6.2 KiB
C++
#pragma once
|
|
|
|
#include "types.h"
|
|
#include "kprintf.h"
|
|
|
|
#define PAGE_SIZE 4096
|
|
#define PAGE_MASK 0xfffff000
|
|
|
|
union [[gnu::packed]] Descriptor {
|
|
struct {
|
|
word limit_lo;
|
|
word base_lo;
|
|
byte base_hi;
|
|
byte type : 4;
|
|
byte descriptor_type : 1;
|
|
byte dpl : 2;
|
|
byte segment_present : 1;
|
|
byte limit_hi : 4;
|
|
byte : 1;
|
|
byte zero : 1;
|
|
byte operation_size : 1;
|
|
byte granularity : 1;
|
|
byte base_hi2;
|
|
};
|
|
struct {
|
|
dword low;
|
|
dword high;
|
|
};
|
|
|
|
enum Type {
|
|
Invalid = 0,
|
|
AvailableTSS_16bit = 0x1,
|
|
LDT = 0x2,
|
|
BusyTSS_16bit = 0x3,
|
|
CallGate_16bit = 0x4,
|
|
TaskGate = 0x5,
|
|
InterruptGate_16bit = 0x6,
|
|
TrapGate_16bit = 0x7,
|
|
AvailableTSS_32bit = 0x9,
|
|
BusyTSS_32bit = 0xb,
|
|
CallGate_32bit = 0xc,
|
|
InterruptGate_32bit = 0xe,
|
|
TrapGate_32bit = 0xf,
|
|
};
|
|
|
|
void set_base(void* b)
|
|
{
|
|
base_lo = (dword)(b) & 0xffff;
|
|
base_hi = ((dword)(b) >> 16) & 0xff;
|
|
base_hi2 = ((dword)(b) >> 24) & 0xff;
|
|
}
|
|
|
|
void set_limit(dword l)
|
|
{
|
|
limit_lo = (dword)l & 0xffff;
|
|
limit_hi = ((dword)l >> 16) & 0xff;
|
|
}
|
|
};
|
|
|
|
class IRQHandler;
|
|
|
|
void gdt_init();
|
|
void idt_init();
|
|
void register_interrupt_handler(byte number, void (*f)());
|
|
void register_user_callable_interrupt_handler(byte number, void (*f)());
|
|
void register_irq_handler(byte number, IRQHandler&);
|
|
void unregister_irq_handler(byte number, IRQHandler&);
|
|
void flush_idt();
|
|
void flush_gdt();
|
|
void load_task_register(word selector);
|
|
word gdt_alloc_entry();
|
|
void gdt_free_entry(word);
|
|
Descriptor& get_gdt_entry(word selector);
|
|
void write_gdt_entry(word selector, Descriptor&);
|
|
|
|
[[noreturn]] static inline void hang()
|
|
{
|
|
asm volatile("cli; hlt");
|
|
for (;;) { }
|
|
}
|
|
|
|
#define LSW(x) ((dword)(x) & 0xFFFF)
|
|
#define MSW(x) (((dword)(x) >> 16) & 0xFFFF)
|
|
#define LSB(x) ((x) & 0xFF)
|
|
#define MSB(x) (((x)>>8) & 0xFF)
|
|
|
|
#define cli() asm volatile("cli" ::: "memory")
|
|
#define sti() asm volatile("sti" ::: "memory")
|
|
#define memory_barrier() asm volatile ("" ::: "memory")
|
|
|
|
inline dword cpu_cr3()
|
|
{
|
|
dword cr3;
|
|
asm volatile("movl %%cr3, %%eax":"=a"(cr3));
|
|
return cr3;
|
|
}
|
|
|
|
inline dword cpu_flags()
|
|
{
|
|
dword flags;
|
|
asm volatile(
|
|
"pushf\n"
|
|
"pop %0\n"
|
|
:"=rm"(flags)
|
|
::"memory");
|
|
return flags;
|
|
}
|
|
|
|
inline bool are_interrupts_enabled()
|
|
{
|
|
return cpu_flags() & 0x200;
|
|
}
|
|
|
|
class InterruptFlagSaver {
|
|
public:
|
|
InterruptFlagSaver()
|
|
{
|
|
m_flags = cpu_flags();
|
|
}
|
|
|
|
~InterruptFlagSaver()
|
|
{
|
|
if (m_flags & 0x200)
|
|
sti();
|
|
else
|
|
cli();
|
|
}
|
|
|
|
private:
|
|
dword m_flags;
|
|
};
|
|
|
|
class InterruptDisabler {
|
|
public:
|
|
InterruptDisabler()
|
|
{
|
|
m_flags = cpu_flags();
|
|
cli();
|
|
}
|
|
|
|
~InterruptDisabler()
|
|
{
|
|
if (m_flags & 0x200)
|
|
sti();
|
|
}
|
|
|
|
private:
|
|
dword m_flags;
|
|
};
|
|
|
|
/* Map IRQ0-15 @ ISR 0x50-0x5F */
|
|
#define IRQ_VECTOR_BASE 0x50
|
|
|
|
struct PageFaultFlags {
|
|
enum Flags {
|
|
NotPresent = 0x00,
|
|
ProtectionViolation = 0x01,
|
|
Read = 0x00,
|
|
Write = 0x02,
|
|
UserMode = 0x04,
|
|
SupervisorMode = 0x00,
|
|
InstructionFetch = 0x08,
|
|
};
|
|
};
|
|
|
|
class PageFault {
|
|
public:
|
|
PageFault(word code, LinearAddress laddr)
|
|
: m_code(code)
|
|
, m_laddr(laddr)
|
|
{
|
|
}
|
|
|
|
LinearAddress laddr() const { return m_laddr; }
|
|
word code() const { return m_code; }
|
|
|
|
bool is_not_present() const { return (m_code & 1) == PageFaultFlags::NotPresent; }
|
|
bool is_protection_violation() const { return (m_code & 1) == PageFaultFlags::ProtectionViolation; }
|
|
bool is_read() const { return (m_code & 2) == PageFaultFlags::Read; }
|
|
bool is_write() const { return (m_code & 2) == PageFaultFlags::Write; }
|
|
bool is_user() const { return (m_code & 4) == PageFaultFlags::UserMode; }
|
|
bool is_supervisor() const { return (m_code & 4) == PageFaultFlags::SupervisorMode; }
|
|
bool is_instruction_fetch() const { return (m_code & 8) == PageFaultFlags::InstructionFetch; }
|
|
|
|
private:
|
|
word m_code;
|
|
LinearAddress m_laddr;
|
|
};
|
|
|
|
struct [[gnu::packed]] RegisterDump {
|
|
word ss;
|
|
word gs;
|
|
word fs;
|
|
word es;
|
|
word ds;
|
|
dword edi;
|
|
dword esi;
|
|
dword ebp;
|
|
dword esp;
|
|
dword ebx;
|
|
dword edx;
|
|
dword ecx;
|
|
dword eax;
|
|
dword eip;
|
|
word cs;
|
|
word __csPadding;
|
|
dword eflags;
|
|
dword esp_if_crossRing;
|
|
word ss_if_crossRing;
|
|
};
|
|
|
|
struct [[gnu::packed]] RegisterDumpWithExceptionCode {
|
|
word ss;
|
|
word gs;
|
|
word fs;
|
|
word es;
|
|
word ds;
|
|
dword edi;
|
|
dword esi;
|
|
dword ebp;
|
|
dword esp;
|
|
dword ebx;
|
|
dword edx;
|
|
dword ecx;
|
|
dword eax;
|
|
word exception_code;
|
|
word __exception_code_padding;
|
|
dword eip;
|
|
word cs;
|
|
word __csPadding;
|
|
dword eflags;
|
|
dword esp_if_crossRing;
|
|
word ss_if_crossRing;
|
|
};
|
|
|
|
struct FPUState {
|
|
dword cwd;
|
|
dword swd;
|
|
dword twd;
|
|
dword fip;
|
|
dword fcs;
|
|
dword foo;
|
|
dword fos;
|
|
dword st[20];
|
|
};
|
|
|
|
inline constexpr dword page_base_of(dword address)
|
|
{
|
|
return address & 0xfffff000;
|
|
}
|
|
|
|
class CPUID {
|
|
public:
|
|
CPUID(dword function) { asm volatile("cpuid" : "=a" (m_eax), "=b" (m_ebx), "=c" (m_ecx), "=d" (m_edx) : "a" (function), "c" (0)); }
|
|
dword eax() const { return m_eax; }
|
|
dword ebx() const { return m_ebx; }
|
|
dword ecx() const { return m_ecx; }
|
|
dword edx() const { return m_edx; }
|
|
private:
|
|
dword m_eax { 0xffffffff };
|
|
dword m_ebx { 0xffffffff };
|
|
dword m_ecx { 0xffffffff };
|
|
dword m_edx { 0xffffffff };
|
|
};
|
|
|
|
inline void read_tsc(dword& lsw, dword& msw)
|
|
{
|
|
asm volatile("rdtsc":"=d"(msw),"=a"(lsw));
|
|
}
|
|
|
|
struct Stopwatch {
|
|
public:
|
|
Stopwatch(const char* name)
|
|
: m_name(name)
|
|
{
|
|
read_tsc(m_start_lsw, m_start_msw);
|
|
}
|
|
|
|
~Stopwatch()
|
|
{
|
|
dword end_lsw;
|
|
dword end_msw;
|
|
read_tsc(end_lsw, end_msw);
|
|
if (m_start_msw != end_msw) {
|
|
dbgprintf("stopwatch: differing msw, no result for %s\n", m_name);
|
|
}
|
|
dword diff = end_lsw - m_start_lsw;
|
|
dbgprintf("Stopwatch(%s): %u ticks\n", m_name, diff);
|
|
}
|
|
|
|
private:
|
|
const char* m_name { nullptr };
|
|
dword m_start_lsw { 0 };
|
|
dword m_start_msw { 0 };
|
|
};
|