Implemented syscalls and jump to usermode.
This commit is contained in:
parent
9c70cfa846
commit
edd9ee85c7
@ -49,6 +49,7 @@ any_target_sources = Split('''
|
||||
src/os/draw.cpp
|
||||
src/os/memory.cpp
|
||||
src/os/panic.cpp
|
||||
src/os/syscall.cpp
|
||||
src/os/tty.cpp
|
||||
src/os/resources/lat9-08.psf.s
|
||||
|
||||
|
57
targets/_any/include/os/cpu.hpp
Normal file
57
targets/_any/include/os/cpu.hpp
Normal file
@ -0,0 +1,57 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !defined(BAD_APPLE_OS_CPU_HPP_INCLUDED)
|
||||
#define BAD_APPLE_OS_CPU_HPP_INCLUDED
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace baos::cpu
|
||||
{
|
||||
enum class MSR : std::uint32_t
|
||||
{
|
||||
IA32_EFER = 0xC000'0080,
|
||||
STAR = 0xC000'0081, // segments for syscall
|
||||
LSTAR = 0xC000'0082, // instruction pointer for syscall
|
||||
};
|
||||
inline constexpr std::uint64_t IA32_EFER_SYSTEM_CALL_EXTENSIONS_BIT = (1 << 0);
|
||||
inline constexpr std::uint64_t IA32_EFER_LONG_MODE_ENABLE_BIT = (1 << 8);
|
||||
inline constexpr std::uint64_t IA32_EFER_LONG_MODE_ACTIVE_BIT = (1 << 10);
|
||||
inline constexpr std::uint64_t IA32_EFER_NO_EXECUTE_ENABLE_BIT = (1 << 11);
|
||||
// ...
|
||||
|
||||
inline std::uint64_t readMSR(MSR msr) noexcept
|
||||
{
|
||||
std::uint32_t lowHalf = 0;
|
||||
std::uint32_t highHalf = 0;
|
||||
__asm__ __volatile__(
|
||||
"rdmsr"
|
||||
: "=a"(lowHalf), "=d"(highHalf)
|
||||
: "c"(msr)
|
||||
);
|
||||
return static_cast<std::uint64_t>(highHalf) << 32 | lowHalf;
|
||||
}
|
||||
|
||||
inline void writeMSR(MSR msr, std::uint64_t value) noexcept
|
||||
{
|
||||
std::uint32_t lowHalf = static_cast<std::uint32_t>(value & 0xFFFFFFFF);
|
||||
std::uint32_t highHalf = static_cast<std::uint32_t>(value >> 32);
|
||||
__asm__ __volatile__(
|
||||
"wrmsr"
|
||||
:
|
||||
: "a"(lowHalf), "d"(highHalf), "c"(msr)
|
||||
);
|
||||
}
|
||||
|
||||
inline void setMSRBits(MSR msr, std::uint64_t bits) noexcept
|
||||
{
|
||||
writeMSR(msr, readMSR(msr) | bits);
|
||||
}
|
||||
|
||||
inline void unsetMSRBits(MSR msr, std::uint64_t bits) noexcept
|
||||
{
|
||||
writeMSR(msr, readMSR(msr) & ~bits);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // !defined(BAD_APPLE_OS_CPU_HPP_INCLUDED)
|
18
targets/_any/include/os/segments.hpp
Normal file
18
targets/_any/include/os/segments.hpp
Normal file
@ -0,0 +1,18 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !defined(BAD_APPLE_OS_SEGMENTS_HPP_INCLUDED)
|
||||
#define BAD_APPLE_OS_SEGMENTS_HPP_INCLUDED
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace baos
|
||||
{
|
||||
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 = 4 << 3;
|
||||
inline constexpr std::uint16_t SEGIDX_USER_DATA = 3 << 3;
|
||||
inline constexpr std::uint16_t SEGIDX_TSS = 5 << 3;
|
||||
}
|
||||
|
||||
#endif // !defined(BAD_APPLE_OS_SEGMENTS_HPP_INCLUDED)
|
33
targets/_any/include/os/syscall.hpp
Normal file
33
targets/_any/include/os/syscall.hpp
Normal file
@ -0,0 +1,33 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !defined(BAD_APPLE_OS_SYSCALL_HPP_INCLUDED)
|
||||
#define BAD_APPLE_OS_SYSCALL_HPP_INCLUDED
|
||||
|
||||
#include <bit>
|
||||
#include <cstdint>
|
||||
|
||||
namespace baos
|
||||
{
|
||||
enum class Syscall : std::uint64_t
|
||||
{
|
||||
FILE_READ = 0,
|
||||
FILE_WRITE = 1
|
||||
};
|
||||
|
||||
void setupSyscall() noexcept;
|
||||
|
||||
template<typename TParam0, typename TParam1, typename TParam2>
|
||||
inline void doSyscall(Syscall cmd, TParam0 param0 = 0, TParam1 param1 = 0, TParam2 param2 = 0) noexcept
|
||||
{
|
||||
register std::uint64_t r8 asm("r8") = param2;
|
||||
__asm__ __volatile__(
|
||||
"syscall"
|
||||
:
|
||||
: "D"(cmd), "S"(param0), "d"(param1)
|
||||
: "%rcx"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // !defined(BAD_APPLE_OS_SYSCALL_HPP_INCLUDED)
|
@ -110,8 +110,6 @@ void cmdDumpPageTable() noexcept
|
||||
|
||||
extern "C" void main()
|
||||
{
|
||||
|
||||
// __asm__ __volatile__("cli");
|
||||
std::string cmd;
|
||||
while(true)
|
||||
{
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <stdarg.h>
|
||||
#include "os/serial.hpp"
|
||||
#include "os/syscall.hpp"
|
||||
#include "os/tty.hpp"
|
||||
#include "os/tools/printf_helper.hpp"
|
||||
#include "os/tools/ringbuffer.hpp"
|
||||
@ -113,6 +113,7 @@ FILE* __stdin = &gStdin;
|
||||
|
||||
int putchar(int chr) noexcept
|
||||
{
|
||||
#if 0
|
||||
tty::putChar(static_cast<char>(chr));
|
||||
if (chr == '\n')
|
||||
{
|
||||
@ -124,10 +125,17 @@ int putchar(int chr) noexcept
|
||||
serialWrite(PORT_COM1, static_cast<std::uint8_t>(chr));
|
||||
}
|
||||
return 0;
|
||||
#endif
|
||||
char asChar = static_cast<char>(chr);
|
||||
baos::doSyscall(baos::Syscall::FILE_WRITE, 0, &asChar, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int puts(const char* str) noexcept
|
||||
{
|
||||
baos::doSyscall(baos::Syscall::FILE_WRITE, 0, str, std::strlen(str));
|
||||
return 0;
|
||||
#if 0
|
||||
while (*str)
|
||||
{
|
||||
putchar(*str);
|
||||
@ -135,6 +143,7 @@ int puts(const char* str) noexcept
|
||||
}
|
||||
putchar('\n');
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
int printf(const char* format, ...) noexcept
|
||||
|
@ -78,6 +78,7 @@ bool initPICs(std::uint8_t masterOffset, std::uint8_t slaveOffset) noexcept
|
||||
return true;
|
||||
}
|
||||
|
||||
__attribute__((no_caller_saved_registers))
|
||||
void sendEndOfInterrupt(std::uint8_t irq) noexcept
|
||||
{
|
||||
if (irq >= 8) {
|
||||
|
@ -24,10 +24,9 @@ struct MemoryRangeAllocationInfo
|
||||
};
|
||||
static_assert(sizeof(MemoryRangeAllocationInfo) == 4096);
|
||||
|
||||
inline constexpr unsigned MAX_USABLE_RANGES = 32;
|
||||
inline constexpr unsigned MAX_USABLE_RANGES = 512;
|
||||
std::array<MemoryRange, MAX_USABLE_RANGES> gUsableMemoryRanges;
|
||||
std::array<MemoryRangeAllocationInfo, MAX_USABLE_RANGES> gRangeAllocationInfo;
|
||||
std::uint8_t gNumUsableRanges = 0;
|
||||
unsigned gNumUsableRanges = 0;
|
||||
|
||||
// initial 2MB page for setting up the page table
|
||||
// std::array<std::uint8_t, 2ul << 20> gInitPage alignas(2ul << 20);
|
||||
@ -75,6 +74,7 @@ PageTableEntry& getOrCreatePageTableEntry(PageTable& pageTable, std::uint16_t in
|
||||
entry.address = std::bit_cast<std::uint64_t>(&childTable) >> 12;
|
||||
entry.writable = true;
|
||||
entry.present = true;
|
||||
entry.user = true;
|
||||
}
|
||||
return entry;
|
||||
}
|
||||
@ -111,60 +111,16 @@ void addUsableRange(const MemoryRange& range) noexcept
|
||||
return;
|
||||
}
|
||||
gUsableMemoryRanges[gNumUsableRanges] = range;
|
||||
gRangeAllocationInfo[gNumUsableRanges].numFreePages = range.numPages;
|
||||
++gNumUsableRanges;
|
||||
}
|
||||
|
||||
std::uint64_t findFreePages(unsigned numConsecutive) noexcept
|
||||
{
|
||||
if (numConsecutive == 0 || numConsecutive > 4086) {
|
||||
return 0;
|
||||
}
|
||||
if (numConsecutive != 1) {
|
||||
return 0; // TODO!!!
|
||||
}
|
||||
|
||||
for (std::uint8_t rangeIdx = 0; rangeIdx < gNumUsableRanges; ++rangeIdx)
|
||||
{
|
||||
std::uint64_t page = gUsableMemoryRanges[rangeIdx].pageBase;
|
||||
for (MemoryRangeAllocationInfo* allocInfo = &gRangeAllocationInfo[rangeIdx]; allocInfo != nullptr; page += allocInfo->usedPages.size(), allocInfo = allocInfo->next)
|
||||
{
|
||||
if (allocInfo->numFreePages < numConsecutive) {
|
||||
continue;
|
||||
}
|
||||
for (unsigned pagesIdx = 0; pagesIdx < allocInfo->usedPages.size(); ++pagesIdx)
|
||||
{
|
||||
if (allocInfo->usedPages[pagesIdx] != 0xFF)
|
||||
{
|
||||
for (unsigned bit = 0; bit < 8; ++bit)
|
||||
{
|
||||
if ((allocInfo->usedPages[pagesIdx] & (1 << bit)) == 0)
|
||||
{
|
||||
allocInfo->usedPages[pagesIdx] |= (1 << bit);
|
||||
return page + (8 * pagesIdx) + bit;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
PageTable& setupPageTableEntry(PageTableEntry& entry, std::uint64_t page) noexcept
|
||||
{
|
||||
entry.address = page;
|
||||
entry.present = true;
|
||||
entry.writable = true;
|
||||
return *(::new(std::bit_cast<void*>(entry.address << 12)) PageTable);
|
||||
}
|
||||
|
||||
/** Finds a free memory range using the provided constraints (size and page alignment). */
|
||||
bool findFreeMemory(std::size_t numPages, std::size_t pageAlignment, std::uint64_t& outPage, MemoryRange*& outRange) noexcept
|
||||
{
|
||||
// first try to find a range that already is already aligned properly
|
||||
for (MemoryRange& range : gUsableMemoryRanges)
|
||||
for (unsigned rangeIdx = 0; rangeIdx < gNumUsableRanges; ++rangeIdx)
|
||||
{
|
||||
MemoryRange& range = gUsableMemoryRanges[rangeIdx];
|
||||
if (range.numPages >= numPages && range.pageBase % pageAlignment == 0)
|
||||
{
|
||||
outPage = range.pageBase;
|
||||
@ -176,8 +132,9 @@ bool findFreeMemory(std::size_t numPages, std::size_t pageAlignment, std::uint64
|
||||
return false; // no need to search further, everything is full!
|
||||
}
|
||||
// now just try to find a range that could be used (needs to be split then)
|
||||
for (MemoryRange& range : gUsableMemoryRanges)
|
||||
for (unsigned rangeIdx = 0; rangeIdx < gNumUsableRanges; ++rangeIdx)
|
||||
{
|
||||
MemoryRange& range = gUsableMemoryRanges[rangeIdx];
|
||||
const std::uint64_t possibleBase = std::alignUp(range.pageBase, pageAlignment); // needs to be 2MB aligned
|
||||
if (range.numPages - (possibleBase - range.pageBase) >= numPages)
|
||||
{
|
||||
@ -239,6 +196,12 @@ bool allocateIdentityMappedPages(std::size_t numPages, std::size_t pageAlignment
|
||||
|
||||
bool setupPaging(std::span<const MemoryRange> memoryRanges) noexcept
|
||||
{
|
||||
std::uint32_t eax, ebx, ecx, edx;
|
||||
|
||||
// TODO: apparently it's not supported in Qemu (or on the host CPU, who knows?) so don't waste time on it
|
||||
// __cpuid(0x8000'0001, eax, ebx, ecx, edx);
|
||||
// g1GBPagesSupported = (edx & (1 << 26)) != 0;
|
||||
|
||||
std::uint64_t firstKernelPage = std::bit_cast<std::uint64_t>(&gKernelStart) / 4096;
|
||||
std::uint64_t lastKernelPage = std::bit_cast<std::uint64_t>(&gKernelEnd) / 4096 + 1;
|
||||
for (MemoryRange range : memoryRanges)
|
||||
@ -309,18 +272,6 @@ const char* memoryTypeName(MemoryType type) noexcept
|
||||
return "<INVALID>";
|
||||
}
|
||||
|
||||
void* allocatePages(unsigned numConsecutive) noexcept
|
||||
{
|
||||
const std::uint64_t firstPage = findFreePages(numConsecutive);
|
||||
if (firstPage == 0)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
setupIdentityPaging(firstPage, firstPage + numConsecutive);
|
||||
return std::bit_cast<void*>(firstPage << 12);
|
||||
}
|
||||
|
||||
|
||||
void setupIdentityPaging(std::uint64_t page) noexcept
|
||||
{
|
||||
PageTableEntry& pageTableEntry = getOrCreatePage(page);
|
||||
|
50
targets/_any/src/os/syscall.cpp
Normal file
50
targets/_any/src/os/syscall.cpp
Normal file
@ -0,0 +1,50 @@
|
||||
|
||||
#include "os/syscall.hpp"
|
||||
|
||||
#include <bit>
|
||||
#include <cstddef>
|
||||
#include "os/cpu.hpp"
|
||||
#include "os/segments.hpp"
|
||||
#include "os/serial.hpp"
|
||||
#include "os/tty.hpp"
|
||||
|
||||
extern "C" void __handleSyscall();
|
||||
|
||||
namespace baos
|
||||
{
|
||||
void setupSyscall() noexcept
|
||||
{
|
||||
// enable syscall/sysexit
|
||||
cpu::setMSRBits(cpu::MSR::IA32_EFER, cpu::IA32_EFER_SYSTEM_CALL_EXTENSIONS_BIT);
|
||||
cpu::writeMSR(cpu::MSR::LSTAR, std::bit_cast<std::uint64_t>(&__handleSyscall));
|
||||
cpu::writeMSR(cpu::MSR::STAR, static_cast<std::uint64_t>(SEGIDX_KERNEL_CODE) << 32 | static_cast<std::uint64_t>(SEGIDX_KERNEL_DATA) << 48);
|
||||
}
|
||||
|
||||
void sysFileRead(unsigned fileDescriptor, char* buffer, std::size_t count) noexcept
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
void sysFileWrite(unsigned fileDescriptor, const char* buffer, std::size_t count) noexcept
|
||||
{
|
||||
for (std::size_t index = 0; index < count; ++index) {
|
||||
serialWrite(PORT_COM1, buffer[index]);
|
||||
}
|
||||
tty::write(buffer, count);
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" void __baosSyscall(baos::Syscall cmd, std::uint64_t param0, std::uint64_t param1, std::uint64_t param2) noexcept
|
||||
{
|
||||
using namespace baos;
|
||||
|
||||
switch (cmd)
|
||||
{
|
||||
case Syscall::FILE_READ:
|
||||
sysFileRead(static_cast<unsigned>(param0), std::bit_cast<char*>(param1), param2);
|
||||
break;
|
||||
case Syscall::FILE_WRITE:
|
||||
sysFileWrite(static_cast<unsigned>(param0), std::bit_cast<const char*>(param1), param2);
|
||||
break;
|
||||
}
|
||||
}
|
@ -94,7 +94,7 @@ __flushTSS:
|
||||
|
||||
.global __enterUsermode
|
||||
.type __enterUsermode @function
|
||||
// void __enterUsermode(uint16_t codeSegment [%di], uint16_t dataSegment [%si], void* rsp [%rdx], void* function [%rcx])
|
||||
// void __enterUsermode(uint16_t codeSegment [%di], uint16_t dataSegment [%si], void* rsp [%rdx], void* function [%rcx], void* stackPtr [r8])
|
||||
__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
|
||||
@ -104,15 +104,25 @@ __enterUsermode:
|
||||
movw %si, %gs
|
||||
|
||||
movq %rsp, (%rdx)
|
||||
movq %rsp, %rax
|
||||
pushq %rsi // data segment
|
||||
pushq %rax
|
||||
pushq %r8
|
||||
pushf // flags
|
||||
pushq %rdi // code segment
|
||||
pushq %rcx
|
||||
iretq
|
||||
|
||||
|
||||
.global __handleSyscall
|
||||
.type __handleSyscall @function
|
||||
// void __handleSyscall()
|
||||
__handleSyscall:
|
||||
pushq %rcx // store the original instruction pointer
|
||||
pushq %rsp // also store the original stack pointer
|
||||
movq %r8, %rcx
|
||||
// movq (__kernel_rsp), %rsp
|
||||
call __baosSyscall
|
||||
popq %rsp
|
||||
popq %rcx
|
||||
sysretq
|
||||
|
||||
/*
|
||||
Set the size of the _start symbol to the current location '.' minus its start.
|
||||
|
@ -5,11 +5,12 @@
|
||||
#include <bit>
|
||||
#include <cassert>
|
||||
#include <cstdio>
|
||||
#include <memory>
|
||||
|
||||
#include "os/draw.hpp"
|
||||
#include "os/memory.hpp"
|
||||
#include "os/segments.hpp"
|
||||
#include "os/serial.hpp"
|
||||
#include "os/syscall.hpp"
|
||||
#include "os/tty.hpp"
|
||||
#include "drivers/pci.hpp"
|
||||
#include "drivers/pic.hpp"
|
||||
@ -56,18 +57,12 @@ constinit std::array GDT alignas(16) = {
|
||||
SEGMENT_NULL,
|
||||
SEGMENT_KERNEL_CODE,
|
||||
SEGMENT_KERNEL_DATA,
|
||||
SEGMENT_USER_CODE,
|
||||
SEGMENT_USER_DATA,
|
||||
SEGMENT_USER_CODE,
|
||||
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);
|
||||
|
||||
|
||||
@ -153,7 +148,7 @@ 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)());
|
||||
extern "C" void __enterUsermode(uint16_t codeSegment, uint16_t dataSegment, void* rsp, void (*function)(), void* stackPtr);
|
||||
|
||||
template<typename THandler>
|
||||
void setupInterrupt(std::uint8_t index, THandler handler) noexcept
|
||||
@ -222,6 +217,8 @@ void kernel_main()
|
||||
__reloadSegments(SEGIDX_KERNEL_CODE, SEGIDX_KERNEL_DATA);
|
||||
__flushTSS(SEGIDX_TSS);
|
||||
|
||||
setupSyscall();
|
||||
|
||||
const bool picsInited = initPICs(MASTER_PIC_OFFSET, SLAVE_PIC_OFFSET);
|
||||
unmaskIRQ(1);
|
||||
|
||||
@ -236,7 +233,10 @@ void kernel_main()
|
||||
|
||||
// init the heap (required for the double buffer)
|
||||
const std::vector<MemoryRange> ranges = detectMemoryRangesFromEfi(gBootInfo->memoryMap);
|
||||
setupPaging({ranges.begin(), ranges.end()});
|
||||
if (!setupPaging({ranges.begin(), ranges.end()}))
|
||||
{
|
||||
panic("Error setting up paging.");
|
||||
}
|
||||
|
||||
// make sure boot info and the frame buffer are accessible
|
||||
identityMapRegion(gBootInfo, sizeof(*gBootInfo));
|
||||
@ -244,8 +244,6 @@ void kernel_main()
|
||||
|
||||
initGlobals();
|
||||
|
||||
// initHeapFromEfiMemoryMap(gBootInfo->memoryMap);
|
||||
|
||||
// initialize the framebuffer
|
||||
draw::initializeDefaultFramebuffer({
|
||||
/* base = */ static_cast<draw::Pixel*>(gBootInfo->displayInfo.frameBufferBase),
|
||||
@ -257,11 +255,6 @@ void kernel_main()
|
||||
// initialize terminal interface
|
||||
tty::initialize();
|
||||
|
||||
for (const MemoryRange& range : ranges)
|
||||
{
|
||||
std::printf("Start: 0x%lX, Pages: %ld, Type: %s\n", range.pageBase << 12, range.numPages, memoryTypeName(range.type));
|
||||
}
|
||||
|
||||
if (!initSerialPort(PORT_COM1))
|
||||
{
|
||||
tty::write("Error initializing serial port.\n");
|
||||
@ -269,6 +262,11 @@ void kernel_main()
|
||||
}
|
||||
serialWriteString(PORT_COM1, "\r\n\r\n"); // write newlines to separate from UEFI output
|
||||
|
||||
for (const MemoryRange& range : ranges)
|
||||
{
|
||||
// std::printf("Start: 0x%lX, Pages: %ld, Type: %s\n", range.pageBase << 12, range.numPages, memoryTypeName(range.type));
|
||||
}
|
||||
|
||||
if (!picsInited)
|
||||
{
|
||||
std::puts("Error initializing the PICs!\n");
|
||||
@ -277,7 +275,7 @@ void kernel_main()
|
||||
|
||||
if (!ps2Inited)
|
||||
{
|
||||
std::puts("Error initializing the PS2 controller!!\n");
|
||||
std::puts("Error initializing the PS2 controller!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -286,11 +284,7 @@ void kernel_main()
|
||||
initializePCIDevice(header);
|
||||
}
|
||||
|
||||
std::puts("This is BadAppleOS and everything is fine!\n");
|
||||
|
||||
// __enterUsermode(SEGIDX_USER_CODE, SEGIDX_USER_DATA, &tss.rsp0, &main);
|
||||
main(); // for now run it in kernel mode, user mode doesn't work yet
|
||||
|
||||
|
||||
static std::array<std::uint8_t, 16384> usermodeStack;
|
||||
__enterUsermode(SEGIDX_USER_CODE, SEGIDX_USER_DATA, &tss.rsp0, &main, &usermodeStack.back());
|
||||
}
|
||||
} // extern "C"
|
||||
|
Loading…
x
Reference in New Issue
Block a user