Move src/modules/main -> src/kernel

This commit is contained in:
Justin C. Miller
2018-04-17 09:44:40 -07:00
parent 504de44ff3
commit 2050b89334
20 changed files with 26 additions and 14 deletions

51
src/kernel/acpi_tables.h Normal file
View File

@@ -0,0 +1,51 @@
#pragma once
#include <stddef.h>
#include <stdint.h>
#include "util.h"
struct acpi_table_header
{
uint32_t type;
uint32_t length;
uint8_t revision;
uint8_t checksum;
char oem_id[6];
char oem_table[8];
uint32_t oem_revision;
uint32_t creator_id;
uint32_t creator_revision;
bool validate(uint32_t expected_type = 0) const;
} __attribute__ ((packed));
#define TABLE_HEADER(signature) \
static const uint32_t type_id = byteswap(signature); \
acpi_table_header header;
template <typename T>
bool acpi_validate(const T *t) { return t->header.validate(T::type_id); }
template <typename T>
size_t acpi_table_entries(const T *t, size_t size)
{
return (t->header.length - sizeof(T)) / size;
}
struct acpi_xsdt
{
TABLE_HEADER('XSDT');
acpi_table_header *headers[0];
} __attribute__ ((packed));
struct acpi_apic
{
TABLE_HEADER('APIC');
uint32_t local_address;
uint32_t flags;
uint8_t controller_data[0];
} __attribute__ ((packed));

40
src/kernel/boot.s Normal file
View File

@@ -0,0 +1,40 @@
MAGIC equ 0x600db007 ; Popcorn OS header magic number
section .header
align 4
global _header
_header:
dd MAGIC ; Kernel header magic
dw 1 ; Header version 1
dw 1 ; Kernel header length
db VERSION_MAJOR ; Kernel version
db VERSION_MINOR
dw VERSION_PATCH
dd VERSION_GITSHA
dq _start ; Kernel entrypoint
section .text
align 16
global _start:function (_start.end - _start)
_start:
cli
extern kernel_main
call kernel_main
cli
.hang:
hlt
jmp .hang
.end:
global interrupts_enable
interrupts_enable:
sti
ret
global interrupts_disable
interrupts_disable:
cli
ret

199
src/kernel/console.cpp Normal file
View File

@@ -0,0 +1,199 @@
#include "console.h"
const char digits[] = "0123456789abcdef";
console *console::default_console = nullptr;
console::console(const font &f, const screen &s, void *scratch, size_t len) :
m_font(f),
m_screen(s),
m_size(s.width() / f.width(), s.height() / f.height()),
m_fg(0xffffff),
m_bg(0),
m_first(0),
m_length(len),
m_data(nullptr),
m_attrs(nullptr),
m_palette(nullptr)
{
const unsigned count = m_size.size();
const size_t palette_size = sizeof(screen::pixel_t) * 256;
const size_t attrs_size = 2 * count;
if (len >= count) {
// We have enough scratch space to keep the contents of the screen
m_data = static_cast<char *>(scratch);
for (unsigned i = 0; i < count; ++i)
m_data[i] = 0;
}
if (len >= count + palette_size + attrs_size) {
// We have enough scratch space to also keep the colors of the text
m_palette = reinterpret_cast<screen::pixel_t *>(m_data + count);
unsigned index = 0;
// Manually add the 16 basic ANSI colors
m_palette[index++] = m_screen.color(0x00, 0x00, 0x00);
m_palette[index++] = m_screen.color(0xcd, 0x00, 0x00);
m_palette[index++] = m_screen.color(0x00, 0xcd, 0x00);
m_palette[index++] = m_screen.color(0xcd, 0xcd, 0x00);
m_palette[index++] = m_screen.color(0x00, 0x00, 0xee);
m_palette[index++] = m_screen.color(0xcd, 0x00, 0xcd);
m_palette[index++] = m_screen.color(0x00, 0xcd, 0xcd);
m_palette[index++] = m_screen.color(0xe5, 0xe5, 0xe5);
m_palette[index++] = m_screen.color(0x7f, 0x7f, 0x7f);
m_palette[index++] = m_screen.color(0xff, 0x00, 0x00);
m_palette[index++] = m_screen.color(0x00, 0xff, 0x00);
m_palette[index++] = m_screen.color(0xff, 0xff, 0x00);
m_palette[index++] = m_screen.color(0x00, 0x50, 0xff);
m_palette[index++] = m_screen.color(0xff, 0x00, 0xff);
m_palette[index++] = m_screen.color(0x00, 0xff, 0xff);
m_palette[index++] = m_screen.color(0xff, 0xff, 0xff);
// Build the high-color portion of the table
const uint32_t intensity[] = {0, 0x5f, 0x87, 0xaf, 0xd7, 0xff};
const uint32_t intensities = sizeof(intensity) / sizeof(uint32_t);
for (uint32_t r = 0; r < intensities; ++r) {
for (uint32_t g = 0; g < intensities; ++g) {
for (uint32_t b = 0; b < intensities; ++b) {
m_palette[index++] = m_screen.color(
intensity[r], intensity[g], intensity[b]);
}
}
}
// Build the greyscale portion of the table
for (uint8_t i = 0x08; i <= 0xee; i += 10)
m_palette[index++] = m_screen.color(i, i, i);
set_color(7, 0); // Grey on black default
m_attrs = reinterpret_cast<uint16_t *>(m_data + count + palette_size);
for (unsigned i = 0; i < count; ++i)
m_attrs[i] = m_attr;
}
repaint();
if (default_console == nullptr)
default_console = this;
}
char *
console::line_pointer(unsigned line)
{
if (!m_data) return nullptr;
return m_data + ((m_first + line) % m_size.y) * m_size.x;
}
uint16_t *
console::attr_pointer(unsigned line)
{
if (!m_attrs) return nullptr;
return m_attrs + ((m_first + line) % m_size.y) * m_size.x;
}
void
console::repaint()
{
m_screen.fill(m_bg);
if (!m_data) return;
for (unsigned y = 0; y < m_size.y; ++y) {
const char *line = line_pointer(y);
const uint16_t *attrs = attr_pointer(y);
for (unsigned x = 0; x < m_size.x; ++x) {
const uint16_t attr = attrs[x];
set_color(static_cast<uint8_t>(attr),
static_cast<uint8_t>(attr >> 8));
m_font.draw_glyph(
m_screen,
line[x] ? line[x] : ' ',
m_fg,
m_bg,
x * m_font.width(),
y * m_font.height());
}
}
}
void
console::set_color(uint8_t fg, uint8_t bg)
{
if (!m_palette) return;
m_bg = m_palette[bg];
m_fg = m_palette[fg];
m_attr = (bg << 8) | fg;
}
void
console::scroll(unsigned lines)
{
if (!m_data) {
m_pos.x = 0;
m_pos.y = 0;
} else {
unsigned bytes = lines * m_size.x;
char *line = line_pointer(0);
for (unsigned i = 0; i < bytes; ++i)
*line++ = 0;
m_first = (m_first + lines) % m_size.y;
m_pos.y -= lines;
}
repaint();
}
size_t
console::puts(const char *message)
{
char *line = line_pointer(m_pos.y);
uint16_t *attrs = attr_pointer(m_pos.y);
size_t count = 0;
while (message && *message) {
const unsigned x = m_pos.x * m_font.width();
const unsigned y = m_pos.y * m_font.height();
const char c = *message++;
++count;
switch (c) {
case '\t':
m_pos.x = (m_pos.x + 4) / 4 * 4;
break;
case '\r':
m_pos.x = 0;
break;
case '\n':
m_pos.x = 0;
m_pos.y++;
break;
default:
if (line) line[m_pos.x] = c;
if (attrs) attrs[m_pos.x] = m_attr;
m_font.draw_glyph(m_screen, c, m_fg, m_bg, x, y);
m_pos.x++;
}
if (m_pos.x >= m_size.x) {
m_pos.x = m_pos.x % m_size.x;
m_pos.y++;
}
if (m_pos.y >= m_size.y) {
scroll(1);
line = line_pointer(m_pos.y);
}
}
return count;
}

78
src/kernel/console.h Normal file
View File

@@ -0,0 +1,78 @@
#pragma once
#include "font.h"
#include "screen.h"
#include "util.h"
struct console_data;
class console
{
public:
console(const font &f, const screen &s, void *scratch, size_t len);
void repaint();
void scroll(unsigned lines);
void set_color(uint8_t fg, uint8_t bg);
size_t puts(const char *message);
size_t printf(const char *fmt, ...);
template <typename T>
void put_hex(T x);
template <typename T>
void put_dec(T x);
static console * get() { return default_console; }
private:
char * line_pointer(unsigned line);
uint16_t * attr_pointer(unsigned line);
font m_font;
screen m_screen;
coord<unsigned> m_size;
coord<unsigned> m_pos;
screen::pixel_t m_fg, m_bg;
uint16_t m_attr;
size_t m_first;
size_t m_length;
char *m_data;
uint16_t *m_attrs;
screen::pixel_t *m_palette;
static console *default_console;
};
extern const char digits[];
template <typename T>
void console::put_hex(T x)
{
static const int chars = sizeof(x) * 2;
char message[chars + 1];
for (int i=0; i<chars; ++i) {
message[chars - i - 1] = digits[(x >> (i*4)) & 0xf];
}
message[chars] = 0;
puts(message);
}
template <typename T>
void console::put_dec(T x)
{
static const int chars = sizeof(x) * 3;
char message[chars + 1];
char *p = message + chars;
*p-- = 0;
do {
*p-- = digits[x % 10];
x /= 10;
} while (x != 0);
puts(++p);
}

12
src/kernel/debug.s Normal file
View File

@@ -0,0 +1,12 @@
section .text
global do_the_set_registers
do_the_set_registers:
mov rax, 0xdeadbeef0badc0de
mov r8, rcx
mov r9, rdi
global _halt
_halt:
hlt
jmp _halt

View File

@@ -0,0 +1,157 @@
#include <stddef.h>
#include <stdint.h>
#include "acpi_tables.h"
#include "device_manager.h"
#include "console.h"
#include "util.h"
static const char expected_signature[] = "RSD PTR ";
struct acpi1_rsdp
{
char signature[8];
uint8_t checksum;
char oem_id[6];
uint8_t revision;
uint32_t rsdt_address;
} __attribute__ ((packed));
struct acpi2_rsdp
{
char signature[8];
uint8_t checksum10;
char oem_id[6];
uint8_t revision;
uint32_t rsdt_address;
uint32_t length;
uint64_t xsdt_address;
uint8_t checksum20;
uint8_t reserved[3];
} __attribute__ ((packed));
uint8_t acpi_checksum(const void *p, size_t len, size_t off = 0)
{
uint8_t sum = 0;
const uint8_t *c = reinterpret_cast<const uint8_t *>(p);
for (int i = off; i < len; ++i) sum += c[i];
return sum;
}
bool
acpi_table_header::validate(uint32_t expected_type) const
{
if (acpi_checksum(this, length) != 0) return false;
return !expected_type || (expected_type == type);
}
device_manager::device_manager(const void *root_table) :
m_local_apic(nullptr)
{
console *cons = console::get();
kassert(root_table != 0, "ACPI root table pointer is null.");
const acpi1_rsdp *acpi1 =
reinterpret_cast<const acpi1_rsdp *>(root_table);
for (int i = 0; i < sizeof(acpi1->signature); ++i)
kassert(acpi1->signature[i] == expected_signature[i],
"ACPI RSDP table signature mismatch");
uint8_t sum = acpi_checksum(acpi1, sizeof(acpi1_rsdp), 0);
kassert(sum == 0, "ACPI 1.0 RSDP checksum mismatch.");
kassert(acpi1->revision > 1, "ACPI 1.0 not supported.");
const acpi2_rsdp *acpi2 =
reinterpret_cast<const acpi2_rsdp *>(acpi1);
sum = acpi_checksum(acpi2, sizeof(acpi2_rsdp), sizeof(acpi1_rsdp));
kassert(sum == 0, "ACPI 2.0 RSDP checksum mismatch.");
load_xsdt(reinterpret_cast<const acpi_xsdt *>(acpi2->xsdt_address));
}
static void
put_sig(console *cons, uint32_t type)
{
char sig[5] = {0,0,0,0,0};
for (int j=0; j<4; ++j)
sig[j] = reinterpret_cast<char *>(&type)[j];
cons->puts(sig);
}
void
device_manager::load_xsdt(const acpi_xsdt *xsdt)
{
kassert(xsdt && acpi_validate(xsdt), "Invalid ACPI XSDT.");
console *cons = console::get();
cons->puts("ACPI 2.0 tables loading: ");
put_sig(cons, xsdt->header.type);
size_t num_tables = acpi_table_entries(xsdt, sizeof(void*));
for (size_t i = 0; i < num_tables; ++i) {
const acpi_table_header *header = xsdt->headers[i];
cons->puts(" ");
put_sig(cons, header->type);
kassert(header->validate(), "Table failed validation.");
switch (header->type) {
case acpi_apic::type_id:
load_apic(reinterpret_cast<const acpi_apic *>(header));
break;
default:
break;
}
}
cons->puts("\n");
}
template <typename T>
T read_from(const uint8_t *p) { return *reinterpret_cast<const T *>(p); }
void
device_manager::load_apic(const acpi_apic *apic)
{
console *cons = console::get();
m_local_apic = reinterpret_cast<uint32_t *>(apic->local_address);
cons->puts(" ");
cons->put_hex(apic->local_address);
uint8_t const *p = apic->controller_data;
uint8_t const *end = p + acpi_table_entries(apic, 1);
while (p < end) {
const uint8_t type = p[0];
const uint8_t length = p[1];
cons->puts(" ");
cons->put_hex(type);
switch (type) {
case 0: // Local APIC
break;
case 1: // I/O APIC
m_io_apic = reinterpret_cast<uint32_t *>(read_from<uint32_t>(p+4));
m_global_interrupt_base = read_from<uint32_t>(p+8);
cons->puts(" ");
cons->put_hex((uint64_t)m_io_apic);
cons->puts(" ");
cons->put_hex(m_global_interrupt_base);
break;
}
p += length;
}
}

View File

@@ -0,0 +1,25 @@
#pragma once
struct acpi_xsdt;
struct acpi_apic;
class device_manager
{
public:
device_manager(const void *root_table);
device_manager() = delete;
device_manager(const device_manager &) = delete;
uint8_t * local_apic() const;
uint8_t * io_apic() const;
private:
uint32_t *m_local_apic;
uint32_t *m_io_apic;
uint32_t m_global_interrupt_base;
void load_xsdt(const acpi_xsdt *xsdt);
void load_apic(const acpi_apic *apic);
};

88
src/kernel/font.cpp Normal file
View File

@@ -0,0 +1,88 @@
#include "font.h"
/* PSF2 header format
* Taken from the Linux KBD documentation
* http://www.win.tue.nl/~aeb/linux/kbd/font-formats-1.html
*/
const static uint8_t magic[] = {0x72, 0xb5, 0x4a, 0x86};
const static uint32_t max_version = 0;
const static uint8_t unicode_sep = 0xff;
const static uint8_t unicode_start = 0xfe;
/* bits used in flags */
enum psf2_flags {
psf2_has_unicode = 0x00000001
};
struct psf2_header {
uint8_t magic[4];
uint32_t version;
uint32_t header_size; // offset of bitmaps in file
uint32_t flags;
uint32_t length; // number of glyphs
uint32_t charsize; // number of bytes for each character
uint32_t height, width; // max dimensions of glyphs
};
font
font::load(void const *data)
{
psf2_header const *psf2 = static_cast<psf2_header const *>(data);
for (int i = 0; i < sizeof(magic); ++i) {
if (psf2->magic[i] != magic[i]) {
return font{};
}
}
uint8_t const *font_data = static_cast<uint8_t const *>(data) + psf2->header_size;
return font{
psf2->height,
psf2->width,
psf2->length,
font_data};
}
font::font() :
m_count(0),
m_data(nullptr)
{}
font::font(unsigned height, unsigned width, unsigned count, uint8_t const *data) :
m_size(width, height),
m_count(count),
m_data(data)
{}
font::font(const font &other) :
m_size(other.m_size),
m_count(other.m_count),
m_data(other.m_data)
{}
void
font::draw_glyph(
screen &s,
uint32_t glyph,
screen::pixel_t fg,
screen::pixel_t bg,
unsigned x,
unsigned y) const
{
unsigned bwidth = (m_size.x+7)/8;
uint8_t const *data = m_data + (glyph * glyph_bytes());
for (int dy = 0; dy < m_size.y; ++dy) {
for (int dx = 0; dx < bwidth; ++dx) {
uint8_t byte = data[dy * bwidth + dx];
for (int i = 0; i < 8; ++i) {
if (dx*8 + i >= m_size.x) continue;
const uint8_t mask = 1 << (7-i);
uint32_t c = (byte & mask) ? fg : bg;
s.draw_pixel(x + dx*8 + i, y + dy, c);
}
}
}
}

35
src/kernel/font.h Normal file
View File

@@ -0,0 +1,35 @@
#pragma once
#include <stdint.h>
#include "screen.h"
#include "util.h"
class font
{
public:
static font load(void const *data);
font(const font &other);
unsigned glyph_bytes() const { return m_size.y * ((m_size.x + 7) / 8); }
unsigned count() const { return m_count; }
unsigned width() const { return m_size.x; }
unsigned height() const { return m_size.y; }
bool valid() const { return m_count > 0; }
void draw_glyph(
screen &s,
uint32_t glyph,
screen::pixel_t fg,
screen::pixel_t bg,
unsigned x,
unsigned y) const;
private:
font();
font(unsigned height, unsigned width, unsigned count, uint8_t const *data);
coord<unsigned> m_size;
unsigned m_count;
uint8_t const *m_data;
};

View File

@@ -0,0 +1,51 @@
ISR ( 0, isr0);
ISR ( 1, isr1);
ISR ( 2, isr2);
ISR ( 3, isr3);
ISR ( 4, isr4);
ISR ( 5, isr5);
ISR ( 6, isr6);
ISR ( 7, isr7);
EISR( 8, isr8);
ISR ( 9, isr9);
EISR(10, isr10);
EISR(11, isr11);
EISR(12, isr12);
EISR(13, isr13);
EISR(14, isr14);
ISR (15, isr15);
ISR (16, isr16);
ISR (17, isr17);
ISR (18, isr18);
ISR (19, isr19);
ISR (20, isr20);
ISR (21, isr21);
ISR (22, isr22);
ISR (23, isr23);
ISR (24, isr24);
ISR (25, isr25);
ISR (26, isr26);
ISR (27, isr27);
ISR (28, isr28);
ISR (29, isr29);
ISR (30, isr30);
ISR (31, isr31);
IRQ (64, 0, irq0);
IRQ (65, 1, irq1);
IRQ (66, 2, irq2);
IRQ (67, 3, irq3);
IRQ (68, 4, irq4);
IRQ (69, 5, irq5);
IRQ (70, 6, irq6);
IRQ (71, 7, irq7);
IRQ (72, 8, irq8);
IRQ (73, 9, irq9);
IRQ (74, 10, irq10);
IRQ (75, 11, irq11);
IRQ (76, 12, irq12);
IRQ (77, 13, irq13);
IRQ (78, 14, irq14);
IRQ (79, 15, irq15);
ISR (0xff, isrSpurious);

356
src/kernel/interrupts.cpp Normal file
View File

@@ -0,0 +1,356 @@
#include <stddef.h>
#include <stdint.h>
#include "console.h"
#include "interrupts.h"
enum class gdt_flags : uint8_t
{
ac = 0x01,
rw = 0x02,
dc = 0x04,
ex = 0x08,
r1 = 0x20,
r2 = 0x40,
r3 = 0x60,
pr = 0x80,
res_1 = 0x10
};
inline gdt_flags
operator | (gdt_flags lhs, gdt_flags rhs)
{
return static_cast<gdt_flags>(
static_cast<uint8_t>(lhs) | static_cast<uint8_t>(rhs));
}
struct gdt_descriptor
{
uint16_t limit_low;
uint16_t base_low;
uint8_t base_mid;
uint8_t flags;
uint8_t granularity;
uint8_t base_high;
} __attribute__ ((packed));
struct idt_descriptor
{
uint16_t base_low;
uint16_t selector;
uint8_t ist;
uint8_t flags;
uint16_t base_mid;
uint32_t base_high;
uint32_t reserved; // must be zero
} __attribute__ ((packed));
struct table_ptr
{
uint16_t limit;
uint64_t base;
} __attribute__ ((packed));
gdt_descriptor g_gdt_table[10];
idt_descriptor g_idt_table[256];
table_ptr g_gdtr;
table_ptr g_idtr;
struct registers;
extern "C" {
void idt_write();
void idt_load();
void gdt_write();
void gdt_load();
void isr_handler(registers);
void irq_handler(registers);
#define ISR(i, name) extern void name ()
#define EISR(i, name) extern void name ()
#define IRQ(i, q, name) extern void name ()
#include "interrupt_isrs.inc"
#undef IRQ
#undef EISR
#undef ISR
}
void idt_dump(const table_ptr &table);
void gdt_dump(const table_ptr &table);
void
set_gdt_entry(uint8_t i, uint32_t base, uint32_t limit, bool is64, gdt_flags flags)
{
g_gdt_table[i].limit_low = limit & 0xffff;
g_gdt_table[i].base_low = base & 0xffff;
g_gdt_table[i].base_mid = (base >> 16) & 0xff;
g_gdt_table[i].base_high = (base >> 24) & 0xff;
g_gdt_table[i].granularity =
((limit >> 16) & 0xf) | (is64 ? 0xa0 : 0xc0);
g_gdt_table[i].flags = static_cast<uint8_t>(flags | gdt_flags::res_1 | gdt_flags::pr);
}
void
set_idt_entry(uint8_t i, uint64_t addr, uint16_t selector, uint8_t flags)
{
g_idt_table[i].base_low = addr & 0xffff;
g_idt_table[i].base_mid = (addr >> 16) & 0xffff;
g_idt_table[i].base_high = (addr >> 32) & 0xffffffff;
g_idt_table[i].selector = selector;
g_idt_table[i].flags = flags;
g_idt_table[i].ist = 0;
g_idt_table[i].reserved = 0;
}
void
interrupts_init()
{
uint8_t *p;
p = reinterpret_cast<uint8_t *>(&g_gdt_table);
for (int i = 0; i < sizeof(g_gdt_table); ++i) p[i] = 0;
g_gdtr.limit = sizeof(g_gdt_table) - 1;
g_gdtr.base = reinterpret_cast<uint64_t>(&g_gdt_table);
set_gdt_entry(1, 0, 0xfffff, false, gdt_flags::rw);
set_gdt_entry(2, 0, 0xfffff, false, gdt_flags::rw | gdt_flags::ex | gdt_flags::dc);
set_gdt_entry(3, 0, 0xfffff, false, gdt_flags::rw);
set_gdt_entry(4, 0, 0xfffff, false, gdt_flags::rw | gdt_flags::ex);
set_gdt_entry(6, 0, 0xfffff, false, gdt_flags::rw);
set_gdt_entry(7, 0, 0xfffff, true, gdt_flags::rw | gdt_flags::ex);
gdt_write();
p = reinterpret_cast<uint8_t *>(&g_idt_table);
for (int i = 0; i < sizeof(g_idt_table); ++i) p[i] = 0;
g_idtr.limit = sizeof(g_idt_table) - 1;
g_idtr.base = reinterpret_cast<uint64_t>(&g_idt_table);
#define ISR(i, name) set_idt_entry(i, reinterpret_cast<uint64_t>(& name), 0x38, 0x8e);
#define EISR(i, name) set_idt_entry(i, reinterpret_cast<uint64_t>(& name), 0x38, 0x8e);
#define IRQ(i, q, name) set_idt_entry(i, reinterpret_cast<uint64_t>(& name), 0x38, 0x8e);
#include "interrupt_isrs.inc"
#undef IRQ
#undef EISR
#undef ISR
idt_write();
}
struct registers
{
uint64_t ds;
uint64_t rdi, rsi, rbp, rsp, rbx, rdx, rcx, rax;
uint64_t interrupt, errorcode;
uint64_t rip, cs, eflags, user_esp, ss;
};
#define print_reg(name, value) \
cons->puts(" " name ": "); \
cons->put_hex((value)); \
cons->puts("\n");
void
isr_handler(registers regs)
{
console *cons = console::get();
cons->puts("received ISR interrupt:\n");
print_reg("ISR", regs.interrupt);
print_reg("ERR", regs.errorcode);
console::get()->puts("\n");
print_reg(" ds", regs.ds);
print_reg("rdi", regs.rdi);
print_reg("rsi", regs.rsi);
print_reg("rbp", regs.rbp);
print_reg("rsp", regs.rsp);
print_reg("rbx", regs.rbx);
print_reg("rdx", regs.rdx);
print_reg("rcx", regs.rcx);
print_reg("rax", regs.rax);
console::get()->puts("\n");
print_reg("rip", regs.rip);
print_reg(" cs", regs.cs);
print_reg(" ef", regs.eflags);
print_reg("esp", regs.user_esp);
print_reg(" ss", regs.ss);
while(1) asm("hlt");
}
void
irq_handler(registers regs)
{
console *cons = console::get();
cons->puts("received IRQ interrupt:\n");
print_reg("ISR", regs.interrupt);
print_reg("ERR", regs.errorcode);
console::get()->puts("\n");
print_reg(" ds", regs.ds);
print_reg("rdi", regs.rdi);
print_reg("rsi", regs.rsi);
print_reg("rbp", regs.rbp);
print_reg("rsp", regs.rsp);
print_reg("rbx", regs.rbx);
print_reg("rdx", regs.rdx);
print_reg("rcx", regs.rcx);
print_reg("rax", regs.rax);
console::get()->puts("\n");
print_reg("rip", regs.rip);
print_reg(" cs", regs.cs);
print_reg(" ef", regs.eflags);
print_reg("esp", regs.user_esp);
print_reg(" ss", regs.ss);
while(1) asm("hlt");
}
void
gdt_dump(const table_ptr &table)
{
console *cons = console::get();
cons->puts("Loaded GDT at: ");
cons->put_hex(table.base);
cons->puts(" size: ");
cons->put_dec(table.limit + 1);
cons->puts(" bytes\n");
int count = (table.limit + 1) / sizeof(gdt_descriptor);
const gdt_descriptor *gdt =
reinterpret_cast<const gdt_descriptor *>(table.base);
for (int i = 0; i < count; ++i) {
uint32_t base =
(gdt[i].base_high << 24) |
(gdt[i].base_mid << 16) |
gdt[i].base_low;
uint32_t limit =
static_cast<uint32_t>(gdt[i].granularity & 0x0f) << 16 |
gdt[i].limit_low;
cons->puts(" Entry ");
cons->put_dec(i);
cons->puts(": Base ");
cons->put_hex(base);
cons->puts(" Limit ");
cons->put_hex(limit);
cons->puts(" Privs ");
cons->put_dec((gdt[i].flags >> 5) & 0x03);
cons->puts(" Flags ");
if (gdt[i].flags & 0x80) {
cons->puts("P ");
if (gdt[i].flags & 0x08)
cons->puts("EX ");
else
cons->puts(" ");
if (gdt[i].flags & 0x04)
cons->puts("DC ");
else
cons->puts(" ");
if (gdt[i].flags & 0x02)
cons->puts("RW ");
else
cons->puts(" ");
if (gdt[i].granularity & 0x80)
cons->puts("KB ");
else
cons->puts(" B ");
if ((gdt[i].granularity & 0x60) == 0x20)
cons->puts("64");
else if ((gdt[i].granularity & 0x60) == 0x40)
cons->puts("32");
else
cons->puts("16");
}
cons->puts("\n");
}
}
void
idt_dump(const table_ptr &table)
{
console *cons = console::get();
cons->puts("Loaded IDT at: ");
cons->put_hex(table.base);
cons->puts(" size: ");
cons->put_dec(table.limit + 1);
cons->puts(" bytes\n");
int count = (table.limit + 1) / sizeof(idt_descriptor);
const idt_descriptor *idt =
reinterpret_cast<const idt_descriptor *>(table.base);
if (count > 32) count = 32;
for (int i = 0; i < count; ++i) {
uint64_t base =
(static_cast<uint64_t>(idt[i].base_high) << 32) |
(static_cast<uint64_t>(idt[i].base_mid) << 16) |
idt[i].base_low;
cons->puts(" Entry ");
cons->put_dec(i);
cons->puts(": Base ");
cons->put_hex(base);
cons->puts(" Sel(");
cons->put_dec(idt[i].selector & 0x3);
cons->puts(",");
cons->put_dec((idt[i].selector & 0x4) >> 2);
cons->puts(",");
cons->put_dec(idt[i].selector >> 3);
cons->puts(") ");
cons->puts("IST ");
cons->put_dec(idt[i].ist);
switch (idt[i].flags & 0xf) {
case 0x5: cons->puts(" 32tsk "); break;
case 0x6: cons->puts(" 16int "); break;
case 0x7: cons->puts(" 16trp "); break;
case 0xe: cons->puts(" 32int "); break;
case 0xf: cons->puts(" 32trp "); break;
default:
cons->puts(" ?");
cons->put_hex(idt[i].flags & 0xf);
cons->puts(" ");
break;
}
cons->puts("DPL ");
cons->put_dec((idt[i].flags >> 5) & 0x3);
if (idt[i].flags & 0x80)
cons->puts(" P");
cons->puts("\n");
}
}

8
src/kernel/interrupts.h Normal file
View File

@@ -0,0 +1,8 @@
#pragma once
extern "C" {
void interrupts_enable();
void interrupts_disable();
}
void interrupts_init();

121
src/kernel/interrupts.s Normal file
View File

@@ -0,0 +1,121 @@
extern g_idtr
extern g_gdtr
global idt_write
idt_write:
lidt [g_idtr]
ret
global idt_load
idt_load:
sidt [g_idtr]
ret
global gdt_write
gdt_write:
lgdt [g_gdtr]
ret
global gdt_load
gdt_load:
sgdt [g_gdtr]
ret
%macro push_all_and_segments 0
push rax
push rcx
push rdx
push rbx
push rsp
push rbp
push rsi
push rdi
mov ax, ds
push rax
%endmacro
%macro pop_all_and_segments 0
pop rax
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
pop rdi
pop rsi
pop rbp
pop rsp
pop rbx
pop rdx
pop rcx
pop rax
%endmacro
%macro load_kernel_segments 0
mov ax, 0x10 ; load the kernel data segment
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
%endmacro
extern isr_handler
global isr_handler_prelude
isr_handler_prelude:
push_all_and_segments
load_kernel_segments
call isr_handler
pop_all_and_segments
add rsp, 16 ; because the ISRs added err/num
sti
iretq
extern irq_handler
global irq_handler_prelude
irq_handler_prelude:
push_all_and_segments
load_kernel_segments
call irq_handler
pop_all_and_segments
add rsp, 16 ; because the ISRs added err/num
sti
iretq
%macro EMIT_ISR 2
global %1
%1:
cli
push byte 0
push byte %2
jmp isr_handler_prelude
%endmacro
%macro EMIT_EISR 2
global %1
%1:
cli
push byte %2
jmp isr_handler_prelude
%endmacro
%macro EMIT_IRQ 2
global %1
%1:
cli
push byte 0
push byte %2
jmp irq_handler_prelude
%endmacro
%define EISR(i, name) EMIT_EISR name, i
%define ISR(i, name) EMIT_ISR name, i
%define IRQ(i, q, name) EMIT_IRQ name, i
%include "interrupt_isrs.inc"

56
src/kernel/main.cpp Normal file
View File

@@ -0,0 +1,56 @@
#include <stddef.h>
#include <stdint.h>
#include "console.h"
#include "device_manager.h"
#include "font.h"
#include "interrupts.h"
#include "kernel_data.h"
#include "screen.h"
extern "C" {
void do_the_set_registers(popcorn_data *header);
void kernel_main(popcorn_data *header);
}
console
load_console(const popcorn_data *header)
{
console cons{
font::load(header->font),
screen{
header->frame_buffer,
header->hres,
header->vres,
header->rmask,
header->gmask,
header->bmask},
header->log,
header->log_length};
cons.set_color(0x21, 0x00);
cons.puts("Popcorn OS ");
cons.set_color(0x08, 0x00);
cons.puts(GIT_VERSION " booting...\n");
return cons;
}
void
kernel_main(popcorn_data *header)
{
console cons = load_console(header);
interrupts_init();
interrupts_enable();
cons.puts("Interrupts initialized.\n");
device_manager devices(header->acpi_table);
// int x = 1 / 0;
// __asm__ __volatile__("int $15");
cons.puts("boogity!");
do_the_set_registers(header);
}

2
src/kernel/module.mk Normal file
View File

@@ -0,0 +1,2 @@
MOD_NAME := main
include modules.mk

77
src/kernel/screen.cpp Normal file
View File

@@ -0,0 +1,77 @@
#include "screen.h"
template <typename T>
static int popcount(T x)
{
int c = 0;
while (x) {
c += (x & 1);
x = x >> 1;
}
return c;
}
template <typename T>
static int ctz(T x)
{
int c = 0;
while ((x & 1) == 0) {
x = x >> 1;
++c;
}
return c;
}
screen::color_masks::color_masks(pixel_t r, pixel_t g, pixel_t b) :
r(r), g(g), b(b)
{
rshift = static_cast<uint8_t>(ctz(r) - (8 - popcount(r)));
gshift = static_cast<uint8_t>(ctz(g) - (8 - popcount(g)));
bshift = static_cast<uint8_t>(ctz(b) - (8 - popcount(b)));
}
screen::color_masks::color_masks(const color_masks &o) :
rshift(o.rshift), gshift(o.gshift), bshift(o.bshift),
r(o.r), g(o.g), b(o.b)
{
}
screen::screen(
void *framebuffer,
unsigned hres, unsigned vres,
pixel_t rmask, pixel_t gmask, pixel_t bmask) :
m_framebuffer(static_cast<pixel_t *>(framebuffer)),
m_masks(rmask, gmask, bmask),
m_resolution(hres, vres)
{
}
screen::screen(const screen &other) :
m_framebuffer(other.m_framebuffer),
m_masks(other.m_masks),
m_resolution(other.m_resolution)
{
}
screen::pixel_t
screen::color(uint8_t r, uint8_t g, uint8_t b) const
{
return
((static_cast<uint32_t>(r) << m_masks.rshift) & m_masks.r) |
((static_cast<uint32_t>(g) << m_masks.gshift) & m_masks.g) |
((static_cast<uint32_t>(b) << m_masks.bshift) & m_masks.b);
}
void
screen::fill(pixel_t color)
{
const size_t len = m_resolution.size();
for (size_t i = 0; i < len; ++i)
m_framebuffer[i] = color;
}
void
screen::draw_pixel(unsigned x, unsigned y, pixel_t color)
{
m_framebuffer[x + y * m_resolution.x] = color;
}

40
src/kernel/screen.h Normal file
View File

@@ -0,0 +1,40 @@
#pragma once
#include <stddef.h>
#include <stdint.h>
#include "util.h"
class screen
{
public:
using pixel_t = uint32_t;
screen(
void *framebuffer,
unsigned hres, unsigned vres,
pixel_t rmask, pixel_t gmask, pixel_t bmask);
screen(const screen &other);
unsigned width() const { return m_resolution.x; }
unsigned height() const { return m_resolution.y; }
pixel_t color(uint8_t r, uint8_t g, uint8_t b) const;
void fill(pixel_t color);
void draw_pixel(unsigned x, unsigned y, pixel_t color);
screen() = delete;
private:
struct color_masks {
uint8_t rshift, gshift, bshift;
pixel_t r, g, b;
color_masks(pixel_t r, pixel_t g, pixel_t b);
color_masks(const color_masks &other);
};
pixel_t *m_framebuffer;
color_masks m_masks;
coord<unsigned> m_resolution;
};

29
src/kernel/util.cpp Normal file
View File

@@ -0,0 +1,29 @@
#include "console.h"
#include "util.h"
[[noreturn]] void
__kernel_assert(const char *file, unsigned line, const char *message)
{
console *cons = console::get();
if (cons) {
cons->set_color(9 , 0);
cons->puts("\n\n ERROR: ");
cons->puts(file);
cons->puts(":");
cons->put_dec(line);
cons->puts(": ");
cons->puts(message);
}
__asm__ __volatile__(
"movq %0, %%r8;"
"movq %1, %%r9;"
"movq %2, %%r10;"
"movq $0, %%rdx;"
"divq %%rdx;"
: // no outputs
: "r"((uint64_t)line), "r"(file), "r"(message)
: "rax", "rdx", "r8", "r9", "r10");
while (1);
}

19
src/kernel/util.h Normal file
View File

@@ -0,0 +1,19 @@
#pragma once
template <typename T>
struct coord {
T x, y;
coord() : x(T{}), y(T{}) {}
coord(T x, T y) : x(x), y(y) {}
T size() const { return x * y; }
};
[[noreturn]] void __kernel_assert(const char *file, unsigned line, const char *message);
#define kassert(stmt, message) if(!(stmt)) { __kernel_assert(__FILE__, __LINE__, (message)); } else {}
constexpr uint32_t byteswap(uint32_t x)
{
return ((x >> 24) & 0x000000ff) | ((x >> 8) & 0x0000ff00)
| ((x << 8) & 0x00ff0000) | ((x << 24) & 0xff000000);
}