31 Commits

Author SHA1 Message Date
Justin C. Miller
2be70976ca Merge branch 'real-hardware' into fb-driver 2021-01-18 13:38:51 -08:00
Justin C. Miller
699fc57e0a [boot] Log address of new table pages
Since it's often needed when debugging between the bootloader and
kernel, log the address of the table pages the bootloader allocated.
2021-01-18 13:36:05 -08:00
Justin C. Miller
f3bb2e5259 [boot] Save commented-out mem map dumping code
This is often needed, so I'm commiting it commented out.
2021-01-18 13:35:01 -08:00
Justin C. Miller
34120fc4c1 [cpu] Split cpuid validation into separate lib
In order to allow the bootloader to do preliminary CPUID validation
while UEFI is still handling displaying information to the user, split
most of the kernel's CPUID handling into a library to be used by both
kernel and boot.
2021-01-18 13:26:45 -08:00
Justin C. Miller
e52fd8eacf [libc] Attempt to speed up memcpy for aligned mem
Copy long-by-long instead of byte-by-byte if both pointers are similarly
aligned.
2021-01-17 20:54:38 -08:00
Justin C. Miller
a97073848c [fb] Use double-buffering in fb driver
Allocate and use a back buffer, so that draws to the screen are always a
single memcpy()
2021-01-17 20:53:41 -08:00
Justin C. Miller
03b2d0dac7 [kernel] Set framebuffer to write-combining
Several changes were needed to make this work:

- Update the page_table::flags to understand memory caching types
- Set up the PAT MSR to add the WC option
- Make page-offset area mapped as WT
- Add all the MTRR and PAT MSRs, and log the MTRRs for verification
- Add a vm_area flag for write_combining
2021-01-17 20:49:47 -08:00
Justin C. Miller
cfeeba4400 [kenrel] Ensure page tables are zeroed before use
I forgot to zero out pages used for page tables, which didn't come back
to bite me until testing on physical hardware..
2021-01-17 10:35:19 -08:00
Justin C. Miller
45b52633bb [boot] Add scanline size to fb boot message
Scanline size can differ from horizontal resolution in some
framebuffers. This isn't currently handled, but at least log it so
it's visible if this lack of handling is a potential error.
2021-01-17 10:28:54 -08:00
Justin C. Miller
b9af081a44 [boot] Don't use custom UEFI memory types
The UEFI spec specifically calls out memory types with the high bit set
as being available for OS loaders' custom use. However, it seems many
UEFI firmware implementations don't handle this well. (Virtualbox, and
the firmware on my Intel NUC and Dell XPS laptop to name a few.)

So sadly since we can't rely on this feature of UEFI in all cases, we
can't use it at all. Instead, treat _all_ memory tagged as EfiLoaderData
as possibly containing data that's been passed to the OS by the
bootloader and don't free it yet.

This will need to be followed up with a change that copies anything we
need to save and frees this memory.

See: https://github.com/kiznit/rainbow-os/blob/master/boot/machine/efi/README.md
2021-01-17 10:26:24 -08:00
Justin C. Miller
d75b9c22d4 [boot] Don't use custom UEFI memory types
The UEFI spec specifically calls out memory types with the high bit set
as being available for OS loaders' custom use. However, it seems many
UEFI firmware implementations don't handle this well. (Virtualbox, and
the firmware on my Intel NUC and Dell XPS laptop to name a few.)

So sadly since we can't rely on this feature of UEFI in all cases, we
can't use it at all. Instead, treat _all_ memory tagged as EfiLoaderData
as possibly containing data that's been passed to the OS by the
bootloader and don't free it yet.

This will need to be followed up with a change that copies anything we
need to save and frees this memory.

See: https://github.com/kiznit/rainbow-os/blob/master/boot/machine/efi/README.md
2021-01-08 22:40:30 -08:00
Justin C. Miller
e20c53f193 [boot] Add framebuffer progress bar
After exiting UEFI, the bootloader had no way of displaying status to
the user. Now it will display a series of small boxes as a progress bar
along the bottom of the screen if a framebuffer exists. Errors or
warnings during a step will cause that step's box to turn red or orange,
and display bars above it to signal the error code.

This caused the simplification of the error handling system (which was
mostly just calling status_line::fail) and added different types of
status objects.
2021-01-08 22:25:37 -08:00
Justin C. Miller
6d4a32b6e8 [boot] List the detected framebuffer in boot log
List information about the detected framebuffer device (or lack thereof)
in the bootloader log messages.
2021-01-06 23:29:31 -08:00
Justin C. Miller
63a5c2da00 Merge branch 'fb-driver' of github.com:justinian/jsix into fb-driver 2021-01-06 23:26:26 -08:00
Justin C. Miller
bdcd0c2fda [kernel] Clean up process::exit
Make process::exit slightly more resilient to being called again.
2021-01-06 23:25:48 -08:00
Justin C. Miller
1be929b9d5 [fb] Simplify scrollback line counting
Using a start and a count was redundant when we know how many lines are
in the buffer already.
2021-01-06 23:20:29 -08:00
Justin C. Miller
d11dd0c3f9 [kernel] Fix memory clobbering from endpoint
The endpoint receive syscalls can block and then write to userspace
memory. Since the current address space may be different after blocking,
make sure to only actually write to the user memory after returning to
the syscall handler - pass values that are on the syscall handler stack
deeper into the kernel.
2021-01-06 23:16:16 -08:00
Justin C. Miller
e08e00790f [kernel] Give processes and threads self handles
It was not consistent how processes got handles to themselves or their
threads, ending up with double entries. Now make such handles automatic
and expose them with new self_handle() methods.
2021-01-06 23:14:39 -08:00
Justin C. Miller
8b3356e9d8 [kutil] Remove uint64_t hash_node specialization
Using a hash of zero to signal an empty slot doesn't play nice with the
hash_node specialization that uses the key for the hash, when 0 is a
common key.

I thought it would be ok, that it'd just be something to remember. But
then I used 0 as a key anyway, so clearly it was a bad idea.
2021-01-06 23:09:50 -08:00
Justin C. Miller
cd30126f17 [boot] Reduce loader spam
Now that the ELF loader is known to be working correctly, remove its
extra print statements about section loading to keep the bootloader
output to one screen.
2021-01-06 11:34:34 -08:00
Justin C. Miller
2c444dccd6 [build] Remove fake terminal.elf
A fake terminal.elf (copy of nulldrv.elf) was added to test the loader.
Now that there actually are multiple programs to load, remove the fake
one.
2021-01-06 11:32:45 -08:00
Justin C. Miller
bd490c4c7b [scripts] Ignore demangle errors building sym table
For some reason, cxxfilt fails to demangle some names on some systems.
Instead of failing the build process, just skip those symbols.
2021-01-06 11:30:40 -08:00
Justin C. Miller
3a67e461de [scripts] Allow qemu.sh to not remove VGA device
Added --vga option to qemu.sh to stop it from passing "-vga none" to
qemu. This allows the console version to act like it has a video device.
2021-01-04 01:00:03 -08:00
Justin C. Miller
972ef39295 [fb] Output klog to fb if video exists
If there's no video, do as we did before, otherwise route logs to the fb
driver instead. (Need to clean this up to just have a log consumer
general interface?) Also added a "scrollback" class to fb driver and
updated the system_get_log syscall.
2021-01-03 18:13:41 -08:00
Justin C. Miller
4c41205e73 [fb] Change to embedding PSF file
Moved old PSF parsing code from kernel, and switched to embedding whole
PSF instead of just glyph data to make font class the same code paths
for both cases.
2021-01-03 00:08:20 -08:00
Justin C. Miller
f6b4a4a103 [fb] Add default hard-coded font
For the fb driver to have a font before loading from disk is available,
create a hard-coded font as a byte array.

To create this, added a new scripts/psf_to_cpp.py which also refactored
out much of scripts/parse_font.py into a new shared module
scripts/fontpsf.py.
2021-01-02 15:52:26 -08:00
327cd93c04 [kernel] Fix vm_space extra deletion
vm_space::clear() was freeing pages on process exit even when free was
false, and potentially double-freeing some pages.
2020-12-31 00:59:48 -08:00
0e6b27e741 [kernel] Improve process init
Move process init from each process needing a main.s with _start to
crt0.s in libc. Also change to a sysv-like initial stack with a
j6-specific array of initialization values after the program arguments.
2020-12-31 00:57:51 -08:00
db8a14720b [kernel] Rename kernel entrypoint
The kernel entrypoint being named _start conflicts with userspace
program entrypoints and makes debugging more difficult. Rename it to
_kernel_start.
2020-12-30 17:56:37 -08:00
87a7293ac1 [tools] Improve j6stack GDB command
Improve the j6stack command in two ways: first, swap the order of the
arguments, as depth is much more likely to be changed. Second, on any
exception accessing memory in the stack, print the exception and
continue instead of failing the whole command.
2020-12-30 17:49:27 -08:00
5787aff866 [fb] Create fb driver
Create a new framebuffer driver. Also hackily passing frame buffer size
in the list of init handles to all processes and mapping the framebuffer
into all processes. Changed bootloader passing frame buffer as a module
to its own struct.
2020-12-27 18:49:38 -08:00
71 changed files with 2065 additions and 1104 deletions

View File

@@ -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)")

View File

@@ -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

View File

@@ -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

View File

@@ -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
View 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
View 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
View 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)

View File

@@ -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

View File

@@ -1,4 +1,4 @@
ENTRY(_start)
ENTRY(_kernel_start)
SECTIONS
{
. = 0xFFFF800000000000;

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -8,6 +8,7 @@
#include "console.h"
#include "error.h"
#include "memory.h"
#include "status.h"
namespace boot {
namespace fs {

View File

@@ -1,6 +1,7 @@
#include "hardware.h"
#include "console.h"
#include "error.h"
#include "status.h"
namespace boot {
namespace hw {

View File

@@ -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;

View File

@@ -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();

View File

@@ -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)];
return L"Bad Type Value";
}
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";
}
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

View File

@@ -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

View File

@@ -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
View 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
View 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

View 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

View File

@@ -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
View 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
View 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
View 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
View 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;
};

View 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);
}
}
}

View 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;
};

View File

@@ -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
View 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;
};

View File

@@ -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.

View File

@@ -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))));

View File

@@ -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 *)

View File

@@ -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

View File

@@ -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);
}

View File

@@ -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;
};

View File

@@ -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;
}

View File

@@ -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();

View File

@@ -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;
};

View File

@@ -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);
}

View File

@@ -6,4 +6,5 @@ namespace log = kutil::log;
namespace logs = kutil::logs;
void logger_init();
void logger_clear_immediate();
void logger_task();

View File

@@ -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);

View File

@@ -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);

View File

@@ -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)
{

View File

@@ -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

View File

@@ -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) {

View File

@@ -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();

View File

@@ -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()

View File

@@ -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;
};

View File

@@ -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
};

View File

@@ -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);
}

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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;
};

View File

@@ -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

View File

@@ -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

View File

@@ -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);

View File

@@ -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);
}
}
}

View File

@@ -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;

View File

@@ -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
View 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;
}
}

View 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];
};
}

View File

@@ -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)

View File

@@ -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

View File

@@ -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:

View 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;
}
}
}

View File

@@ -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;
}