Added TSS and code to enter user mode (kind of).

This commit is contained in:
Patrick 2024-01-19 09:42:58 +01:00
parent 355b1641bd
commit d711938821
4 changed files with 113 additions and 7 deletions

View File

@ -1,4 +1,6 @@
extern "C" void main()
{
// __asm__ __volatile__("cli");
while(true);
}

View File

@ -85,6 +85,35 @@ __reloadSegments:
movw %ax, %ss
ret
.global __flushTSS
.type __flushTSS @function
// void __flushTSS(uint16_t segment [%di])
__flushTSS:
ltr %di
ret
.global __enterUsermode
.type __enterUsermode @function
// void __enterUsermode(uint16_t codeSegment [%di], uint16_t dataSegment [%si], void* rsp [%rdx], void* function [%rcx])
__enterUsermode:
orw $0x3, %di // we are switching to ring 3, therefore set the bottom 2 bits to 3
orw $0x3, %si // same for the data segment
movw %si, %ds
movw %si, %es
movw %si, %fs
movw %si, %gs
movq %rsp, (%rdx)
movq %rsp, %rax
pushq %rsi // data segment
pushq %rax
pushf // flags
pushq %rdi // code segment
pushq %rcx
iretq
/*
Set the size of the _start symbol to the current location '.' minus its start.
This is useful when debugging or when you implement call tracing.

View File

@ -46,15 +46,24 @@ inline constexpr std::uint8_t INTERRUPT_VIRTUALIZATION_EXCEPTION = 0x14;
inline constexpr std::uint8_t INTERRUPT_CONTROL_PROTECTION_EXCEPTION = 0x15;
inline constexpr std::uint8_t INTERRUPT_KEYBOARD = irqToInterrupt(1);
TaskStateSegment tss alignas(16);
constinit std::array GDT alignas(16) = {
SEGMENT_NULL,
SEGMENT_KERNEL_CODE,
SEGMENT_KERNEL_DATA,
SEGMENT_USER_CODE,
SEGMENT_USER_DATA,
SEGMENT_NULL
SEGMENT_NULL, // TSS lower
SEGMENT_NULL // TSS higher
};
inline constexpr std::uint16_t SEGIDX_KERNEL_CODE = 1 << 3;
inline constexpr std::uint16_t SEGIDX_KERNEL_DATA = 2 << 3;
inline constexpr std::uint16_t SEGIDX_USER_CODE = 3 << 3;
inline constexpr std::uint16_t SEGIDX_USER_DATA = 4 << 3;
inline constexpr std::uint16_t SEGIDX_TSS = 5 << 3;
constinit std::array<InterruptDescriptor, 256> IDT alignas(16);
void initHeapFromEfiMemoryMap(const EfiMemoryMap& memoryMap) noexcept
@ -133,6 +142,8 @@ void initGlobals()
extern "C" void __setGDT(uint16_t limit, void* base);
extern "C" void __setIDT(uint16_t limit, void* base);
extern "C" void __reloadSegments(uint64_t code, uint64_t data);
extern "C" void __flushTSS(uint16_t segment);
extern "C" void __enterUsermode(uint16_t codeSegment, uint16_t dataSegment, void* rsp, void (*function)());
template<typename THandler>
void setupInterrupt(std::uint8_t index, THandler handler) noexcept
@ -180,9 +191,11 @@ void kernel_main()
setupInterrupt(INTERRUPT_CONTROL_PROTECTION_EXCEPTION, &baos::isrControlProtectionException);
setupInterrupt(INTERRUPT_KEYBOARD, &ps2::isrKeyboard);
makeTSSSegment(&tss, &GDT[5]);
__setGDT(sizeof(GDT), &GDT);
__setIDT(sizeof(IDT), &IDT);
__reloadSegments(0x08, 0x10);
__reloadSegments(SEGIDX_KERNEL_CODE, SEGIDX_KERNEL_DATA);
__flushTSS(SEGIDX_TSS);
const bool picsInited = initPICs(MASTER_PIC_OFFSET, SLAVE_PIC_OFFSET);
unmaskIRQ(1);
@ -229,6 +242,8 @@ void kernel_main()
}
std::puts("This is BadAppleOS and everything is fine!\n");
__enterUsermode(SEGIDX_USER_CODE, SEGIDX_USER_DATA, &tss.rsp0, &main);
while (true)
{
ps2::KeyEvent event;
@ -240,12 +255,8 @@ void kernel_main()
event.down ? "true" : "false",
event.repeat ? "true" : "false"
);
if (event.down && event.scancode == ps2::Scancode::ESCAPE)
{
int x = 1 / 0;
}
}
main();
}
} // extern "C"

View File

@ -5,6 +5,7 @@
#define BAD_APPLE_OS_X86_64_HPP_INCLUDED
#include <cstdint>
#include <cstring>
// --- Segments --- //
@ -78,6 +79,30 @@ struct SegmentDescriptor
/* 56 */ unsigned baseHigh : 8 = 0;
} __attribute__((packed));
enum class SystemSegmentDescriptorType
{
TSS = 0,
LDT = 1
};
struct SystemSegmentDescriptor
{
/* 0 */ unsigned limitLow : 16 = 0;
/* 16 */ unsigned baseLow : 24 = 0;
/* 40 */ unsigned type : 4 = 0;
/* 44 */ SystemSegmentDescriptorType descType : 1 = SystemSegmentDescriptorType::TSS;
/* 45 */ unsigned privilegeLevel : 2 = 0;
/* 47 */ bool present : 1 = false;
/* 48 */ unsigned limitHigh : 4 = 0;
/* 52 */ bool available : 1 = 0;
/* 53 */ bool long_ : 1 = 0;
/* 54 */ bool big : 1 = 0;
/* 55 */ SegmentGranularity granularity : 1 = SegmentGranularity::BYTE;
/* 56 */ unsigned long baseHigh : 40 = 0;
/* 96 */ unsigned reserved : 32 = 0;
} __attribute__((packed));
static_assert(2 * sizeof(SegmentDescriptor) == sizeof(SystemSegmentDescriptor));
inline constexpr const SegmentDescriptor SEGMENT_NULL = {};
inline constexpr const SegmentDescriptor SEGMENT_KERNEL_CODE = {
@ -175,4 +200,43 @@ struct InterruptDescriptor
/* 96 */ unsigned reserved2_ : 32 = 0;
} __attribute__((packed));
struct TaskStateSegment
{
/* 0 */ std::uint32_t reserved0 = 0;
/* 32 */ std::uint64_t rsp0 = 0;
/* 96 */ std::uint64_t rsp1 = 0;
/* 160 */ std::uint64_t rsp2 = 0;
/* 224 */ std::uint64_t reserved1 = 0;
/* 288 */ std::uint64_t ist1 = 0;
/* 352 */ std::uint64_t ist2 = 0;
/* 416 */ std::uint64_t ist3 = 0;
/* 480 */ std::uint64_t ist4 = 0;
/* 544 */ std::uint64_t ist5 = 0;
/* 608 */ std::uint64_t ist6 = 0;
/* 672 */ std::uint64_t ist7 = 0;
/* 736 */ std::uint64_t reserved2 = 0;
/* 800 */ std::uint16_t reserved3 = 0;
/* 816 */ std::uint16_t iobpOffset = 0;
} __attribute__((packed));
inline void makeTSSSegment(TaskStateSegment* tssEntry, SegmentDescriptor* outSegments) noexcept
{
const std::uint64_t base = std::bit_cast<std::uint64_t>(tssEntry);
SystemSegmentDescriptor descriptor {
.limitLow = sizeof(TaskStateSegment),
.baseLow = static_cast<unsigned>(base) & 0xFFFFFF,
.type = static_cast<unsigned>(SystemSegmentType::TSS_32_AVAILABLE),
.descType = SystemSegmentDescriptorType::TSS,
.privilegeLevel = 0,
.present = true,
.limitHigh = 0,
.available = false,
.long_ = false,
.big = false,
.granularity = SegmentGranularity::BYTE,
.baseHigh = (base & 0xFFFFFFFFFF000000) >> 24
};
std::memcpy(outSegments, &descriptor, 2 * sizeof(SegmentDescriptor));
}
#endif // !defined(BAD_APPLE_OS_X86_64_HPP_INCLUDED)