feat: scheduling, usermode, shell
This commit is contained in:
@@ -8,6 +8,7 @@ section .text ; Text/code section
|
||||
|
||||
global ReloadSegments
|
||||
global LoadGDT
|
||||
global LoadTR
|
||||
|
||||
LoadGDT:
|
||||
lgdt [rdi] ; Run LGDT on the contents of 1st C parameter
|
||||
@@ -28,4 +29,9 @@ ReloadSegments:
|
||||
mov gs, ax
|
||||
mov ss, ax
|
||||
|
||||
ret
|
||||
ret
|
||||
|
||||
LoadTR:
|
||||
mov ax, 0x28 ; TSS selector
|
||||
ltr ax
|
||||
ret
|
||||
|
||||
+47
-14
@@ -1,43 +1,76 @@
|
||||
/*
|
||||
* gdt.hpp
|
||||
* gdt.cpp
|
||||
* Intel Global Descriptor Table
|
||||
* Copyright (c) 2025 Daniel Hammer
|
||||
*/
|
||||
|
||||
#include "GDT.hpp"
|
||||
#include "../Terminal/Terminal.hpp"
|
||||
#include <Libraries/Memory.hpp>
|
||||
|
||||
namespace Hal {
|
||||
using namespace Kt;
|
||||
|
||||
GDTPointer gdtPointer{};
|
||||
BasicGDT kernelGDT{};
|
||||
|
||||
void PrepareGDT() {
|
||||
kernelGDT = {
|
||||
{0xFFFF, 0, 0, 0x00, 0x00, 0},
|
||||
{0xFFFF, 0, 0, 0x9A, 0xA0, 0},
|
||||
{0xFFFF, 0, 0, 0x92, 0xA0, 0},
|
||||
{0xFFFF, 0, 0, 0x9A, 0xA0, 0},
|
||||
{0xFFFF, 0, 0, 0x92, 0xA0, 0},
|
||||
TSS64 g_tss{};
|
||||
|
||||
{0, 0, 0, 0xFA, 0x00, 0x0},
|
||||
void PrepareGDT() {
|
||||
// Zero the TSS
|
||||
memset(&g_tss, 0, sizeof(g_tss));
|
||||
g_tss.iopbOffset = sizeof(TSS64);
|
||||
|
||||
kernelGDT = {
|
||||
{0xFFFF, 0, 0, 0x00, 0x00, 0}, // Null
|
||||
{0xFFFF, 0, 0, 0x9A, 0xA0, 0}, // KernelCode (DPL=0, code, 64-bit)
|
||||
{0xFFFF, 0, 0, 0x92, 0xA0, 0}, // KernelData (DPL=0, data)
|
||||
{0xFFFF, 0, 0, 0xF2, 0xA0, 0}, // UserData (DPL=3, data)
|
||||
{0xFFFF, 0, 0, 0xFA, 0xA0, 0}, // UserCode (DPL=3, code, 64-bit)
|
||||
{0, 0, 0, 0, 0, 0}, // TSS low (filled below)
|
||||
{0, 0, 0, 0, 0, 0}, // TSS high (filled below)
|
||||
};
|
||||
|
||||
|
||||
// Encode 16-byte TSS descriptor
|
||||
uint64_t base = (uint64_t)&g_tss;
|
||||
uint32_t limit = sizeof(TSS64) - 1;
|
||||
|
||||
// Low 8 bytes (normal GDT entry format)
|
||||
kernelGDT.TSS.LimitLow = limit & 0xFFFF;
|
||||
kernelGDT.TSS.BaseLow = base & 0xFFFF;
|
||||
kernelGDT.TSS.BaseMiddle = (base >> 16) & 0xFF;
|
||||
kernelGDT.TSS.AccessByte = 0x89; // Present, 64-bit TSS Available
|
||||
kernelGDT.TSS.GranularityByte = (limit >> 16) & 0x0F;
|
||||
kernelGDT.TSS.BaseHigh = (base >> 24) & 0xFF;
|
||||
|
||||
// High 8 bytes (base[63:32] + reserved)
|
||||
uint32_t baseUpper = (uint32_t)(base >> 32);
|
||||
kernelGDT.TSSHigh.LimitLow = baseUpper & 0xFFFF;
|
||||
kernelGDT.TSSHigh.BaseLow = (baseUpper >> 16) & 0xFFFF;
|
||||
kernelGDT.TSSHigh.BaseMiddle = 0;
|
||||
kernelGDT.TSSHigh.AccessByte = 0;
|
||||
kernelGDT.TSSHigh.GranularityByte = 0;
|
||||
kernelGDT.TSSHigh.BaseHigh = 0;
|
||||
|
||||
gdtPointer = GDTPointer{
|
||||
.Size = sizeof(kernelGDT) - 1,
|
||||
.GDTAddress = (uint64_t)&kernelGDT
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
// Helpers implemented in gdt.asm
|
||||
extern "C" void LoadGDT(GDTPointer *gdtPointer);
|
||||
extern "C" void ReloadSegments();
|
||||
|
||||
extern "C" void LoadTR();
|
||||
|
||||
void BridgeLoadGDT() {
|
||||
LoadGDT(&gdtPointer);
|
||||
ReloadSegments();
|
||||
|
||||
KernelLogStream(DEBUG, "Hal") << "Set new GDT (0x" << base::hex << (uint64_t)&kernelGDT << ")";
|
||||
}
|
||||
};
|
||||
|
||||
void LoadTSS() {
|
||||
LoadTR();
|
||||
KernelLogStream(OK, "Hal") << "Loaded TSS (selector 0x28)";
|
||||
}
|
||||
};
|
||||
|
||||
+33
-13
@@ -17,25 +17,45 @@ namespace Hal {
|
||||
uint8_t BaseMiddle;
|
||||
uint8_t AccessByte;
|
||||
uint8_t GranularityByte;
|
||||
uint8_t BaseHigh;
|
||||
uint8_t BaseHigh;
|
||||
}__attribute__((packed));
|
||||
|
||||
|
||||
struct BasicGDT {
|
||||
GDTEntry Null;
|
||||
GDTEntry KernelCode;
|
||||
GDTEntry KernelData;
|
||||
GDTEntry UserCode;
|
||||
GDTEntry UserData;
|
||||
|
||||
// Task State Segment
|
||||
GDTEntry TSS;
|
||||
GDTEntry Null; // 0x00
|
||||
GDTEntry KernelCode; // 0x08
|
||||
GDTEntry KernelData; // 0x10
|
||||
GDTEntry UserData; // 0x18 (before UserCode for SYSRET)
|
||||
GDTEntry UserCode; // 0x20
|
||||
GDTEntry TSS; // 0x28 (low 8 bytes of 16-byte TSS descriptor)
|
||||
GDTEntry TSSHigh; // 0x30 (high 8 bytes of 16-byte TSS descriptor)
|
||||
}__attribute__((packed));
|
||||
|
||||
|
||||
struct GDTPointer {
|
||||
uint16_t Size;
|
||||
uint64_t GDTAddress;
|
||||
}__attribute__((packed));
|
||||
|
||||
|
||||
struct TSS64 {
|
||||
uint32_t reserved0;
|
||||
uint64_t rsp0;
|
||||
uint64_t rsp1;
|
||||
uint64_t rsp2;
|
||||
uint64_t reserved1;
|
||||
uint64_t ist1;
|
||||
uint64_t ist2;
|
||||
uint64_t ist3;
|
||||
uint64_t ist4;
|
||||
uint64_t ist5;
|
||||
uint64_t ist6;
|
||||
uint64_t ist7;
|
||||
uint64_t reserved2;
|
||||
uint16_t reserved3;
|
||||
uint16_t iopbOffset;
|
||||
}__attribute__((packed));
|
||||
|
||||
extern TSS64 g_tss;
|
||||
|
||||
void BridgeLoadGDT();
|
||||
void PrepareGDT();
|
||||
};
|
||||
void LoadTSS();
|
||||
};
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* MSR.hpp
|
||||
* Model-Specific Register read/write helpers
|
||||
* Copyright (c) 2025 Daniel Hammer
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
|
||||
namespace Hal {
|
||||
|
||||
inline uint64_t ReadMSR(uint32_t msr) {
|
||||
uint32_t lo, hi;
|
||||
asm volatile("rdmsr" : "=a"(lo), "=d"(hi) : "c"(msr));
|
||||
return ((uint64_t)hi << 32) | lo;
|
||||
}
|
||||
|
||||
inline void WriteMSR(uint32_t msr, uint64_t value) {
|
||||
uint32_t lo = (uint32_t)(value & 0xFFFFFFFF);
|
||||
uint32_t hi = (uint32_t)(value >> 32);
|
||||
asm volatile("wrmsr" : : "a"(lo), "d"(hi), "c"(msr));
|
||||
}
|
||||
|
||||
// Well-known MSR addresses
|
||||
static constexpr uint32_t IA32_EFER = 0xC0000080;
|
||||
static constexpr uint32_t IA32_STAR = 0xC0000081;
|
||||
static constexpr uint32_t IA32_LSTAR = 0xC0000082;
|
||||
static constexpr uint32_t IA32_FMASK = 0xC0000084;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
;
|
||||
; SyscallEntry.asm
|
||||
; SYSCALL/SYSRET entry point and user-mode transition
|
||||
; Copyright (c) 2025 Daniel Hammer
|
||||
;
|
||||
|
||||
[bits 64]
|
||||
section .text
|
||||
|
||||
extern SyscallDispatch
|
||||
extern g_kernelRsp
|
||||
|
||||
; ============================================================
|
||||
; SyscallEntry — called by the SYSCALL instruction
|
||||
; RCX = user RIP, R11 = user RFLAGS, RAX = syscall number
|
||||
; Args: RDI, RSI, RDX, R10, R8, R9
|
||||
; Interrupts are masked (FMASK clears IF)
|
||||
; ============================================================
|
||||
global SyscallEntry
|
||||
SyscallEntry:
|
||||
mov [rel g_userRsp], rsp ; stash user RSP
|
||||
mov rsp, [rel g_kernelRsp] ; switch to kernel stack
|
||||
|
||||
; Build SyscallFrame on kernel stack (push order matches struct)
|
||||
push qword [rel g_userRsp] ; user_rsp
|
||||
push rcx ; user_rip
|
||||
push r11 ; user_rflags
|
||||
push rax ; syscall_nr
|
||||
push rdi ; arg1
|
||||
push rsi ; arg2
|
||||
push rdx ; arg3
|
||||
push r10 ; arg4
|
||||
push r8 ; arg5
|
||||
push r9 ; arg6
|
||||
|
||||
; Callee-saved registers (preserve for user)
|
||||
push rbx
|
||||
push rbp
|
||||
push r12
|
||||
push r13
|
||||
push r14
|
||||
push r15
|
||||
|
||||
sti ; safe to take interrupts now
|
||||
|
||||
mov rdi, rsp ; arg1 = pointer to SyscallFrame
|
||||
call SyscallDispatch ; returns int64_t in rax
|
||||
|
||||
cli ; disable interrupts for sysret
|
||||
|
||||
pop r15
|
||||
pop r14
|
||||
pop r13
|
||||
pop r12
|
||||
pop rbp
|
||||
pop rbx
|
||||
|
||||
add rsp, 56 ; skip arg6..arg1 (6*8) + syscall_nr (1*8) = 56
|
||||
|
||||
pop r11 ; user RFLAGS
|
||||
pop rcx ; user RIP
|
||||
pop rsp ; user RSP
|
||||
|
||||
o64 sysret
|
||||
|
||||
; ============================================================
|
||||
; JumpToUserMode — initial transition to ring 3 via IRETQ
|
||||
; RDI = user RIP (entry point)
|
||||
; RSI = user RSP (top of user stack)
|
||||
; ============================================================
|
||||
global JumpToUserMode
|
||||
JumpToUserMode:
|
||||
mov ax, 0x1B ; UserData | RPL3
|
||||
mov ds, ax
|
||||
mov es, ax
|
||||
|
||||
push 0x1B ; SS = UserData | RPL3
|
||||
push rsi ; RSP = user stack top
|
||||
push 0x202 ; RFLAGS (IF=1)
|
||||
push 0x23 ; CS = UserCode | RPL3
|
||||
push rdi ; RIP = entry point
|
||||
iretq
|
||||
|
||||
; ============================================================
|
||||
; BSS: scratch space for user RSP save
|
||||
; ============================================================
|
||||
section .bss
|
||||
global g_userRsp
|
||||
g_userRsp: resq 1
|
||||
Reference in New Issue
Block a user