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() extern "C" void main()
{ {
// __asm__ __volatile__("cli");
while(true);
} }

View File

@ -85,6 +85,35 @@ __reloadSegments:
movw %ax, %ss movw %ax, %ss
ret 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. 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. 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_CONTROL_PROTECTION_EXCEPTION = 0x15;
inline constexpr std::uint8_t INTERRUPT_KEYBOARD = irqToInterrupt(1); inline constexpr std::uint8_t INTERRUPT_KEYBOARD = irqToInterrupt(1);
TaskStateSegment tss alignas(16);
constinit std::array GDT alignas(16) = { constinit std::array GDT alignas(16) = {
SEGMENT_NULL, SEGMENT_NULL,
SEGMENT_KERNEL_CODE, SEGMENT_KERNEL_CODE,
SEGMENT_KERNEL_DATA, SEGMENT_KERNEL_DATA,
SEGMENT_USER_CODE, SEGMENT_USER_CODE,
SEGMENT_USER_DATA, 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); constinit std::array<InterruptDescriptor, 256> IDT alignas(16);
void initHeapFromEfiMemoryMap(const EfiMemoryMap& memoryMap) noexcept void initHeapFromEfiMemoryMap(const EfiMemoryMap& memoryMap) noexcept
@ -133,6 +142,8 @@ void initGlobals()
extern "C" void __setGDT(uint16_t limit, void* base); extern "C" void __setGDT(uint16_t limit, void* base);
extern "C" void __setIDT(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 __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> template<typename THandler>
void setupInterrupt(std::uint8_t index, THandler handler) noexcept 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_CONTROL_PROTECTION_EXCEPTION, &baos::isrControlProtectionException);
setupInterrupt(INTERRUPT_KEYBOARD, &ps2::isrKeyboard); setupInterrupt(INTERRUPT_KEYBOARD, &ps2::isrKeyboard);
makeTSSSegment(&tss, &GDT[5]);
__setGDT(sizeof(GDT), &GDT); __setGDT(sizeof(GDT), &GDT);
__setIDT(sizeof(IDT), &IDT); __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); const bool picsInited = initPICs(MASTER_PIC_OFFSET, SLAVE_PIC_OFFSET);
unmaskIRQ(1); unmaskIRQ(1);
@ -229,6 +242,8 @@ void kernel_main()
} }
std::puts("This is BadAppleOS and everything is fine!\n"); std::puts("This is BadAppleOS and everything is fine!\n");
__enterUsermode(SEGIDX_USER_CODE, SEGIDX_USER_DATA, &tss.rsp0, &main);
while (true) while (true)
{ {
ps2::KeyEvent event; ps2::KeyEvent event;
@ -240,12 +255,8 @@ void kernel_main()
event.down ? "true" : "false", event.down ? "true" : "false",
event.repeat ? "true" : "false" event.repeat ? "true" : "false"
); );
if (event.down && event.scancode == ps2::Scancode::ESCAPE)
{
int x = 1 / 0;
}
} }
main();
} }
} // extern "C" } // extern "C"

View File

@ -5,6 +5,7 @@
#define BAD_APPLE_OS_X86_64_HPP_INCLUDED #define BAD_APPLE_OS_X86_64_HPP_INCLUDED
#include <cstdint> #include <cstdint>
#include <cstring>
// --- Segments --- // // --- Segments --- //
@ -78,6 +79,30 @@ struct SegmentDescriptor
/* 56 */ unsigned baseHigh : 8 = 0; /* 56 */ unsigned baseHigh : 8 = 0;
} __attribute__((packed)); } __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_NULL = {};
inline constexpr const SegmentDescriptor SEGMENT_KERNEL_CODE = { inline constexpr const SegmentDescriptor SEGMENT_KERNEL_CODE = {
@ -175,4 +200,43 @@ struct InterruptDescriptor
/* 96 */ unsigned reserved2_ : 32 = 0; /* 96 */ unsigned reserved2_ : 32 = 0;
} __attribute__((packed)); } __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) #endif // !defined(BAD_APPLE_OS_X86_64_HPP_INCLUDED)