Compare commits
31 Commits
feature/mu
...
fb-driver
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2be70976ca | ||
|
|
699fc57e0a | ||
|
|
f3bb2e5259 | ||
|
|
34120fc4c1 | ||
|
|
e52fd8eacf | ||
|
|
a97073848c | ||
|
|
03b2d0dac7 | ||
|
|
cfeeba4400 | ||
|
|
45b52633bb | ||
|
|
b9af081a44 | ||
|
|
d75b9c22d4 | ||
|
|
e20c53f193 | ||
|
|
6d4a32b6e8 | ||
|
|
63a5c2da00 | ||
|
|
bdcd0c2fda | ||
|
|
1be929b9d5 | ||
|
|
d11dd0c3f9 | ||
|
|
e08e00790f | ||
|
|
8b3356e9d8 | ||
|
|
cd30126f17 | ||
|
|
2c444dccd6 | ||
|
|
bd490c4c7b | ||
|
|
3a67e461de | ||
|
|
972ef39295 | ||
|
|
4c41205e73 | ||
|
|
f6b4a4a103 | ||
| 327cd93c04 | |||
| 0e6b27e741 | |||
| db8a14720b | |||
| 87a7293ac1 | |||
| 5787aff866 |
@@ -16,10 +16,14 @@ class PrintStackCommand(gdb.Command):
|
||||
depth = int(args[1])
|
||||
|
||||
for i in range(depth-1, -1, -1):
|
||||
try:
|
||||
offset = i * 8
|
||||
base_addr = gdb.parse_and_eval(base)
|
||||
value = gdb.parse_and_eval(f"*(uint64_t*)({base} + {offset})")
|
||||
print("{:016x} (+{:04x}): {:016x}".format(int(base_addr) + offset, offset, int(value)))
|
||||
except Exception as e:
|
||||
print(e)
|
||||
continue
|
||||
|
||||
|
||||
class PrintBacktraceCommand(gdb.Command):
|
||||
@@ -29,13 +33,13 @@ class PrintBacktraceCommand(gdb.Command):
|
||||
def invoke(self, arg, from_tty):
|
||||
args = gdb.string_to_argv(arg)
|
||||
|
||||
frame = "$rbp"
|
||||
if len(args) > 0:
|
||||
frame = args[0]
|
||||
|
||||
depth = 30
|
||||
if len(args) > 0:
|
||||
depth = int(args[0])
|
||||
|
||||
frame = "$rbp"
|
||||
if len(args) > 1:
|
||||
depth = int(args[1])
|
||||
frame = args[1]
|
||||
|
||||
for i in range(depth-1, -1, -1):
|
||||
ret = gdb.parse_and_eval(f"*(uint64_t*)({frame} + 8)")
|
||||
|
||||
29
modules.yaml
29
modules.yaml
@@ -6,6 +6,7 @@ modules:
|
||||
output: jsix.elf
|
||||
target: host
|
||||
deps:
|
||||
- cpu
|
||||
- kutil
|
||||
includes:
|
||||
- src/kernel
|
||||
@@ -20,7 +21,6 @@ modules:
|
||||
- src/kernel/debug.cpp
|
||||
- src/kernel/debug.s
|
||||
- src/kernel/device_manager.cpp
|
||||
- src/kernel/font.cpp
|
||||
- src/kernel/frame_allocator.cpp
|
||||
- src/kernel/fs/gpt.cpp
|
||||
- src/kernel/gdt.cpp
|
||||
@@ -44,7 +44,6 @@ modules:
|
||||
- src/kernel/page_table.cpp
|
||||
- src/kernel/pci.cpp
|
||||
- src/kernel/scheduler.cpp
|
||||
- src/kernel/screen.cpp
|
||||
- src/kernel/serial.cpp
|
||||
- src/kernel/symbol_table.cpp
|
||||
- src/kernel/syscall.cpp
|
||||
@@ -64,6 +63,8 @@ modules:
|
||||
kind: exe
|
||||
target: boot
|
||||
output: boot.efi
|
||||
deps:
|
||||
- cpu
|
||||
source:
|
||||
- src/boot/main.cpp
|
||||
- src/boot/console.cpp
|
||||
@@ -73,6 +74,7 @@ modules:
|
||||
- src/boot/loader.cpp
|
||||
- src/boot/memory.cpp
|
||||
- src/boot/paging.cpp
|
||||
- src/boot/status.cpp
|
||||
- src/boot/support.cpp
|
||||
|
||||
nulldrv:
|
||||
@@ -84,9 +86,20 @@ modules:
|
||||
source:
|
||||
- src/drivers/nulldrv/io.cpp
|
||||
- src/drivers/nulldrv/main.cpp
|
||||
- src/drivers/nulldrv/main.s
|
||||
- src/drivers/nulldrv/serial.cpp
|
||||
|
||||
fb:
|
||||
kind: exe
|
||||
target: user
|
||||
output: fb.elf
|
||||
deps:
|
||||
- libc
|
||||
source:
|
||||
- src/drivers/fb/font.cpp
|
||||
- src/drivers/fb/main.cpp
|
||||
- src/drivers/fb/screen.cpp
|
||||
- src/drivers/fb/scrollback.cpp
|
||||
|
||||
kutil:
|
||||
kind: lib
|
||||
output: libkutil.a
|
||||
@@ -100,6 +113,14 @@ modules:
|
||||
- src/libraries/kutil/memory.cpp
|
||||
- src/libraries/kutil/printf.c
|
||||
|
||||
cpu:
|
||||
kind: lib
|
||||
output: libcpu.a
|
||||
includes:
|
||||
- src/libraries/cpu/include
|
||||
source:
|
||||
- src/libraries/cpu/cpu.cpp
|
||||
|
||||
|
||||
libc:
|
||||
kind: lib
|
||||
@@ -122,6 +143,8 @@ modules:
|
||||
#- LACKS_TIME_H
|
||||
source:
|
||||
- src/libraries/libc/arch/x86_64/_Exit.s
|
||||
- src/libraries/libc/arch/x86_64/crt0.s
|
||||
- src/libraries/libc/arch/x86_64/init_libc.c
|
||||
- src/libraries/libc/arch/x86_64/syscalls.s
|
||||
- src/libraries/libc/ctype/isalnum.c
|
||||
- src/libraries/libc/ctype/isalpha.c
|
||||
|
||||
7
qemu.sh
7
qemu.sh
@@ -6,6 +6,7 @@ debug=""
|
||||
debugtarget="${build}/jsix.elf"
|
||||
flash_name="ovmf_vars"
|
||||
gfx="-nographic"
|
||||
vga="-vga none"
|
||||
kvm=""
|
||||
cpu="Broadwell,+pdpe1gb"
|
||||
|
||||
@@ -22,6 +23,10 @@ for arg in $@; do
|
||||
;;
|
||||
--gfx)
|
||||
gfx=""
|
||||
vga=""
|
||||
;;
|
||||
--vga)
|
||||
vga=""
|
||||
;;
|
||||
--kvm)
|
||||
kvm="-enable-kvm"
|
||||
@@ -72,4 +77,4 @@ exec qemu-system-x86_64 \
|
||||
-cpu "${cpu}" \
|
||||
-M q35 \
|
||||
-no-reboot \
|
||||
$gfx $kvm $debug
|
||||
$gfx $vga $kvm $debug
|
||||
|
||||
@@ -19,15 +19,19 @@ def parse_syms(infile):
|
||||
representing the symbols in the text segment of the binary. Returns
|
||||
a list of (address, symbol_name)."""
|
||||
|
||||
from cxxfilt import demangle
|
||||
from cxxfilt import demangle, InvalidName
|
||||
|
||||
syms = []
|
||||
for line in sys.stdin:
|
||||
addr, t, mangled = line.split()
|
||||
if t not in "tTvVwW": continue
|
||||
|
||||
addr = int(addr, base=16)
|
||||
try:
|
||||
name = demangle(mangled)
|
||||
except InvalidName:
|
||||
continue
|
||||
|
||||
addr = int(addr, base=16)
|
||||
syms.append((addr, name))
|
||||
|
||||
return sorted(syms)
|
||||
|
||||
75
scripts/fontpsf.py
Normal file
75
scripts/fontpsf.py
Normal file
@@ -0,0 +1,75 @@
|
||||
_MAGIC = (0x72, 0xb5, 0x4a, 0x86)
|
||||
_VERSION = 0
|
||||
|
||||
class PSF2:
|
||||
from collections import namedtuple
|
||||
Header = namedtuple("PSF2Header",
|
||||
["version", "offset", "flags", "count", "charsize", "height", "width"])
|
||||
|
||||
def __init__(self, filename, header, data):
|
||||
self.__filename = filename
|
||||
self.__header = header
|
||||
self.__data = data
|
||||
|
||||
data = property(lambda self: self.__data)
|
||||
header = property(lambda self: self.__header)
|
||||
count = property(lambda self: self.__header.count)
|
||||
charsize = property(lambda self: self.__header.charsize)
|
||||
dimension = property(lambda self: (self.__header.width, self.__header.height))
|
||||
filename = property(lambda self: self.__filename)
|
||||
|
||||
@classmethod
|
||||
def load(cls, filename):
|
||||
from os.path import basename
|
||||
from struct import unpack_from
|
||||
|
||||
data = open(filename, 'rb').read()
|
||||
|
||||
fmt = "BBBBIIIIIII"
|
||||
values = unpack_from(fmt, data)
|
||||
|
||||
if values[:len(_MAGIC)] != _MAGIC:
|
||||
raise Exception("Bad magic number in header")
|
||||
|
||||
header = PSF2.Header(*values[len(_MAGIC):])
|
||||
if header.version != _VERSION:
|
||||
raise Exception(f"Bad version {header.version} in header")
|
||||
|
||||
return cls(basename(filename), header, data)
|
||||
|
||||
class Glyph:
|
||||
__slots__ = ['index', 'data']
|
||||
def __init__(self, i, data):
|
||||
self.index = i
|
||||
self.data = data
|
||||
def __index__(self):
|
||||
return self.index
|
||||
def empty(self):
|
||||
return not bool([b for b in self.data if b != 0])
|
||||
def description(self):
|
||||
c = chr(self.index)
|
||||
if c.isprintable():
|
||||
return "Glyph {:02x}: '{}'".format(self.index, c)
|
||||
else:
|
||||
return "Glyph {:02x}".format(self.index)
|
||||
|
||||
def __getitem__(self, i):
|
||||
c = self.__header.charsize
|
||||
n = i * c + self.__header.offset
|
||||
return PSF2.Glyph(i, self.__data[n:n+c])
|
||||
|
||||
class __iter:
|
||||
__slots__ = ['font', 'n']
|
||||
def __init__(self, font):
|
||||
self.font = font
|
||||
self.n = 0
|
||||
def __next__(self):
|
||||
if self.n < self.font.count:
|
||||
glyph = self.font[self.n]
|
||||
self.n += 1
|
||||
return glyph
|
||||
else:
|
||||
raise StopIteration
|
||||
|
||||
def __iter__(self):
|
||||
return PSF2.__iter(self)
|
||||
34
scripts/parse_font.py
Normal file → Executable file
34
scripts/parse_font.py
Normal file → Executable file
@@ -1,21 +1,6 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
MAGIC = (0x72, 0xb5, 0x4a, 0x86)
|
||||
|
||||
from collections import namedtuple
|
||||
PSF2 = namedtuple("PSF2", ["version", "offset", "flags", "count", "charsize", "height", "width"])
|
||||
|
||||
def read_header(data):
|
||||
from struct import unpack_from, calcsize
|
||||
|
||||
fmt = "BBBBIIIIIII"
|
||||
|
||||
values = unpack_from(fmt, data)
|
||||
if values[:len(MAGIC)] != MAGIC:
|
||||
raise Exception("Bad magic number in header")
|
||||
|
||||
return PSF2(*values[len(MAGIC):])
|
||||
|
||||
from fontpsf import PSF2
|
||||
|
||||
def print_glyph(header, data):
|
||||
bw = (header.width + 7) // 8
|
||||
@@ -28,16 +13,15 @@ def print_glyph(header, data):
|
||||
|
||||
|
||||
def display_font(filename):
|
||||
data = open(filename, 'rb').read()
|
||||
font = PSF2.load(filename)
|
||||
print(font.header)
|
||||
|
||||
header = read_header(data)
|
||||
print(header)
|
||||
|
||||
c = header.charsize
|
||||
for i in range(0, header.count):
|
||||
n = i * c + header.offset
|
||||
print("Glyph {}:".format(i))
|
||||
print_glyph(header, data[n:n+c])
|
||||
for glyph in font:
|
||||
if glyph.empty():
|
||||
print("{}: BLANK".format(glyph.description()))
|
||||
else:
|
||||
print("{}:".format(glyph.description()))
|
||||
print_glyph(font.header, glyph.data)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
27
scripts/psf_to_cpp.py
Executable file
27
scripts/psf_to_cpp.py
Executable file
@@ -0,0 +1,27 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
from fontpsf import PSF2
|
||||
|
||||
def print_header(filename):
|
||||
font = PSF2.load(filename)
|
||||
|
||||
print("#pragma once")
|
||||
print(f"// This file was autogenerated by psf_to_cpp.py from {font.filename}\n")
|
||||
|
||||
print(f"const uint8_t font_glyph_size = {font.charsize};")
|
||||
print(f"const uint8_t font_glyph_width = {font.dimension[0]};")
|
||||
print(f"const uint8_t font_glyph_height = {font.dimension[1]};")
|
||||
print(f"const uint16_t font_glyph_count = {font.count};\n")
|
||||
|
||||
print('const uint8_t font_glyph_data[] = {')
|
||||
|
||||
for glyph in font:
|
||||
print(" ", "".join([f"0x{b:02x}," for b in glyph.data]), end="")
|
||||
print(" // {}".format(glyph.description()))
|
||||
|
||||
print("};")
|
||||
|
||||
if __name__ == "__main__":
|
||||
import sys
|
||||
for filename in sys.argv[1:]:
|
||||
print_header(filename)
|
||||
@@ -190,15 +190,15 @@ build $builddir/fatroot/efi/boot/bootx64.efi : cp $builddir/boot/boot.efi
|
||||
build $builddir/fatroot/nulldrv.elf : cp $builddir/user/nulldrv.elf
|
||||
name = null driver to FAT image
|
||||
|
||||
build $builddir/fatroot/terminal.elf : cp $builddir/user/nulldrv.elf
|
||||
name = terminal driver to FAT image
|
||||
build $builddir/fatroot/fb.elf : cp $builddir/user/fb.elf
|
||||
name = fb driver to FAT image
|
||||
|
||||
build ${builddir}/fatroot/symbol_table.dat : makest ${builddir}/jsix.elf
|
||||
|
||||
build $builddir/jsix.img : makefat | $
|
||||
$builddir/fatroot/symbol_table.dat $
|
||||
$builddir/fatroot/nulldrv.elf $
|
||||
$builddir/fatroot/terminal.elf $
|
||||
$builddir/fatroot/fb.elf $
|
||||
$builddir/fatroot/jsix.elf $
|
||||
$builddir/fatroot/efi/boot/bootx64.efi
|
||||
name = jsix.img
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
ENTRY(_start)
|
||||
ENTRY(_kernel_start)
|
||||
SECTIONS
|
||||
{
|
||||
. = 0xFFFF800000000000;
|
||||
|
||||
@@ -17,23 +17,7 @@ namespace boot {
|
||||
size_t ROWS = 0;
|
||||
size_t COLS = 0;
|
||||
|
||||
static constexpr int level_ok = 0;
|
||||
static constexpr int level_warn = 1;
|
||||
static constexpr int level_fail = 2;
|
||||
|
||||
static const wchar_t *level_tags[] = {
|
||||
L" ok ",
|
||||
L" warn ",
|
||||
L"failed"
|
||||
};
|
||||
static const uefi::attribute level_colors[] = {
|
||||
uefi::attribute::green,
|
||||
uefi::attribute::brown,
|
||||
uefi::attribute::light_red
|
||||
};
|
||||
|
||||
console *console::s_console = nullptr;
|
||||
status_line *status_line::s_current = nullptr;
|
||||
|
||||
static const wchar_t digits[] = {u'0', u'1', u'2', u'3', u'4', u'5',
|
||||
u'6', u'7', u'8', u'9', u'a', u'b', u'c', u'd', u'e', u'f'};
|
||||
@@ -49,9 +33,10 @@ wstrlen(const wchar_t *s)
|
||||
|
||||
|
||||
console::console(uefi::boot_services *bs, uefi::protos::simple_text_output *out) :
|
||||
m_rows(0),
|
||||
m_cols(0),
|
||||
m_out(out)
|
||||
m_rows {0},
|
||||
m_cols {0},
|
||||
m_out {out},
|
||||
m_fb {0, 0}
|
||||
{
|
||||
pick_mode(bs);
|
||||
|
||||
@@ -72,6 +57,25 @@ console::console(uefi::boot_services *bs, uefi::protos::simple_text_output *out)
|
||||
m_out->set_attribute(uefi::attribute::light_gray);
|
||||
m_out->output_string(L" booting...\r\n\n");
|
||||
|
||||
if (m_fb.type != kernel::args::fb_type::none) {
|
||||
wchar_t const * type = nullptr;
|
||||
switch (m_fb.type) {
|
||||
case kernel::args::fb_type::rgb8:
|
||||
type = L"rgb8";
|
||||
break;
|
||||
case kernel::args::fb_type::bgr8:
|
||||
type = L"bgr8";
|
||||
break;
|
||||
default:
|
||||
type = L"unknown";
|
||||
}
|
||||
|
||||
printf(L"Found framebuffer: %dx%d[%d] type %s @0x%x\r\n",
|
||||
m_fb.horizontal, m_fb.vertical, m_fb.scanline, type, m_fb.phys_addr);
|
||||
} else {
|
||||
printf(L"No framebuffer found.\r\n");
|
||||
}
|
||||
|
||||
s_console = this;
|
||||
}
|
||||
|
||||
@@ -82,9 +86,14 @@ console::pick_mode(uefi::boot_services *bs)
|
||||
uefi::protos::graphics_output *gfx_out_proto;
|
||||
uefi::guid guid = uefi::protos::graphics_output::guid;
|
||||
|
||||
try_or_raise(
|
||||
bs->locate_protocol(&guid, nullptr, (void **)&gfx_out_proto),
|
||||
L"Failed to find a Graphics Output Protocol handle");
|
||||
m_fb.type = kernel::args::fb_type::none;
|
||||
|
||||
uefi::status has_gop = bs->locate_protocol(&guid, nullptr,
|
||||
(void **)&gfx_out_proto);
|
||||
|
||||
if (has_gop != uefi::status::success)
|
||||
// No video output found, skip it
|
||||
return;
|
||||
|
||||
const uint32_t modes = gfx_out_proto->mode->max_mode;
|
||||
uint32_t best = gfx_out_proto->mode->mode;
|
||||
@@ -93,7 +102,7 @@ console::pick_mode(uefi::boot_services *bs)
|
||||
(uefi::graphics_output_mode_info *)gfx_out_proto->mode;
|
||||
|
||||
uint32_t res = info->horizontal_resolution * info->vertical_resolution;
|
||||
int is_fb = info->pixel_format != uefi::pixel_format::blt_only;
|
||||
int pixmode = static_cast<int>(info->pixel_format);
|
||||
|
||||
for (uint32_t i = 0; i < modes; ++i) {
|
||||
size_t size = 0;
|
||||
@@ -107,17 +116,37 @@ console::pick_mode(uefi::boot_services *bs)
|
||||
#endif
|
||||
|
||||
const uint32_t new_res = info->horizontal_resolution * info->vertical_resolution;
|
||||
const int new_is_fb = info->pixel_format != uefi::pixel_format::blt_only;
|
||||
int new_pixmode = static_cast<int>(info->pixel_format);
|
||||
|
||||
if (new_is_fb > is_fb && new_res >= res) {
|
||||
if (new_pixmode <= pixmode && new_res >= res) {
|
||||
best = i;
|
||||
res = new_res;
|
||||
pixmode = new_pixmode;
|
||||
}
|
||||
}
|
||||
|
||||
try_or_raise(
|
||||
gfx_out_proto->set_mode(best),
|
||||
L"Failed to set graphics mode");
|
||||
|
||||
if (pixmode <= static_cast<int>(uefi::pixel_format::bgr8)) {
|
||||
m_fb.phys_addr = gfx_out_proto->mode->frame_buffer_base;
|
||||
m_fb.size = gfx_out_proto->mode->frame_buffer_size;
|
||||
m_fb.vertical = gfx_out_proto->mode->info->vertical_resolution;
|
||||
m_fb.horizontal = gfx_out_proto->mode->info->horizontal_resolution;
|
||||
m_fb.scanline = gfx_out_proto->mode->info->pixels_per_scanline;
|
||||
|
||||
switch (gfx_out_proto->mode->info->pixel_format) {
|
||||
case uefi::pixel_format::rgb8:
|
||||
m_fb.type = kernel::args::fb_type::rgb8;
|
||||
break;
|
||||
case uefi::pixel_format::bgr8:
|
||||
m_fb.type = kernel::args::fb_type::bgr8;
|
||||
break;
|
||||
default:
|
||||
m_fb.type = kernel::args::fb_type::none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size_t
|
||||
@@ -272,176 +301,4 @@ console::print(const wchar_t *fmt, ...)
|
||||
return result;
|
||||
}
|
||||
|
||||
status_line::status_line(const wchar_t *message, const wchar_t *context) :
|
||||
m_level(level_ok)
|
||||
{
|
||||
auto out = console::get().m_out;
|
||||
m_line = out->mode->cursor_row;
|
||||
m_depth = (s_current ? 1 + s_current->m_depth : 0);
|
||||
|
||||
int indent = 2 * m_depth;
|
||||
out->set_cursor_position(indent, m_line);
|
||||
out->set_attribute(uefi::attribute::light_gray);
|
||||
out->output_string(message);
|
||||
|
||||
if (context) {
|
||||
out->output_string(L": ");
|
||||
out->output_string(context);
|
||||
}
|
||||
|
||||
out->output_string(L"\r\n");
|
||||
|
||||
m_next = s_current;
|
||||
s_current = this;
|
||||
}
|
||||
|
||||
status_line::~status_line()
|
||||
{
|
||||
if (s_current != this)
|
||||
error::raise(uefi::status::unsupported, L"Destroying non-current status_line");
|
||||
|
||||
finish();
|
||||
if (m_next && m_level > m_next->m_level) {
|
||||
m_next->m_level = m_level;
|
||||
m_next->print_status_tag();
|
||||
}
|
||||
s_current = m_next;
|
||||
}
|
||||
|
||||
void
|
||||
status_line::print_status_tag()
|
||||
{
|
||||
auto out = console::get().m_out;
|
||||
int row = out->mode->cursor_row;
|
||||
int col = out->mode->cursor_column;
|
||||
|
||||
uefi::attribute color = level_colors[m_level];
|
||||
const wchar_t *tag = level_tags[m_level];
|
||||
|
||||
out->set_cursor_position(50, m_line);
|
||||
|
||||
out->set_attribute(uefi::attribute::light_gray);
|
||||
out->output_string(L"[");
|
||||
out->set_attribute(color);
|
||||
out->output_string(tag);
|
||||
out->set_attribute(uefi::attribute::light_gray);
|
||||
out->output_string(L"]\r\n");
|
||||
|
||||
out->set_cursor_position(col, row);
|
||||
}
|
||||
|
||||
void
|
||||
status_line::do_warn(const wchar_t *message, const wchar_t *error)
|
||||
{
|
||||
auto out = console::get().m_out;
|
||||
int row = out->mode->cursor_row;
|
||||
|
||||
if (m_level < level_warn) {
|
||||
m_level = level_warn;
|
||||
print_status_tag();
|
||||
}
|
||||
|
||||
int indent = 2 + 2 * m_depth;
|
||||
out->set_cursor_position(indent, row);
|
||||
out->set_attribute(uefi::attribute::yellow);
|
||||
out->output_string(message);
|
||||
|
||||
if (error) {
|
||||
out->output_string(L": ");
|
||||
out->output_string(error);
|
||||
}
|
||||
|
||||
out->set_attribute(uefi::attribute::light_gray);
|
||||
out->output_string(L"\r\n");
|
||||
}
|
||||
|
||||
void
|
||||
status_line::do_fail(const wchar_t *message, const wchar_t *error)
|
||||
{
|
||||
auto out = console::get().m_out;
|
||||
int row = out->mode->cursor_row;
|
||||
|
||||
if (s_current->m_level < level_fail) {
|
||||
m_level = level_fail;
|
||||
print_status_tag();
|
||||
}
|
||||
|
||||
int indent = 2 + 2 * m_depth;
|
||||
out->set_cursor_position(indent, row);
|
||||
out->set_attribute(uefi::attribute::red);
|
||||
out->output_string(message);
|
||||
|
||||
if (error) {
|
||||
out->output_string(L": ");
|
||||
out->output_string(error);
|
||||
}
|
||||
|
||||
out->set_attribute(uefi::attribute::light_gray);
|
||||
out->output_string(L"\r\n");
|
||||
}
|
||||
|
||||
void
|
||||
status_line::finish()
|
||||
{
|
||||
if (m_level <= level_ok)
|
||||
print_status_tag();
|
||||
}
|
||||
|
||||
/*
|
||||
uefi::status
|
||||
con_get_framebuffer(
|
||||
EFI_BOOT_SERVICES *bootsvc,
|
||||
void **buffer,
|
||||
size_t *buffer_size,
|
||||
uint32_t *hres,
|
||||
uint32_t *vres,
|
||||
uint32_t *rmask,
|
||||
uint32_t *gmask,
|
||||
uint32_t *bmask)
|
||||
{
|
||||
uefi::status status;
|
||||
|
||||
uefi::protos::graphics_output *gop;
|
||||
status = bootsvc->LocateProtocol(&guid_gfx_out, NULL, (void **)&gop);
|
||||
if (status != EFI_NOT_FOUND) {
|
||||
CHECK_EFI_STATUS_OR_RETURN(status, "LocateProtocol gfx");
|
||||
|
||||
*buffer = (void *)gop->Mode->FrameBufferBase;
|
||||
*buffer_size = gop->Mode->FrameBufferSize;
|
||||
*hres = gop->Mode->Info->horizontal_resolution;
|
||||
*vres = gop->Mode->Info->vertical_resolution;
|
||||
|
||||
switch (gop->Mode->Info->PixelFormat) {
|
||||
case PixelRedGreenBlueReserved8BitPerColor:
|
||||
*rmask = 0x0000ff;
|
||||
*gmask = 0x00ff00;
|
||||
*bmask = 0xff0000;
|
||||
return EFI_SUCCESS;
|
||||
|
||||
case PixelBlueGreenRedReserved8BitPerColor:
|
||||
*bmask = 0x0000ff;
|
||||
*gmask = 0x00ff00;
|
||||
*rmask = 0xff0000;
|
||||
return EFI_SUCCESS;
|
||||
|
||||
case PixelBitMask:
|
||||
*rmask = gop->Mode->Info->PixelInformation.RedMask;
|
||||
*gmask = gop->Mode->Info->PixelInformation.GreenMask;
|
||||
*bmask = gop->Mode->Info->PixelInformation.BlueMask;
|
||||
return EFI_SUCCESS;
|
||||
|
||||
default:
|
||||
// Not a framebuffer, fall through to zeroing out
|
||||
// values below.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
*buffer = NULL;
|
||||
*buffer_size = *hres = *vres = 0;
|
||||
*rmask = *gmask = *bmask = 0;
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
*/
|
||||
|
||||
} // namespace boot
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
/// \file console.h
|
||||
/// Text output and status message handling
|
||||
/// Text output handler
|
||||
#pragma once
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <uefi/boot_services.h>
|
||||
#include <uefi/protos/simple_text_output.h>
|
||||
#include "kernel_args.h"
|
||||
#include "types.h"
|
||||
|
||||
namespace boot {
|
||||
|
||||
@@ -12,6 +14,8 @@ namespace boot {
|
||||
class console
|
||||
{
|
||||
public:
|
||||
using framebuffer = kernel::args::framebuffer;
|
||||
|
||||
console(uefi::boot_services *bs, uefi::protos::simple_text_output *out);
|
||||
|
||||
size_t print_hex(uint32_t n) const;
|
||||
@@ -20,6 +24,8 @@ public:
|
||||
size_t print_long_dec(uint64_t n) const;
|
||||
size_t printf(const wchar_t *fmt, ...) const;
|
||||
|
||||
const framebuffer & fb() const { return m_fb; };
|
||||
|
||||
static console & get() { return *s_console; }
|
||||
static size_t print(const wchar_t *fmt, ...);
|
||||
|
||||
@@ -31,50 +37,9 @@ private:
|
||||
|
||||
size_t m_rows, m_cols;
|
||||
uefi::protos::simple_text_output *m_out;
|
||||
framebuffer m_fb;
|
||||
|
||||
static console *s_console;
|
||||
};
|
||||
|
||||
/// Scoped status line reporter. Prints a message and an "OK" if no errors
|
||||
/// or warnings were reported before destruction, otherwise reports the
|
||||
/// error or warning.
|
||||
class status_line
|
||||
{
|
||||
public:
|
||||
/// Constructor.
|
||||
/// \arg message Description of the operation in progress
|
||||
/// \arg context If non-null, printed after `message` and a colon
|
||||
status_line(const wchar_t *message, const wchar_t *context = nullptr);
|
||||
~status_line();
|
||||
|
||||
/// Set the state to warning, and print a message. If the state is already at
|
||||
/// warning or error, the state is unchanged but the message is still printed.
|
||||
/// \arg message The warning message to print
|
||||
/// \arg error If non-null, printed after `message`
|
||||
inline static void warn(const wchar_t *message, const wchar_t *error = nullptr) {
|
||||
if (s_current) s_current->do_warn(message, error);
|
||||
}
|
||||
|
||||
/// Set the state to error, and print a message. If the state is already at
|
||||
/// error, the state is unchanged but the message is still printed.
|
||||
/// \arg message The error message to print
|
||||
/// \arg error If non-null, printed after `message`
|
||||
inline static void fail(const wchar_t *message, const wchar_t *error = nullptr) {
|
||||
if (s_current) s_current->do_fail(message, error);
|
||||
}
|
||||
|
||||
private:
|
||||
void print_status_tag();
|
||||
void do_warn(const wchar_t *message, const wchar_t *error);
|
||||
void do_fail(const wchar_t *message, const wchar_t *error);
|
||||
void finish();
|
||||
|
||||
size_t m_line;
|
||||
int m_level;
|
||||
int m_depth;
|
||||
|
||||
status_line *m_next;
|
||||
static status_line *s_current;
|
||||
};
|
||||
|
||||
} // namespace boot
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
#include "error.h"
|
||||
#include "console.h"
|
||||
#include "kernel_args.h"
|
||||
#include "status.h"
|
||||
|
||||
namespace boot {
|
||||
namespace error {
|
||||
|
||||
handler *handler::s_current = nullptr;
|
||||
|
||||
struct error_code_desc {
|
||||
uefi::status code;
|
||||
const wchar_t *name;
|
||||
@@ -20,8 +20,8 @@ struct error_code_desc error_table[] = {
|
||||
{ uefi::status::success, nullptr }
|
||||
};
|
||||
|
||||
static const wchar_t *
|
||||
error_message(uefi::status status)
|
||||
const wchar_t *
|
||||
message(uefi::status status)
|
||||
{
|
||||
int32_t i = -1;
|
||||
while (error_table[++i].name != nullptr) {
|
||||
@@ -34,56 +34,31 @@ error_message(uefi::status status)
|
||||
return L"Unknown Warning";
|
||||
}
|
||||
|
||||
[[ noreturn ]] void
|
||||
raise(uefi::status status, const wchar_t *message)
|
||||
{
|
||||
if (handler::s_current) {
|
||||
handler::s_current->handle(status, message);
|
||||
}
|
||||
while (1) asm("hlt");
|
||||
}
|
||||
|
||||
handler::handler() :
|
||||
m_next(s_current)
|
||||
{
|
||||
s_current = this;
|
||||
}
|
||||
|
||||
handler::~handler()
|
||||
{
|
||||
if (s_current != this)
|
||||
raise(uefi::status::warn_stale_data,
|
||||
L"Non-current error handler destructing");
|
||||
s_current = m_next;
|
||||
}
|
||||
|
||||
uefi_handler::uefi_handler(console &con) :
|
||||
handler(),
|
||||
m_con(con)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
uefi_handler::handle(uefi::status s, const wchar_t *message)
|
||||
{
|
||||
status_line::fail(message, error_message(s));
|
||||
}
|
||||
|
||||
cpu_assert_handler::cpu_assert_handler() : handler() {}
|
||||
|
||||
void
|
||||
cpu_assert_handler::handle(uefi::status s, const wchar_t *message)
|
||||
[[ noreturn ]] static void
|
||||
cpu_assert(uefi::status s, const wchar_t *message)
|
||||
{
|
||||
asm volatile (
|
||||
"movq $0xeeeeeeebadbadbad, %%r8;"
|
||||
"movq %0, %%r9;"
|
||||
"movq %1, %%r10;"
|
||||
"movq $0, %%rdx;"
|
||||
"divq %%rdx;"
|
||||
:
|
||||
: "r"((uint64_t)s)
|
||||
: "rax", "rdx", "r8", "r9");
|
||||
: "r"((uint64_t)s), "r"(message)
|
||||
: "rax", "rdx", "r8", "r9", "r10");
|
||||
while (1) asm("hlt");
|
||||
}
|
||||
|
||||
[[ noreturn ]] void
|
||||
raise(uefi::status status, const wchar_t *message)
|
||||
{
|
||||
if(status_line::fail(message, status))
|
||||
while (1) asm("hlt");
|
||||
else
|
||||
cpu_assert(status, message);
|
||||
}
|
||||
|
||||
|
||||
} // namespace error
|
||||
} // namespace boot
|
||||
|
||||
|
||||
@@ -14,48 +14,7 @@ namespace error {
|
||||
/// Halt or exit the program with the given error status/message
|
||||
[[ noreturn ]] void raise(uefi::status status, const wchar_t *message);
|
||||
|
||||
/// Interface for error-handling functors
|
||||
class handler
|
||||
{
|
||||
public:
|
||||
/// Constructor must be called by implementing classes.
|
||||
handler();
|
||||
virtual ~handler();
|
||||
|
||||
/// Interface for implementations of error handling.
|
||||
virtual void handle(uefi::status, const wchar_t*) = 0;
|
||||
|
||||
private:
|
||||
friend void raise(uefi::status, const wchar_t *);
|
||||
|
||||
handler *m_next;
|
||||
static handler *s_current;
|
||||
};
|
||||
|
||||
/// Error handler using UEFI boot services. Integrates with `status_line`
|
||||
/// to print formatted error messages to the screen.
|
||||
class uefi_handler :
|
||||
public handler
|
||||
{
|
||||
public:
|
||||
uefi_handler(console &con);
|
||||
virtual ~uefi_handler() {}
|
||||
void handle(uefi::status, const wchar_t*) override;
|
||||
|
||||
private:
|
||||
console &m_con;
|
||||
};
|
||||
|
||||
/// Error handler that doesn't rely on UEFI. Sets status into CPU
|
||||
/// registers and then causes a CPU #DE exception.
|
||||
class cpu_assert_handler :
|
||||
public handler
|
||||
{
|
||||
public:
|
||||
cpu_assert_handler();
|
||||
virtual ~cpu_assert_handler() {}
|
||||
void handle(uefi::status, const wchar_t*) override;
|
||||
};
|
||||
const wchar_t * message(uefi::status status);
|
||||
|
||||
} // namespace error
|
||||
} // namespace boot
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "console.h"
|
||||
#include "error.h"
|
||||
#include "memory.h"
|
||||
#include "status.h"
|
||||
|
||||
namespace boot {
|
||||
namespace fs {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "hardware.h"
|
||||
#include "console.h"
|
||||
#include "error.h"
|
||||
#include "status.h"
|
||||
|
||||
namespace boot {
|
||||
namespace hw {
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "fs.h"
|
||||
#include "memory.h"
|
||||
#include "paging.h"
|
||||
#include "status.h"
|
||||
|
||||
namespace args = kernel::args;
|
||||
|
||||
@@ -81,7 +82,7 @@ load_program(
|
||||
|
||||
try_or_raise(
|
||||
bs->allocate_pages(uefi::allocate_type::any_pages,
|
||||
memory::program_type, num_pages, &pages),
|
||||
uefi::memory_type::loader_data, num_pages, &pages),
|
||||
L"Failed allocating space for program");
|
||||
|
||||
bs->set_mem(pages, total_size, 0);
|
||||
@@ -97,13 +98,8 @@ load_program(
|
||||
void *src_start = offset_ptr<void>(data.data, pheader->offset);
|
||||
void *dest_start = offset_ptr<void>(pages, pheader->vaddr - prog_base);
|
||||
bs->copy_mem(dest_start, src_start, pheader->file_size);
|
||||
|
||||
console::print(L" section %d phys: 0x%lx\r\n", i, pages);
|
||||
console::print(L" section %d virt: 0x%lx\r\n", i, pheader->vaddr);
|
||||
}
|
||||
|
||||
console::print(L" entrypoint: 0x%lx\r\n", header->entrypoint);
|
||||
|
||||
program.phys_addr = reinterpret_cast<uintptr_t>(pages);
|
||||
program.size = total_size;
|
||||
program.virt_addr = prog_base;
|
||||
|
||||
@@ -8,12 +8,14 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#include "console.h"
|
||||
#include "cpu/cpu.h"
|
||||
#include "error.h"
|
||||
#include "fs.h"
|
||||
#include "hardware.h"
|
||||
#include "loader.h"
|
||||
#include "memory.h"
|
||||
#include "paging.h"
|
||||
#include "status.h"
|
||||
|
||||
#include "kernel_args.h"
|
||||
|
||||
@@ -37,7 +39,7 @@ struct program_desc
|
||||
const program_desc program_list[] = {
|
||||
{L"kernel", L"jsix.elf"},
|
||||
{L"null driver", L"nulldrv.elf"},
|
||||
//{L"terminal driver", L"terminal.elf"},
|
||||
{L"fb driver", L"fb.elf"},
|
||||
};
|
||||
|
||||
/// Change a pointer to point to the higher-half linear-offset version
|
||||
@@ -56,7 +58,7 @@ allocate_args_structure(
|
||||
size_t max_modules,
|
||||
size_t max_programs)
|
||||
{
|
||||
status_line status(L"Setting up kernel args memory");
|
||||
status_line status {L"Setting up kernel args memory"};
|
||||
|
||||
args::header *args = nullptr;
|
||||
|
||||
@@ -66,7 +68,7 @@ allocate_args_structure(
|
||||
max_programs * sizeof(args::program); // The program structures
|
||||
|
||||
try_or_raise(
|
||||
bs->allocate_pool(memory::args_type, args_size,
|
||||
bs->allocate_pool(uefi::memory_type::loader_data, args_size,
|
||||
reinterpret_cast<void**>(&args)),
|
||||
L"Could not allocate argument memory");
|
||||
|
||||
@@ -93,17 +95,35 @@ add_module(args::header *args, args::mod_type type, buffer &data)
|
||||
m.size = data.size;
|
||||
}
|
||||
|
||||
/// Check that all required cpu features are supported
|
||||
void
|
||||
check_cpu_supported()
|
||||
{
|
||||
status_line status {L"Checking CPU features"};
|
||||
|
||||
cpu::cpu_id cpu;
|
||||
uint64_t missing = cpu.missing();
|
||||
if (missing) {
|
||||
#define CPU_FEATURE_OPT(...)
|
||||
#define CPU_FEATURE_REQ(name, ...) \
|
||||
if (!cpu.has_feature(cpu::feature::name)) { \
|
||||
status::fail(L"CPU required feature " L ## #name, uefi::status::unsupported); \
|
||||
}
|
||||
#include "cpu/features.inc"
|
||||
#undef CPU_FEATURE_REQ
|
||||
#undef CPU_FEATURE_OPT
|
||||
|
||||
error::raise(uefi::status::unsupported, L"CPU not supported");
|
||||
}
|
||||
}
|
||||
|
||||
/// The main procedure for the portion of the loader that runs while
|
||||
/// UEFI is still in control of the machine. (ie, while the loader still
|
||||
/// has access to boot services.
|
||||
args::header *
|
||||
bootloader_main_uefi(
|
||||
uefi::handle image,
|
||||
uefi::system_table *st,
|
||||
console &con)
|
||||
uefi_preboot(uefi::handle image, uefi::system_table *st)
|
||||
{
|
||||
error::uefi_handler handler(con);
|
||||
status_line status(L"Performing UEFI pre-boot");
|
||||
status_line status {L"Performing UEFI pre-boot"};
|
||||
|
||||
uefi::boot_services *bs = st->boot_services;
|
||||
uefi::runtime_services *rs = st->runtime_services;
|
||||
@@ -122,9 +142,8 @@ bootloader_main_uefi(
|
||||
|
||||
fs::file disk = fs::get_boot_volume(image, bs);
|
||||
|
||||
const uefi::memory_type mod_type = memory::module_type;
|
||||
buffer symbols = loader::load_file(disk, L"symbol table", L"symbol_table.dat",
|
||||
memory::module_type);
|
||||
uefi::memory_type::loader_data);
|
||||
add_module(args, args::mod_type::symbol_table, symbols);
|
||||
|
||||
for (auto &desc : program_list) {
|
||||
@@ -141,35 +160,49 @@ bootloader_main_uefi(
|
||||
return args;
|
||||
}
|
||||
|
||||
memory::efi_mem_map
|
||||
uefi_exit(args::header *args, uefi::handle image, uefi::boot_services *bs)
|
||||
{
|
||||
status_line status {L"Exiting UEFI"};
|
||||
|
||||
memory::efi_mem_map map =
|
||||
memory::build_kernel_mem_map(args, bs);
|
||||
|
||||
try_or_raise(
|
||||
bs->exit_boot_services(image, map.key),
|
||||
L"Failed to exit boot services");
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
} // namespace boot
|
||||
|
||||
/// The UEFI entrypoint for the loader.
|
||||
extern "C" uefi::status
|
||||
efi_main(uefi::handle image_handle, uefi::system_table *st)
|
||||
efi_main(uefi::handle image, uefi::system_table *st)
|
||||
{
|
||||
using namespace boot;
|
||||
|
||||
error::cpu_assert_handler handler;
|
||||
console con(st->boot_services, st->con_out);
|
||||
check_cpu_supported();
|
||||
|
||||
args::header *args =
|
||||
bootloader_main_uefi(image_handle, st, con);
|
||||
args::header *args = uefi_preboot(image, st);
|
||||
memory::efi_mem_map map = uefi_exit(args, image, st->boot_services);
|
||||
|
||||
args->video = con.fb();
|
||||
status_bar status {con.fb()}; // Switch to fb status display
|
||||
|
||||
args::program &kernel = args->programs[0];
|
||||
paging::map_pages(args, kernel.phys_addr, kernel.virt_addr, kernel.size);
|
||||
kernel::entrypoint kentry =
|
||||
reinterpret_cast<kernel::entrypoint>(kernel.entrypoint);
|
||||
|
||||
memory::efi_mem_map map =
|
||||
memory::build_kernel_mem_map(args, st->boot_services);
|
||||
|
||||
try_or_raise(
|
||||
st->boot_services->exit_boot_services(image_handle, map.key),
|
||||
L"Failed to exit boot services");
|
||||
status.next();
|
||||
|
||||
memory::virtualize(args->pml4, map, st->runtime_services);
|
||||
status.next();
|
||||
|
||||
change_pointer(args->pml4);
|
||||
hw::setup_cr4();
|
||||
status.next();
|
||||
|
||||
kentry(args);
|
||||
debug_break();
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "error.h"
|
||||
#include "memory.h"
|
||||
#include "paging.h"
|
||||
#include "status.h"
|
||||
|
||||
namespace boot {
|
||||
namespace memory {
|
||||
@@ -35,20 +36,28 @@ static const wchar_t *memory_type_names[] = {
|
||||
L"persistent memory"
|
||||
};
|
||||
|
||||
static const wchar_t *kernel_memory_type_names[] = {
|
||||
L"free",
|
||||
L"pending",
|
||||
L"acpi",
|
||||
L"uefi_runtime",
|
||||
L"mmio",
|
||||
L"persistent"
|
||||
};
|
||||
|
||||
static const wchar_t *
|
||||
memory_type_name(uefi::memory_type t)
|
||||
{
|
||||
if (t < uefi::memory_type::max_memory_type) {
|
||||
if (t < uefi::memory_type::max_memory_type)
|
||||
return memory_type_names[static_cast<uint32_t>(t)];
|
||||
}
|
||||
|
||||
switch(t) {
|
||||
case args_type: return L"jsix kernel args";
|
||||
case module_type: return L"jsix bootloader module";
|
||||
case program_type: return L"jsix kernel or program code";
|
||||
case table_type: return L"jsix page tables";
|
||||
default: return L"Bad Type Value";
|
||||
}
|
||||
return L"Bad Type Value";
|
||||
}
|
||||
|
||||
static const wchar_t *
|
||||
kernel_memory_type_name(kernel::args::mem_type t)
|
||||
{
|
||||
return kernel_memory_type_names[static_cast<uint32_t>(t)];
|
||||
}
|
||||
|
||||
void
|
||||
@@ -100,14 +109,15 @@ can_merge(mem_entry &prev, mem_type type, uefi::memory_descriptor *next)
|
||||
void
|
||||
get_uefi_mappings(efi_mem_map *map, bool allocate, uefi::boot_services *bs)
|
||||
{
|
||||
status_line(L"Getting UEFI memory map");
|
||||
|
||||
size_t length = 0;
|
||||
uefi::status status = bs->get_memory_map(
|
||||
&map->length, nullptr, &map->key, &map->size, &map->version);
|
||||
&length, nullptr, &map->key, &map->size, &map->version);
|
||||
|
||||
if (status != uefi::status::buffer_too_small)
|
||||
error::raise(status, L"Error getting memory map size");
|
||||
|
||||
map->length = length;
|
||||
|
||||
if (allocate) {
|
||||
map->length += 10*map->size;
|
||||
|
||||
@@ -126,29 +136,30 @@ get_uefi_mappings(efi_mem_map *map, bool allocate, uefi::boot_services *bs)
|
||||
efi_mem_map
|
||||
build_kernel_mem_map(kernel::args::header *args, uefi::boot_services *bs)
|
||||
{
|
||||
status_line(L"Creating kernel memory map");
|
||||
status_line status {L"Creating kernel memory map"};
|
||||
|
||||
efi_mem_map efi_map;
|
||||
get_uefi_mappings(&efi_map, false, bs);
|
||||
efi_mem_map map;
|
||||
get_uefi_mappings(&map, false, bs);
|
||||
|
||||
size_t map_size = efi_map.num_entries() * sizeof(mem_entry);
|
||||
size_t map_size = map.num_entries() * sizeof(mem_entry);
|
||||
|
||||
kernel::args::mem_entry *kernel_map = nullptr;
|
||||
try_or_raise(
|
||||
bs->allocate_pages(
|
||||
uefi::allocate_type::any_pages,
|
||||
module_type,
|
||||
uefi::memory_type::loader_data,
|
||||
bytes_to_pages(map_size),
|
||||
reinterpret_cast<void**>(&kernel_map)),
|
||||
L"Error allocating kernel memory map module space");
|
||||
|
||||
bs->set_mem(kernel_map, map_size, 0);
|
||||
get_uefi_mappings(&efi_map, true, bs);
|
||||
get_uefi_mappings(&map, true, bs);
|
||||
|
||||
size_t i = 0;
|
||||
bool first = true;
|
||||
for (auto desc : efi_map) {
|
||||
for (auto desc : map) {
|
||||
/*
|
||||
// EFI map dump
|
||||
console::print(L" Range %lx (%lx) %x(%s) [%lu]\r\n",
|
||||
desc->physical_start, desc->attribute, desc->type, memory_type_name(desc->type), desc->number_of_pages);
|
||||
*/
|
||||
@@ -162,13 +173,16 @@ build_kernel_mem_map(kernel::args::header *args, uefi::boot_services *bs)
|
||||
continue;
|
||||
|
||||
case uefi::memory_type::loader_code:
|
||||
case uefi::memory_type::loader_data:
|
||||
case uefi::memory_type::boot_services_code:
|
||||
case uefi::memory_type::boot_services_data:
|
||||
case uefi::memory_type::conventional_memory:
|
||||
type = mem_type::free;
|
||||
break;
|
||||
|
||||
case uefi::memory_type::loader_data:
|
||||
type = mem_type::pending;
|
||||
break;
|
||||
|
||||
case uefi::memory_type::runtime_services_code:
|
||||
case uefi::memory_type::runtime_services_data:
|
||||
type = mem_type::uefi_runtime;
|
||||
@@ -187,22 +201,6 @@ build_kernel_mem_map(kernel::args::header *args, uefi::boot_services *bs)
|
||||
type = mem_type::persistent;
|
||||
break;
|
||||
|
||||
case args_type:
|
||||
type = mem_type::args;
|
||||
break;
|
||||
|
||||
case module_type:
|
||||
type = mem_type::module;
|
||||
break;
|
||||
|
||||
case program_type:
|
||||
type = mem_type::program;
|
||||
break;
|
||||
|
||||
case table_type:
|
||||
type = mem_type::table;
|
||||
break;
|
||||
|
||||
default:
|
||||
error::raise(
|
||||
uefi::status::invalid_parameter,
|
||||
@@ -235,7 +233,16 @@ build_kernel_mem_map(kernel::args::header *args, uefi::boot_services *bs)
|
||||
args->mem_map = kernel_map;
|
||||
args->map_count = i;
|
||||
|
||||
return efi_map;
|
||||
/*
|
||||
// kernel map dump
|
||||
for (unsigned i = 0; i < args->map_count; ++i) {
|
||||
const kernel::args::mem_entry &e = kernel_map[i];
|
||||
console::print(L" Range %lx (%lx) %x(%s) [%lu]\r\n",
|
||||
e.start, e.attr, e.type, kernel_memory_type_name(e.type), e.pages);
|
||||
}
|
||||
*/
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -18,28 +18,6 @@ inline constexpr size_t bytes_to_pages(size_t bytes) {
|
||||
return ((bytes - 1) / page_size) + 1;
|
||||
}
|
||||
|
||||
/// \defgroup memory_types
|
||||
/// Custom UEFI memory type values used for data being passed to the kernel
|
||||
/// @{
|
||||
|
||||
/// Memory containing the kernel args structure
|
||||
constexpr uefi::memory_type args_type =
|
||||
static_cast<uefi::memory_type>(0x80000000);
|
||||
|
||||
/// Memory containing any loaded modules to be passed to the kernel
|
||||
constexpr uefi::memory_type module_type =
|
||||
static_cast<uefi::memory_type>(0x80000001);
|
||||
|
||||
/// Memory containing loaded kernel or program code and data sections
|
||||
constexpr uefi::memory_type program_type =
|
||||
static_cast<uefi::memory_type>(0x80000002);
|
||||
|
||||
/// Memory containing page tables set up by the loader
|
||||
constexpr uefi::memory_type table_type =
|
||||
static_cast<uefi::memory_type>(0x80000003);
|
||||
|
||||
/// @}
|
||||
|
||||
/// \defgroup pointer_fixup
|
||||
/// Memory virtualization pointer fixup functions. Handles changing affected pointers
|
||||
/// when calling UEFI's `set_virtual_address_map` function to change the location of
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "memory.h"
|
||||
#include "paging.h"
|
||||
#include "pointer_manipulation.h"
|
||||
#include "status.h"
|
||||
|
||||
namespace boot {
|
||||
namespace paging {
|
||||
@@ -27,7 +28,7 @@ using ::memory::table_entries;
|
||||
/// Page table entry flags for entries pointing at a page
|
||||
constexpr uint16_t page_flags = 0x103;
|
||||
|
||||
// Flags: 0 0 0 0 1 1 0 0 0 0 0 1 1 = 0x0183
|
||||
// Flags: 0 0 0 0 1 1 0 0 0 1 0 1 1 = 0x018b
|
||||
// | IGN | | | | | | | | +- Present
|
||||
// | | | | | | | | +--- Writeable
|
||||
// | | | | | | | +----- Supervisor only
|
||||
@@ -201,18 +202,21 @@ allocate_tables(kernel::args::header *args, uefi::boot_services *bs)
|
||||
try_or_raise(
|
||||
bs->allocate_pages(
|
||||
uefi::allocate_type::any_pages,
|
||||
memory::table_type,
|
||||
uefi::memory_type::loader_data,
|
||||
tables_needed,
|
||||
&addr),
|
||||
L"Error allocating page table pages.");
|
||||
|
||||
bs->set_mem(addr, tables_needed*page_size, 0);
|
||||
|
||||
args->pml4 = addr;
|
||||
page_table *pml4 = reinterpret_cast<page_table*>(addr);
|
||||
|
||||
args->pml4 = pml4;
|
||||
args->table_count = tables_needed - 1;
|
||||
args->page_tables = offset_ptr<void>(addr, page_size);
|
||||
|
||||
page_table *pml4 = reinterpret_cast<page_table*>(addr);
|
||||
console::print(L" First page (pml4) at: 0x%lx\r\n", pml4);
|
||||
|
||||
add_kernel_pds(pml4, args->page_tables, args->table_count);
|
||||
add_offset_mappings(pml4, args->page_tables, args->table_count);
|
||||
|
||||
|
||||
263
src/boot/status.cpp
Normal file
263
src/boot/status.cpp
Normal file
@@ -0,0 +1,263 @@
|
||||
#include <uefi/types.h>
|
||||
#include <uefi/graphics.h>
|
||||
|
||||
#include "console.h"
|
||||
#include "error.h"
|
||||
#include "kernel_args.h"
|
||||
#include "status.h"
|
||||
|
||||
constexpr int num_boxes = 30;
|
||||
|
||||
namespace boot {
|
||||
|
||||
static constexpr int level_ok = 0;
|
||||
static constexpr int level_warn = 1;
|
||||
static constexpr int level_fail = 2;
|
||||
|
||||
static const wchar_t *level_tags[] = {
|
||||
L" ok ",
|
||||
L" warn ",
|
||||
L"failed"
|
||||
};
|
||||
|
||||
static const uefi::attribute level_colors[] = {
|
||||
uefi::attribute::green,
|
||||
uefi::attribute::brown,
|
||||
uefi::attribute::light_red
|
||||
};
|
||||
|
||||
status *status::s_current = nullptr;
|
||||
unsigned status::s_current_type = 0;
|
||||
unsigned status_bar::s_count = 0;
|
||||
|
||||
status_line::status_line(const wchar_t *message, const wchar_t *context) :
|
||||
m_level(level_ok),
|
||||
m_depth(0),
|
||||
m_outer(nullptr)
|
||||
{
|
||||
if (status::s_current_type == status_line::type) {
|
||||
m_outer = static_cast<status_line*>(s_current);
|
||||
m_depth = (m_outer ? 1 + m_outer->m_depth : 0);
|
||||
}
|
||||
s_current = this;
|
||||
s_current_type = status_line::type;
|
||||
|
||||
auto out = console::get().m_out;
|
||||
m_line = out->mode->cursor_row;
|
||||
|
||||
int indent = 2 * m_depth;
|
||||
out->set_cursor_position(indent, m_line);
|
||||
out->set_attribute(uefi::attribute::light_gray);
|
||||
out->output_string(message);
|
||||
|
||||
if (context) {
|
||||
out->output_string(L": ");
|
||||
out->output_string(context);
|
||||
}
|
||||
|
||||
out->output_string(L"\r\n");
|
||||
print_status_tag();
|
||||
}
|
||||
|
||||
status_line::~status_line()
|
||||
{
|
||||
if (s_current != this)
|
||||
error::raise(uefi::status::unsupported, L"Destroying non-current status_line");
|
||||
|
||||
if (m_outer && m_level > m_outer->m_level) {
|
||||
m_outer->m_level = m_level;
|
||||
m_outer->print_status_tag();
|
||||
}
|
||||
s_current = m_outer;
|
||||
}
|
||||
|
||||
void
|
||||
status_line::print_status_tag()
|
||||
{
|
||||
auto out = console::get().m_out;
|
||||
int row = out->mode->cursor_row;
|
||||
int col = out->mode->cursor_column;
|
||||
|
||||
uefi::attribute color = level_colors[m_level];
|
||||
const wchar_t *tag = level_tags[m_level];
|
||||
|
||||
out->set_cursor_position(50, m_line);
|
||||
|
||||
out->set_attribute(uefi::attribute::light_gray);
|
||||
out->output_string(L"[");
|
||||
out->set_attribute(color);
|
||||
out->output_string(tag);
|
||||
out->set_attribute(uefi::attribute::light_gray);
|
||||
out->output_string(L"]\r\n");
|
||||
|
||||
out->set_cursor_position(col, row);
|
||||
}
|
||||
|
||||
void
|
||||
status_line::do_warn(const wchar_t *message, uefi::status status)
|
||||
{
|
||||
auto out = console::get().m_out;
|
||||
int row = out->mode->cursor_row;
|
||||
|
||||
if (m_level < level_warn) {
|
||||
m_level = level_warn;
|
||||
print_status_tag();
|
||||
}
|
||||
|
||||
int indent = 2 + 2 * m_depth;
|
||||
out->set_cursor_position(indent, row);
|
||||
out->set_attribute(uefi::attribute::yellow);
|
||||
out->output_string(message);
|
||||
|
||||
const wchar_t *error = error::message(status);
|
||||
if (error) {
|
||||
out->output_string(L": ");
|
||||
out->output_string(error);
|
||||
}
|
||||
|
||||
out->set_attribute(uefi::attribute::light_gray);
|
||||
out->output_string(L"\r\n");
|
||||
}
|
||||
|
||||
void
|
||||
status_line::do_fail(const wchar_t *message, uefi::status status)
|
||||
{
|
||||
auto out = console::get().m_out;
|
||||
int row = out->mode->cursor_row;
|
||||
|
||||
if (m_level < level_fail) {
|
||||
m_level = level_fail;
|
||||
print_status_tag();
|
||||
}
|
||||
|
||||
int indent = 2 + 2 * m_depth;
|
||||
out->set_cursor_position(indent, row);
|
||||
out->set_attribute(uefi::attribute::red);
|
||||
out->output_string(message);
|
||||
|
||||
const wchar_t *error = error::message(status);
|
||||
if (error) {
|
||||
out->output_string(L": ");
|
||||
out->output_string(error);
|
||||
}
|
||||
|
||||
out->set_attribute(uefi::attribute::light_gray);
|
||||
out->output_string(L"\r\n");
|
||||
}
|
||||
|
||||
|
||||
|
||||
status_bar::status_bar(kernel::args::framebuffer const &fb) :
|
||||
m_outer(nullptr)
|
||||
{
|
||||
m_size = (fb.vertical / num_boxes) - 1;
|
||||
m_top = fb.vertical - m_size;
|
||||
m_horiz = fb.horizontal;
|
||||
m_fb = reinterpret_cast<uint32_t*>(fb.phys_addr);
|
||||
m_type = static_cast<uint16_t>(fb.type);
|
||||
next();
|
||||
|
||||
if (status::s_current_type == status_bar::type)
|
||||
m_outer = static_cast<status_bar*>(s_current);
|
||||
s_current = this;
|
||||
s_current_type = status_bar::type;
|
||||
}
|
||||
|
||||
status_bar::~status_bar()
|
||||
{
|
||||
if (s_current != this)
|
||||
error::raise(uefi::status::unsupported, L"Destroying non-current status_bar");
|
||||
draw_box();
|
||||
s_current = m_outer;
|
||||
}
|
||||
|
||||
void
|
||||
status_bar::do_warn(const wchar_t *message, uefi::status status)
|
||||
{
|
||||
m_status = status;
|
||||
if (m_level < level_warn) {
|
||||
m_level = level_warn;
|
||||
draw_box();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
status_bar::do_fail(const wchar_t *message, uefi::status status)
|
||||
{
|
||||
m_status = status;
|
||||
if (m_level < level_fail) {
|
||||
m_level = level_fail;
|
||||
draw_box();
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
make_color(uint8_t r, uint8_t g, uint8_t b, uint16_t type)
|
||||
{
|
||||
switch (static_cast<kernel::args::fb_type>(type)) {
|
||||
case kernel::args::fb_type::bgr8:
|
||||
return
|
||||
(static_cast<uint32_t>(b) << 0) |
|
||||
(static_cast<uint32_t>(g) << 8) |
|
||||
(static_cast<uint32_t>(r) << 16);
|
||||
|
||||
case kernel::args::fb_type::rgb8:
|
||||
return
|
||||
(static_cast<uint32_t>(r) << 0) |
|
||||
(static_cast<uint32_t>(g) << 8) |
|
||||
(static_cast<uint32_t>(b) << 16);
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
status_bar::draw_box()
|
||||
{
|
||||
static const uint32_t colors[] = {0x909090, 0xf0f0f0};
|
||||
constexpr unsigned ncolors = sizeof(colors) / sizeof(uint32_t);
|
||||
|
||||
if (m_fb == nullptr)
|
||||
return;
|
||||
|
||||
unsigned x0 = m_current * m_size;
|
||||
unsigned x1 = x0 + m_size - 3;
|
||||
unsigned y0 = m_top;
|
||||
unsigned y1 = m_top + m_size - 3;
|
||||
|
||||
uint32_t color = 0;
|
||||
switch (m_level) {
|
||||
case level_ok:
|
||||
color = colors[m_current % ncolors];
|
||||
break;
|
||||
case level_warn:
|
||||
color = make_color(0xff, 0xb2, 0x34, m_type);
|
||||
break;
|
||||
case level_fail:
|
||||
color = make_color(0xfb, 0x0a, 0x1e, m_type);
|
||||
break;
|
||||
default:
|
||||
color = 0;
|
||||
}
|
||||
|
||||
for (unsigned y = y0; y < y1; ++y)
|
||||
for (unsigned x = x0; x < x1; ++x)
|
||||
m_fb[y * m_horiz + x] = color;
|
||||
|
||||
if (m_level > level_ok) {
|
||||
unsigned nbars = static_cast<uint64_t>(m_status) & 0xffff;
|
||||
constexpr unsigned bar_height = 4;
|
||||
|
||||
for (unsigned i = 1; i <= nbars; ++i) {
|
||||
y0 = m_top - 2 * i * bar_height;
|
||||
y1 = y0 + bar_height;
|
||||
|
||||
for (unsigned y = y0; y < y1; ++y)
|
||||
for (unsigned x = x0; x < x1; ++x)
|
||||
m_fb[y * m_horiz + x] = color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace boot
|
||||
122
src/boot/status.h
Normal file
122
src/boot/status.h
Normal file
@@ -0,0 +1,122 @@
|
||||
/// \file status.h
|
||||
/// Status message and indicator handling
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <uefi/types.h>
|
||||
|
||||
namespace kernel {
|
||||
namespace args {
|
||||
class framebuffer;
|
||||
}
|
||||
}
|
||||
|
||||
namespace boot {
|
||||
|
||||
// Abstract base class for status reporters.
|
||||
class status
|
||||
{
|
||||
public:
|
||||
virtual void do_warn(const wchar_t *message, uefi::status status) = 0;
|
||||
virtual void do_fail(const wchar_t *message, uefi::status status) = 0;
|
||||
|
||||
/// Set the state to warning, and print a message. If the state is already at
|
||||
/// warning or error, the state is unchanged but the message is still printed.
|
||||
/// \arg message The warning message to print, if text is supported
|
||||
/// \arg status If set, the error or warning code that should be represented
|
||||
/// \returns True if there was a status handler to display the warning
|
||||
inline static bool warn(const wchar_t *message, uefi::status status = uefi::status::success) {
|
||||
if (!s_current) return false;
|
||||
s_current->do_warn(message, status);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Set the state to error, and print a message. If the state is already at
|
||||
/// error, the state is unchanged but the message is still printed.
|
||||
/// \arg message The error message to print, if text is supported
|
||||
/// \arg status The error or warning code that should be represented
|
||||
/// \returns True if there was a status handler to display the failure
|
||||
inline static bool fail(const wchar_t *message, uefi::status status) {
|
||||
if (!s_current) return false;
|
||||
s_current->do_fail(message, status);
|
||||
return true;
|
||||
}
|
||||
|
||||
protected:
|
||||
static status *s_current;
|
||||
static unsigned s_current_type;
|
||||
};
|
||||
|
||||
/// Scoped status line reporter. Prints a message and an "OK" if no errors
|
||||
/// or warnings were reported before destruction, otherwise reports the
|
||||
/// error or warning.
|
||||
class status_line :
|
||||
public status
|
||||
{
|
||||
public:
|
||||
constexpr static unsigned type = 1;
|
||||
|
||||
/// Constructor.
|
||||
/// \arg message Description of the operation in progress
|
||||
/// \arg context If non-null, printed after `message` and a colon
|
||||
status_line(const wchar_t *message, const wchar_t *context = nullptr);
|
||||
~status_line();
|
||||
|
||||
virtual void do_warn(const wchar_t *message, uefi::status status) override;
|
||||
virtual void do_fail(const wchar_t *message, uefi::status status) override;
|
||||
|
||||
private:
|
||||
void print_status_tag();
|
||||
|
||||
size_t m_line;
|
||||
int m_level;
|
||||
int m_depth;
|
||||
|
||||
status_line *m_outer;
|
||||
};
|
||||
|
||||
/// Scoped status bar reporter. Draws a row of boxes along the bottom of
|
||||
/// the screen, turning one red if there's an error in that step.
|
||||
class status_bar :
|
||||
public status
|
||||
{
|
||||
public:
|
||||
constexpr static unsigned type = 2;
|
||||
|
||||
using framebuffer = kernel::args::framebuffer;
|
||||
|
||||
/// Constructor.
|
||||
/// \arg fb The framebuffer descriptor to draw to
|
||||
status_bar(kernel::args::framebuffer const &fb);
|
||||
~status_bar();
|
||||
|
||||
virtual void do_warn(const wchar_t *message, uefi::status status) override;
|
||||
virtual void do_fail(const wchar_t *message, uefi::status status) override;
|
||||
|
||||
inline void next() {
|
||||
m_current = s_count++;
|
||||
m_level = 0;
|
||||
m_status = uefi::status::success;
|
||||
draw_box();
|
||||
}
|
||||
|
||||
private:
|
||||
void draw_box();
|
||||
|
||||
uint32_t *m_fb;
|
||||
uint32_t m_size;
|
||||
uint32_t m_top;
|
||||
uint32_t m_horiz;
|
||||
|
||||
int m_level;
|
||||
uefi::status m_status;
|
||||
|
||||
uint16_t m_type;
|
||||
uint16_t m_current;
|
||||
|
||||
status_bar *m_outer;
|
||||
|
||||
static unsigned s_count;
|
||||
};
|
||||
|
||||
} // namespace boot
|
||||
390
src/drivers/fb/default_font.inc
Normal file
390
src/drivers/fb/default_font.inc
Normal file
@@ -0,0 +1,390 @@
|
||||
0x72, 0xb5, 0x4a, 0x86, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
|
||||
0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x7e, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x7e, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa,
|
||||
0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x38, 0x44, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0xf8,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0xf8, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x08, 0x08, 0x08, 0x08,
|
||||
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x0f,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08,
|
||||
0x08, 0x08, 0x08, 0xff, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08,
|
||||
0x08, 0x08, 0x08, 0x0f, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
|
||||
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0xf8, 0x08, 0x08, 0x08, 0x08,
|
||||
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0xff,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0xff, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
|
||||
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
|
||||
0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c,
|
||||
0x22, 0x20, 0x20, 0xf8, 0x20, 0x20, 0x72, 0x8c, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10,
|
||||
0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x24, 0x24, 0x24, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x24, 0x7e, 0x24, 0x24,
|
||||
0x24, 0x7e, 0x24, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08,
|
||||
0x1e, 0x20, 0x20, 0x1c, 0x02, 0x02, 0x3c, 0x08, 0x08, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x30, 0x49, 0x4a, 0x34, 0x08, 0x16, 0x29, 0x49, 0x06,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x48, 0x48, 0x48, 0x30, 0x31,
|
||||
0x49, 0x46, 0x46, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10,
|
||||
0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x04, 0x08, 0x08, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x08,
|
||||
0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x20, 0x10, 0x10, 0x08, 0x08, 0x08,
|
||||
0x08, 0x08, 0x08, 0x10, 0x10, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x24, 0x18, 0x7e, 0x18, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x7f, 0x08, 0x08, 0x08, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x18, 0x18, 0x08, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x04, 0x04, 0x08, 0x08,
|
||||
0x10, 0x10, 0x20, 0x20, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
|
||||
0x42, 0x46, 0x4a, 0x52, 0x62, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x08, 0x18, 0x28, 0x08, 0x08, 0x08, 0x08, 0x08, 0x3e,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x02, 0x02, 0x04,
|
||||
0x08, 0x10, 0x20, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e,
|
||||
0x04, 0x08, 0x1c, 0x02, 0x02, 0x02, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x04, 0x0c, 0x14, 0x24, 0x44, 0x7e, 0x04, 0x04, 0x04,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x40, 0x40, 0x7c, 0x02,
|
||||
0x02, 0x02, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c,
|
||||
0x20, 0x40, 0x40, 0x7c, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x7e, 0x02, 0x04, 0x04, 0x08, 0x08, 0x10, 0x10, 0x10,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x3c,
|
||||
0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
|
||||
0x42, 0x42, 0x42, 0x3e, 0x02, 0x02, 0x04, 0x38, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00,
|
||||
0x00, 0x00, 0x18, 0x18, 0x08, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x04,
|
||||
0x08, 0x10, 0x20, 0x40, 0x20, 0x10, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x7e, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x10, 0x08, 0x04, 0x02,
|
||||
0x04, 0x08, 0x10, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x42,
|
||||
0x02, 0x04, 0x08, 0x10, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x1c, 0x22, 0x41, 0x4f, 0x51, 0x51, 0x51, 0x53, 0x4d, 0x40,
|
||||
0x20, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x24, 0x42, 0x42, 0x42,
|
||||
0x7e, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c,
|
||||
0x42, 0x42, 0x42, 0x7c, 0x42, 0x42, 0x42, 0x7c, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x1e, 0x20, 0x40, 0x40, 0x40, 0x40, 0x40, 0x20, 0x1e,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x44, 0x42, 0x42, 0x42,
|
||||
0x42, 0x42, 0x44, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e,
|
||||
0x40, 0x40, 0x40, 0x7c, 0x40, 0x40, 0x40, 0x7e, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x7e, 0x40, 0x40, 0x40, 0x7c, 0x40, 0x40, 0x40, 0x40,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x20, 0x40, 0x40, 0x46,
|
||||
0x42, 0x42, 0x22, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42,
|
||||
0x42, 0x42, 0x42, 0x7e, 0x42, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x3e, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x3e,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02,
|
||||
0x02, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42,
|
||||
0x44, 0x48, 0x50, 0x60, 0x50, 0x48, 0x44, 0x42, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x7e,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x63, 0x55, 0x49, 0x49,
|
||||
0x41, 0x41, 0x41, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42,
|
||||
0x62, 0x52, 0x4a, 0x46, 0x42, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x42, 0x42, 0x42, 0x7c,
|
||||
0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
|
||||
0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x04, 0x02, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x7c, 0x42, 0x42, 0x42, 0x7c, 0x48, 0x44, 0x42, 0x42,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x40, 0x40, 0x20, 0x18,
|
||||
0x04, 0x02, 0x02, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f,
|
||||
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x42, 0x42, 0x42, 0x42,
|
||||
0x24, 0x24, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41,
|
||||
0x41, 0x41, 0x41, 0x49, 0x49, 0x49, 0x55, 0x63, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x41, 0x41, 0x22, 0x14, 0x08, 0x14, 0x22, 0x41, 0x41,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x41, 0x22, 0x14, 0x08,
|
||||
0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e,
|
||||
0x04, 0x08, 0x08, 0x10, 0x10, 0x20, 0x20, 0x7e, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x1e, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
|
||||
0x10, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x40, 0x40, 0x20, 0x20, 0x10, 0x10,
|
||||
0x08, 0x08, 0x04, 0x04, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x78, 0x08,
|
||||
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x78, 0x00, 0x00,
|
||||
0x00, 0x00, 0x10, 0x28, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x20, 0x10, 0x08,
|
||||
0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x02, 0x02, 0x3e, 0x42, 0x42, 0x3e,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x40, 0x40, 0x7c, 0x42, 0x42,
|
||||
0x42, 0x42, 0x42, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x3c, 0x42, 0x40, 0x40, 0x40, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x02, 0x02, 0x02, 0x3e, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3e,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x42,
|
||||
0x7e, 0x40, 0x40, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x10,
|
||||
0x10, 0x7e, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3e,
|
||||
0x02, 0x02, 0x3c, 0x00, 0x00, 0x00, 0x40, 0x40, 0x40, 0x7c, 0x42, 0x42,
|
||||
0x42, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08,
|
||||
0x00, 0x38, 0x08, 0x08, 0x08, 0x08, 0x08, 0x3e, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x04, 0x04, 0x00, 0x1c, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
|
||||
0x04, 0x04, 0x38, 0x00, 0x00, 0x00, 0x40, 0x40, 0x40, 0x44, 0x48, 0x50,
|
||||
0x70, 0x48, 0x44, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x08,
|
||||
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x3e, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x42, 0x42,
|
||||
0x42, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x42, 0x42, 0x42, 0x42, 0x42, 0x7c,
|
||||
0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x42, 0x42,
|
||||
0x42, 0x42, 0x42, 0x3e, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x2e, 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x40, 0x20, 0x18, 0x04, 0x02, 0x7c,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x7e, 0x10, 0x10,
|
||||
0x10, 0x10, 0x10, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3e, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x42, 0x42, 0x24, 0x24, 0x18, 0x18,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x41, 0x41,
|
||||
0x49, 0x49, 0x55, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x41, 0x22, 0x14, 0x08, 0x14, 0x22, 0x41, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3e,
|
||||
0x02, 0x02, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x04, 0x08,
|
||||
0x10, 0x20, 0x40, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x10, 0x10,
|
||||
0x10, 0x10, 0x10, 0xe0, 0x10, 0x10, 0x10, 0x10, 0x10, 0x0e, 0x00, 0x00,
|
||||
0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
|
||||
0x08, 0x08, 0x00, 0x00, 0x00, 0x70, 0x08, 0x08, 0x08, 0x08, 0x08, 0x07,
|
||||
0x08, 0x08, 0x08, 0x08, 0x08, 0x70, 0x00, 0x00, 0x00, 0x00, 0x31, 0x49,
|
||||
0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x00,
|
||||
0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x08, 0x08,
|
||||
0x1c, 0x22, 0x40, 0x40, 0x40, 0x22, 0x1c, 0x08, 0x08, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x1c, 0x22, 0x20, 0x20, 0xf8, 0x20, 0x20, 0x72, 0x8c,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x3c, 0x24, 0x24,
|
||||
0x24, 0x3c, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41,
|
||||
0x22, 0x14, 0x08, 0x3e, 0x08, 0x3e, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x08, 0x08,
|
||||
0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x1c, 0x22, 0x41, 0x4d, 0x51, 0x51, 0x4d, 0x41, 0x22,
|
||||
0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x09, 0x12, 0x24, 0x48, 0x24, 0x12, 0x09, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x44, 0x44, 0x44, 0x38,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x08, 0x08, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x24, 0x12, 0x09, 0x12, 0x24, 0x48,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x00,
|
||||
0x00, 0x08, 0x10, 0x20, 0x40, 0x42, 0x3c, 0x00, 0x20, 0x10, 0x00, 0x18,
|
||||
0x18, 0x24, 0x24, 0x24, 0x7e, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00,
|
||||
0x04, 0x08, 0x00, 0x18, 0x18, 0x24, 0x24, 0x24, 0x7e, 0x42, 0x42, 0x42,
|
||||
0x00, 0x00, 0x00, 0x00, 0x18, 0x24, 0x00, 0x18, 0x18, 0x24, 0x24, 0x24,
|
||||
0x7e, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00, 0x32, 0x4c, 0x00, 0x18,
|
||||
0x18, 0x24, 0x24, 0x24, 0x7e, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00,
|
||||
0x24, 0x24, 0x00, 0x18, 0x18, 0x24, 0x24, 0x24, 0x7e, 0x42, 0x42, 0x42,
|
||||
0x00, 0x00, 0x00, 0x00, 0x18, 0x24, 0x24, 0x18, 0x18, 0x24, 0x24, 0x24,
|
||||
0x7e, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f,
|
||||
0x14, 0x14, 0x24, 0x27, 0x3c, 0x44, 0x44, 0x47, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x1e, 0x20, 0x40, 0x40, 0x40, 0x40, 0x40, 0x20, 0x1e,
|
||||
0x08, 0x08, 0x30, 0x00, 0x20, 0x10, 0x00, 0x7e, 0x40, 0x40, 0x40, 0x7c,
|
||||
0x40, 0x40, 0x40, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x04, 0x08, 0x00, 0x7e,
|
||||
0x40, 0x40, 0x40, 0x7c, 0x40, 0x40, 0x40, 0x7e, 0x00, 0x00, 0x00, 0x00,
|
||||
0x18, 0x24, 0x00, 0x7e, 0x40, 0x40, 0x40, 0x7c, 0x40, 0x40, 0x40, 0x7e,
|
||||
0x00, 0x00, 0x00, 0x00, 0x24, 0x24, 0x00, 0x7e, 0x40, 0x40, 0x40, 0x7c,
|
||||
0x40, 0x40, 0x40, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x10, 0x08, 0x00, 0x3e,
|
||||
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x3e, 0x00, 0x00, 0x00, 0x00,
|
||||
0x04, 0x08, 0x00, 0x3e, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x3e,
|
||||
0x00, 0x00, 0x00, 0x00, 0x18, 0x24, 0x00, 0x3e, 0x08, 0x08, 0x08, 0x08,
|
||||
0x08, 0x08, 0x08, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x00, 0x3e,
|
||||
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x3e, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x3c, 0x22, 0x21, 0x21, 0x79, 0x21, 0x21, 0x22, 0x3c,
|
||||
0x00, 0x00, 0x00, 0x00, 0x32, 0x4c, 0x00, 0x42, 0x62, 0x52, 0x4a, 0x46,
|
||||
0x42, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00, 0x10, 0x08, 0x00, 0x1c,
|
||||
0x22, 0x41, 0x41, 0x41, 0x41, 0x41, 0x22, 0x1c, 0x00, 0x00, 0x00, 0x00,
|
||||
0x04, 0x08, 0x00, 0x1c, 0x22, 0x41, 0x41, 0x41, 0x41, 0x41, 0x22, 0x1c,
|
||||
0x00, 0x00, 0x00, 0x00, 0x18, 0x24, 0x00, 0x1c, 0x22, 0x41, 0x41, 0x41,
|
||||
0x41, 0x41, 0x22, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x32, 0x4c, 0x00, 0x1c,
|
||||
0x22, 0x41, 0x41, 0x41, 0x41, 0x41, 0x22, 0x1c, 0x00, 0x00, 0x00, 0x00,
|
||||
0x24, 0x24, 0x00, 0x1c, 0x22, 0x41, 0x41, 0x41, 0x41, 0x41, 0x22, 0x1c,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x14,
|
||||
0x08, 0x14, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x3c,
|
||||
0x42, 0x46, 0x4a, 0x52, 0x62, 0x42, 0x42, 0x3c, 0x40, 0x00, 0x00, 0x00,
|
||||
0x20, 0x10, 0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c,
|
||||
0x00, 0x00, 0x00, 0x00, 0x04, 0x08, 0x00, 0x42, 0x42, 0x42, 0x42, 0x42,
|
||||
0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x18, 0x24, 0x00, 0x42,
|
||||
0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00,
|
||||
0x24, 0x24, 0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c,
|
||||
0x00, 0x00, 0x00, 0x00, 0x04, 0x08, 0x00, 0x41, 0x41, 0x22, 0x14, 0x08,
|
||||
0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40,
|
||||
0x40, 0x7c, 0x42, 0x42, 0x42, 0x7c, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x3c, 0x42, 0x44, 0x4c, 0x42, 0x42, 0x42, 0x44, 0x58,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x10, 0x00, 0x3c, 0x02, 0x02,
|
||||
0x3e, 0x42, 0x42, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x08,
|
||||
0x00, 0x3c, 0x02, 0x02, 0x3e, 0x42, 0x42, 0x3e, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x18, 0x24, 0x00, 0x00, 0x3c, 0x02, 0x02, 0x3e, 0x42, 0x42, 0x3e,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0x4c, 0x00, 0x00, 0x3c, 0x02, 0x02,
|
||||
0x3e, 0x42, 0x42, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x24,
|
||||
0x00, 0x3c, 0x02, 0x02, 0x3e, 0x42, 0x42, 0x3e, 0x00, 0x00, 0x00, 0x00,
|
||||
0x18, 0x24, 0x24, 0x18, 0x00, 0x3c, 0x02, 0x02, 0x3e, 0x42, 0x42, 0x3e,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x09, 0x39,
|
||||
0x4f, 0x48, 0x48, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x3c, 0x42, 0x40, 0x40, 0x40, 0x42, 0x3c, 0x08, 0x08, 0x30, 0x00,
|
||||
0x00, 0x00, 0x20, 0x10, 0x00, 0x3c, 0x42, 0x42, 0x7e, 0x40, 0x40, 0x3e,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x08, 0x00, 0x3c, 0x42, 0x42,
|
||||
0x7e, 0x40, 0x40, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x24, 0x00,
|
||||
0x00, 0x3c, 0x42, 0x42, 0x7e, 0x40, 0x40, 0x3e, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x24, 0x24, 0x00, 0x3c, 0x42, 0x42, 0x7e, 0x40, 0x40, 0x3e,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x08, 0x00, 0x38, 0x08, 0x08,
|
||||
0x08, 0x08, 0x08, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x08,
|
||||
0x00, 0x38, 0x08, 0x08, 0x08, 0x08, 0x08, 0x3e, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x18, 0x24, 0x00, 0x00, 0x38, 0x08, 0x08, 0x08, 0x08, 0x08, 0x3e,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x24, 0x00, 0x38, 0x08, 0x08,
|
||||
0x08, 0x08, 0x08, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x06, 0x1a,
|
||||
0x01, 0x1d, 0x23, 0x41, 0x41, 0x41, 0x22, 0x1c, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x32, 0x4c, 0x00, 0x00, 0x7c, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x08, 0x00, 0x3c, 0x42, 0x42,
|
||||
0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x08,
|
||||
0x00, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x18, 0x24, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0x4c, 0x00, 0x00, 0x3c, 0x42, 0x42,
|
||||
0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x24,
|
||||
0x00, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x18, 0x18,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x3c, 0x46, 0x4a,
|
||||
0x52, 0x62, 0x42, 0x3c, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x10,
|
||||
0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3e, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x04, 0x08, 0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3e,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x24, 0x00, 0x00, 0x42, 0x42, 0x42,
|
||||
0x42, 0x42, 0x42, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x24,
|
||||
0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3e, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x04, 0x08, 0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3e,
|
||||
0x02, 0x02, 0x3c, 0x00, 0x00, 0x00, 0x40, 0x40, 0x40, 0x5c, 0x62, 0x41,
|
||||
0x41, 0x41, 0x62, 0x5c, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x24, 0x24,
|
||||
0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3e, 0x02, 0x02, 0x3c, 0x00,
|
||||
0xff, 0xff, 0xe2, 0x96, 0x92, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc2, 0xb0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xe2, 0x94, 0x98, 0xff, 0xe2, 0x94, 0x90, 0xff,
|
||||
0xe2, 0x94, 0x8c, 0xff, 0xe2, 0x94, 0x94, 0xff, 0xe2, 0x94, 0xbc, 0xff,
|
||||
0xff, 0xff, 0xe2, 0x94, 0x80, 0xff, 0xff, 0xff, 0xe2, 0x94, 0x9c, 0xff,
|
||||
0xe2, 0x94, 0xa4, 0xff, 0xe2, 0x94, 0xb4, 0xff, 0xe2, 0x94, 0xac, 0xff,
|
||||
0xe2, 0x94, 0x82, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc2, 0xa3, 0xff, 0xff,
|
||||
0x20, 0xff, 0x21, 0xff, 0x22, 0xff, 0x23, 0xff, 0x24, 0xff, 0x25, 0xff,
|
||||
0x26, 0xff, 0x27, 0xff, 0x28, 0xff, 0x29, 0xff, 0x2a, 0xff, 0x2b, 0xff,
|
||||
0x2c, 0xff, 0x2d, 0xff, 0x2e, 0xff, 0x2f, 0xff, 0x30, 0xff, 0x31, 0xff,
|
||||
0x32, 0xff, 0x33, 0xff, 0x34, 0xff, 0x35, 0xff, 0x36, 0xff, 0x37, 0xff,
|
||||
0x38, 0xff, 0x39, 0xff, 0x3a, 0xff, 0x3b, 0xff, 0x3c, 0xff, 0x3d, 0xff,
|
||||
0x3e, 0xff, 0x3f, 0xff, 0x40, 0xff, 0x41, 0xff, 0x42, 0xff, 0x43, 0xff,
|
||||
0x44, 0xff, 0x45, 0xff, 0x46, 0xff, 0x47, 0xff, 0x48, 0xff, 0x49, 0xff,
|
||||
0x4a, 0xff, 0x4b, 0xff, 0x4c, 0xff, 0x4d, 0xff, 0x4e, 0xff, 0x4f, 0xff,
|
||||
0x50, 0xff, 0x51, 0xff, 0x52, 0xff, 0x53, 0xff, 0x54, 0xff, 0x55, 0xff,
|
||||
0x56, 0xff, 0x57, 0xff, 0x58, 0xff, 0x59, 0xff, 0x5a, 0xff, 0x5b, 0xff,
|
||||
0x5c, 0xff, 0x5d, 0xff, 0x5e, 0xff, 0x5f, 0xff, 0x60, 0xff, 0x61, 0xff,
|
||||
0x62, 0xff, 0x63, 0xff, 0x64, 0xff, 0x65, 0xff, 0x66, 0xff, 0x67, 0xff,
|
||||
0x68, 0xff, 0x69, 0xff, 0x6a, 0xff, 0x6b, 0xff, 0x6c, 0xff, 0x6d, 0xff,
|
||||
0x6e, 0xff, 0x6f, 0xff, 0x70, 0xff, 0x71, 0xff, 0x72, 0xff, 0x73, 0xff,
|
||||
0x74, 0xff, 0x75, 0xff, 0x76, 0xff, 0x77, 0xff, 0x78, 0xff, 0x79, 0xff,
|
||||
0x7a, 0xff, 0x7b, 0xff, 0x7c, 0xff, 0x7d, 0xff, 0x7e, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc2, 0xa0, 0xff, 0xc2, 0xa1,
|
||||
0xff, 0xc2, 0xa2, 0xff, 0xc2, 0xa3, 0xff, 0xc2, 0xa4, 0xff, 0xc2, 0xa5,
|
||||
0xff, 0xc2, 0xa6, 0xff, 0xff, 0xc2, 0xa8, 0xff, 0xc2, 0xa9, 0xff, 0xff,
|
||||
0xc2, 0xab, 0xff, 0xff, 0xc2, 0xad, 0xff, 0xff, 0xff, 0xc2, 0xb0, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc2, 0xb8, 0xff, 0xff, 0xff,
|
||||
0xc2, 0xbb, 0xff, 0xff, 0xff, 0xff, 0xc2, 0xbf, 0xff, 0xc3, 0x80, 0xff,
|
||||
0xc3, 0x81, 0xff, 0xc3, 0x82, 0xff, 0xc3, 0x83, 0xff, 0xc3, 0x84, 0xff,
|
||||
0xc3, 0x85, 0xff, 0xc3, 0x86, 0xff, 0xc3, 0x87, 0xff, 0xc3, 0x88, 0xff,
|
||||
0xc3, 0x89, 0xff, 0xc3, 0x8a, 0xff, 0xc3, 0x8b, 0xff, 0xc3, 0x8c, 0xff,
|
||||
0xc3, 0x8d, 0xff, 0xc3, 0x8e, 0xff, 0xc3, 0x8f, 0xff, 0xc3, 0x90, 0xff,
|
||||
0xc3, 0x91, 0xff, 0xc3, 0x92, 0xff, 0xc3, 0x93, 0xff, 0xc3, 0x94, 0xff,
|
||||
0xc3, 0x95, 0xff, 0xc3, 0x96, 0xff, 0xc3, 0x97, 0xff, 0xc3, 0x98, 0xff,
|
||||
0xc3, 0x99, 0xff, 0xc3, 0x9a, 0xff, 0xc3, 0x9b, 0xff, 0xc3, 0x9c, 0xff,
|
||||
0xc3, 0x9d, 0xff, 0xc3, 0x9e, 0xff, 0xc3, 0x9f, 0xff, 0xc3, 0xa0, 0xff,
|
||||
0xc3, 0xa1, 0xff, 0xc3, 0xa2, 0xff, 0xc3, 0xa3, 0xff, 0xc3, 0xa4, 0xff,
|
||||
0xc3, 0xa5, 0xff, 0xc3, 0xa6, 0xff, 0xc3, 0xa7, 0xff, 0xc3, 0xa8, 0xff,
|
||||
0xc3, 0xa9, 0xff, 0xc3, 0xaa, 0xff, 0xc3, 0xab, 0xff, 0xc3, 0xac, 0xff,
|
||||
0xc3, 0xad, 0xff, 0xc3, 0xae, 0xff, 0xc3, 0xaf, 0xff, 0xc3, 0xb0, 0xff,
|
||||
0xc3, 0xb1, 0xff, 0xc3, 0xb2, 0xff, 0xc3, 0xb3, 0xff, 0xc3, 0xb4, 0xff,
|
||||
0xc3, 0xb5, 0xff, 0xc3, 0xb6, 0xff, 0xc3, 0xb7, 0xff, 0xc3, 0xb8, 0xff,
|
||||
0xc3, 0xb9, 0xff, 0xc3, 0xba, 0xff, 0xc3, 0xbb, 0xff, 0xc3, 0xbc, 0xff,
|
||||
0xc3, 0xbd, 0xff, 0xc3, 0xbe, 0xff, 0xc3, 0xbf, 0xff
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "kutil/assert.h"
|
||||
#include <assert.h>
|
||||
#include "font.h"
|
||||
|
||||
|
||||
/* PSF2 header format
|
||||
* Taken from the Linux KBD documentation
|
||||
* http://www.win.tue.nl/~aeb/linux/kbd/font-formats-1.html
|
||||
@@ -27,43 +28,51 @@ struct psf2_header {
|
||||
uint32_t height, width; // max dimensions of glyphs
|
||||
};
|
||||
|
||||
const uint8_t default_font[] = {
|
||||
// xxd -i < font_file.psf > default_font.inc
|
||||
#include "default_font.inc"
|
||||
};
|
||||
|
||||
font::font(void const *data) :
|
||||
m_size(0, 0),
|
||||
m_count(0),
|
||||
m_data(nullptr)
|
||||
m_sizex {0},
|
||||
m_sizey {0},
|
||||
m_count {0},
|
||||
m_data {nullptr}
|
||||
{
|
||||
if (!data)
|
||||
data = default_font;
|
||||
|
||||
psf2_header const *psf2 = static_cast<psf2_header const *>(data);
|
||||
for (int i = 0; i < sizeof(magic); ++i) {
|
||||
kassert(psf2->magic[i] == magic[i], "Bad font magic number.");
|
||||
assert(psf2->magic[i] == magic[i] && "Bad font magic number.");
|
||||
}
|
||||
|
||||
m_data = static_cast<uint8_t const *>(data) + psf2->header_size;
|
||||
m_size.x = psf2->width;
|
||||
m_size.y = psf2->height;
|
||||
m_sizex = psf2->width;
|
||||
m_sizey = psf2->height;
|
||||
m_count = psf2->length;
|
||||
}
|
||||
|
||||
void
|
||||
font::draw_glyph(
|
||||
screen *s,
|
||||
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;
|
||||
unsigned bwidth = (m_sizex+7)/8;
|
||||
uint8_t const *data = m_data + (glyph * glyph_bytes());
|
||||
|
||||
for (int dy = 0; dy < m_size.y; ++dy) {
|
||||
for (int dy = 0; dy < m_sizey; ++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;
|
||||
if (dx*8 + i >= m_sizex) break;
|
||||
const uint8_t mask = 1 << (7-i);
|
||||
uint32_t c = (byte & mask) ? fg : bg;
|
||||
s->draw_pixel(x + dx*8 + i, y + dy, c);
|
||||
s.draw_pixel(x + dx*8 + i, y + dy, c);
|
||||
}
|
||||
}
|
||||
}
|
||||
33
src/drivers/fb/font.h
Normal file
33
src/drivers/fb/font.h
Normal file
@@ -0,0 +1,33 @@
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
|
||||
#include "screen.h"
|
||||
|
||||
class font
|
||||
{
|
||||
public:
|
||||
/// Constructor.
|
||||
/// \arg data The font data to load. If null, will load the default
|
||||
/// built-in font.
|
||||
font(void const *data = nullptr);
|
||||
|
||||
unsigned glyph_bytes() const { return m_sizey * ((m_sizex + 7) / 8); }
|
||||
unsigned count() const { return m_count; }
|
||||
unsigned width() const { return m_sizex; }
|
||||
unsigned height() const { return m_sizey; }
|
||||
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:
|
||||
unsigned m_sizex, m_sizey;
|
||||
unsigned m_count;
|
||||
uint8_t const *m_data;
|
||||
};
|
||||
|
||||
105
src/drivers/fb/main.cpp
Normal file
105
src/drivers/fb/main.cpp
Normal file
@@ -0,0 +1,105 @@
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "j6/init.h"
|
||||
#include "j6/errors.h"
|
||||
#include "j6/signals.h"
|
||||
#include "j6/types.h"
|
||||
|
||||
#include <j6libc/syscalls.h>
|
||||
|
||||
#include "font.h"
|
||||
#include "screen.h"
|
||||
#include "scrollback.h"
|
||||
|
||||
extern "C" {
|
||||
int main(int, const char **);
|
||||
void _get_init(size_t *initc, struct j6_init_value **initv);
|
||||
}
|
||||
|
||||
extern j6_handle_t __handle_sys;
|
||||
|
||||
struct entry
|
||||
{
|
||||
uint8_t bytes;
|
||||
uint8_t area;
|
||||
uint8_t severity;
|
||||
uint8_t sequence;
|
||||
char message[0];
|
||||
};
|
||||
|
||||
int
|
||||
main(int argc, const char **argv)
|
||||
{
|
||||
_syscall_system_log("fb driver starting");
|
||||
|
||||
size_t initc = 0;
|
||||
j6_init_value *initv = nullptr;
|
||||
_get_init(&initc, &initv);
|
||||
|
||||
j6_init_framebuffer *fb = nullptr;
|
||||
for (unsigned i = 0; i < initc; ++i) {
|
||||
if (initv[i].type == j6_init_desc_framebuffer) {
|
||||
fb = reinterpret_cast<j6_init_framebuffer*>(initv[i].value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!fb || fb->addr == nullptr) {
|
||||
_syscall_system_log("fb driver didn't find a framebuffer, exiting");
|
||||
return 1;
|
||||
}
|
||||
|
||||
const screen::pixel_order order = (fb->flags & 1) ?
|
||||
screen::pixel_order::bgr8 : screen::pixel_order::rgb8;
|
||||
|
||||
screen scr(fb->addr, fb->horizontal, fb->vertical, order);
|
||||
font fnt;
|
||||
|
||||
screen::pixel_t fg = scr.color(0xb0, 0xb0, 0xb0);
|
||||
screen::pixel_t bg = scr.color(49, 79, 128);
|
||||
scr.fill(bg);
|
||||
scr.update();
|
||||
|
||||
constexpr int margin = 2;
|
||||
const unsigned xstride = (margin + fnt.width());
|
||||
const unsigned ystride = (margin + fnt.height());
|
||||
const unsigned rows = (scr.height() - margin) / ystride;
|
||||
const unsigned cols = (scr.width() - margin) / xstride;
|
||||
|
||||
scrollback scroll(rows, cols);
|
||||
|
||||
int pending = 0;
|
||||
constexpr int pending_threshold = 10;
|
||||
|
||||
char message_buffer[256];
|
||||
while (true) {
|
||||
size_t size = sizeof(message_buffer);
|
||||
_syscall_system_get_log(__handle_sys, message_buffer, &size);
|
||||
if (size != 0) {
|
||||
entry *e = reinterpret_cast<entry*>(&message_buffer);
|
||||
|
||||
size_t eom = e->bytes - sizeof(entry);
|
||||
e->message[eom] = 0;
|
||||
|
||||
scroll.add_line(e->message, eom);
|
||||
if (++pending > pending_threshold) {
|
||||
scroll.render(scr, fnt);
|
||||
scr.update();
|
||||
pending = 0;
|
||||
}
|
||||
} else {
|
||||
if (pending) {
|
||||
scroll.render(scr, fnt);
|
||||
scr.update();
|
||||
pending = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
_syscall_system_log("fb driver done, exiting");
|
||||
return 0;
|
||||
}
|
||||
|
||||
50
src/drivers/fb/screen.cpp
Normal file
50
src/drivers/fb/screen.cpp
Normal file
@@ -0,0 +1,50 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "screen.h"
|
||||
|
||||
screen::screen(void *addr, unsigned hres, unsigned vres, pixel_order order) :
|
||||
m_fb(static_cast<pixel_t *>(addr)),
|
||||
m_order(order),
|
||||
m_resx(hres),
|
||||
m_resy(vres)
|
||||
{
|
||||
m_back = reinterpret_cast<pixel_t*>(malloc(hres*vres*sizeof(pixel_t)));
|
||||
}
|
||||
|
||||
screen::pixel_t
|
||||
screen::color(uint8_t r, uint8_t g, uint8_t b) const
|
||||
{
|
||||
switch (m_order) {
|
||||
case pixel_order::bgr8:
|
||||
return
|
||||
(static_cast<uint32_t>(b) << 0) |
|
||||
(static_cast<uint32_t>(g) << 8) |
|
||||
(static_cast<uint32_t>(r) << 16);
|
||||
|
||||
case pixel_order::rgb8:
|
||||
return
|
||||
(static_cast<uint32_t>(r) << 0) |
|
||||
(static_cast<uint32_t>(g) << 8) |
|
||||
(static_cast<uint32_t>(b) << 16);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
screen::fill(pixel_t color)
|
||||
{
|
||||
const size_t len = m_resx * m_resy;
|
||||
for (size_t i = 0; i < len; ++i)
|
||||
m_back[i] = color;
|
||||
}
|
||||
|
||||
void
|
||||
screen::draw_pixel(unsigned x, unsigned y, pixel_t color)
|
||||
{
|
||||
m_back[x + y * m_resx] = color;
|
||||
}
|
||||
|
||||
void
|
||||
screen::update()
|
||||
{
|
||||
memcpy(m_fb, m_back, m_resx*m_resy*sizeof(pixel_t));
|
||||
}
|
||||
30
src/drivers/fb/screen.h
Normal file
30
src/drivers/fb/screen.h
Normal file
@@ -0,0 +1,30 @@
|
||||
#pragma once
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
class screen
|
||||
{
|
||||
public:
|
||||
using pixel_t = uint32_t;
|
||||
|
||||
enum class pixel_order : uint8_t { bgr8, rgb8, };
|
||||
|
||||
screen(void *addr, unsigned hres, unsigned vres, pixel_order order);
|
||||
|
||||
unsigned width() const { return m_resx; }
|
||||
unsigned height() const { return m_resy; }
|
||||
|
||||
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);
|
||||
|
||||
void update();
|
||||
|
||||
private:
|
||||
pixel_t *m_fb, *m_back;
|
||||
pixel_order m_order;
|
||||
unsigned m_resx, m_resy;
|
||||
|
||||
screen() = delete;
|
||||
};
|
||||
56
src/drivers/fb/scrollback.cpp
Normal file
56
src/drivers/fb/scrollback.cpp
Normal file
@@ -0,0 +1,56 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "font.h"
|
||||
#include "screen.h"
|
||||
#include "scrollback.h"
|
||||
|
||||
scrollback::scrollback(unsigned lines, unsigned cols, unsigned margin) :
|
||||
m_rows {lines},
|
||||
m_cols {cols},
|
||||
m_count {0},
|
||||
m_margin {margin}
|
||||
{
|
||||
m_data = reinterpret_cast<char*>(malloc(lines*cols));
|
||||
m_lines = reinterpret_cast<char**>(malloc(lines*sizeof(char*)));
|
||||
for (unsigned i = 0; i < lines; ++i)
|
||||
m_lines[i] = &m_data[i*cols];
|
||||
|
||||
memset(m_data, ' ', lines*cols);
|
||||
}
|
||||
|
||||
void
|
||||
scrollback::add_line(const char *line, size_t len)
|
||||
{
|
||||
unsigned i = m_count++ % m_rows;
|
||||
|
||||
if (len > m_cols)
|
||||
len = m_cols;
|
||||
|
||||
memcpy(m_lines[i], line, len);
|
||||
if (len < m_cols)
|
||||
memset(m_lines[i]+len, ' ', m_cols - len);
|
||||
}
|
||||
|
||||
char *
|
||||
scrollback::get_line(unsigned i)
|
||||
{
|
||||
return m_lines[(i+m_count)%m_rows];
|
||||
}
|
||||
|
||||
void
|
||||
scrollback::render(screen &scr, font &fnt)
|
||||
{
|
||||
screen::pixel_t fg = scr.color(0xb0, 0xb0, 0xb0);
|
||||
screen::pixel_t bg = scr.color(49, 79, 128);
|
||||
|
||||
const unsigned xstride = (m_margin + fnt.width());
|
||||
const unsigned ystride = (m_margin + fnt.height());
|
||||
|
||||
for (unsigned y = 0; y < m_rows; ++y) {
|
||||
char *line = get_line(y);
|
||||
for (unsigned x = 0; x < m_cols; ++x) {
|
||||
fnt.draw_glyph(scr, line[x], fg, bg, m_margin+x*xstride, m_margin+y*ystride);
|
||||
}
|
||||
}
|
||||
}
|
||||
26
src/drivers/fb/scrollback.h
Normal file
26
src/drivers/fb/scrollback.h
Normal file
@@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
/// \file scrollback.h
|
||||
|
||||
class screen;
|
||||
class font;
|
||||
|
||||
class scrollback
|
||||
{
|
||||
public:
|
||||
scrollback(unsigned lines, unsigned cols, unsigned margin = 2);
|
||||
|
||||
void add_line(const char *line, size_t len);
|
||||
|
||||
char * get_line(unsigned i);
|
||||
|
||||
void render(screen &scr, font &fnt);
|
||||
|
||||
private:
|
||||
char *m_data;
|
||||
char **m_lines;
|
||||
unsigned m_rows, m_cols;
|
||||
unsigned m_start;
|
||||
unsigned m_count;
|
||||
unsigned m_margin;
|
||||
};
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
#include "serial.h"
|
||||
|
||||
char inbuf[1024];
|
||||
j6_handle_t sys = j6_handle_invalid;
|
||||
extern j6_handle_t __handle_sys;
|
||||
j6_handle_t endp = j6_handle_invalid;
|
||||
|
||||
extern "C" {
|
||||
@@ -51,12 +51,6 @@ thread_proc()
|
||||
_syscall_thread_exit(0);
|
||||
}
|
||||
|
||||
void
|
||||
_init_libc(j6_process_init *init)
|
||||
{
|
||||
sys = init->handles[0];
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, const char **argv)
|
||||
{
|
||||
@@ -65,6 +59,9 @@ main(int argc, const char **argv)
|
||||
|
||||
_syscall_system_log("main thread starting");
|
||||
|
||||
for (int i = 0; i < argc; ++i)
|
||||
_syscall_system_log(argv[i]);
|
||||
|
||||
void *base = malloc(0x1000);
|
||||
if (!base)
|
||||
return 1;
|
||||
@@ -97,7 +94,7 @@ main(int argc, const char **argv)
|
||||
if (tag != 17)
|
||||
_syscall_system_log("GOT WRONG TAG FROM SENDRECV");
|
||||
|
||||
result = _syscall_system_bind_irq(sys, endp, 3);
|
||||
result = _syscall_system_bind_irq(__handle_sys, endp, 3);
|
||||
if (result != j6_status_ok)
|
||||
return result;
|
||||
|
||||
|
||||
30
src/include/j6/init.h
Normal file
30
src/include/j6/init.h
Normal file
@@ -0,0 +1,30 @@
|
||||
#pragma once
|
||||
/// \file init.h
|
||||
/// Types used in process and thread initialization
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
enum j6_init_type { // `value` is a:
|
||||
j6_init_handle_system, // Handle to the system
|
||||
j6_init_handle_process, // Handle to this process
|
||||
j6_init_handle_thread, // Handle to this thread
|
||||
j6_init_handle_space, // Handle to this process' address space
|
||||
j6_init_desc_framebuffer // Pointer to a j6_init_framebuffer descriptor
|
||||
};
|
||||
|
||||
struct j6_init_value {
|
||||
enum j6_init_type type;
|
||||
uint64_t value;
|
||||
};
|
||||
|
||||
/// Structure defining a framebuffer.
|
||||
/// `flags` has the following bits:
|
||||
/// 0-3: Pixel layout. 0000: rgb8, 0001: bgr8
|
||||
struct j6_init_framebuffer {
|
||||
void* addr;
|
||||
size_t size;
|
||||
uint32_t vertical;
|
||||
uint32_t horizontal;
|
||||
uint32_t scanline;
|
||||
uint32_t flags;
|
||||
};
|
||||
@@ -18,6 +18,7 @@ typedef uint64_t j6_signal_t;
|
||||
typedef uint64_t j6_tag_t;
|
||||
|
||||
#define j6_tag_system_flag 0x8000000000000000
|
||||
#define j6_tag_invalid 0x0000000000000000
|
||||
|
||||
/// If all high bits except the last 16 are set, then the tag represents
|
||||
/// an IRQ.
|
||||
|
||||
@@ -11,8 +11,7 @@ constexpr uint32_t magic = 0x600dda7a;
|
||||
constexpr uint16_t version = 1;
|
||||
|
||||
enum class mod_type : uint32_t {
|
||||
symbol_table,
|
||||
framebuffer
|
||||
symbol_table
|
||||
};
|
||||
|
||||
struct module {
|
||||
@@ -21,6 +20,21 @@ struct module {
|
||||
mod_type type;
|
||||
};
|
||||
|
||||
enum class fb_type : uint16_t {
|
||||
none,
|
||||
rgb8,
|
||||
bgr8
|
||||
};
|
||||
|
||||
struct framebuffer {
|
||||
uintptr_t phys_addr;
|
||||
size_t size;
|
||||
uint32_t vertical;
|
||||
uint32_t horizontal;
|
||||
uint16_t scanline;
|
||||
fb_type type;
|
||||
};
|
||||
|
||||
struct program {
|
||||
uintptr_t phys_addr;
|
||||
uintptr_t virt_addr;
|
||||
@@ -30,10 +44,7 @@ struct program {
|
||||
|
||||
enum class mem_type : uint32_t {
|
||||
free,
|
||||
args,
|
||||
program,
|
||||
module,
|
||||
table,
|
||||
pending,
|
||||
acpi,
|
||||
uefi_runtime,
|
||||
mmio,
|
||||
@@ -74,6 +85,8 @@ struct header {
|
||||
|
||||
void *runtime_services;
|
||||
void *acpi_table;
|
||||
|
||||
framebuffer video;
|
||||
}
|
||||
__attribute__((aligned(alignof(max_align_t))));
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
SYSCALL(0x00, system_log, const char *)
|
||||
SYSCALL(0x01, system_noop, void)
|
||||
SYSCALL(0x02, system_get_log, j6_handle_t, j6_handle_t *)
|
||||
SYSCALL(0x02, system_get_log, j6_handle_t, char *, size_t *)
|
||||
SYSCALL(0x03, system_bind_irq, j6_handle_t, j6_handle_t, unsigned)
|
||||
|
||||
SYSCALL(0x08, object_koid, j6_handle_t, j6_koid_t *)
|
||||
|
||||
@@ -14,8 +14,8 @@ _header:
|
||||
|
||||
section .text
|
||||
align 16
|
||||
global _start:function (_start.end - _start)
|
||||
_start:
|
||||
global _kernel_start:function (_kernel_start.end - _kernel_start)
|
||||
_kernel_start:
|
||||
cli
|
||||
|
||||
mov rsp, idle_stack_end
|
||||
|
||||
@@ -4,8 +4,6 @@
|
||||
#include "kutil/no_construct.h"
|
||||
#include "kutil/printf.h"
|
||||
#include "console.h"
|
||||
#include "font.h"
|
||||
#include "screen.h"
|
||||
#include "serial.h"
|
||||
|
||||
|
||||
@@ -15,212 +13,12 @@ static kutil::no_construct<console> __g_console_storage;
|
||||
console &g_console = __g_console_storage.value;
|
||||
|
||||
|
||||
class console::screen_out
|
||||
{
|
||||
public:
|
||||
screen_out(screen *s, font *f) :
|
||||
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_data(nullptr),
|
||||
m_attrs(nullptr),
|
||||
m_palette(nullptr)
|
||||
{
|
||||
const unsigned count = m_size.size();
|
||||
const size_t attrs_size = 2 * count;
|
||||
|
||||
m_data = new char[count];
|
||||
kutil::memset(m_data, 0, count);
|
||||
|
||||
m_palette = new screen::pixel_t[256];
|
||||
fill_palette();
|
||||
|
||||
m_attrs = new uint16_t[count];
|
||||
set_color(7, 0); // Grey on black default
|
||||
for (unsigned i = 0; i < count; ++i) m_attrs[i] = m_attr;
|
||||
|
||||
repaint();
|
||||
}
|
||||
|
||||
~screen_out()
|
||||
{
|
||||
delete [] m_data;
|
||||
delete [] m_palette;
|
||||
delete [] m_attrs;
|
||||
}
|
||||
|
||||
void fill_palette()
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
void 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 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();
|
||||
}
|
||||
|
||||
void set_color(uint8_t fg, uint8_t bg)
|
||||
{
|
||||
m_bg = m_palette[bg];
|
||||
m_fg = m_palette[fg];
|
||||
m_attr = (bg << 8) | fg;
|
||||
}
|
||||
|
||||
void putc(char c)
|
||||
{
|
||||
char *line = line_pointer(m_pos.y);
|
||||
uint16_t *attrs = attr_pointer(m_pos.y);
|
||||
|
||||
|
||||
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;
|
||||
|
||||
const unsigned x = m_pos.x * m_font->width();
|
||||
const unsigned y = m_pos.y * m_font->height();
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
char * line_pointer(unsigned line)
|
||||
{
|
||||
if (!m_data) return nullptr;
|
||||
return m_data + ((m_first + line) % m_size.y) * m_size.x;
|
||||
}
|
||||
|
||||
uint16_t * attr_pointer(unsigned line)
|
||||
{
|
||||
if (!m_attrs) return nullptr;
|
||||
return m_attrs + ((m_first + line) % m_size.y) * m_size.x;
|
||||
}
|
||||
|
||||
font *m_font;
|
||||
screen *m_screen;
|
||||
|
||||
kutil::coord<unsigned> m_size;
|
||||
kutil::coord<unsigned> m_pos;
|
||||
screen::pixel_t m_fg, m_bg;
|
||||
uint16_t m_attr;
|
||||
|
||||
size_t m_first;
|
||||
|
||||
char *m_data;
|
||||
uint16_t *m_attrs;
|
||||
screen::pixel_t *m_palette;
|
||||
};
|
||||
|
||||
|
||||
console::console() :
|
||||
m_screen(nullptr),
|
||||
m_serial(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
console::console(serial_port *serial) :
|
||||
m_screen(nullptr),
|
||||
m_serial(serial)
|
||||
{
|
||||
if (m_serial) {
|
||||
@@ -239,9 +37,6 @@ console::echo()
|
||||
void
|
||||
console::set_color(uint8_t fg, uint8_t bg)
|
||||
{
|
||||
if (m_screen)
|
||||
m_screen->set_color(fg, bg);
|
||||
|
||||
if (m_serial) {
|
||||
const char *fgseq = "\x1b[38;5;";
|
||||
while (*fgseq)
|
||||
@@ -276,8 +71,6 @@ console::puts(const char *message)
|
||||
void
|
||||
console::putc(char c)
|
||||
{
|
||||
if (m_screen) m_screen->putc(c);
|
||||
|
||||
if (m_serial) {
|
||||
if (c == '\n') m_serial->write('\r');
|
||||
m_serial->write(c);
|
||||
@@ -291,9 +84,3 @@ void console::vprintf(const char *fmt, va_list args)
|
||||
vsnprintf_(buffer, buf_size, fmt, args);
|
||||
puts(buffer);
|
||||
}
|
||||
|
||||
void
|
||||
console::init_screen(screen *s, font *f)
|
||||
{
|
||||
m_screen = new screen_out(s, f);
|
||||
}
|
||||
|
||||
@@ -2,9 +2,7 @@
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
|
||||
class font;
|
||||
struct kernel_data;
|
||||
class screen;
|
||||
class serial_port;
|
||||
|
||||
class console
|
||||
@@ -35,13 +33,9 @@ public:
|
||||
|
||||
void echo();
|
||||
|
||||
void init_screen(screen *s, font *f);
|
||||
|
||||
static console * get();
|
||||
|
||||
private:
|
||||
class screen_out;
|
||||
screen_out *m_screen;
|
||||
serial_port *m_serial;
|
||||
};
|
||||
|
||||
|
||||
@@ -1,116 +1,31 @@
|
||||
#include <stdint.h>
|
||||
#include "kutil/assert.h"
|
||||
#include "kutil/memory.h"
|
||||
#include "cpu.h"
|
||||
#include "cpu/cpu.h"
|
||||
#include "log.h"
|
||||
|
||||
cpu_data bsp_cpu_data;
|
||||
|
||||
static constexpr uint32_t cpuid_extended = 0x80000000;
|
||||
|
||||
|
||||
inline static void
|
||||
__cpuid(
|
||||
uint32_t leaf,
|
||||
uint32_t subleaf,
|
||||
uint32_t *eax,
|
||||
uint32_t *ebx = nullptr,
|
||||
uint32_t *ecx = nullptr,
|
||||
uint32_t *edx = nullptr)
|
||||
{
|
||||
uint32_t a, b, c, d;
|
||||
__asm__ __volatile__ ( "cpuid"
|
||||
: "=a"(a), "=b"(b), "=c"(c), "=d"(d)
|
||||
: "a"(leaf), "c"(subleaf)
|
||||
);
|
||||
if (eax) *eax = a;
|
||||
if (ebx) *ebx = b;
|
||||
if (ecx) *ecx = c;
|
||||
if (edx) *edx = d;
|
||||
}
|
||||
|
||||
cpu_id::cpu_id() :
|
||||
m_features(0)
|
||||
{
|
||||
__cpuid(0, 0,
|
||||
&m_high_basic,
|
||||
reinterpret_cast<uint32_t *>(&m_vendor_id[0]),
|
||||
reinterpret_cast<uint32_t *>(&m_vendor_id[8]),
|
||||
reinterpret_cast<uint32_t *>(&m_vendor_id[4]));
|
||||
|
||||
__cpuid(cpuid_extended, 0, &m_high_ext);
|
||||
|
||||
if (m_high_ext >= cpuid_extended + 4) {
|
||||
__cpuid(cpuid_extended + 2, 0,
|
||||
reinterpret_cast<uint32_t *>(&m_brand_name[0]),
|
||||
reinterpret_cast<uint32_t *>(&m_brand_name[4]),
|
||||
reinterpret_cast<uint32_t *>(&m_brand_name[8]),
|
||||
reinterpret_cast<uint32_t *>(&m_brand_name[12]));
|
||||
__cpuid(cpuid_extended + 3, 0,
|
||||
reinterpret_cast<uint32_t *>(&m_brand_name[16]),
|
||||
reinterpret_cast<uint32_t *>(&m_brand_name[20]),
|
||||
reinterpret_cast<uint32_t *>(&m_brand_name[24]),
|
||||
reinterpret_cast<uint32_t *>(&m_brand_name[28]));
|
||||
__cpuid(cpuid_extended + 4, 0,
|
||||
reinterpret_cast<uint32_t *>(&m_brand_name[32]),
|
||||
reinterpret_cast<uint32_t *>(&m_brand_name[36]),
|
||||
reinterpret_cast<uint32_t *>(&m_brand_name[40]),
|
||||
reinterpret_cast<uint32_t *>(&m_brand_name[44]));
|
||||
} else {
|
||||
m_brand_name[0] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
cpu_id::regs
|
||||
cpu_id::get(uint32_t leaf, uint32_t sub) const
|
||||
{
|
||||
regs ret {0, 0, 0, 0};
|
||||
|
||||
if ((leaf & cpuid_extended) == 0 && leaf > m_high_basic) return ret;
|
||||
if ((leaf & cpuid_extended) != 0 && leaf > m_high_ext) return ret;
|
||||
|
||||
__cpuid(leaf, sub, &ret.eax, &ret.ebx, &ret.ecx, &ret.edx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
cpu_id::validate()
|
||||
cpu_validate()
|
||||
{
|
||||
bool fail = false;
|
||||
uint32_t leaf = 0;
|
||||
uint32_t sub = 0;
|
||||
regs r;
|
||||
cpu::cpu_id cpu;
|
||||
|
||||
log::info(logs::boot, "CPU: %s", brand_name());
|
||||
log::debug(logs::boot, " Vendor is %s", vendor_id());
|
||||
log::info(logs::boot, "CPU: %s", cpu.brand_name());
|
||||
log::debug(logs::boot, " Vendor is %s", cpu.vendor_id());
|
||||
|
||||
log::debug(logs::boot, " Higest basic CPUID: 0x%02x", highest_basic());
|
||||
log::debug(logs::boot, " Higest ext CPUID: 0x%02x", highest_ext() & ~cpuid_extended);
|
||||
log::debug(logs::boot, " Higest basic CPUID: 0x%02x", cpu.highest_basic());
|
||||
log::debug(logs::boot, " Higest ext CPUID: 0x%02x", cpu.highest_ext() & ~cpu::cpu_id::cpuid_extended);
|
||||
|
||||
#define CPU_FEATURE_OPT(name, feat_leaf, feat_sub, regname, bit) \
|
||||
if (leaf != feat_leaf || sub != feat_sub) { \
|
||||
leaf = feat_leaf; sub = feat_sub; r = get(leaf, sub); \
|
||||
} \
|
||||
if (r.regname & (1ull << bit)) \
|
||||
m_features |= (1ull << static_cast<uint64_t>(cpu_feature::name)); \
|
||||
log::debug(logs::boot, " Supports %9s: %s", #name, (r.regname & (1ull << bit)) ? "yes" : "no");
|
||||
#define CPU_FEATURE_OPT(name, ...) \
|
||||
log::debug(logs::boot, " Supports %9s: %s", #name, cpu.has_feature(cpu::feature::name) ? "yes" : "no");
|
||||
|
||||
#define CPU_FEATURE_REQ(name, feat_leaf, feat_sub, regname, bit) \
|
||||
CPU_FEATURE_OPT(name, feat_leaf, feat_sub, regname, bit); \
|
||||
if ((r.regname & (1ull << bit)) == 0) { \
|
||||
log::error(logs::boot, "CPU missing required feature " #name); \
|
||||
fail = true; \
|
||||
}
|
||||
kassert(cpu.has_feature(cpu::feature::name), "Missing required CPU feature " #name );
|
||||
|
||||
#include "cpu_features.inc"
|
||||
#include "cpu/features.inc"
|
||||
#undef CPU_FEATURE_OPT
|
||||
#undef CPU_FEATURE_REQ
|
||||
|
||||
if (fail)
|
||||
log::fatal(logs::boot, "CPU not supported.");
|
||||
}
|
||||
|
||||
bool
|
||||
cpu_id::has_feature(cpu_feature feat)
|
||||
{
|
||||
return (m_features & (1 << static_cast<uint64_t>(feat))) != 0;
|
||||
}
|
||||
|
||||
@@ -27,69 +27,6 @@ struct cpu_data
|
||||
|
||||
extern cpu_data bsp_cpu_data;
|
||||
|
||||
/// Enum of the cpu features jsix cares about
|
||||
enum class cpu_feature {
|
||||
#define CPU_FEATURE_REQ(name, ...) name,
|
||||
#define CPU_FEATURE_OPT(name, ...) name,
|
||||
#include "cpu_features.inc"
|
||||
#undef CPU_FEATURE_OPT
|
||||
#undef CPU_FEATURE_REQ
|
||||
max
|
||||
};
|
||||
|
||||
class cpu_id
|
||||
{
|
||||
public:
|
||||
/// CPUID result register values
|
||||
struct regs {
|
||||
union {
|
||||
uint32_t reg[4];
|
||||
uint32_t eax, ebx, ecx, edx;
|
||||
};
|
||||
|
||||
/// Return true if bit |bit| of EAX is set
|
||||
bool eax_bit(unsigned bit) { return (eax >> bit) & 0x1; }
|
||||
|
||||
/// Return true if bit |bit| of EBX is set
|
||||
bool ebx_bit(unsigned bit) { return (ebx >> bit) & 0x1; }
|
||||
|
||||
/// Return true if bit |bit| of ECX is set
|
||||
bool ecx_bit(unsigned bit) { return (ecx >> bit) & 0x1; }
|
||||
|
||||
/// Return true if bit |bit| of EDX is set
|
||||
bool edx_bit(unsigned bit) { return (edx >> bit) & 0x1; }
|
||||
};
|
||||
|
||||
cpu_id();
|
||||
|
||||
/// The the result of a given CPUID leaf/subleaf
|
||||
/// \arg leaf The leaf selector (initial EAX)
|
||||
/// \arg subleaf The subleaf selector (initial ECX)
|
||||
/// \returns A |regs| struct of the values retuned
|
||||
regs get(uint32_t leaf, uint32_t sub = 0) const;
|
||||
|
||||
/// Get the name of the cpu vendor (eg, "GenuineIntel")
|
||||
inline const char * vendor_id() const { return m_vendor_id; }
|
||||
|
||||
/// Get the brand name of this processor model
|
||||
inline const char * brand_name() const { return m_brand_name; }
|
||||
|
||||
/// Get the highest basic CPUID leaf supported
|
||||
inline uint32_t highest_basic() const { return m_high_basic; }
|
||||
|
||||
/// Get the highest extended CPUID leaf supported
|
||||
inline uint32_t highest_ext() const { return m_high_ext; }
|
||||
|
||||
/// Validate the CPU supports the necessary options for jsix
|
||||
void validate();
|
||||
|
||||
/// Return true if the CPU claims to support the given feature
|
||||
bool has_feature(cpu_feature feat);
|
||||
|
||||
private:
|
||||
uint32_t m_high_basic;
|
||||
uint32_t m_high_ext;
|
||||
char m_vendor_id[13];
|
||||
char m_brand_name[48];
|
||||
uint64_t m_features;
|
||||
};
|
||||
// We already validated the required options in the bootloader,
|
||||
// but iterate the options and log about them.
|
||||
void cpu_validate();
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
|
||||
#include "kutil/coord.h"
|
||||
#include "screen.h"
|
||||
|
||||
class font
|
||||
{
|
||||
public:
|
||||
font(void const *data);
|
||||
|
||||
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:
|
||||
kutil::coord<unsigned> m_size;
|
||||
unsigned m_count;
|
||||
uint8_t const *m_data;
|
||||
|
||||
font() = delete;
|
||||
};
|
||||
|
||||
@@ -10,7 +10,7 @@ static uint8_t log_buffer[0x10000];
|
||||
// so that we can start log output immediately. Keep its constructor
|
||||
// from being called here so as to not overwrite the previous initialization.
|
||||
static kutil::no_construct<log::logger> __g_logger_storage;
|
||||
static log::logger &g_logger = __g_logger_storage.value;
|
||||
log::logger &g_logger = __g_logger_storage.value;
|
||||
|
||||
static const uint8_t level_colors[] = {0x07, 0x07, 0x0f, 0x0b, 0x09};
|
||||
|
||||
@@ -57,3 +57,8 @@ void logger_init()
|
||||
{
|
||||
new (&g_logger) log::logger(log_buffer, sizeof(log_buffer), output_log);
|
||||
}
|
||||
|
||||
void logger_clear_immediate()
|
||||
{
|
||||
g_logger.set_immediate(nullptr);
|
||||
}
|
||||
|
||||
@@ -6,4 +6,5 @@ namespace log = kutil::log;
|
||||
namespace logs = kutil::logs;
|
||||
|
||||
void logger_init();
|
||||
void logger_clear_immediate();
|
||||
void logger_task();
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include "log.h"
|
||||
#include "objects/channel.h"
|
||||
#include "objects/event.h"
|
||||
#include "objects/thread.h"
|
||||
#include "scheduler.h"
|
||||
#include "serial.h"
|
||||
#include "symbol_table.h"
|
||||
@@ -32,24 +33,18 @@ extern "C" {
|
||||
void (*__ctors_end)(void);
|
||||
}
|
||||
|
||||
void
|
||||
run_constructors()
|
||||
{
|
||||
void (**p)(void) = &__ctors;
|
||||
while (p < &__ctors_end) {
|
||||
void (*ctor)(void) = *p++;
|
||||
ctor();
|
||||
}
|
||||
}
|
||||
|
||||
extern void __kernel_assert(const char *, unsigned, const char *);
|
||||
|
||||
/// Bootstrap the memory managers.
|
||||
void setup_pat();
|
||||
void memory_initialize_pre_ctors(kernel::args::header *kargs);
|
||||
void memory_initialize_post_ctors(kernel::args::header *kargs);
|
||||
|
||||
using namespace kernel;
|
||||
|
||||
/// TODO: not this. this is awful.
|
||||
args::framebuffer *fb = nullptr;
|
||||
|
||||
void
|
||||
init_console()
|
||||
{
|
||||
@@ -60,7 +55,16 @@ init_console()
|
||||
cons->puts("jsix OS ");
|
||||
cons->set_color(0x08, 0x00);
|
||||
cons->puts(GIT_VERSION " booting...\n");
|
||||
logger_init();
|
||||
}
|
||||
|
||||
void
|
||||
run_constructors()
|
||||
{
|
||||
void (**p)(void) = &__ctors;
|
||||
while (p < &__ctors_end) {
|
||||
void (*ctor)(void) = *p++;
|
||||
ctor();
|
||||
}
|
||||
}
|
||||
|
||||
channel *std_out = nullptr;
|
||||
@@ -107,7 +111,22 @@ void
|
||||
kernel_main(args::header *header)
|
||||
{
|
||||
kutil::assert_set_callback(__kernel_assert);
|
||||
|
||||
init_console();
|
||||
logger_init();
|
||||
|
||||
setup_pat();
|
||||
|
||||
bool has_video = false;
|
||||
if (header->video.size > 0) {
|
||||
has_video = true;
|
||||
fb = memory::to_virtual<args::framebuffer>(reinterpret_cast<uintptr_t>(&header->video));
|
||||
|
||||
const args::framebuffer &video = header->video;
|
||||
log::debug(logs::boot, "Framebuffer: %dx%d[%d] type %s @ %016llx",
|
||||
video.horizontal, video.vertical, video.scanline, video.type, video.phys_addr);
|
||||
logger_clear_immediate();
|
||||
}
|
||||
|
||||
gdt_init();
|
||||
interrupts_init();
|
||||
@@ -116,8 +135,7 @@ kernel_main(args::header *header)
|
||||
run_constructors();
|
||||
memory_initialize_post_ctors(header);
|
||||
|
||||
cpu_id cpu;
|
||||
cpu.validate();
|
||||
cpu_validate();
|
||||
|
||||
for (size_t i = 0; i < header->num_modules; ++i) {
|
||||
args::module &mod = header->modules[i];
|
||||
@@ -141,7 +159,6 @@ kernel_main(args::header *header)
|
||||
|
||||
interrupts_enable();
|
||||
devices.init_drivers();
|
||||
|
||||
devices.get_lapic()->calibrate_timer();
|
||||
|
||||
/*
|
||||
@@ -176,9 +193,13 @@ kernel_main(args::header *header)
|
||||
// Skip program 0, which is the kernel itself
|
||||
for (size_t i = 1; i < header->num_programs; ++i) {
|
||||
args::program &prog = header->programs[i];
|
||||
sched->load_process(prog.phys_addr, prog.virt_addr, prog.size, prog.entrypoint);
|
||||
thread *th = sched->load_process(prog.phys_addr, prog.virt_addr, prog.size, prog.entrypoint);
|
||||
if (i == 2) {
|
||||
//th->set_state(thread::state::constant);
|
||||
}
|
||||
}
|
||||
|
||||
if (!has_video)
|
||||
sched->create_kernel_task(logger_task, scheduler::max_priority-1, true);
|
||||
sched->create_kernel_task(stdout_task, scheduler::max_priority-1, true);
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "frame_allocator.h"
|
||||
#include "io.h"
|
||||
#include "log.h"
|
||||
#include "msr.h"
|
||||
#include "objects/process.h"
|
||||
#include "objects/vm_area.h"
|
||||
#include "vm_space.h"
|
||||
@@ -100,6 +101,71 @@ void walk_page_table(
|
||||
}
|
||||
*/
|
||||
|
||||
static void
|
||||
log_mtrrs()
|
||||
{
|
||||
uint64_t mtrrcap = rdmsr(msr::ia32_mtrrcap);
|
||||
uint64_t mtrrdeftype = rdmsr(msr::ia32_mtrrdeftype);
|
||||
unsigned vcap = mtrrcap & 0xff;
|
||||
log::debug(logs::boot, "MTRRs: vcap=%d %s %s def=%02x %s %s",
|
||||
vcap,
|
||||
(mtrrcap & (1<< 8)) ? "fix" : "",
|
||||
(mtrrcap & (1<<10)) ? "wc" : "",
|
||||
mtrrdeftype & 0xff,
|
||||
(mtrrdeftype & (1<<10)) ? "fe" : "",
|
||||
(mtrrdeftype & (1<<11)) ? "enabled" : ""
|
||||
);
|
||||
|
||||
for (unsigned i = 0; i < vcap; ++i) {
|
||||
uint64_t base = rdmsr(find_mtrr(msr::ia32_mtrrphysbase, i));
|
||||
uint64_t mask = rdmsr(find_mtrr(msr::ia32_mtrrphysmask, i));
|
||||
log::debug(logs::boot, " vcap[%2d] base:%016llx mask:%016llx type:%02x %s", i,
|
||||
(base & ~0xfffull),
|
||||
(mask & ~0xfffull),
|
||||
(base & 0xff),
|
||||
(mask & (1<<11)) ? "valid" : "");
|
||||
}
|
||||
|
||||
msr mtrr_fixed[] = {
|
||||
msr::ia32_mtrrfix64k_00000,
|
||||
msr::ia32_mtrrfix16k_80000,
|
||||
msr::ia32_mtrrfix16k_a0000,
|
||||
msr::ia32_mtrrfix4k_c0000,
|
||||
msr::ia32_mtrrfix4k_c8000,
|
||||
msr::ia32_mtrrfix4k_d0000,
|
||||
msr::ia32_mtrrfix4k_d8000,
|
||||
msr::ia32_mtrrfix4k_e0000,
|
||||
msr::ia32_mtrrfix4k_e8000,
|
||||
msr::ia32_mtrrfix4k_f0000,
|
||||
msr::ia32_mtrrfix4k_f8000,
|
||||
};
|
||||
|
||||
for (int i = 0; i < 11; ++i) {
|
||||
uint64_t v = rdmsr(mtrr_fixed[i]);
|
||||
log::debug(logs::boot, " fixed[%2d] %02x %02x %02x %02x %02x %02x %02x %02x", i,
|
||||
((v << 0) & 0xff), ((v << 8) & 0xff), ((v << 16) & 0xff), ((v << 24) & 0xff),
|
||||
((v << 32) & 0xff), ((v << 40) & 0xff), ((v << 48) & 0xff), ((v << 56) & 0xff));
|
||||
}
|
||||
|
||||
uint64_t pat = rdmsr(msr::ia32_pat);
|
||||
static const char *pat_names[] = {"UC ","WC ","XX ","XX ","WT ","WP ","WB ","UC-"};
|
||||
log::debug(logs::boot, " PAT: 0:%s 1:%s 2:%s 3:%s 4:%s 5:%s 6:%s 7:%s",
|
||||
pat_names[(pat >> (0*8)) & 7], pat_names[(pat >> (1*8)) & 7],
|
||||
pat_names[(pat >> (2*8)) & 7], pat_names[(pat >> (3*8)) & 7],
|
||||
pat_names[(pat >> (4*8)) & 7], pat_names[(pat >> (5*8)) & 7],
|
||||
pat_names[(pat >> (6*8)) & 7], pat_names[(pat >> (7*8)) & 7]);
|
||||
}
|
||||
|
||||
void
|
||||
setup_pat()
|
||||
{
|
||||
uint64_t pat = rdmsr(msr::ia32_pat);
|
||||
pat = (pat & 0x00ffffffffffffffull) | (0x01ull << 56); // set PAT 7 to WC
|
||||
wrmsr(msr::ia32_pat, pat);
|
||||
log_mtrrs();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
memory_initialize_pre_ctors(args::header *kargs)
|
||||
{
|
||||
@@ -110,6 +176,7 @@ memory_initialize_pre_ctors(args::header *kargs)
|
||||
const size_t count = kargs->map_count;
|
||||
for (unsigned i = 0; i < count; ++i) {
|
||||
// TODO: use entry attributes
|
||||
// TODO: copy anything we need from "pending" memory and free it
|
||||
args::mem_entry &e = entries[i];
|
||||
if (e.type == args::mem_type::free)
|
||||
g_frame_allocator.free(e.start, e.pages);
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
#include "msr.h"
|
||||
|
||||
msr
|
||||
find_mtrr(msr type, unsigned index)
|
||||
{
|
||||
return static_cast<msr>(static_cast<uint32_t>(type) + (2 * index));
|
||||
}
|
||||
|
||||
uint64_t
|
||||
rdmsr(msr addr)
|
||||
{
|
||||
|
||||
@@ -6,6 +6,27 @@
|
||||
|
||||
enum class msr : uint32_t
|
||||
{
|
||||
ia32_mtrrcap = 0x000000fe,
|
||||
ia32_mtrrdeftype = 0x000002ff,
|
||||
|
||||
ia32_mtrrphysbase = 0x00000200,
|
||||
ia32_mtrrphysmask = 0x00000201,
|
||||
|
||||
ia32_mtrrfix64k_00000 = 0x00000250,
|
||||
|
||||
ia32_mtrrfix16k_80000 = 0x00000258,
|
||||
ia32_mtrrfix16k_a0000 = 0x00000259,
|
||||
|
||||
ia32_mtrrfix4k_c0000 = 0x00000268,
|
||||
ia32_mtrrfix4k_c8000 = 0x00000269,
|
||||
ia32_mtrrfix4k_d0000 = 0x0000026A,
|
||||
ia32_mtrrfix4k_d8000 = 0x0000026B,
|
||||
ia32_mtrrfix4k_e0000 = 0x0000026C,
|
||||
ia32_mtrrfix4k_e8000 = 0x0000026D,
|
||||
ia32_mtrrfix4k_f0000 = 0x0000026E,
|
||||
ia32_mtrrfix4k_f8000 = 0x0000026F,
|
||||
|
||||
ia32_pat = 0x00000277,
|
||||
ia32_efer = 0xc0000080,
|
||||
ia32_star = 0xc0000081,
|
||||
ia32_lstar = 0xc0000082,
|
||||
@@ -15,6 +36,9 @@ enum class msr : uint32_t
|
||||
ia32_kernel_gs_base = 0xc0000102
|
||||
};
|
||||
|
||||
/// Find the msr for MTRR physical base or mask
|
||||
msr find_mtrr(msr type, unsigned index);
|
||||
|
||||
/// Read the value of a MSR
|
||||
/// \arg addr The MSR address
|
||||
/// \returns The current value of the MSR
|
||||
|
||||
@@ -21,13 +21,16 @@ process::process() :
|
||||
m_state {state::running}
|
||||
{
|
||||
s_processes.append(this);
|
||||
|
||||
j6_handle_t self = add_handle(this);
|
||||
kassert(self == self_handle(), "Process self-handle is not 0");
|
||||
}
|
||||
|
||||
// The "kernel process"-only constructor
|
||||
process::process(page_table *kpml4) :
|
||||
kobject {kobject::type::process},
|
||||
m_space {kpml4},
|
||||
m_next_handle {0},
|
||||
m_next_handle {self_handle()+1},
|
||||
m_state {state::running}
|
||||
{
|
||||
}
|
||||
@@ -52,16 +55,13 @@ void
|
||||
process::exit(unsigned code)
|
||||
{
|
||||
// TODO: make this thread-safe
|
||||
if (m_state != state::running)
|
||||
return;
|
||||
else
|
||||
m_state = state::exited;
|
||||
m_return_code = code;
|
||||
close();
|
||||
|
||||
for (auto *thread : m_threads) {
|
||||
thread->exit(code);
|
||||
}
|
||||
m_return_code = code;
|
||||
close();
|
||||
|
||||
if (this == bsp_cpu_data.p)
|
||||
scheduler::get().schedule();
|
||||
@@ -120,6 +120,7 @@ process::thread_exited(thread *th)
|
||||
kassert(&th->m_parent == this, "Process got thread_exited for non-child!");
|
||||
uint32_t status = th->m_return_code;
|
||||
m_threads.remove_swap(th);
|
||||
remove_handle(th->self_handle());
|
||||
delete th;
|
||||
|
||||
if (m_threads.count() == 0) {
|
||||
|
||||
@@ -68,6 +68,9 @@ public:
|
||||
/// \returns True if this thread ending has ended the process
|
||||
bool thread_exited(thread *th);
|
||||
|
||||
/// Get the handle for this process to refer to itself
|
||||
inline j6_handle_t self_handle() const { return 0; }
|
||||
|
||||
/// Get the process object that owns kernel threads and the
|
||||
/// kernel address space
|
||||
static process & kernel_process();
|
||||
|
||||
@@ -26,6 +26,8 @@ thread::thread(process &parent, uint8_t pri, uintptr_t rsp0) :
|
||||
setup_kernel_stack();
|
||||
else
|
||||
m_tcb.rsp0 = rsp0;
|
||||
|
||||
m_self_handle = parent.add_handle(this);
|
||||
}
|
||||
|
||||
thread::~thread()
|
||||
|
||||
@@ -141,6 +141,9 @@ public:
|
||||
/// \arg rip The address to return to, must be user space
|
||||
void add_thunk_user(uintptr_t rip);
|
||||
|
||||
/// Get the handle representing this thread to its process
|
||||
j6_handle_t self_handle() const { return m_self_handle; }
|
||||
|
||||
/// Create the kernel idle thread
|
||||
/// \arg kernel The process object that owns kernel tasks
|
||||
/// \arg pri The idle thread priority value
|
||||
@@ -175,4 +178,6 @@ private:
|
||||
uint64_t m_wait_data;
|
||||
j6_status_t m_wait_result;
|
||||
j6_koid_t m_wait_obj;
|
||||
|
||||
j6_handle_t m_self_handle;
|
||||
};
|
||||
|
||||
@@ -28,6 +28,9 @@ enum class vm_flags : uint32_t
|
||||
large_pages = 0x00000100,
|
||||
huge_pages = 0x00000200,
|
||||
|
||||
mmio = 0x00010000,
|
||||
write_combine = 0x00020000,
|
||||
|
||||
user_mask = 0x0000ffff ///< flags allowed via syscall
|
||||
};
|
||||
|
||||
|
||||
@@ -181,6 +181,7 @@ page_table::get_table_page()
|
||||
s_page_cache = s_page_cache->next;
|
||||
--s_cache_count;
|
||||
|
||||
kutil::memset(page, 0, memory::frame_size);
|
||||
return reinterpret_cast<page_table*>(page);
|
||||
}
|
||||
|
||||
|
||||
@@ -21,14 +21,21 @@ struct page_table
|
||||
present = 0x0001, /// Entry is present in the table
|
||||
write = 0x0002, /// Section may be written
|
||||
user = 0x0004, /// User-accessible
|
||||
mtrr0 = 0x0008, /// MTRR selector bit 0
|
||||
mtrr1 = 0x0010, /// MTRR selector bit 1
|
||||
pat0 = 0x0008, /// PAT selector bit 0
|
||||
pat1 = 0x0010, /// PAT selector bit 1
|
||||
accessed = 0x0020, /// Entry has been accessed
|
||||
dirty = 0x0040, /// Page has been written to
|
||||
page = 0x0080, /// Entry is a large page
|
||||
pte_mtrr2 = 0x0080, /// MTRR selector bit 2 on PT entries
|
||||
pat2 = 0x0080, /// PAT selector bit 2 on PT entries
|
||||
global = 0x0100, /// Entry is not PCID-specific
|
||||
mtrr2 = 0x1000 /// MTRR selector bit 2 on PD and PDP entries
|
||||
pat2_lg = 0x1000, /// PAT selector bit 2 on large/huge pages
|
||||
|
||||
wb = none,
|
||||
wt = pat0,
|
||||
uc_ = pat1,
|
||||
uc = pat0 | pat1,
|
||||
wc = pat0 | pat1 | pat2,
|
||||
wc_lg = pat0 | pat1 | pat2_lg,
|
||||
};
|
||||
|
||||
/// Helper for getting the next level value
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#include <stddef.h>
|
||||
|
||||
#include <j6/init.h>
|
||||
|
||||
#include "apic.h"
|
||||
#include "clock.h"
|
||||
#include "console.h"
|
||||
@@ -17,11 +19,16 @@
|
||||
#include "objects/vm_area.h"
|
||||
#include "scheduler.h"
|
||||
|
||||
// here for the framebuffer hack
|
||||
#include "kernel_args.h"
|
||||
|
||||
#include "kutil/assert.h"
|
||||
|
||||
|
||||
scheduler *scheduler::s_instance = nullptr;
|
||||
|
||||
extern kernel::args::framebuffer *fb;
|
||||
|
||||
const uint64_t rflags_noint = 0x002;
|
||||
const uint64_t rflags_int = 0x202;
|
||||
|
||||
@@ -60,6 +67,14 @@ scheduler::scheduler(lapic *apic) :
|
||||
bsp_cpu_data.t = idle;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T * push(uintptr_t &rsp, size_t size = sizeof(T)) {
|
||||
rsp -= size;
|
||||
T *p = reinterpret_cast<T*>(rsp);
|
||||
rsp &= ~(sizeof(uint64_t)-1); // Align the stack
|
||||
return p;
|
||||
}
|
||||
|
||||
uintptr_t
|
||||
load_process_image(uintptr_t phys, uintptr_t virt, size_t bytes, TCB *tcb)
|
||||
{
|
||||
@@ -69,25 +84,69 @@ load_process_image(uintptr_t phys, uintptr_t virt, size_t bytes, TCB *tcb)
|
||||
// We're now in the process space for this process, allocate memory for the
|
||||
// process code and load it
|
||||
process &proc = process::current();
|
||||
thread &th = thread::current();
|
||||
vm_space &space = proc.space();
|
||||
|
||||
vm_area *vma = new vm_area_open(bytes, space, vm_flags::zero|vm_flags::write);
|
||||
space.add(virt, vma);
|
||||
vma->commit(phys, 0, memory::page_count(bytes));
|
||||
|
||||
tcb->rsp3 -= 2 * sizeof(uint64_t);
|
||||
uint64_t *sentinel = reinterpret_cast<uint64_t*>(tcb->rsp3);
|
||||
sentinel[0] = sentinel[1] = 0;
|
||||
// double zero stack sentinel
|
||||
*push<uint64_t>(tcb->rsp3) = 0;
|
||||
*push<uint64_t>(tcb->rsp3) = 0;
|
||||
|
||||
tcb->rsp3 -= sizeof(j6_process_init);
|
||||
j6_process_init *init = reinterpret_cast<j6_process_init*>(tcb->rsp3);
|
||||
const char message[] = "Hello from the kernel!";
|
||||
char *message_arg = push<char>(tcb->rsp3, sizeof(message));
|
||||
kutil::memcpy(message_arg, message, sizeof(message));
|
||||
|
||||
init->process = proc.add_handle(&proc);
|
||||
init->handles[0] = proc.add_handle(system::get());
|
||||
init->handles[1] = j6_handle_invalid;
|
||||
init->handles[2] = j6_handle_invalid;
|
||||
j6_init_framebuffer *fb_desc = push<j6_init_framebuffer>(tcb->rsp3);
|
||||
fb_desc->addr = fb ? reinterpret_cast<void*>(0x100000000) : nullptr;
|
||||
fb_desc->size = fb ? fb->size : 0;
|
||||
fb_desc->vertical = fb ? fb->vertical : 0;
|
||||
fb_desc->horizontal = fb ? fb->horizontal : 0;
|
||||
fb_desc->scanline = fb ? fb->scanline : 0;
|
||||
fb_desc->flags = 0;
|
||||
|
||||
thread::current().clear_state(thread::state::loading);
|
||||
if (fb && fb->type == kernel::args::fb_type::bgr8)
|
||||
fb_desc->flags |= 1;
|
||||
|
||||
j6_init_value *initv = push<j6_init_value>(tcb->rsp3);
|
||||
initv->type = j6_init_handle_system;
|
||||
initv->value = static_cast<uint64_t>(proc.add_handle(system::get()));
|
||||
|
||||
initv = push<j6_init_value>(tcb->rsp3);
|
||||
initv->type = j6_init_handle_process;
|
||||
initv->value = static_cast<uint64_t>(proc.self_handle());
|
||||
|
||||
initv = push<j6_init_value>(tcb->rsp3);
|
||||
initv->type = j6_init_handle_thread;
|
||||
initv->value = static_cast<uint64_t>(th.self_handle());
|
||||
|
||||
initv = push<j6_init_value>(tcb->rsp3);
|
||||
initv->type = j6_init_handle_space;
|
||||
//initv->value = static_cast<uint64_t>(proc.add_handle(&space));
|
||||
|
||||
initv = push<j6_init_value>(tcb->rsp3);
|
||||
initv->type = j6_init_desc_framebuffer;
|
||||
initv->value = reinterpret_cast<uint64_t>(fb_desc);
|
||||
|
||||
uint64_t *initc = push<uint64_t>(tcb->rsp3);
|
||||
*initc = 5;
|
||||
|
||||
char **argv0 = push<char*>(tcb->rsp3);
|
||||
*argv0 = message_arg;
|
||||
|
||||
uint64_t *argc = push<uint64_t>(tcb->rsp3);
|
||||
*argc = 1;
|
||||
|
||||
// Crazypants framebuffer part
|
||||
if (fb) {
|
||||
vma = new vm_area_open(fb->size, space, vm_flags::write|vm_flags::mmio|vm_flags::write_combine);
|
||||
space.add(0x100000000, vma);
|
||||
vma->commit(fb->phys_addr, 0, memory::page_count(fb->size));
|
||||
}
|
||||
|
||||
th.clear_state(thread::state::loading);
|
||||
return tcb->rsp3;
|
||||
}
|
||||
|
||||
@@ -107,7 +166,7 @@ scheduler::create_process(bool user)
|
||||
return th;
|
||||
}
|
||||
|
||||
void
|
||||
thread *
|
||||
scheduler::load_process(uintptr_t phys, uintptr_t virt, size_t size, uintptr_t entry)
|
||||
{
|
||||
|
||||
@@ -145,6 +204,8 @@ scheduler::load_process(uintptr_t phys, uintptr_t virt, size_t size, uintptr_t e
|
||||
log::debug(logs::task, " RSP %016lx", tcb->rsp);
|
||||
log::debug(logs::task, " RSP0 %016lx", tcb->rsp0);
|
||||
log::debug(logs::task, " PML4 %016lx", tcb->pml4);
|
||||
|
||||
return th;
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -45,7 +45,8 @@ public:
|
||||
/// \arg virt Virtual address of the loaded program image
|
||||
/// \arg size Size of the program image, in bytes
|
||||
/// \arg entry Virtual address of the program entrypoint
|
||||
void load_process(uintptr_t phys, uintptr_t virt, size_t size, uintptr_t entry);
|
||||
/// \returns The main thread of the loaded process
|
||||
thread * load_process(uintptr_t phys, uintptr_t virt, size_t size, uintptr_t entry);
|
||||
|
||||
/// Create a new kernel task
|
||||
/// \arg proc Function to run as a kernel task
|
||||
|
||||
@@ -1,70 +0,0 @@
|
||||
#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::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;
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
#pragma once
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "kutil/coord.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);
|
||||
|
||||
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);
|
||||
|
||||
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;
|
||||
kutil::coord<unsigned> m_resolution;
|
||||
|
||||
screen() = delete;
|
||||
};
|
||||
@@ -35,7 +35,12 @@ endpoint_receive(j6_handle_t handle, j6_tag_t *tag, size_t *len, void *data)
|
||||
endpoint *e = get_handle<endpoint>(handle);
|
||||
if (!e) return j6_err_invalid_arg;
|
||||
|
||||
return e->receive(tag, len, data);
|
||||
j6_tag_t out_tag = j6_tag_invalid;
|
||||
size_t out_len = 0;
|
||||
j6_status_t s = e->receive(&out_tag, &out_len, data);
|
||||
*tag = out_tag;
|
||||
*len = out_len;
|
||||
return s;
|
||||
}
|
||||
|
||||
j6_status_t
|
||||
@@ -51,7 +56,12 @@ endpoint_sendrecv(j6_handle_t handle, j6_tag_t *tag, size_t *len, void *data)
|
||||
if (status != j6_status_ok)
|
||||
return status;
|
||||
|
||||
return e->receive(tag, len, data);
|
||||
j6_tag_t out_tag = j6_tag_invalid;
|
||||
size_t out_len = 0;
|
||||
j6_status_t s = e->receive(&out_tag, &out_len, data);
|
||||
*tag = out_tag;
|
||||
*len = out_len;
|
||||
return s;
|
||||
}
|
||||
|
||||
} // namespace syscalls
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
#include "objects/thread.h"
|
||||
#include "syscalls/helpers.h"
|
||||
|
||||
extern log::logger &g_logger;
|
||||
|
||||
namespace syscalls {
|
||||
|
||||
j6_status_t
|
||||
@@ -29,9 +31,10 @@ system_noop()
|
||||
}
|
||||
|
||||
j6_status_t
|
||||
system_get_log(j6_handle_t sys, j6_handle_t *log)
|
||||
system_get_log(j6_handle_t sys, char *buffer, size_t *size)
|
||||
{
|
||||
return j6_err_nyi;
|
||||
*size = g_logger.get_entry(buffer, *size);
|
||||
return j6_status_ok;
|
||||
}
|
||||
|
||||
j6_status_t
|
||||
|
||||
@@ -15,7 +15,7 @@ thread_create(void *rip, j6_handle_t *handle)
|
||||
|
||||
thread *child = p.create_thread();
|
||||
child->add_thunk_user(reinterpret_cast<uintptr_t>(rip));
|
||||
*handle = p.add_handle(child);
|
||||
*handle = p.self_handle();
|
||||
child->clear_state(thread::state::loading);
|
||||
child->set_state(thread::state::ready);
|
||||
|
||||
|
||||
@@ -30,6 +30,14 @@ vm_mapper_single::unmap(uintptr_t offset, size_t count)
|
||||
m_space.clear(m_area, offset, count, true);
|
||||
}
|
||||
|
||||
void
|
||||
vm_mapper_single::remove(vm_space *space)
|
||||
{
|
||||
size_t count = memory::page_count(m_area.size());
|
||||
bool keep = m_area.flags() && vm_flags::mmio;
|
||||
m_space.clear(m_area, 0, count, !keep);
|
||||
}
|
||||
|
||||
|
||||
|
||||
vm_mapper_multi::vm_mapper_multi(vm_area &area) :
|
||||
@@ -88,11 +96,13 @@ void
|
||||
vm_mapper_multi::remove(vm_space *space)
|
||||
{
|
||||
size_t count = memory::page_count(m_area.size());
|
||||
bool keep = m_area.flags() && vm_flags::mmio;
|
||||
|
||||
for (int i = 0; i < m_spaces.count(); ++i) {
|
||||
if (m_spaces[i] == space) {
|
||||
m_spaces.remove_swap_at(i);
|
||||
space->clear(m_area, 0, count, m_spaces.count() == 0);
|
||||
keep &= m_spaces.count() > 0;
|
||||
space->clear(m_area, 0, count, !keep);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,6 +54,8 @@ public:
|
||||
|
||||
vm_space & space() { return m_space; }
|
||||
|
||||
virtual void remove(vm_space *space) override;
|
||||
|
||||
private:
|
||||
vm_area &m_area;
|
||||
vm_space &m_space;
|
||||
|
||||
@@ -170,13 +170,16 @@ vm_space::page_in(const vm_area &vma, uintptr_t offset, uintptr_t phys, size_t c
|
||||
page_table::flag flags =
|
||||
page_table::flag::present |
|
||||
(m_kernel ? page_table::flag::none : page_table::flag::user) |
|
||||
((vma.flags() && vm_flags::write) ? page_table::flag::write : page_table::flag::none);
|
||||
((vma.flags() && vm_flags::write) ? page_table::flag::write : page_table::flag::none) |
|
||||
((vma.flags() && vm_flags::write_combine) ? page_table::flag::wc : page_table::flag::none);
|
||||
|
||||
page_table::iterator it {virt, m_pml4};
|
||||
|
||||
for (size_t i = 0; i < count; ++i) {
|
||||
it.entry(page_table::level::pt) =
|
||||
(phys + i * frame_size) | flags;
|
||||
uint64_t &entry = it.entry(page_table::level::pt);
|
||||
entry = (phys + i * frame_size) | flags;
|
||||
log::debug(logs::paging, "Setting entry for %016llx: %016llx [%04llx]",
|
||||
it.vaddress(), (phys + i * frame_size), flags);
|
||||
++it;
|
||||
}
|
||||
}
|
||||
@@ -210,7 +213,6 @@ vm_space::clear(const vm_area &vma, uintptr_t offset, size_t count, bool free)
|
||||
free_start = phys;
|
||||
free_count = 1;
|
||||
}
|
||||
fa.free(e & ~0xfffull, 1);
|
||||
}
|
||||
|
||||
e = 0;
|
||||
|
||||
97
src/libraries/cpu/cpu.cpp
Normal file
97
src/libraries/cpu/cpu.cpp
Normal file
@@ -0,0 +1,97 @@
|
||||
#include <stdint.h>
|
||||
#include "cpu/cpu.h"
|
||||
|
||||
namespace cpu {
|
||||
|
||||
inline static void
|
||||
__cpuid(
|
||||
uint32_t leaf,
|
||||
uint32_t subleaf,
|
||||
uint32_t *eax,
|
||||
uint32_t *ebx = nullptr,
|
||||
uint32_t *ecx = nullptr,
|
||||
uint32_t *edx = nullptr)
|
||||
{
|
||||
uint32_t a, b, c, d;
|
||||
__asm__ __volatile__ ( "cpuid"
|
||||
: "=a"(a), "=b"(b), "=c"(c), "=d"(d)
|
||||
: "a"(leaf), "c"(subleaf)
|
||||
);
|
||||
if (eax) *eax = a;
|
||||
if (ebx) *ebx = b;
|
||||
if (ecx) *ecx = c;
|
||||
if (edx) *edx = d;
|
||||
}
|
||||
|
||||
cpu_id::cpu_id() :
|
||||
m_features {0},
|
||||
m_missing {0}
|
||||
{
|
||||
__cpuid(0, 0,
|
||||
&m_high_basic,
|
||||
reinterpret_cast<uint32_t *>(&m_vendor_id[0]),
|
||||
reinterpret_cast<uint32_t *>(&m_vendor_id[8]),
|
||||
reinterpret_cast<uint32_t *>(&m_vendor_id[4]));
|
||||
|
||||
__cpuid(cpuid_extended, 0, &m_high_ext);
|
||||
|
||||
if (m_high_ext >= cpuid_extended + 4) {
|
||||
__cpuid(cpuid_extended + 2, 0,
|
||||
reinterpret_cast<uint32_t *>(&m_brand_name[0]),
|
||||
reinterpret_cast<uint32_t *>(&m_brand_name[4]),
|
||||
reinterpret_cast<uint32_t *>(&m_brand_name[8]),
|
||||
reinterpret_cast<uint32_t *>(&m_brand_name[12]));
|
||||
__cpuid(cpuid_extended + 3, 0,
|
||||
reinterpret_cast<uint32_t *>(&m_brand_name[16]),
|
||||
reinterpret_cast<uint32_t *>(&m_brand_name[20]),
|
||||
reinterpret_cast<uint32_t *>(&m_brand_name[24]),
|
||||
reinterpret_cast<uint32_t *>(&m_brand_name[28]));
|
||||
__cpuid(cpuid_extended + 4, 0,
|
||||
reinterpret_cast<uint32_t *>(&m_brand_name[32]),
|
||||
reinterpret_cast<uint32_t *>(&m_brand_name[36]),
|
||||
reinterpret_cast<uint32_t *>(&m_brand_name[40]),
|
||||
reinterpret_cast<uint32_t *>(&m_brand_name[44]));
|
||||
} else {
|
||||
m_brand_name[0] = 0;
|
||||
}
|
||||
|
||||
uint32_t leaf = -1u;
|
||||
uint32_t sub = -1u;
|
||||
regs r;
|
||||
#define CPU_FEATURE_OPT(name, feat_leaf, feat_sub, regname, bit) \
|
||||
if (leaf != feat_leaf || sub != feat_sub) { \
|
||||
leaf = feat_leaf; sub = feat_sub; r = get(leaf, sub); \
|
||||
} \
|
||||
if (r.regname & (1ull << bit)) \
|
||||
m_features |= (1ull << static_cast<uint64_t>(feature::name)); \
|
||||
|
||||
#define CPU_FEATURE_REQ(name, feat_leaf, feat_sub, regname, bit) \
|
||||
CPU_FEATURE_OPT(name, feat_leaf, feat_sub, regname, bit); \
|
||||
if ((r.regname & (1ull << bit)) == 0) { \
|
||||
m_missing |= (1ull << static_cast<uint64_t>(feature::name)); \
|
||||
}
|
||||
|
||||
#include "cpu/features.inc"
|
||||
#undef CPU_FEATURE_OPT
|
||||
#undef CPU_FEATURE_REQ
|
||||
}
|
||||
|
||||
cpu_id::regs
|
||||
cpu_id::get(uint32_t leaf, uint32_t sub) const
|
||||
{
|
||||
regs ret {0, 0, 0, 0};
|
||||
|
||||
if ((leaf & cpuid_extended) == 0 && leaf > m_high_basic) return ret;
|
||||
if ((leaf & cpuid_extended) != 0 && leaf > m_high_ext) return ret;
|
||||
|
||||
__cpuid(leaf, sub, &ret.eax, &ret.ebx, &ret.ecx, &ret.edx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool
|
||||
cpu_id::has_feature(feature feat)
|
||||
{
|
||||
return (m_features & (1 << static_cast<uint64_t>(feat))) != 0;
|
||||
}
|
||||
|
||||
}
|
||||
81
src/libraries/cpu/include/cpu/cpu.h
Normal file
81
src/libraries/cpu/include/cpu/cpu.h
Normal file
@@ -0,0 +1,81 @@
|
||||
#pragma once
|
||||
/// \file cpu.h Definition of required cpu features for jsix
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace cpu {
|
||||
|
||||
/// Enum of the cpu features jsix cares about
|
||||
enum class feature {
|
||||
#define CPU_FEATURE_REQ(name, ...) name,
|
||||
#define CPU_FEATURE_OPT(name, ...) name,
|
||||
#include "cpu/features.inc"
|
||||
#undef CPU_FEATURE_OPT
|
||||
#undef CPU_FEATURE_REQ
|
||||
max
|
||||
};
|
||||
|
||||
class cpu_id
|
||||
{
|
||||
public:
|
||||
static constexpr uint32_t cpuid_extended = 0x80000000;
|
||||
|
||||
/// CPUID result register values
|
||||
struct regs {
|
||||
union {
|
||||
uint32_t reg[4];
|
||||
uint32_t eax, ebx, ecx, edx;
|
||||
};
|
||||
|
||||
/// Return true if bit |bit| of EAX is set
|
||||
bool eax_bit(unsigned bit) { return (eax >> bit) & 0x1; }
|
||||
|
||||
/// Return true if bit |bit| of EBX is set
|
||||
bool ebx_bit(unsigned bit) { return (ebx >> bit) & 0x1; }
|
||||
|
||||
/// Return true if bit |bit| of ECX is set
|
||||
bool ecx_bit(unsigned bit) { return (ecx >> bit) & 0x1; }
|
||||
|
||||
/// Return true if bit |bit| of EDX is set
|
||||
bool edx_bit(unsigned bit) { return (edx >> bit) & 0x1; }
|
||||
};
|
||||
|
||||
cpu_id();
|
||||
|
||||
/// The the result of a given CPUID leaf/subleaf
|
||||
/// \arg leaf The leaf selector (initial EAX)
|
||||
/// \arg subleaf The subleaf selector (initial ECX)
|
||||
/// \returns A |regs| struct of the values retuned
|
||||
regs get(uint32_t leaf, uint32_t sub = 0) const;
|
||||
|
||||
/// Get the name of the cpu vendor (eg, "GenuineIntel")
|
||||
inline const char * vendor_id() const { return m_vendor_id; }
|
||||
|
||||
/// Get the brand name of this processor model
|
||||
inline const char * brand_name() const { return m_brand_name; }
|
||||
|
||||
/// Get the highest basic CPUID leaf supported
|
||||
inline uint32_t highest_basic() const { return m_high_basic; }
|
||||
|
||||
/// Get the highest extended CPUID leaf supported
|
||||
inline uint32_t highest_ext() const { return m_high_ext; }
|
||||
|
||||
/// Get which required options are missing as flags
|
||||
inline uint64_t missing() const { return m_missing; }
|
||||
|
||||
/// Validate the CPU supports the necessary options for jsix
|
||||
inline bool supported() const { return m_missing; }
|
||||
|
||||
/// Return true if the CPU claims to support the given feature
|
||||
bool has_feature(feature feat);
|
||||
|
||||
private:
|
||||
uint32_t m_high_basic;
|
||||
uint32_t m_high_ext;
|
||||
uint64_t m_features;
|
||||
uint64_t m_missing;
|
||||
char m_vendor_id[13];
|
||||
char m_brand_name[48];
|
||||
};
|
||||
|
||||
}
|
||||
@@ -7,8 +7,9 @@ CPU_FEATURE_REQ(pse, 0x00000001, 0, edx, 3)
|
||||
CPU_FEATURE_OPT(tsc, 0x00000001, 0, edx, 4)
|
||||
CPU_FEATURE_REQ(msr, 0x00000001, 0, edx, 5)
|
||||
CPU_FEATURE_REQ(apic, 0x00000001, 0, edx, 9)
|
||||
CPU_FEATURE_REQ(mtrr, 0x00000001, 0, edx, 12)
|
||||
CPU_FEATURE_REQ(pge, 0x00000001, 0, edx, 13)
|
||||
CPU_FEATURE_OPT(pat, 0x00000001, 0, edx, 16)
|
||||
CPU_FEATURE_REQ(pat, 0x00000001, 0, edx, 16)
|
||||
CPU_FEATURE_REQ(fxsr, 0x00000001, 0, edx, 24)
|
||||
|
||||
CPU_FEATURE_OPT(fsgsbase, 0x00000007, 0, ebx, 0)
|
||||
@@ -45,20 +45,6 @@ struct hash_node
|
||||
inline uint64_t hash() const { return h; }
|
||||
};
|
||||
|
||||
template <typename V>
|
||||
struct hash_node <uint64_t, V>
|
||||
{
|
||||
uint64_t key;
|
||||
V val;
|
||||
|
||||
hash_node(hash_node &&o) : key(std::move(o.key)), val(std::move(o.val)) {}
|
||||
hash_node(uint64_t h, uint64_t &&k, V &&v) : key(std::move(k)), val(std::move(v)) {}
|
||||
~hash_node() {}
|
||||
|
||||
inline uint64_t & hash() { return key; }
|
||||
inline uint64_t hash() const { return key; }
|
||||
};
|
||||
|
||||
/// Base class for hash maps
|
||||
template <typename K, typename V>
|
||||
class base_map
|
||||
|
||||
@@ -1,24 +1,19 @@
|
||||
section .bss
|
||||
mymessage:
|
||||
resq 1024
|
||||
|
||||
extern main
|
||||
extern _init_libc
|
||||
extern exit
|
||||
extern _init_libc
|
||||
|
||||
section .text
|
||||
|
||||
global _start
|
||||
global _start:function (_start.end - _start)
|
||||
_start:
|
||||
mov rbp, rsp
|
||||
|
||||
mov rdi, rsp
|
||||
|
||||
call _init_libc
|
||||
|
||||
mov rdi, 0
|
||||
mov rsi, 0
|
||||
pop rdi
|
||||
mov rsi, rsp
|
||||
|
||||
call main
|
||||
|
||||
mov rdi, rax
|
||||
call exit
|
||||
.end:
|
||||
36
src/libraries/libc/arch/x86_64/init_libc.c
Normal file
36
src/libraries/libc/arch/x86_64/init_libc.c
Normal file
@@ -0,0 +1,36 @@
|
||||
#include <stdint.h>
|
||||
#include <j6/init.h>
|
||||
#include <j6/types.h>
|
||||
|
||||
static size_t __initc = 0;
|
||||
static struct j6_init_value *__initv = 0;
|
||||
|
||||
j6_handle_t __handle_sys = j6_handle_invalid;
|
||||
|
||||
void
|
||||
_get_init(size_t *initc, struct j6_init_value **initv)
|
||||
{
|
||||
if (!initc)
|
||||
return;
|
||||
|
||||
*initc = __initc;
|
||||
if (initv)
|
||||
*initv = __initv;
|
||||
}
|
||||
|
||||
void
|
||||
_init_libc(uint64_t *rsp)
|
||||
{
|
||||
uint64_t argc = *rsp++;
|
||||
rsp += argc;
|
||||
|
||||
__initc = *rsp++;
|
||||
__initv = (struct j6_init_value *)rsp;
|
||||
|
||||
for (unsigned i = 0; i < __initc; ++i) {
|
||||
if (__initv[i].type == j6_init_handle_system) {
|
||||
__handle_sys = __initv[i].value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,9 +10,24 @@ void * memcpy( void * restrict s1, const void * restrict s2, size_t n )
|
||||
{
|
||||
char * dest = (char *) s1;
|
||||
const char * src = (const char *) s2;
|
||||
while ( n-- )
|
||||
{
|
||||
|
||||
if (((uintptr_t)src & 7) == ((uintptr_t)dest & 7)) {
|
||||
while (((uintptr_t)src & 7) && n--)
|
||||
*dest++ = *src++;
|
||||
|
||||
const uint64_t *srcq = (const uint64_t*)src;
|
||||
uint64_t *destq = (uint64_t*)dest;
|
||||
while (n >= 8) {
|
||||
*destq++ = *srcq++;
|
||||
n -= 8;
|
||||
}
|
||||
|
||||
src = (const char*)srcq;
|
||||
dest = (char*)destq;
|
||||
}
|
||||
|
||||
while (n--)
|
||||
*dest++ = *src++;
|
||||
|
||||
return s1;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user