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