Added PIC initialization and keyboard.
This commit is contained in:
parent
f03963a485
commit
04d25d498d
36
targets/_any/include/os/port.hpp
Normal file
36
targets/_any/include/os/port.hpp
Normal file
@ -0,0 +1,36 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !defined(BAD_APPLE_OS_PORT_HPP_INCLUDED)
|
||||
#define BAD_APPLE_OS_PORT_HPP_INCLUDED
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#define writePortByte(port, value) \
|
||||
{ \
|
||||
__asm__ __volatile__( \
|
||||
"outb %0, %1" \
|
||||
: \
|
||||
: "a"(static_cast<std::uint8_t>(value)), \
|
||||
"Nd"(static_cast<std::uint16_t>(port)) \
|
||||
); \
|
||||
}
|
||||
|
||||
#define readPortByte(port) \
|
||||
[&]() \
|
||||
{ \
|
||||
std::uint8_t value = 0; \
|
||||
__asm__ __volatile__( \
|
||||
"inb %1, %0" \
|
||||
: "=a"(value) \
|
||||
: "Nd"(static_cast<std::uint16_t>(port)) \
|
||||
); \
|
||||
return value; \
|
||||
}()
|
||||
|
||||
inline void ioWait() noexcept
|
||||
{
|
||||
writePortByte(0x80, 0);
|
||||
}
|
||||
|
||||
#endif // !defined(BAD_APPLE_OS_PORT_HPP_INCLUDED)
|
@ -6,6 +6,8 @@
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "./port.hpp"
|
||||
|
||||
inline constexpr std::uint16_t PORT_COM1 = 0x3F8;
|
||||
inline constexpr std::uint16_t PORT_COM2 = 0x2F8;
|
||||
inline constexpr std::uint16_t PORT_COM3 = 0x3E8;
|
||||
@ -15,26 +17,6 @@ inline constexpr std::uint16_t PORT_COM6 = 0x4F8;
|
||||
inline constexpr std::uint16_t PORT_COM7 = 0x5E8;
|
||||
inline constexpr std::uint16_t PORT_COM8 = 0x4E8;
|
||||
|
||||
inline void writePortByte(std::uint16_t port, std::uint8_t value) noexcept
|
||||
{
|
||||
__asm__ __volatile__(
|
||||
"outb %0, %1"
|
||||
:
|
||||
: "a"(value), "Nd"(port)
|
||||
);
|
||||
}
|
||||
|
||||
inline std::uint8_t readPortByte(std::uint16_t port) noexcept
|
||||
{
|
||||
std::uint8_t value = 0;
|
||||
__asm__ __volatile__(
|
||||
"inb %1, %0"
|
||||
: "=a"(value)
|
||||
: "Nd"(port)
|
||||
);
|
||||
return value;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline bool initSerialPort(std::uint16_t port) noexcept
|
||||
{
|
||||
writePortByte(port + 1, 0x00); // Disable all interrupts
|
||||
|
@ -27,12 +27,16 @@ crti_o = kernel_env.Object('src/crt/crti.s')
|
||||
crtn_o = kernel_env.Object('src/crt/crtn.s')
|
||||
kernel_env['LINKCOM'] = env['LINKCOM'].replace('$_LIBFLAGS', f'{crti_o[0].abspath} {crtbegin_o} $_LIBFLAGS -lgcc {crtend_o} {crtn_o[0].abspath}')
|
||||
|
||||
kernel_irs_sources = Split('''
|
||||
src/kernel/keyboard.cpp
|
||||
src/kernel/pic.cpp
|
||||
''')
|
||||
kernel_sources = env['KERNEL_SOURCES'] + Split('''
|
||||
src/cstdlib/memory.s
|
||||
|
||||
src/kernel/boot.s
|
||||
src/kernel/startup.cpp
|
||||
''')
|
||||
''') + [kernel_env.Object(f, CCFLAGS = kernel_env['CCFLAGS'] + ['-mgeneral-regs-only']) for f in kernel_irs_sources]
|
||||
|
||||
kernel_target = kernel_env.File('#kernel.x86_64.bin')
|
||||
prog_kernel = kernel_env.Program(
|
||||
|
@ -6,6 +6,10 @@
|
||||
|
||||
#include <efi.h>
|
||||
|
||||
// srsly, FUCK YOU
|
||||
#undef ARROW_UP
|
||||
#undef ARROW_DOWN
|
||||
|
||||
class EfiMemoryMapIterator
|
||||
{
|
||||
private:
|
||||
|
@ -63,6 +63,23 @@ __setIDT:
|
||||
lidt __idt_storage
|
||||
ret
|
||||
|
||||
.global __reloadSegments
|
||||
.type __reloadSegments @function
|
||||
// void __reloadSegments(uint64_t code [%rdi], uint64_t data [%rsi])
|
||||
__reloadSegments:
|
||||
push %rdi
|
||||
lea (.reloadCS), %rax
|
||||
push %rax
|
||||
lretq
|
||||
.reloadCS:
|
||||
movw %si, %ax
|
||||
movw %ax, %ds
|
||||
movw %ax, %es
|
||||
movw %ax, %fs
|
||||
movw %ax, %gs
|
||||
movw %ax, %ss
|
||||
ret
|
||||
|
||||
/*
|
||||
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.
|
||||
|
560
targets/x86_64/src/kernel/keyboard.cpp
Normal file
560
targets/x86_64/src/kernel/keyboard.cpp
Normal file
@ -0,0 +1,560 @@
|
||||
|
||||
#include "./keyboard.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
inline constexpr std::uint16_t PORT_PS2_DATA = 0x60;
|
||||
inline constexpr std::uint16_t PORT_PS2_STATUS = 0x64;
|
||||
inline constexpr std::uint8_t FLAG_PS2_OUTPUT_FULL = (1 << 0);
|
||||
inline constexpr std::uint8_t FLAG_PS2_INPUT_FULL = (1 << 1);
|
||||
inline constexpr std::uint8_t PS2_CMD_DISABLE_FIRST = 0xAD;
|
||||
inline constexpr std::uint8_t PS2_CMD_ENABLE_FIRST = 0xAE;
|
||||
inline constexpr std::uint8_t PS2_CMD_DISABLE_SECOND = 0xA7;
|
||||
inline constexpr std::uint8_t PS2_CMD_ENABLE_SECOND = 0xA8;
|
||||
inline constexpr std::uint8_t PS2_CMD_READ_CONF_BYTE = 0x20;
|
||||
inline constexpr std::uint8_t PS2_CMD_WRITE_CONF_BYTE = 0x60;
|
||||
inline constexpr std::uint8_t PS2_CMD_SELFTEST = 0xAA;
|
||||
inline constexpr std::uint8_t PS2_CMD_PORTTEST_FIRST = 0xAB;
|
||||
inline constexpr std::uint8_t PS2_CMD_PORTTEST_SECOND = 0xA9;
|
||||
inline constexpr std::uint8_t PS2_CMD_WRITE_TO_SECOND = 0xD4;
|
||||
inline constexpr std::uint8_t PS2_DEVICE_CMD_RESET = 0xFF;
|
||||
inline constexpr std::uint8_t PS2_RESPONSE_ACK = 0xFA;
|
||||
inline constexpr std::uint8_t PS2_RESPONSE_RESEND = 0xFE;
|
||||
inline constexpr std::uint8_t PS2_RESPONSE_SELFTEST_PASSED = 0x55;
|
||||
inline constexpr std::uint8_t PS2_RESPONSE_SELFTEST_FAILED = 0xFC;
|
||||
inline constexpr std::uint8_t PS2_RESPONSE_PORTTEST_PASSED = 0x00;
|
||||
inline constexpr std::uint8_t PS2_CONFIGFLAG_IRQ_ENABLE_FIRST = (1 << 0);
|
||||
inline constexpr std::uint8_t PS2_CONFIGFLAG_IRQ_ENABLE_SECOND = (1 << 1);
|
||||
inline constexpr std::uint8_t PS2_CONFIGFLAG_CLOCK_FIRST = (1 << 4);
|
||||
inline constexpr std::uint8_t PS2_CONFIGFLAG_CLOCK_SECOND = (1 << 5);
|
||||
inline constexpr std::uint8_t PS2_CONFIGFLAG_TRANSLATION = (1 << 6);
|
||||
|
||||
inline constexpr unsigned KEY_BUFFER_LENGTH = 16;
|
||||
std::uint8_t gKeyboardBuffer[KEY_BUFFER_LENGTH];
|
||||
unsigned gBufferedKeys = 0;
|
||||
unsigned gKeyPos = 0;
|
||||
|
||||
__attribute__((no_caller_saved_registers))
|
||||
void pushKey(std::uint8_t data) noexcept
|
||||
{
|
||||
if (gBufferedKeys == KEY_BUFFER_LENGTH) {
|
||||
return;
|
||||
}
|
||||
gKeyboardBuffer[gKeyPos] = data;
|
||||
++gBufferedKeys;
|
||||
gKeyPos = (gKeyPos + 1) % KEY_BUFFER_LENGTH;
|
||||
}
|
||||
}
|
||||
|
||||
namespace kbd
|
||||
{
|
||||
inline bool waitForResponse(unsigned tries = -1) noexcept
|
||||
{
|
||||
for (unsigned t = 0; t < tries; ++t)
|
||||
{
|
||||
if (readPortByte(PORT_PS2_STATUS) & FLAG_PS2_OUTPUT_FULL) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline void waitForInputFree() noexcept
|
||||
{
|
||||
while (readPortByte(PORT_PS2_STATUS) & FLAG_PS2_INPUT_FULL);
|
||||
}
|
||||
|
||||
inline std::uint8_t cmdWithResponse(std::uint8_t cmd) noexcept
|
||||
{
|
||||
writePortByte(PORT_PS2_STATUS, cmd);
|
||||
waitForResponse();
|
||||
return readPortByte(PORT_PS2_DATA);
|
||||
}
|
||||
|
||||
inline void cmdWithData(std::uint8_t cmd, std::uint8_t data) noexcept
|
||||
{
|
||||
writePortByte(PORT_PS2_STATUS, cmd);
|
||||
waitForInputFree();
|
||||
writePortByte(PORT_PS2_DATA, data);
|
||||
}
|
||||
|
||||
inline void sendToFirstDevice(std::uint8_t cmd) noexcept
|
||||
{
|
||||
waitForInputFree();
|
||||
writePortByte(PORT_PS2_DATA, cmd);
|
||||
}
|
||||
|
||||
inline void sendToSecondDevice(std::uint8_t cmd) noexcept
|
||||
{
|
||||
cmdWithData(PS2_CMD_WRITE_TO_SECOND, cmd);
|
||||
waitForResponse();
|
||||
}
|
||||
|
||||
bool initialize() noexcept
|
||||
{
|
||||
// disable PS2
|
||||
writePortByte(PORT_PS2_STATUS, PS2_CMD_DISABLE_FIRST);
|
||||
writePortByte(PORT_PS2_STATUS, PS2_CMD_DISABLE_SECOND);
|
||||
|
||||
// flush output register
|
||||
readPortByte(PORT_PS2_DATA);
|
||||
|
||||
// read configuration
|
||||
std::uint8_t config = cmdWithResponse(PS2_CMD_READ_CONF_BYTE);
|
||||
|
||||
// adjust configuration
|
||||
const bool secondDevice = (config & PS2_CONFIGFLAG_CLOCK_SECOND) != 0;
|
||||
config &= ~PS2_CONFIGFLAG_IRQ_ENABLE_FIRST;
|
||||
config &= ~PS2_CONFIGFLAG_IRQ_ENABLE_SECOND;
|
||||
config &= ~PS2_CONFIGFLAG_TRANSLATION;
|
||||
|
||||
// write configuration
|
||||
cmdWithData(PS2_CMD_WRITE_CONF_BYTE, config);
|
||||
|
||||
// run self-test
|
||||
const std::uint8_t testResult = cmdWithResponse(PS2_CMD_SELFTEST);
|
||||
if (testResult != PS2_RESPONSE_SELFTEST_PASSED) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// write configuration again, in case it was reset
|
||||
cmdWithData(PS2_CMD_WRITE_CONF_BYTE, config);
|
||||
|
||||
// check if dual-channel
|
||||
bool dualChannel = false;
|
||||
if ((config & PS2_CONFIGFLAG_CLOCK_SECOND) != 0) // it may be
|
||||
{
|
||||
writePortByte(PORT_PS2_STATUS, PS2_CMD_ENABLE_SECOND);
|
||||
dualChannel = (cmdWithResponse(PS2_CMD_READ_CONF_BYTE) & PS2_CONFIGFLAG_CLOCK_SECOND) == 0;
|
||||
if (dualChannel)
|
||||
{
|
||||
writePortByte(PORT_PS2_STATUS, PS2_CMD_DISABLE_SECOND);
|
||||
}
|
||||
}
|
||||
|
||||
// test interfaces
|
||||
if (cmdWithResponse(PS2_CMD_PORTTEST_FIRST) != PS2_RESPONSE_PORTTEST_PASSED)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (dualChannel && cmdWithResponse(PS2_CMD_PORTTEST_SECOND) != PS2_RESPONSE_PORTTEST_PASSED)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// enable devices
|
||||
writePortByte(PORT_PS2_STATUS, PS2_CMD_ENABLE_FIRST);
|
||||
if (dualChannel) {
|
||||
writePortByte(PORT_PS2_STATUS, PS2_CMD_ENABLE_SECOND);
|
||||
}
|
||||
|
||||
// enable interrupts
|
||||
config |= PS2_CONFIGFLAG_IRQ_ENABLE_FIRST;
|
||||
if (dualChannel) {
|
||||
config |= PS2_CONFIGFLAG_IRQ_ENABLE_SECOND;
|
||||
}
|
||||
cmdWithData(PS2_CMD_WRITE_CONF_BYTE, config);
|
||||
|
||||
// reset
|
||||
sendToFirstDevice(PS2_DEVICE_CMD_RESET);
|
||||
bool firstOk = false;
|
||||
while (waitForResponse(10))
|
||||
{
|
||||
const std::uint8_t response = readPortByte(PORT_PS2_DATA);
|
||||
if (response == PS2_RESPONSE_SELFTEST_FAILED) {
|
||||
return false;
|
||||
}
|
||||
firstOk = true;
|
||||
}
|
||||
if (!firstOk) {
|
||||
return false;
|
||||
}
|
||||
if (dualChannel)
|
||||
{
|
||||
sendToSecondDevice(PS2_DEVICE_CMD_RESET);
|
||||
bool secondOk = false;
|
||||
while (waitForResponse(10))
|
||||
{
|
||||
const std::uint8_t response = readPortByte(PORT_PS2_DATA);
|
||||
if (response == PS2_RESPONSE_SELFTEST_FAILED) {
|
||||
return false;
|
||||
}
|
||||
secondOk = true;
|
||||
}
|
||||
if (!secondOk) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
__attribute__((interrupt))
|
||||
void isrKeyboard(InterruptFrame* interruptFrame) noexcept
|
||||
{
|
||||
(void) interruptFrame;
|
||||
const std::uint8_t data = readPortByte(PORT_PS2_DATA);
|
||||
if (data != 0)
|
||||
{
|
||||
pushKey(data);
|
||||
}
|
||||
sendEndOfInterrupt(1);
|
||||
}
|
||||
|
||||
[[nodiscard]] bool readRaw(std::uint8_t& outData) noexcept
|
||||
{
|
||||
maskIRQ(1);
|
||||
bool result = false;
|
||||
if (gBufferedKeys > 0)
|
||||
{
|
||||
outData = gKeyboardBuffer[(gKeyPos + KEY_BUFFER_LENGTH - gBufferedKeys) % KEY_BUFFER_LENGTH];
|
||||
--gBufferedKeys;
|
||||
result = true;
|
||||
}
|
||||
unmaskIRQ(1);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool gNextIsRelease = false;
|
||||
bool gNextIsExtended = false;
|
||||
bool gNextIsMoreExtended = false;
|
||||
bool gNextIsExtendedest = false;
|
||||
bool gPrevWasExtendedest = false;
|
||||
|
||||
[[nodiscard]] bool read(KeyEvent& outEvent) noexcept
|
||||
{
|
||||
if (gPrevWasExtendedest)
|
||||
{
|
||||
gPrevWasExtendedest = gNextIsExtended = gNextIsMoreExtended = gNextIsExtendedest = false;
|
||||
outEvent.scancode = Scancode::PAUSE;
|
||||
outEvent.down = false;
|
||||
outEvent.repeat = false;
|
||||
return true;
|
||||
}
|
||||
std::uint8_t data = 0;
|
||||
if (!readRaw(data)) {
|
||||
return false;
|
||||
}
|
||||
if (gNextIsExtendedest)
|
||||
{
|
||||
if (data == 0x77)
|
||||
{
|
||||
// second 0x77, our most special key is done
|
||||
if (gNextIsExtended)
|
||||
{
|
||||
gPrevWasExtendedest = true; // the next scan will return the key up event
|
||||
outEvent.scancode = Scancode::PAUSE;
|
||||
outEvent.down = true;
|
||||
outEvent.repeat = false;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// first 0x77 in sequence, wait for the second one
|
||||
gNextIsExtended = true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false; // ignore everything else until we finished the most special key
|
||||
}
|
||||
|
||||
switch (data)
|
||||
{
|
||||
case 0xF0:
|
||||
gNextIsRelease = true;
|
||||
return false;
|
||||
case 0xE0:
|
||||
gNextIsExtended = true;
|
||||
return false;
|
||||
case 0x12:
|
||||
if (gNextIsExtended)
|
||||
{
|
||||
gNextIsMoreExtended = true;
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case 0xE1:
|
||||
gNextIsExtendedest = true;
|
||||
return false;
|
||||
default: break;
|
||||
}
|
||||
|
||||
std::uint16_t scancode = data;
|
||||
if (gNextIsExtended)
|
||||
{
|
||||
if (gNextIsMoreExtended)
|
||||
{
|
||||
scancode = static_cast<std::uint16_t>(Scancode::PRINT_SCREEN);
|
||||
}
|
||||
else
|
||||
{
|
||||
scancode |= 0xE000;
|
||||
}
|
||||
}
|
||||
outEvent.scancode = static_cast<Scancode>(scancode);
|
||||
outEvent.down = !gNextIsRelease;
|
||||
outEvent.repeat = false; // TODO
|
||||
|
||||
// reset state
|
||||
gNextIsExtendedest = gNextIsMoreExtended = gNextIsRelease = gNextIsExtended = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
[[nodiscard]] const char* keyName(Scancode scancode) noexcept
|
||||
{
|
||||
switch (scancode)
|
||||
{
|
||||
case Scancode::INVALID:
|
||||
default:
|
||||
return "INVALID";
|
||||
case Scancode::F9:
|
||||
return "F9";
|
||||
case Scancode::F5:
|
||||
return "F5";
|
||||
case Scancode::F3:
|
||||
return "F3";
|
||||
case Scancode::F1:
|
||||
return "F1";
|
||||
case Scancode::F2:
|
||||
return "F2";
|
||||
case Scancode::F12:
|
||||
return "F12";
|
||||
case Scancode::F10:
|
||||
return "F10";
|
||||
case Scancode::F8:
|
||||
return "F8";
|
||||
case Scancode::F6:
|
||||
return "F6";
|
||||
case Scancode::F4:
|
||||
return "F4";
|
||||
case Scancode::TAB:
|
||||
return "TAB";
|
||||
case Scancode::BACKTICK:
|
||||
return "BACKTICK";
|
||||
case Scancode::LEFT_ALT:
|
||||
return "LEFT_ALT";
|
||||
case Scancode::LEFT_SHIFT:
|
||||
return "LEFT_SHIFT";
|
||||
case Scancode::LEFT_CONTROL:
|
||||
return "LEFT_CONTROL";
|
||||
case Scancode::Q:
|
||||
return "Q";
|
||||
case Scancode::_1:
|
||||
return "_1";
|
||||
case Scancode::Z:
|
||||
return "Z";
|
||||
case Scancode::S:
|
||||
return "S";
|
||||
case Scancode::A:
|
||||
return "A";
|
||||
case Scancode::W:
|
||||
return "W";
|
||||
case Scancode::_2:
|
||||
return "_2";
|
||||
case Scancode::C:
|
||||
return "C";
|
||||
case Scancode::X:
|
||||
return "X";
|
||||
case Scancode::D:
|
||||
return "D";
|
||||
case Scancode::E:
|
||||
return "E";
|
||||
case Scancode::_4:
|
||||
return "_4";
|
||||
case Scancode::_3:
|
||||
return "_3";
|
||||
case Scancode::SPACE:
|
||||
return "SPACE";
|
||||
case Scancode::V:
|
||||
return "V";
|
||||
case Scancode::F:
|
||||
return "F";
|
||||
case Scancode::T:
|
||||
return "T";
|
||||
case Scancode::R:
|
||||
return "R";
|
||||
case Scancode::_5:
|
||||
return "_5";
|
||||
case Scancode::N:
|
||||
return "N";
|
||||
case Scancode::B:
|
||||
return "B";
|
||||
case Scancode::H:
|
||||
return "H";
|
||||
case Scancode::G:
|
||||
return "G";
|
||||
case Scancode::Y:
|
||||
return "Y";
|
||||
case Scancode::_6:
|
||||
return "_6";
|
||||
case Scancode::M:
|
||||
return "M";
|
||||
case Scancode::J:
|
||||
return "J";
|
||||
case Scancode::U:
|
||||
return "U";
|
||||
case Scancode::_7:
|
||||
return "_7";
|
||||
case Scancode::_8:
|
||||
return "_8";
|
||||
case Scancode::COMMA:
|
||||
return "COMMA";
|
||||
case Scancode::K:
|
||||
return "K";
|
||||
case Scancode::I:
|
||||
return "I";
|
||||
case Scancode::O:
|
||||
return "O";
|
||||
case Scancode::_0:
|
||||
return "_0";
|
||||
case Scancode::_9:
|
||||
return "_9";
|
||||
case Scancode::DOT:
|
||||
return "DOT";
|
||||
case Scancode::SLASH:
|
||||
return "SLASH";
|
||||
case Scancode::L:
|
||||
return "L";
|
||||
case Scancode::SEMICOLON:
|
||||
return "SEMICOLON";
|
||||
case Scancode::P:
|
||||
return "P";
|
||||
case Scancode::MINUS:
|
||||
return "MINUS";
|
||||
case Scancode::APOSTROPHE:
|
||||
return "APOSTROPHE";
|
||||
case Scancode::BRACKET_OPEN:
|
||||
return "BRACKET_OPEN";
|
||||
case Scancode::EQUALS:
|
||||
return "EQUALS";
|
||||
case Scancode::CAPSLOCK:
|
||||
return "CAPSLOCK";
|
||||
case Scancode::RIGHT_SHIFT:
|
||||
return "RIGHT_SHIFT";
|
||||
case Scancode::ENTER:
|
||||
return "ENTER";
|
||||
case Scancode::BRACKET_CLOSE:
|
||||
return "BRACKET_CLOSE";
|
||||
case Scancode::BACKSLASH:
|
||||
return "BACKSLASH";
|
||||
case Scancode::BACKSPACE:
|
||||
return "BACKSPACE";
|
||||
case Scancode::KP_1:
|
||||
return "KP_1";
|
||||
case Scancode::KP_4:
|
||||
return "KP_4";
|
||||
case Scancode::KP_7:
|
||||
return "KP_7";
|
||||
case Scancode::KP_0:
|
||||
return "KP_0";
|
||||
case Scancode::KP_DOT:
|
||||
return "KP_DOT";
|
||||
case Scancode::KP_2:
|
||||
return "KP_2";
|
||||
case Scancode::KP_5:
|
||||
return "KP_5";
|
||||
case Scancode::KP_6:
|
||||
return "KP_6";
|
||||
case Scancode::KP_8:
|
||||
return "KP_8";
|
||||
case Scancode::ESCAPE:
|
||||
return "ESCAPE";
|
||||
case Scancode::NUMLOCK:
|
||||
return "NUMLOCK";
|
||||
case Scancode::F11:
|
||||
return "F11";
|
||||
case Scancode::KP_PLUS:
|
||||
return "KP_PLUS";
|
||||
case Scancode::KP_3:
|
||||
return "KP_3";
|
||||
case Scancode::KP_MINUS:
|
||||
return "KP_MINUS";
|
||||
case Scancode::KP_ASTERISK:
|
||||
return "KP_ASTERISK";
|
||||
case Scancode::KP_9:
|
||||
return "KP_9";
|
||||
case Scancode::SCROLLOCK:
|
||||
return "SCROLLOCK";
|
||||
case Scancode::F7:
|
||||
return "F7";
|
||||
case Scancode::MM_WWW_SEARCH:
|
||||
return "MM_WWW_SEARCH";
|
||||
case Scancode::RIGHT_ALT:
|
||||
return "RIGHT_ALT";
|
||||
case Scancode::RIGHT_CONTROL:
|
||||
return "RIGHT_CONTROL";
|
||||
case Scancode::MM_PREV_TRACK:
|
||||
return "MM_PREV_TRACK";
|
||||
case Scancode::LEFT_GUI:
|
||||
return "LEFT_GUI";
|
||||
case Scancode::MM_WWW_FAVORITES:
|
||||
return "MM_WWW_FAVORITES";
|
||||
case Scancode::MM_VOLUME_DOWN:
|
||||
return "MM_VOLUME_DOWN";
|
||||
case Scancode::MM_MUTE:
|
||||
return "MM_MUTE";
|
||||
case Scancode::RIGHT_GUI:
|
||||
return "RIGHT_GUI";
|
||||
case Scancode::MM_WWW_STOP:
|
||||
return "MM_WWW_STOP";
|
||||
case Scancode::MM_CALCULATOR:
|
||||
return "MM_CALCULATOR";
|
||||
case Scancode::APPS:
|
||||
return "APPS";
|
||||
case Scancode::MM_WWW_FORWARD:
|
||||
return "MM_WWW_FORWARD";
|
||||
case Scancode::MM_VOLUME_UP:
|
||||
return "MM_VOLUME_UP";
|
||||
case Scancode::MM_PLAY_PAUSE:
|
||||
return "MM_PLAY_PAUSE";
|
||||
case Scancode::ACPI_POWER:
|
||||
return "ACPI_POWER";
|
||||
case Scancode::MM_WWW_BACK:
|
||||
return "MM_WWW_BACK";
|
||||
case Scancode::MM_WWW_HOME:
|
||||
return "MM_WWW_HOME";
|
||||
case Scancode::MM_STOP:
|
||||
return "MM_STOP";
|
||||
case Scancode::ACPI_SLEEP:
|
||||
return "ACPI_SLEEP";
|
||||
case Scancode::MM_MY_COMPUTER:
|
||||
return "MM_MY_COMPUTER";
|
||||
case Scancode::MM_EMAIL:
|
||||
return "MM_EMAIL";
|
||||
case Scancode::KP_SLASH:
|
||||
return "KP_SLASH";
|
||||
case Scancode::MM_NEXT_TRACK:
|
||||
return "MM_NEXT_TRACK";
|
||||
case Scancode::MM_MEDIA_SELECT:
|
||||
return "MM_MEDIA_SELECT";
|
||||
case Scancode::KP_ENTER:
|
||||
return "KP_ENTER";
|
||||
case Scancode::ACPI_WAKE:
|
||||
return "ACPI_WAKE";
|
||||
case Scancode::END:
|
||||
return "END";
|
||||
case Scancode::ARROW_LEFT:
|
||||
return "ARROW_LEFT";
|
||||
case Scancode::HOME:
|
||||
return "HOME";
|
||||
case Scancode::INSERT:
|
||||
return "INSERT";
|
||||
case Scancode::DELETE:
|
||||
return "DELETE";
|
||||
case Scancode::ARROW_DOWN:
|
||||
return "ARROW_DOWN";
|
||||
case Scancode::ARROW_RIGHT:
|
||||
return "ARROW_RIGHT";
|
||||
case Scancode::ARROW_UP:
|
||||
return "ARROW_UP";
|
||||
case Scancode::PAGE_DOWN:
|
||||
return "PAGE_DOWN";
|
||||
case Scancode::PAGE_UP:
|
||||
return "PAGE_UP";
|
||||
case Scancode::PRINT_SCREEN:
|
||||
return "PRINT_SCREEN";
|
||||
case Scancode::PAUSE:
|
||||
return "PAUSE";
|
||||
}
|
||||
}
|
||||
}
|
161
targets/x86_64/src/kernel/keyboard.hpp
Normal file
161
targets/x86_64/src/kernel/keyboard.hpp
Normal file
@ -0,0 +1,161 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !defined(BAD_APPLE_OS_KERNEL_KEYBOARD_HPP_INCLUDED)
|
||||
#define BAD_APPLE_OS_KERNEL_KEYBOARD_HPP_INCLUDED
|
||||
|
||||
#include "./pic.hpp"
|
||||
|
||||
namespace kbd
|
||||
{
|
||||
[[nodiscard]] bool initialize() noexcept;
|
||||
|
||||
__attribute__((interrupt))
|
||||
void isrKeyboard(InterruptFrame* interruptFrame) noexcept;
|
||||
|
||||
enum class Scancode
|
||||
{
|
||||
INVALID = 0,
|
||||
|
||||
F9 = 0x01,
|
||||
F5 = 0x03,
|
||||
F3 = 0x04,
|
||||
F1 = 0x05,
|
||||
F2 = 0x06,
|
||||
F12 = 0x07,
|
||||
F10 = 0x09,
|
||||
F8 = 0x0A,
|
||||
F6 = 0x0B,
|
||||
F4 = 0x0C,
|
||||
TAB = 0x0D,
|
||||
BACKTICK = 0x0E,
|
||||
LEFT_ALT = 0x11,
|
||||
LEFT_SHIFT = 0x12,
|
||||
LEFT_CONTROL = 0x14,
|
||||
Q = 0x15,
|
||||
_1 = 0x16,
|
||||
Z = 0x1A,
|
||||
S = 0x1B,
|
||||
A = 0x1C,
|
||||
W = 0x1D,
|
||||
_2 = 0x1E,
|
||||
C = 0x21,
|
||||
X = 0x22,
|
||||
D = 0x23,
|
||||
E = 0x24,
|
||||
_4 = 0x25,
|
||||
_3 = 0x26,
|
||||
SPACE = 0x29,
|
||||
V = 0x2A,
|
||||
F = 0x2B,
|
||||
T = 0x2C,
|
||||
R = 0x2D,
|
||||
_5 = 0x2E,
|
||||
N = 0x31,
|
||||
B = 0x32,
|
||||
H = 0x33,
|
||||
G = 0x34,
|
||||
Y = 0x35,
|
||||
_6 = 0x36,
|
||||
M = 0x3A,
|
||||
J = 0x3B,
|
||||
U = 0x3C,
|
||||
_7 = 0x3D,
|
||||
_8 = 0x3E,
|
||||
COMMA = 0x41,
|
||||
K = 0x42,
|
||||
I = 0x43,
|
||||
O = 0x44,
|
||||
_0 = 0x45,
|
||||
_9 = 0x46,
|
||||
DOT = 0x49,
|
||||
SLASH = 0x4A,
|
||||
L = 0x4B,
|
||||
SEMICOLON = 0x4C,
|
||||
P = 0x4D,
|
||||
MINUS = 0x4E,
|
||||
APOSTROPHE = 0x52,
|
||||
BRACKET_OPEN = 0x54,
|
||||
EQUALS = 0x55,
|
||||
CAPSLOCK = 0x58,
|
||||
RIGHT_SHIFT = 0x59,
|
||||
ENTER = 0x5A,
|
||||
BRACKET_CLOSE = 0x5B,
|
||||
BACKSLASH = 0x5D,
|
||||
BACKSPACE = 0x66,
|
||||
KP_1 = 0x69,
|
||||
KP_4 = 0x6B,
|
||||
KP_7 = 0x6C,
|
||||
KP_0 = 0x70,
|
||||
KP_DOT = 0x71,
|
||||
KP_2 = 0x72,
|
||||
KP_5 = 0x73,
|
||||
KP_6 = 0x74,
|
||||
KP_8 = 0x75,
|
||||
ESCAPE = 0x76,
|
||||
NUMLOCK = 0x77,
|
||||
F11 = 0x78,
|
||||
KP_PLUS = 0x79,
|
||||
KP_3 = 0x7A,
|
||||
KP_MINUS = 0x7B,
|
||||
KP_ASTERISK = 0x7C,
|
||||
KP_9 = 0x7D,
|
||||
SCROLLOCK = 0x7E,
|
||||
F7 = 0x83,
|
||||
|
||||
MM_WWW_SEARCH = 0xE010,
|
||||
RIGHT_ALT = 0xE011,
|
||||
RIGHT_CONTROL = 0xE014,
|
||||
MM_PREV_TRACK = 0xE015,
|
||||
LEFT_GUI = 0xE01F,
|
||||
MM_WWW_FAVORITES = 0xE020,
|
||||
MM_VOLUME_DOWN = 0xE021,
|
||||
MM_MUTE = 0xE023,
|
||||
RIGHT_GUI = 0xE027,
|
||||
MM_WWW_STOP = 0xE028,
|
||||
MM_CALCULATOR = 0xE02B,
|
||||
APPS = 0xE02F,
|
||||
MM_WWW_FORWARD = 0xE030,
|
||||
MM_VOLUME_UP = 0xE032,
|
||||
MM_PLAY_PAUSE = 0xE034,
|
||||
ACPI_POWER = 0xE037,
|
||||
MM_WWW_BACK = 0xE038,
|
||||
MM_WWW_HOME = 0xE03A,
|
||||
MM_STOP = 0xE03B,
|
||||
ACPI_SLEEP = 0xE03F,
|
||||
MM_MY_COMPUTER = 0xE040,
|
||||
MM_EMAIL = 0xE048,
|
||||
KP_SLASH = 0xE04A,
|
||||
MM_NEXT_TRACK = 0xE04D,
|
||||
MM_MEDIA_SELECT = 0xE050,
|
||||
KP_ENTER = 0xE05A,
|
||||
ACPI_WAKE = 0xE05E,
|
||||
END = 0xE069,
|
||||
ARROW_LEFT = 0xE06B,
|
||||
HOME = 0xE06C,
|
||||
INSERT = 0xE070,
|
||||
DELETE = 0xE071,
|
||||
ARROW_DOWN = 0xE072,
|
||||
ARROW_RIGHT = 0xE074,
|
||||
ARROW_UP = 0xE075,
|
||||
PAGE_DOWN = 0xE07A,
|
||||
PAGE_UP = 0xE07D,
|
||||
|
||||
PRINT_SCREEN = 0xF000,
|
||||
PAUSE = 0xF001
|
||||
};
|
||||
|
||||
struct KeyEvent
|
||||
{
|
||||
Scancode scancode = Scancode::INVALID;
|
||||
bool down : 1 = false;
|
||||
bool repeat : 1 = false;
|
||||
};
|
||||
|
||||
[[nodiscard]] bool readRaw(std::uint8_t& outData) noexcept;
|
||||
[[nodiscard]] bool read(KeyEvent& outEvent) noexcept;
|
||||
|
||||
[[nodiscard]] const char* keyName(Scancode scancode) noexcept;
|
||||
}
|
||||
|
||||
#endif // !defined(BAD_APPLE_OS_KERNEL_KEYBOARD_HPP_INCLUDED)
|
121
targets/x86_64/src/kernel/pic.cpp
Normal file
121
targets/x86_64/src/kernel/pic.cpp
Normal file
@ -0,0 +1,121 @@
|
||||
|
||||
#include "./pic.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
inline constexpr std::uint8_t PIC_CMD_INIT = 0x10;
|
||||
inline constexpr std::uint8_t PIC_CMD_READ_IRR = 0x0a;
|
||||
inline constexpr std::uint8_t PIC_CMD_READ_ISR = 0x0b;
|
||||
inline constexpr std::uint8_t PIC_INIT_WITH_ICW4 = 0x01;
|
||||
inline constexpr std::uint8_t PIC_CFG_8086 = 0x01;
|
||||
|
||||
void picWriteCmd(std::uint16_t port, std::uint8_t command) noexcept
|
||||
{
|
||||
writePortByte(port, command);
|
||||
}
|
||||
|
||||
[[nodiscard]] std::uint8_t picReadResponse(std::uint8_t port) noexcept
|
||||
{
|
||||
return readPortByte(port);
|
||||
}
|
||||
|
||||
void picWriteData(std::uint16_t port, std::uint8_t data) noexcept
|
||||
{
|
||||
writePortByte(port + 1, data);
|
||||
}
|
||||
|
||||
[[nodiscard]] std::uint8_t picReadData(std::uint16_t port) noexcept
|
||||
{
|
||||
return readPortByte(port + 1);
|
||||
}
|
||||
|
||||
[[nodiscard]] std::uint16_t readPICIRQRegisters(std::uint8_t readCommand) noexcept
|
||||
{
|
||||
picWriteCmd(PORT_PIC1, readCommand);
|
||||
picWriteCmd(PORT_PIC2, readCommand);
|
||||
return (picReadResponse(PORT_PIC1) << 8) | picReadResponse(PORT_PIC2);
|
||||
}
|
||||
}
|
||||
|
||||
bool initPICs(std::uint8_t masterOffset, std::uint8_t slaveOffset) noexcept
|
||||
{
|
||||
if (!isValidPICOffset(masterOffset) || !isValidPICOffset(slaveOffset))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const uint8_t mask1 = picReadData(PORT_PIC1);
|
||||
const uint8_t mask2 = picReadData(PORT_PIC2);
|
||||
|
||||
// ICW1 - init command
|
||||
picWriteCmd(PORT_PIC1, PIC_CMD_INIT | PIC_INIT_WITH_ICW4);
|
||||
ioWait();
|
||||
picWriteCmd(PORT_PIC2, PIC_CMD_INIT | PIC_INIT_WITH_ICW4);
|
||||
ioWait();
|
||||
|
||||
// ICW2 - offset
|
||||
picWriteData(PORT_PIC1, masterOffset);
|
||||
ioWait();
|
||||
picWriteData(PORT_PIC2, slaveOffset);
|
||||
ioWait();
|
||||
|
||||
// ICW3 - master/slave config
|
||||
picWriteData(PORT_PIC1, (1 << 2)); // there is a slave at IRQ2
|
||||
ioWait();
|
||||
picWriteData(PORT_PIC2, 2); // you are slave no. 2
|
||||
ioWait();
|
||||
|
||||
// ICW3 - additional config
|
||||
picWriteData(PORT_PIC1, PIC_CFG_8086);
|
||||
ioWait();
|
||||
picWriteData(PORT_PIC2, PIC_CFG_8086);
|
||||
ioWait();
|
||||
|
||||
// restore masks
|
||||
picWriteData(PORT_PIC1, mask1);
|
||||
picWriteData(PORT_PIC2, mask2);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void sendEndOfInterrupt(std::uint8_t irq) noexcept
|
||||
{
|
||||
if (irq >= 8) {
|
||||
writePortByte(PORT_PIC2, PIC_CMD_EOI);
|
||||
}
|
||||
writePortByte(PORT_PIC1, PIC_CMD_EOI);
|
||||
}
|
||||
|
||||
void maskIRQ(std::uint8_t irq) noexcept
|
||||
{
|
||||
std::uint16_t port = PORT_PIC1;
|
||||
if (irq >= 8)
|
||||
{
|
||||
port = PORT_PIC2;
|
||||
irq -= 8;
|
||||
}
|
||||
const std::uint8_t currentMask = picReadData(port);
|
||||
picWriteData(port, currentMask | (1 << irq));
|
||||
}
|
||||
|
||||
void unmaskIRQ(std::uint8_t irq) noexcept
|
||||
{
|
||||
std::uint16_t port = PORT_PIC1;
|
||||
if (irq >= 8)
|
||||
{
|
||||
port = PORT_PIC2;
|
||||
irq -= 8;
|
||||
}
|
||||
const std::uint8_t currentMask = picReadData(port);
|
||||
picWriteData(port, currentMask & ~(1 << irq));
|
||||
}
|
||||
|
||||
std::uint16_t readPICIRR() noexcept
|
||||
{
|
||||
return readPICIRQRegisters(PIC_CMD_READ_IRR);
|
||||
}
|
||||
|
||||
std::uint16_t readPICISR() noexcept
|
||||
{
|
||||
return readPICIRQRegisters(PIC_CMD_READ_ISR);
|
||||
}
|
39
targets/x86_64/src/kernel/pic.hpp
Normal file
39
targets/x86_64/src/kernel/pic.hpp
Normal file
@ -0,0 +1,39 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !defined(BAD_APPLE_OS_KERNEL_PIC_HPP_INCLUDED)
|
||||
#define BAD_APPLE_OS_KERNEL_PIC_HPP_INCLUDED
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "os/port.hpp"
|
||||
|
||||
inline constexpr std::uint16_t PORT_PIC1 = 0x20;
|
||||
inline constexpr std::uint16_t PORT_PIC2 = 0xA0;
|
||||
inline constexpr std::uint8_t PIC_CMD_EOI = 0x20;
|
||||
|
||||
[[nodiscard]] bool initPICs(std::uint8_t masterOffset, std::uint8_t slaveOffset) noexcept;
|
||||
__attribute__((no_caller_saved_registers))
|
||||
void sendEndOfInterrupt(std::uint8_t irq) noexcept;
|
||||
void maskIRQ(std::uint8_t irq) noexcept;
|
||||
void unmaskIRQ(std::uint8_t irq) noexcept;
|
||||
[[nodiscard]] std::uint16_t readPICIRR() noexcept;
|
||||
[[nodiscard]] std::uint16_t readPICISR() noexcept;
|
||||
|
||||
[[nodiscard]] constexpr bool isValidPICOffset(std::uint8_t offset) noexcept
|
||||
{
|
||||
return (offset & 7) == 0;
|
||||
}
|
||||
|
||||
struct InterruptFrame
|
||||
{
|
||||
std::uint64_t ip;
|
||||
std::uint64_t cs;
|
||||
std::uint64_t flags;
|
||||
std::uint64_t sp;
|
||||
std::uint64_t ss;
|
||||
};
|
||||
|
||||
using interrupt_handler_t = __attribute__((interrupt)) void(*)(InterruptFrame*);
|
||||
|
||||
#endif // !defined(BAD_APPLE_OS_KERNEL_PIC_HPP_INCLUDED)
|
@ -7,12 +7,39 @@
|
||||
#include "os/draw.hpp"
|
||||
#include "os/serial.hpp"
|
||||
#include "os/tty.hpp"
|
||||
#include "./keyboard.hpp"
|
||||
#include "./pic.hpp"
|
||||
#include "./x86_64.hpp"
|
||||
|
||||
extern "C" int gKernelEnd;
|
||||
|
||||
namespace
|
||||
{
|
||||
inline constexpr std::uint8_t MASTER_PIC_OFFSET = 0x20;
|
||||
inline constexpr std::uint8_t SLAVE_PIC_OFFSET = 0x28;
|
||||
static_assert(isValidPICOffset(MASTER_PIC_OFFSET));
|
||||
static_assert(isValidPICOffset(SLAVE_PIC_OFFSET));
|
||||
|
||||
constexpr std::uint8_t irqToInterrupt(std::uint8_t irq) noexcept
|
||||
{
|
||||
if (irq < 8) {
|
||||
return MASTER_PIC_OFFSET + irq;
|
||||
}
|
||||
return SLAVE_PIC_OFFSET + irq;
|
||||
}
|
||||
inline constexpr std::uint8_t INTERRUPT_KEYBOARD = irqToInterrupt(1);
|
||||
|
||||
constinit std::array GDT alignas(16) = {
|
||||
SEGMENT_NULL,
|
||||
SEGMENT_KERNEL_CODE,
|
||||
SEGMENT_KERNEL_DATA,
|
||||
SEGMENT_USER_CODE,
|
||||
SEGMENT_USER_DATA,
|
||||
SEGMENT_NULL
|
||||
};
|
||||
|
||||
constinit std::array<InterruptDescriptor, 256> IDT alignas(16);
|
||||
|
||||
void initHeapFromEfiMemoryMap(const EfiMemoryMap& memoryMap) noexcept
|
||||
{
|
||||
const uint64_t minAddr = reinterpret_cast<uint64_t>(&gKernelEnd);
|
||||
@ -86,24 +113,17 @@ void initGlobals()
|
||||
}
|
||||
}
|
||||
|
||||
constinit std::array GDT alignas(16) = {
|
||||
SEGMENT_NULL,
|
||||
SEGMENT_KERNEL_CODE,
|
||||
SEGMENT_KERNEL_DATA,
|
||||
SEGMENT_USER_CODE,
|
||||
SEGMENT_USER_DATA
|
||||
};
|
||||
|
||||
constinit std::array<InterruptDescriptor, 256> IDT alignas(16);
|
||||
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);
|
||||
|
||||
void setupInterrupt(std::uint8_t index, void* handler, std::uint8_t flags) noexcept
|
||||
void setupInterrupt(std::uint8_t index, interrupt_handler_t handler, std::uint8_t flags) noexcept
|
||||
{
|
||||
const std::uint64_t offset = std::bit_cast<std::uint64_t>(handler);
|
||||
IDT[index] = InterruptDescriptor{
|
||||
.offsetLow = static_cast<unsigned>(offset & 0xFFFF),
|
||||
.selector = 1, // kernel code
|
||||
.selectorPrivilegeLevel = 0,
|
||||
.selectorIndex = 1, // kernel code
|
||||
.interruptStackTable = 0,
|
||||
.gateType = InterruptGateType::INTERRUPT_GATE,
|
||||
.privilegeLevel = 0,
|
||||
@ -119,10 +139,21 @@ EfiBootInfo* gBootInfo;
|
||||
|
||||
void main();
|
||||
|
||||
extern void __isr21(InterruptFrame*);
|
||||
|
||||
void kernel_main()
|
||||
{
|
||||
setupInterrupt(INTERRUPT_KEYBOARD, &kbd::isrKeyboard, 0);
|
||||
|
||||
__setGDT(sizeof(GDT), &GDT);
|
||||
__setIDT(sizeof(IDT), &IDT);
|
||||
__reloadSegments(0x08, 0x10);
|
||||
|
||||
const bool picsInited = initPICs(MASTER_PIC_OFFSET, SLAVE_PIC_OFFSET);
|
||||
unmaskIRQ(1);
|
||||
|
||||
// initialize the hardware
|
||||
const bool kbdInited = kbd::initialize();
|
||||
|
||||
// done initializing OS stuff, enable interrupts
|
||||
__asm__ __volatile__("sti");
|
||||
@ -150,7 +181,31 @@ void kernel_main()
|
||||
}
|
||||
serialWriteString(PORT_COM1, "\r\n\r\n"); // write newlines to separate from UEFI output
|
||||
|
||||
if (!picsInited)
|
||||
{
|
||||
std::puts("Error initializing the PICs!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!kbdInited)
|
||||
{
|
||||
std::puts("Error initializing the keyboard!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
std::puts("This is BadAppleOS and everything is fine!\n");
|
||||
while (true)
|
||||
{
|
||||
kbd::KeyEvent event;
|
||||
while (!kbd::read(event));
|
||||
std::printf(
|
||||
"Key event: scancode=%s(0x%X), down=%s, repeat=%s\n",
|
||||
kbd::keyName(event.scancode),
|
||||
static_cast<unsigned>(event.scancode),
|
||||
event.down ? "true" : "false",
|
||||
event.repeat ? "true" : "false"
|
||||
);
|
||||
}
|
||||
|
||||
main();
|
||||
}
|
||||
|
@ -148,17 +148,26 @@ inline constexpr const SegmentDescriptor SEGMENT_USER_DATA = {
|
||||
|
||||
enum class InterruptGateType
|
||||
{
|
||||
NONE = 0,
|
||||
INTERRUPT_GATE = 0xE,
|
||||
TRAP_GATE = 0xF
|
||||
};
|
||||
|
||||
enum class InterruptSelectorTable
|
||||
{
|
||||
GDT = 0,
|
||||
LDT = 1
|
||||
};
|
||||
|
||||
struct InterruptDescriptor
|
||||
{
|
||||
/* 0 */ unsigned offsetLow : 16 = 0;
|
||||
/* 16 */ unsigned selector : 16 = 0;
|
||||
/* 16 */ unsigned selectorPrivilegeLevel : 2 = 0;
|
||||
/* 18 */ InterruptSelectorTable selectorTable : 1 = InterruptSelectorTable::GDT;
|
||||
/* 19 */ unsigned selectorIndex : 13 = 0;
|
||||
/* 32 */ unsigned interruptStackTable : 3 = 0;
|
||||
/* 35 */ unsigned reserved0_ : 5 = 0;
|
||||
/* 40 */ InterruptGateType gateType : 4 = InterruptGateType::INTERRUPT_GATE;
|
||||
/* 40 */ InterruptGateType gateType : 4 = InterruptGateType::NONE;
|
||||
/* 44 */ unsigned reserved1_ : 1 = 0;
|
||||
/* 45 */ unsigned privilegeLevel : 2 = 0;
|
||||
/* 47 */ bool present : 1 = 0;
|
||||
|
Loading…
x
Reference in New Issue
Block a user