this has the os booting. but when running the keyboard_handler function in a while loop, it just shows key pressed as 0FA0 even when not pressing anything. my updated code is the following:
Code: Select all
#include <cstdint>
#include <cstddef>
#include <limine.h>
#include "utils.hpp"
#include <flanterm/flanterm.h>
#include <flanterm/backends/fb.h>
// Set the base revision to 2, this is recommended as this is the latest
// base revision described by the Limine boot protocol specification.
// See specification for further info.
namespace {
__attribute__((used, section(".requests")))
volatile LIMINE_BASE_REVISION(2);
}
// The Limine requests can be placed anywhere, but it is important that
// the compiler does not optimise them away, so, usually, they should
// be made volatile or equivalent, _and_ they should be accessed at least
// once or marked as used with the "used" attribute as done here.
namespace {
__attribute__((used, section(".requests")))
volatile limine_framebuffer_request framebuffer_request = {
.id = LIMINE_FRAMEBUFFER_REQUEST,
.revision = 0,
.response = nullptr
};
}
// Finally, define the start and end markers for the Limine requests.
// These can also be moved anywhere, to any .cpp file, as seen fit.
namespace {
__attribute__((used, section(".requests_start_marker")))
volatile LIMINE_REQUESTS_START_MARKER;
__attribute__((used, section(".requests_end_marker")))
volatile LIMINE_REQUESTS_END_MARKER;
}
// Halt and catch fire function.
namespace {
void hcf() {
asm ("cli");
for (;;) {
asm ("hlt");
}
}
}
std::size_t strlen(const char* str) {
const char* s = str;
while (*s) {
++s;
}
return s - str;
}
// Outb and Inb functions
static inline void outb(uint16_t port, uint8_t value) {
asm volatile ("outb %0, %1" : : "a"(value), "Nd"(port));
}
static inline uint8_t inb(uint16_t port) {
uint8_t ret;
asm volatile ("inb %1, %0" : "=a"(ret) : "Nd"(port));
return ret;
}
// IDT entry
struct idt_entry {
uint16_t offset_low;
uint16_t selector;
uint8_t zero;
uint8_t type_attr;
uint16_t offset_mid;
uint32_t offset_high;
uint32_t zero2;
} __attribute__((packed));
// IDT pointers
struct idt_ptr {
uint16_t limit;
uint64_t base;
} __attribute__((packed));
static struct idt_entry idt[256];
static struct idt_ptr idtp;
bool set_idt_gate(int n, uint64_t handler) {
// try{
idt[n].offset_low = handler & 0xFFFF;
idt[n].selector = 0x08; // Kernel code segment
idt[n].zero = 0;
idt[n].type_attr = 0x8E; // Interrupt gate
idt[n].offset_mid = (handler >> 16) & 0xFFFF;
idt[n].offset_high = (handler >> 32) & 0xFFFFFFFF;
idt[n].zero2 = 0;
return true;
// }
// catch(...){
// return false;
// }
}
extern "C" void load_idt(struct idt_ptr* idt_ptr);
extern "C" void keyboard_isr(void);
bool init_idt() {
// try{
idtp.limit = sizeof(idt) - 1;
idtp.base = (uint64_t)&idt;
load_idt(&idtp);
return true;
// }
// catch(...){
// return false;
// }
}
bool pic_remap() {
// try{
outb(0x20, 0x11);
outb(0xA0, 0x11);
outb(0x21, 0x20);
outb(0xA1, 0x28);
outb(0x21, 0x04);
outb(0xA1, 0x02);
outb(0x21, 0x01);
outb(0xA1, 0x01);
outb(0x21, 0x0);
outb(0xA1, 0x0);
return true;
// }
// catch(...){
// return false;
// }
}
struct flanterm_context *ft_ctx;
// The following stubs are required by the Itanium C++ ABI (the one we use,
// regardless of the "Itanium" nomenclature).
// Like the memory functions above, these stubs can be moved to a different .cpp file,
// but should not be removed, unless you know what you are doing.
extern "C" {
int __cxa_atexit(void (*)(void *), void *, void *) { return 0; }
void __cxa_pure_virtual() { hcf(); }
void *__dso_handle;
}
void __fb_init(struct limine_framebuffer_response *fb_response) {
struct limine_framebuffer *fb = fb_response->framebuffers[0];
uint32_t fg = 0x000000;
uint32_t bg = 0xffffff;
ft_ctx = flanterm_fb_init(NULL, NULL, (uint32_t*)fb->address, fb->width, fb->height, fb->pitch, fb->red_mask_size, fb->red_mask_shift, fb->green_mask_size, fb->green_mask_shift, fb->blue_mask_size, fb->blue_mask_shift, NULL, NULL, NULL, &bg, &fg, NULL, NULL, NULL, 8, 16, 1, 1, 1, 5);
}
void print(const char msg[]){
std::size_t length = strlen(msg);
flanterm_write(ft_ctx, msg, length);
}
void clear_screen() {
const char* clear_sequence = "\x1b[2J\x1b[H";
std::size_t length = strlen(clear_sequence);
flanterm_write(ft_ctx, clear_sequence, length);
}
extern "C" void keyboard_handler() {
uint8_t scancode = inb(0x60);
char msg[] = "Key pressed: 0x00\n";
const char *hex = "0123456789ABCDEF";
msg[14] = hex[(scancode >> 4) & 0xF];
msg[15] = hex[scancode & 0xF];
print(msg);
// End of interrupt
outb(0x20, 0x20);
}
extern "C" void _secondKernelPhase(){
hcf();
}
// Extern declarations for global constructors array.
extern void (*__init_array[])();
extern void (*__init_array_end[])();
// The following will be our kernel's entry point.
// If renaming _start() to something else, make sure to change the
// linker script accordingly.
extern "C" void _start() {
// Ensure the bootloader actually understands our base revision (see spec).
if (LIMINE_BASE_REVISION_SUPPORTED == false) {
hcf();
}
// Call global constructors.
for (std::size_t i = 0; &__init_array[i] != __init_array_end; i++) {
__init_array[i]();
}
// Ensure we got a framebuffer.
if (framebuffer_request.response == nullptr
|| framebuffer_request.response->framebuffer_count < 1) {
hcf();
}
if (framebuffer_request.response->framebuffers[0] != NULL){
__fb_init(framebuffer_request.response);
}
print("cOS First Phase Kernel: Initializing... ");
init_idt();
pic_remap();
set_idt_gate(33, (uint64_t)keyboard_isr);
asm volatile("sti");
while(true){
keyboard_handler();
}
hcf();
}
__asm__(
".global load_idt\n"
"load_idt:\n"
" lidt (%rdi)\n"
" ret\n"
".global keyboard_isr\n"
"keyboard_isr:\n"
" push %rax\n"
" push %rbx\n"
" push %rcx\n"
" push %rdx\n"
" push %rsi\n"
" push %rdi\n"
" push %r8\n"
" push %r9\n"
" push %r10\n"
" push %r11\n"
" push %r12\n"
" push %r13\n"
" push %r14\n"
" push %r15\n"
" call keyboard_handler\n"
" pop %r15\n"
" pop %r14\n"
" pop %r13\n"
" pop %r12\n"
" pop %r11\n"
" pop %r10\n"
" pop %r9\n"
" pop %r8\n"
" pop %rdi\n"
" pop %rsi\n"
" pop %rdx\n"
" pop %rcx\n"
" pop %rbx\n"
" pop %rax\n"
" iretq\n"
);