Move src/modules/main -> src/kernel
This commit is contained in:
51
src/kernel/acpi_tables.h
Normal file
51
src/kernel/acpi_tables.h
Normal 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
40
src/kernel/boot.s
Normal 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
199
src/kernel/console.cpp
Normal 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
78
src/kernel/console.h
Normal 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
12
src/kernel/debug.s
Normal 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
|
||||
157
src/kernel/device_manager.cpp
Normal file
157
src/kernel/device_manager.cpp
Normal 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;
|
||||
}
|
||||
}
|
||||
25
src/kernel/device_manager.h
Normal file
25
src/kernel/device_manager.h
Normal 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
88
src/kernel/font.cpp
Normal 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
35
src/kernel/font.h
Normal 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;
|
||||
};
|
||||
|
||||
51
src/kernel/interrupt_isrs.inc
Normal file
51
src/kernel/interrupt_isrs.inc
Normal 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
356
src/kernel/interrupts.cpp
Normal 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
8
src/kernel/interrupts.h
Normal 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
121
src/kernel/interrupts.s
Normal 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
56
src/kernel/main.cpp
Normal 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
2
src/kernel/module.mk
Normal file
@@ -0,0 +1,2 @@
|
||||
MOD_NAME := main
|
||||
include modules.mk
|
||||
77
src/kernel/screen.cpp
Normal file
77
src/kernel/screen.cpp
Normal 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
40
src/kernel/screen.h
Normal 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
29
src/kernel/util.cpp
Normal 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
19
src/kernel/util.h
Normal 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);
|
||||
}
|
||||
Reference in New Issue
Block a user