4 Commits
Author SHA1 Message Date
josh 4a39341a83 Turn off local APIC timer 2022-12-14 23:56:11 -05:00
josh 42ab6f396d Processing multiple RTC interrupts 2022-12-14 23:51:35 -05:00
josh 58d685a15b Program I/O APIC; got one RTC interrupt 2022-12-14 23:43:26 -05:00
josh d49f9e32cd dev checkpoint 2022-12-14 19:40:22 -05:00
32 changed files with 451 additions and 1319 deletions

No files matched your search

-1
View File
@@ -1,4 +1,3 @@
.rscons*
/x86_64-elf-gcc/
/build/
/qemu/
+2 -12
View File
@@ -17,8 +17,6 @@ the build command.
# Running HOS
HOS can run on a physical machine, in VirtualBox, or in QEMU.
## Physical Machine
To install HOS to an EFI partition, follow these steps:
@@ -69,13 +67,5 @@ To create a VM in VirtualBox:
12. Move the HOS.vmdk file generated to the HOS VirtualBox folder.
13. In VirtualBox Manager, open HOS VM settings.
14. Under System, check the Enable EFI checkbox.
15. Under System, change the Chipset to ICH9.
16. Under Storage, add a hard disk and browse to select the HOS.vmdk file.
17. To run HOS, either start the VM through VirtualBox or with "./rscons run-vb".
## QEMU
Make sure QEMU is installed (possibly the `qemu-desktop` package). Then:
1. Build HOS ("./rscons").
2. Run `./rscons run` to run HOS in QEMU.
15. Under Storage, add a hard disk and browse to select the HOS.vmdk file.
16. To run HOS, either start the VM through VirtualBox or with "./rscons run-vb".
+9 -53
View File
@@ -26,7 +26,7 @@ MB = 1024 * 1024
class HulkBinObj < Builder
def run(options)
@cache.mkdir_p(File.dirname(@target))
FileUtils.mkdir_p(File.dirname(@target))
File.write(@target, <<EOF)
.section ".rodata"
.balign 4096
@@ -136,7 +136,7 @@ hulk_env = env "hulk", use: %w[ldc2 x86_64-elf-gcc] do |env|
env["D_IMPORT_PATH"] += %w[src]
env["D_IMPORT_PATH"] << env.expand("^/src")
env["LD"] = "x86_64-elf-gcc"
env["LDFLAGS"] += %w[-nostdlib -Tsrc/hulk/hulk.ld -Wl,--gc-sections -Wl,-Map,${_TARGET}.map]
env["LDFLAGS"] += %w[-nostdlib -Tsrc/hulk/hulk.ld -Wl,-Map,${_TARGET}.map]
env["LDCMD"] = %w[${LD} -o ${_TARGET} ${LDFLAGS} ${_SOURCES} ${LIBDIRPREFIX}${LIBPATH} ${LIBLINKPREFIX}${LIBS}]
env["OBJDUMP"] = "x86_64-elf-objdump"
env["OBJCOPY"] = "x86_64-elf-objcopy"
@@ -145,8 +145,8 @@ hulk_env = env "hulk", use: %w[ldc2 x86_64-elf-gcc] do |env|
env.CheckThreadLocal(:hulk_map_check, "^/hulk.elf.map")
env.depends("^/hulk.elf", "src/hulk/hulk.ld")
env["SIZE"] = "x86_64-elf-size"
env.Size("^/hulk.elf.size", "^/hulk.elf")
env.Disassemble("^/hulk.elf.txt", "^/hulk.elf")
env.Size("^/hulk.size", "^/hulk.elf")
env.Disassemble("^/hulk.txt", "^/hulk.elf")
env.Command("^/hulk.bin", "^/hulk.elf",
"CMD" => %W[${OBJCOPY} -O binary ${_SOURCES} ${_TARGET}],
"CMD_DESC" => "Convert ELF to binary:")
@@ -162,10 +162,6 @@ hello_env = env "hello", use: %w[ldc2 x86_64-w64-mingw32-gcc] do |env|
env.add_builder(CheckThreadLocal)
env.add_builder(HulkBinObj)
env["sources"] = glob("src/hello/**/*.d")
env["sources"] += %w[
src/hulk/serial.d
src/hulk/writef.d
]
env["sources"] += glob("uefi-d/source/**/*.d")
env.HulkBinObj("^/hulk_bin.S", hulk_env.expand("^/hulk.bin"))
env.Object("^/hulk_bin.o", "^/hulk_bin.S")
@@ -187,56 +183,16 @@ hello_env = env "hello", use: %w[ldc2 x86_64-w64-mingw32-gcc] do |env|
end
task "run", desc: "Run HOS in QEMU" do
FileUtils.rm_rf("qemu")
FileUtils.mkdir_p("qemu")
img = hello_env.expand("^/HOS.img")
FileUtils.cp(img, "qemu")
ovmf = "OVMF.fd"
if File.exist?("/usr/share/edk2/x64/OVMF.fd")
ovmf = "/usr/share/edk2/x64/OVMF.fd"
Dir.mktmpdir do |tmpdir|
img = hello_env.expand("^/HOS.img")
FileUtils.cp(img, tmpdir)
sh %W[qemu-system-x86_64 -cpu max -bios OVMF.fd -drive file=#{tmpdir}/HOS.img,format=raw -device qemu-xhci -device usb-tablet]
end
sh %W[
qemu-system-x86_64
-machine q35
-cpu max
-serial file:qemu/serial.out
-bios #{ovmf}
-drive file=qemu/HOS.img,format=raw
-device qemu-xhci
-device usb-tablet]
end
# See README.md for how to set up VirtualBox for HOS.
task "mk-vmdk", desc: "Create VirtualBox VMDK virtual drive for HOS" do
path = File.expand_path(hello_env.expand("^/HOS.img"))
sectors = File.stat(path).size / 512
File.binwrite("HOS.vmdk", <<EOF)
# Disk DescriptorFile
version=1
CID=1d1c3615
parentCID=ffffffff
createType="fullDevice"
# Extent description
RW #{sectors} FLAT "#{path}" 0
# The disk Data Base
#DDB
ddb.virtualHWVersion = "4"
ddb.adapterType="ide"
ddb.geometry.cylinders="8"
ddb.geometry.heads="16"
ddb.geometry.sectors="63"
ddb.uuid.image="03783b5a-7587-4d8b-ad04-9d70f70a94c2"
ddb.uuid.parent="00000000-0000-0000-0000-000000000000"
ddb.uuid.modification="00000000-0000-0000-0000-000000000000"
ddb.uuid.parentmodification="00000000-0000-0000-0000-000000000000"
ddb.geometry.biosCylinders="8"
ddb.geometry.biosHeads="16"
ddb.geometry.biosSectors="63"
EOF
#sh %W[VBoxManage createmedium disk --filename=HOS.vmdk --variant=RawDisk --format=VMDK --property RawDrive=#{File.expand_path(hello_env.expand("^/HOS.img"))}]
sh %W[VBoxManage internalcommands createrawvmdk -filename HOS.vmdk -rawdisk #{File.expand_path(hello_env.expand("^/HOS.img"))}]
end
# See README.md for how to set up VirtualBox for HOS.
+15 -77
View File
@@ -1,6 +1,5 @@
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <ft2build.h>
#include <stdio.h>
#include FT_FREETYPE_H
@@ -87,43 +86,35 @@ static void generate_bytes(FILE * file, const uint8_t * bytes, int count)
}
}
static bool generate(const char * d_file_name)
static void generate(const char * d_file_name)
{
FILE * fh = fopen(d_file_name, "wb");
fprintf(fh, "module hulk.kfont;\n");
fprintf(fh, "struct CharInfo {\n");
fprintf(fh, " /** Glyph bitmap width. */\n");
fprintf(fh, " ubyte width;\n");
fprintf(fh, " /** Glyph bitmap height. */\n");
fprintf(fh, " ubyte height;\n");
fprintf(fh, " /** Glyph bitmap top offset (descent from top of text row). */\n");
fprintf(fh, " ubyte top;\n");
fprintf(fh, " /** Glyph bitmap left offset. */\n");
fprintf(fh, " ubyte left;\n");
fprintf(fh, " /** Glyph bitmap. */\n");
fprintf(fh, " uint width;\n");
fprintf(fh, " uint height;\n");
fprintf(fh, " int top;\n");
fprintf(fh, " int left;\n");
fprintf(fh, " const ubyte[] bitmap;\n");
fprintf(fh, "};\n");
fprintf(fh, "struct FontInfo {\n");
fprintf(fh, " /** Font line height. */\n");
fprintf(fh, " ubyte line_height;\n");
fprintf(fh, " /** Font advance. */\n");
fprintf(fh, " ubyte advance;\n");
fprintf(fh, " /** Characters. */\n");
fprintf(fh, " uint line_height;\n");
fprintf(fh, " uint advance;\n");
fprintf(fh, " int baseline_offset;\n");
fprintf(fh, " const CharInfo[] chars;\n");
fprintf(fh, "};\n");
fprintf(fh, "/** Kernel font data. */\n");
fprintf(fh, "__gshared const FontInfo Kfont = {\n");
fprintf(fh, "__gshared const FontInfo kfont = {\n");
fprintf(fh, " %du,\n", line_height);
fprintf(fh, " %du,\n", max_advance);
fprintf(fh, " %d,\n", baseline_offset);
fprintf(fh, " [\n");
for (int i = 0; i < N_CHARS; i++)
{
fprintf(fh, " /* %d */", i);
fprintf(fh, " CharInfo(\n");
fprintf(fh, " %du /* width */,\n", char_infos[i].width);
fprintf(fh, " %du /* height */,\n", char_infos[i].height);
fprintf(fh, " %du /* top */,\n", char_infos[i].top);
fprintf(fh, " %du /* left */,\n", char_infos[i].left);
fprintf(fh, " %du,\n", char_infos[i].width);
fprintf(fh, " %du,\n", char_infos[i].height);
fprintf(fh, " %d,\n", char_infos[i].top);
fprintf(fh, " %d,\n", char_infos[i].left);
if (char_infos[i].width > 0)
{
fprintf(fh, " [\n");
@@ -139,7 +130,6 @@ static bool generate(const char * d_file_name)
fprintf(fh, " ],\n");
fprintf(fh, "};\n");
fclose(fh);
return true;
}
int main(int argc, char * argv[])
@@ -177,59 +167,7 @@ int main(int argc, char * argv[])
line_height = round_up_26_6(face->size->metrics.height);
baseline_offset = (line_height - (max_top - min_bottom)) / 2 - min_bottom;
if ((line_height < 1) || (line_height > 0xFF))
{
fprintf(stderr, "Error: invalid line_height %d\n", line_height);
return false;
}
if ((max_advance < 1) || (max_advance > 0xFF))
{
fprintf(stderr, "Error: invalid max_advance %d\n", max_advance);
return false;
}
for (int i = 0; i < N_CHARS; i++)
{
if ((char_infos[i].width < 0) || (char_infos[i].width > max_advance))
{
fprintf(stderr, "Error: invalid character %d width: %d\n", i, char_infos[i].width);
return false;
}
if ((char_infos[i].height < 0) || (char_infos[i].height > line_height))
{
fprintf(stderr, "Error: invalid character %d height: %d\n", i, char_infos[i].height);
return false;
}
if ((char_infos[i].left < 0) || (char_infos[i].left >= max_advance))
{
fprintf(stderr, "Error: invalid character %d left: %d\n", i, char_infos[i].left);
return false;
}
/* Adjust character top to be index downward from top of font box. */
char_infos[i].top = line_height - baseline_offset - char_infos[i].top;
if ((char_infos[i].top < 0) || (char_infos[i].top >= line_height))
{
fprintf(stderr, "Error: invalid character %d top: %d\n", i, char_infos[i].top);
return false;
}
if ((char_infos[i].left + char_infos[i].width) > max_advance)
{
fprintf(stderr, "Error: character %d left (%d) + width (%d) > advance (%d)\n",
i, char_infos[i].left, char_infos[i].width, max_advance);
return false;
}
if ((char_infos[i].top + char_infos[i].height) > line_height)
{
fprintf(stderr, "Error: character %d top (%d) + height (%d) > line height (%d)\n",
i, char_infos[i].top, char_infos[i].height, line_height);
return false;
}
}
if (!generate(out_file))
{
return 1;
}
generate(out_file);
return 0;
}
+115 -22
View File
@@ -6,62 +6,155 @@ module hello.console;
import uefi;
import hello.hello;
import core.stdc.stdarg;
import hulk.writef;
struct Console
struct console
{
/**
* Write a character to the console.
* Format a hexadecimal value to a string.
*
* @param ch Character to write.
* @param s String buffer.
* @param v Value to format.
* @param ptr If true, always output all 16 digits, and separate the upper and
* lower halves with an underscore.
*/
public static void write(ubyte ch)
private static size_t format_hex(CHAR16 * s, ulong v, bool ptr)
{
if (ch == '\n')
string hex_chars = "0123456789ABCDEF";
bool print = ptr;
size_t si = 0u;
for (size_t i = 0u; i < 16u; i++)
{
write('\r');
if (ptr && (i == 8u))
{
s[si++] = '_';
}
ulong n = (v >> (60u - 4u * i)) & 0xFu;
if (n != 0u)
{
print = true;
}
if (print || (i == 15u))
{
s[si++] = hex_chars[n];
}
}
CHAR16[2] s16 = [ch, 0];
st.ConOut.OutputString(st.ConOut, &s16[0]);
return si;
}
/**
* Write a formatted string to the console.
* Format a decimal value to a string.
*
* @param s String buffer.
* @param v Value to format.
*/
private static size_t format_dec(CHAR16 * s, ulong v)
{
string dec_chars = "0123456789";
bool print;
char[20] buf;
size_t buf_i;
while ((buf_i == 0u) || (v != 0u))
{
ulong n = v % 10u;
buf[buf_i++] = dec_chars[n];
v /= 10u;
}
for (size_t si = 0u; si < buf_i; si++)
{
s[si] = buf[buf_i - si - 1u];
}
return buf_i;
}
/**
* Write a string to the console.
*
* @param s Format string.
* @param args Variable arguments structure.
*/
public static void writef(string s, va_list args)
public static void write(string s, va_list args)
{
hulk.writef.writef(s, args, function void(ubyte ch) {
Console.write(ch);
});
__gshared static CHAR16[256] s16;
size_t i = 0u;
bool escape = false;
foreach (char c; s)
{
if (escape)
{
if (c == '%')
{
s16[i++] = '%';
}
else if (c == 'x')
{
ulong v;
va_arg(args, v);
i += format_hex(&s16[i], v, false);
}
else if (c == 'p')
{
ulong v;
va_arg(args, v);
i += format_hex(&s16[i], v, true);
}
else if (c == 'S')
{
const(CHAR16) * s2;
va_arg(args, s2);
for (size_t s2_i = 0u; s2[s2_i] != 0; s2_i++)
{
s16[i++] = s2[s2_i];
}
}
else if (c == 'u')
{
ulong v;
va_arg(args, v);
i += format_dec(&s16[i], v);
}
else
{
s16[i++] = c;
}
escape = false;
}
else if (c == '%')
{
escape = true;
}
else
{
s16[i++] = c;
}
}
s16[i++] = 0u;
st.ConOut.OutputString(st.ConOut, &s16[0]);
}
/**
* Write a formatted string to the console.
* Write a string to the console.
*
* @param s Format string.
*/
public static extern (C) void writef(string s, ...)
public static extern (C) void write(string s, ...)
{
va_list args;
va_start(args, s);
writef(s, args);
write(s, args);
va_end(args);
}
/**
* Write a formatted string and newline to the console.
* Write a string to the console.
*
* @param s Format string.
*/
public static extern (C) void writefln(string s, ...)
public static extern (C) void writeln(string s, ...)
{
va_list args;
va_start(args, s);
writef(s, args);
writef("\n", args);
write(s, args);
write("\r\n", args);
va_end(args);
}
@@ -70,7 +163,7 @@ struct Console
*/
public static void wait_key()
{
writefln("Press any key...");
writeln("Press any key...");
st.ConIn.Reset(st.ConIn, FALSE);
EFI_INPUT_KEY key;
while (st.ConIn.ReadKeyStroke(st.ConIn, &key) == EFI_NOT_READY)
+14 -29
View File
@@ -11,7 +11,6 @@ import hulk.pagetable;
import hulk.cpu;
import hulk.memory;
import ldc.llvmasm;
import hulk.serial;
__gshared EFI_SYSTEM_TABLE * st;
/** HULK binary start address, 4KB-aligned. */
@@ -94,7 +93,7 @@ private bool set_graphics_mode()
&gop_guid, null, &buffer_size, handles);
if (status != EFI_SUCCESS)
{
Console.writefln("LocateHandle: error %x", status);
console.writeln("LocateHandle: error %x", status);
return false;
}
EFI_HANDLE gop_handle = handles[0];
@@ -103,12 +102,12 @@ private bool set_graphics_mode()
&gop_guid, &gop_interface);
if (status != EFI_SUCCESS)
{
Console.writefln("HandleProtocol: error %x", status);
console.writeln("HandleProtocol: error %x", status);
return false;
}
if (gop_interface == null)
{
Console.writefln("null interface from HandleProtocol");
console.writeln("null interface from HandleProtocol");
return false;
}
EFI_GRAPHICS_OUTPUT_PROTOCOL * gop = cast(EFI_GRAPHICS_OUTPUT_PROTOCOL *)gop_interface;
@@ -130,7 +129,7 @@ private bool set_graphics_mode()
}
if ((status = gop.SetMode(gop, best_mode_number)) != EFI_SUCCESS)
{
Console.writefln("SetMode: Error %x\n", status);
console.writeln("SetMode: Error %x\n", status);
return false;
}
bootinfo().fb.buffer = cast(uint *)gop.Mode.FrameBufferBase;
@@ -175,7 +174,7 @@ private void get_memory_map(ulong * physical_address_limit, UINTN * memory_map_k
&descriptor_version);
if (status != EFI_SUCCESS)
{
Console.writefln("GetMemoryMap: Error %x", status);
console.writeln("GetMemoryMap: Error %x", status);
for (;;) {}
}
size_t n_entries = memory_map_size / descriptor_size;
@@ -188,7 +187,7 @@ private void get_memory_map(ulong * physical_address_limit, UINTN * memory_map_k
{
if (count > bootinfo().memory_map.length)
{
Console.writefln("Memory map too large");
console.writeln("Memory map too large");
for (;;) {}
}
EFI_MEMORY_DESCRIPTOR * descriptor = cast(EFI_MEMORY_DESCRIPTOR *)&scratch_base[count * descriptor_size];
@@ -206,7 +205,6 @@ private void get_memory_map(ulong * physical_address_limit, UINTN * memory_map_k
}
if (descriptor.Type >= efi_to_hulk_memory_map_type.length)
{
Serial.writefln("Unexpected descriptor type %u", descriptor.Type);
continue;
}
bootinfo().memory_map[count].base = descriptor.PhysicalStart;
@@ -219,9 +217,6 @@ private void get_memory_map(ulong * physical_address_limit, UINTN * memory_map_k
bootinfo().bss_phys = bootinfo().memory_map[count].base;
bootinfo().memory_map[count].base += hulk_bss_size();
bootinfo().memory_map[count].size -= hulk_bss_size();
Serial.writefln("Locating HULK BSS at %x:%x",
bootinfo().bss_phys,
bootinfo().bss_phys + hulk_bss_size() - 1u);
found_bss = true;
}
if ((!found_stack) &&
@@ -231,9 +226,6 @@ private void get_memory_map(ulong * physical_address_limit, UINTN * memory_map_k
bootinfo().stack_phys = bootinfo().memory_map[count].base;
bootinfo().memory_map[count].base += hulk_stack_size();
bootinfo().memory_map[count].size -= hulk_stack_size();
Serial.writefln("Locating HULK stack at %x:%x",
bootinfo().stack_phys,
bootinfo().stack_phys + hulk_stack_size() - 1u);
found_stack = true;
}
if ((!found_fb_buffer1) &&
@@ -243,15 +235,8 @@ private void get_memory_map(ulong * physical_address_limit, UINTN * memory_map_k
bootinfo().fb_buffer1_phys = bootinfo().memory_map[count].base;
bootinfo().memory_map[count].base += fb_size;
bootinfo().memory_map[count].size -= fb_size;
Serial.writefln("Locating HULK FB1 at %x:%x",
bootinfo().fb_buffer1_phys,
bootinfo().fb_buffer1_phys + fb_size - 1u);
found_fb_buffer1 = true;
}
Serial.writefln("Memory range %x:%x (%u)",
bootinfo().memory_map[count].base,
bootinfo().memory_map[count].base + bootinfo().memory_map[count].size - 1u,
bootinfo().memory_map[count].type);
}
bootinfo().memory_map_count = count;
if ((!found_bss) || (!found_stack) || (!found_fb_buffer1))
@@ -526,21 +511,21 @@ extern (C) EFI_STATUS efi_main(EFI_HANDLE image_handle, EFI_SYSTEM_TABLE * st)
{
.st = st;
Console.clear();
console.clear();
Console.writefln("Welcome to HELLO, HOS EFI Lightweight LOader, v0.1.0");
Console.writefln("Firmware vendor: '%S', version: 0x%x", st.FirmwareVendor, st.FirmwareVendor);
console.writeln("Welcome to HELLO, HOS EFI Lightweight LOader, v0.1.0");
console.writeln("Firmware vendor: '%S', version: 0x%x", st.FirmwareVendor, st.FirmwareVendor);
if (!find_acpi_xsdt())
{
Console.writefln("Error: Could not locate ACPI XSDT");
Console.wait_key();
console.writeln("Error: Could not locate ACPI XSDT");
console.wait_key();
return EFI_SUCCESS;
}
if (!set_graphics_mode())
{
Console.wait_key();
console.wait_key();
return EFI_SUCCESS;
}
@@ -559,8 +544,8 @@ extern (C) EFI_STATUS efi_main(EFI_HANDLE image_handle, EFI_SYSTEM_TABLE * st)
{
break;
}
Console.writefln("ExitBootServices: Error %x", status);
Console.wait_key();
console.writeln("ExitBootServices: Error %x", status);
console.wait_key();
return EFI_SUCCESS;
}
+46 -110
View File
@@ -7,18 +7,12 @@ import hulk.hurl;
import hulk.klog;
import hulk.memory;
struct Acpi
struct acpi
{
private static uint signature(string s)
{
return s[0] | (s[1] << 8) | (s[2] << 16) | (s[3] << 24);
}
enum uint APIC_SIGNATURE = 0x43495041u;
enum uint XSDT_SIGNATURE = 0x54445358u;
enum uint APIC_SIGNATURE = signature("APIC");
enum uint MCFG_SIGNATURE = signature("MCFG");
enum uint XSDT_SIGNATURE = signature("XSDT");
static align(4) struct Header
static struct XsdtHeader
{
uint signature;
uint length;
@@ -31,136 +25,78 @@ struct Acpi
uint creator_revision;
}
static struct XSDT
static struct Xsdt
{
Header header;
/* Table pointers are not ulong-aligned! They begin at offset 36. */
align(4) ulong[1] tables;
XsdtHeader header;
uint _pad;
ulong[0] tables;
}
static struct MADT
static struct MadtHeader
{
static struct Entry
{
enum LOCAL_APIC_ADDRESS_OVERRIDE = 5;
ubyte type;
ubyte length;
}
Header header;
uint signature;
uint length;
ubyte revision;
ubyte checksum;
char[6] oemid;
ulong oemtableid;
uint oem_revision;
uint creator_id;
uint creator_revision;
uint local_apic_address;
uint flags;
void initialize()
{
apic_address = local_apic_address;
Klog.writefln("Found 32-bit APIC address: 0x%x", apic_address);
const(void) * end = cast(const(void) *)(&this) + header.length;
const(Entry) * entry = cast(const(Entry) *)(cast(ulong)&this + MADT.sizeof);
while (entry < end)
{
entry = cast(const(Entry) *)(cast(size_t)entry + entry.length);
if (entry.type == Entry.LOCAL_APIC_ADDRESS_OVERRIDE)
{
/* Found a 64-bit Local APIC Address Override entry. */
Klog.writefln("Found 64-bit APIC address: 0x%x", apic_address);
memcpy(cast(void *)&apic_address, cast(const(void) *)entry + 4u, apic_address.sizeof);
}
}
}
}
static struct MCFG
static struct MadtEntry
{
/* PCI Segment Group Memory Area Descriptor. */
static struct SGMADesc
{
uint[2] base_address_a;
ushort pci_segment_group_number;
ubyte start_pci_bus_number;
ubyte end_pci_bus_number;
uint _reserved;
public @property ulong base_address() const
{
return base_address_a[0] | (cast(ulong)base_address_a[1] << 32);
}
}
static assert(SGMADesc.sizeof == 16);
static assert(SGMADesc.alignof == 4);
Header header;
uint[2] _reserved;
SGMADesc[0] sgma_descs;
size_t n_sgma_descs()
{
return (header.length - MCFG.sgma_descs.offsetof) / MCFG.SGMADesc.sizeof;
}
ubyte type;
ubyte length;
}
public __gshared ulong apic_address;
public __gshared MADT * madt;
public __gshared MCFG * mcfg;
public static __gshared ulong apic_address;
public static void initialize(ulong acpi_xsdt_phys)
{
/* Map the XSDT header. */
map_table(acpi_xsdt_phys, PAGE_SIZE);
const(XSDT) * xsdt = cast(const(XSDT) *)acpi_xsdt_phys;
hurl.identity_map_range(acpi_xsdt_phys, Xsdt.sizeof, 0u);
const(Xsdt) * xsdt = cast(const(Xsdt) *)acpi_xsdt_phys;
if (xsdt.header.signature != XSDT_SIGNATURE)
{
Klog.fatal_error("XSDT signature invalid");
klog.writef("XSDT signature invalid\n");
return;
}
/* Map the entire XSDT. */
if (xsdt.header.length > PAGE_SIZE)
{
map_table(acpi_xsdt_phys, xsdt.header.length);
}
hurl.identity_map_range(acpi_xsdt_phys, xsdt.header.length, 0u);
size_t n_entries = (xsdt.header.length - xsdt.header.sizeof) / xsdt.tables[0].sizeof;
for (size_t i = 0u; i < n_entries; i++)
{
ulong address = xsdt.tables[i];
map_table(address, PAGE_SIZE);
const(Header) * header = cast(const(Header) *)address;
uint length = header.length;
if (length > PAGE_SIZE)
{
map_table(address, length);
}
uint signature = header.signature;
Klog.writefln("Found ACPI table %08x (%c%c%c%c)",
signature,
signature & 0xFFu,
(signature >> 8u) & 0xFFu,
(signature >> 16u) & 0xFFu,
(signature >> 24u) & 0xFFu);
hurl.identity_map_range(address, 4u, 0u);
uint signature = *cast(const(uint) *)address;
if (signature == APIC_SIGNATURE)
{
madt = cast(MADT *)address;
madt.initialize();
parse_apic_table(address);
}
else if (signature == MCFG_SIGNATURE)
{
mcfg = cast(MCFG *)address;
}
}
if (madt == null)
{
Klog.fatal_error("MADT table not found");
}
if (mcfg == null)
{
Klog.fatal_error("MCFG table not found");
}
}
private static void map_table(ulong address, ulong length)
private static parse_apic_table(ulong address)
{
Hurl.identity_map_range(address, length, PT_DISABLE_CACHE | PT_NO_EXECUTE);
const(MadtHeader) * madt_header = cast(const(MadtHeader) *)address;
hurl.identity_map_range(address, madt_header.length, 0u);
apic_address = madt_header.local_apic_address;
klog.writefln("Found 32-bit APIC address: 0x%x", apic_address);
const(void) * madt_end = cast(const(void) *)(address + madt_header.length);
const(MadtEntry) * madt_entry = cast(const(MadtEntry) *)(address + 0x2Cu);
while (madt_entry < madt_end)
{
madt_entry = cast(const(MadtEntry) *)(cast(size_t)madt_entry + madt_entry.length);
if (madt_entry.type == 5u)
{
/* Found a 64-bit Local APIC Address Override entry. */
memcpy(cast(void *)&apic_address, cast(const(void) *)madt_entry + 4u, 8u);
klog.writefln("Found 64-bit APIC address: 0x%x", apic_address);
}
}
}
}
+14 -24
View File
@@ -7,14 +7,11 @@ import hulk.klog;
import hulk.hurl;
import hulk.acpi;
import hulk.idt;
import hulk.rtc;
struct Apic
struct apic
{
private enum uint PERIODIC_MODE = 0x2_0000u;
private enum ulong IRQ_RTC = 8u;
static struct ApicRegister
{
public uint value;
@@ -66,22 +63,23 @@ struct Apic
public static void initialize()
{
apic_registers = cast(ApicRegisters *)Acpi.apic_address;
apic_registers = cast(ApicRegisters *)acpi.apic_address;
io_apic_registers = cast(IoApicRegisters *)0xFEC0_0000u;
Hurl.map(cast(ulong)apic_registers, cast(ulong)apic_registers,
hurl.map(cast(ulong)apic_registers, cast(ulong)apic_registers,
PT_WRITABLE | PT_WRITE_THROUGH | PT_DISABLE_CACHE | PT_NO_EXECUTE);
Hurl.map(cast(ulong)io_apic_registers, cast(ulong)io_apic_registers,
hurl.map(cast(ulong)io_apic_registers, cast(ulong)io_apic_registers,
PT_WRITABLE | PT_WRITE_THROUGH | PT_DISABLE_CACHE | PT_NO_EXECUTE);
Klog.writefln("LAPIC ID: 0x%08x", apic_registers.lapic_id.value);
Klog.writefln("LAPIC version: 0x%08x", apic_registers.lapic_version.value);
klog.writefln("LAPIC ID: 0x%08x", apic_registers.lapic_id.value);
klog.writefln("LAPIC version: 0x%08x", apic_registers.lapic_version.value);
/* Enable local APIC to receive interrupts and set spurious interrupt
* vector to 0xFF. */
apic_registers.spurious_interrupt_vector.value = 0x100u | Idt.INT_APIC_SPURIOUS;
apic_registers.lvt_timer.value = Idt.INT_APIC_TIMER;
apic_registers.lvt_lint[0].value = Idt.INT_APIC_LINT0;
apic_registers.lvt_lint[1].value = Idt.INT_APIC_LINT1;
/* Enable RTC interrupt. */
configure_io_apic_irq(IRQ_RTC, Idt.INT_APIC_BASE + IRQ_RTC);
apic_registers.spurious_interrupt_vector.value = 0x1FFu;
// apic_registers.lvt_timer.value = idt.INT_LAPIC_TIMER | PERIODIC_MODE;
apic_registers.lvt_timer.value = idt.INT_LAPIC_TIMER;
apic_registers.lvt_lint[0].value = idt.INT_LAPIC_LINT0;
apic_registers.lvt_lint[1].value = idt.INT_LAPIC_LINT1;
// apic_registers.divide_configuration.value = 3u;
configure_io_apic_irq(8u, 0x48u);
}
private static void configure_io_apic_irq(size_t io_apic_irq, size_t interrupt_id)
@@ -100,15 +98,7 @@ struct Apic
public static void isr(ulong vector)
{
switch (vector)
{
case Idt.INT_APIC_BASE + IRQ_RTC:
Rtc.isr();
break;
default:
break;
}
klog.writefln("APIC ISR 0x%x", vector);
eoi();
}
}
+12 -17
View File
@@ -6,12 +6,7 @@ module hulk.console;
import hulk.fb;
import hulk.kfont;
/**
* Represent the HULK console.
*
* Coordinate (0,0) is the top-left console position.
*/
struct Console
struct console
{
/** Console width in text columns. */
private static __gshared size_t m_width;
@@ -30,8 +25,8 @@ struct Console
*/
public static void initialize()
{
m_width = Fb.width / Kfont.advance;
m_height = Fb.height / Kfont.line_height;
m_width = fb.width / kfont.advance;
m_height = fb.height / kfont.line_height;
}
/**
@@ -39,7 +34,7 @@ struct Console
*/
public static void clear()
{
Fb.clear();
fb.clear();
m_x = 0u;
m_y = 0u;
}
@@ -69,10 +64,10 @@ struct Console
if (m_y == m_height)
{
m_y--;
Fb.copy_rows_up(fb_y(1u),
(m_height - 1u) * Kfont.line_height,
Kfont.line_height);
Fb.rect(0u, fb_y(m_height - 1u), fb_x(m_width), Kfont.line_height, 0u);
fb.copy_rows_up(fb_y(m_height - 1u),
(m_height - 1u) * kfont.line_height,
kfont.line_height);
fb.rect(0u, fb_y(m_height - 1u), fb_x(m_width), kfont.line_height, 0u);
}
}
@@ -85,8 +80,8 @@ struct Console
*/
private static void render_char(size_t x, size_t y, char ch)
{
const(CharInfo) * ci = &Kfont.chars[ch];
Fb.blit_alpha_bitmap(fb_x(x) + ci.left, fb_y(y) + ci.top, ci.bitmap, ci.width, ci.height);
const(CharInfo) * ci = &kfont.chars[ch];
fb.blit_alpha_bitmap(fb_x(x) + ci.left, fb_y(y) + ci.top - ci.height, ci.bitmap, ci.width, ci.height);
}
/**
@@ -94,7 +89,7 @@ struct Console
*/
private static size_t fb_x(size_t x)
{
return x * Kfont.advance;
return x * kfont.advance;
}
/**
@@ -102,6 +97,6 @@ struct Console
*/
private static size_t fb_y(size_t y)
{
return y * Kfont.line_height;
return fb.height - ((y + 1u) * kfont.line_height);
}
}
+3 -3
View File
@@ -221,9 +221,9 @@ ushort in16(ushort ioaddr)
return __asm!ushort("inw %dx, %ax", "={ax},{dx}", ioaddr);
}
uint in32(ushort ioaddr)
ulong in32(ushort ioaddr)
{
return __asm!uint("inl %dx, %eax", "={eax},{dx}", ioaddr);
return __asm!ulong("inl %dx, %eax", "={eax},{dx}", ioaddr);
}
void out8(ushort ioaddr, ubyte v)
@@ -236,7 +236,7 @@ void out16(ushort ioaddr, ushort v)
__asm("outw %ax, %dx", "{dx},{ax}", ioaddr, v);
}
void out32(ushort ioaddr, uint v)
void out32(ushort ioaddr, ulong v)
{
__asm("outl %eax, %dx", "{dx},{eax}", ioaddr, v);
}
+95 -17
View File
@@ -9,11 +9,9 @@ import hulk.kfont;
/**
* Represent a graphical frame buffer.
*
* Coordinate (0,0) is the top-left corner of the framebuffer.
*
* TODO: Handle other pixel formats. Currently only BGRx is supported.
*/
struct Fb
struct fb
{
/** Device frame buffer base address. */
private __gshared static uint * m_device_buffer;
@@ -82,8 +80,8 @@ struct Fb
/**
* Draw a solid rectangle on the framebuffer.
*
* @param x X coordinate of left of rectangle.
* @param y Y coordinate of top of rectangle.
* @param x X coordinate of left side of rectangle.
* @param y Y coordinate of bottom side of rectangle.
* @param width Width of rectangle.
* @param height Height of rectangle.
* @param color Color of rectangle.
@@ -102,7 +100,7 @@ struct Fb
/**
* Draw a horizontal line.
*
* @param x X coordinate of left of line.
* @param x X coordinate of left side of line.
* @param y Y coordinate of line.
* @param width Width of line.
* @param color Color of line.
@@ -118,7 +116,7 @@ struct Fb
* Draw a vertical line.
*
* @param x X coordinate of line.
* @param y Y coordinate of top of line.
* @param y Y coordinate of bottom of line.
* @param height Height of line.
* @param color Color of line.
*/
@@ -129,17 +127,81 @@ struct Fb
{
m_buffer1[buffer_index] = color;
m_device_buffer[buffer_index] = color;
buffer_index += m_stride;
buffer_index -= m_stride;
}
}
/**
* Draw a character.
*
* @param x X coordinate of left side of character.
* @param y Y coordinate of bottom side of character.
* @param ch Character to draw.
* @param color Color of character.
*/
static void character(int x, int y, char ch, uint color)
{
const(CharInfo) * ci = &kfont.chars[ch];
blend_alpha_bitmap(x + ci.left, y + kfont.baseline_offset + ci.top - ci.height, ci.bitmap, ci.width, ci.height, color);
}
/**
* Blend an 8-bit alpha bitmap to the framebuffer.
*
* @param x X coordinate of left side of target location.
* @param y Y coordinate of bottom side of target location.
* @param alpha_bitmap 8-bit alpha-channel bitmap.
* @param width Bitmap width.
* @param height Bitmap height.
* @param color Color to blend with alpha value.
*/
static void blend_alpha_bitmap(size_t x, size_t y, const(ubyte) * alpha_bitmap,
size_t width, size_t height, uint color)
{
y += height - 1u;
size_t bitmap_index;
for (size_t iy = 0u; iy < height; iy++)
{
size_t row_buffer_index = buffer_index(x, y);
for (size_t ix = 0u; ix < width; ix++)
{
size_t buffer_index = row_buffer_index + ix;
ubyte alpha = alpha_bitmap[bitmap_index];
uint current_color = m_buffer1[buffer_index];
uint in_color_scaled = scale_color(color, alpha);
uint old_color_scaled = scale_color(current_color, 255u - alpha);
uint new_color = old_color_scaled + in_color_scaled;
m_buffer1[buffer_index] = new_color;
bitmap_index++;
}
memcpy32(&m_device_buffer[row_buffer_index], &m_buffer1[row_buffer_index], width);
y--;
}
}
/**
* Blend an 8-bit alpha bitmap to the framebuffer.
*
* @param x X coordinate of left side of target location.
* @param y Y coordinate of bottom side of target location.
* @param alpha_bitmap 8-bit alpha-channel bitmap.
* @param width Bitmap width.
* @param height Bitmap height.
* @param color Color to blend with alpha value.
*/
static void blend_alpha_bitmap(size_t x, size_t y, const(ubyte)[] alpha_bitmap,
size_t width, size_t height, uint color)
{
blend_alpha_bitmap(x, y, alpha_bitmap.ptr, width, height, color);
}
/**
* Blit an 8-bit alpha bitmap to the framebuffer.
* The foreground will be white (based on the alpha value), and the
* background black.
*
* @param x X coordinate of left of target location.
* @param y Y coordinate of top of target location.
* @param x X coordinate of left side of target location.
* @param y Y coordinate of bottom side of target location.
* @param alpha_bitmap 8-bit alpha-channel bitmap.
* @param width Bitmap width.
* @param height Bitmap height.
@@ -147,6 +209,7 @@ struct Fb
static void blit_alpha_bitmap(size_t x, size_t y, const(ubyte) * alpha_bitmap,
size_t width, size_t height)
{
y += height - 1u;
size_t bitmap_index;
for (size_t iy = 0u; iy < height; iy++)
{
@@ -159,7 +222,7 @@ struct Fb
bitmap_index++;
}
memcpy32(&m_device_buffer[row_buffer_index], &m_buffer1[row_buffer_index], width);
y++;
y--;
}
}
@@ -168,8 +231,8 @@ struct Fb
* The foreground will be white (based on the alpha value), and the
* background black.
*
* @param x X coordinate of left of target location.
* @param y Y coordinate of top of target location.
* @param x X coordinate of left side of target location.
* @param y Y coordinate of bottom side of target location.
* @param alpha_bitmap 8-bit alpha-channel bitmap.
* @param width Bitmap width.
* @param height Bitmap height.
@@ -183,14 +246,14 @@ struct Fb
/**
* Copy framebuffer rows up in the framebuffer.
*
* @param y Y coordinate of top of region to copy up.
* @param y Y coordinate of bottom side of region to copy up.
* @param height Height of region to copy up.
* @param offset Number of rows to copy region up by.
*/
static void copy_rows_up(size_t y, size_t height, size_t offset)
{
size_t dest_buffer_index = buffer_index(0u, y - offset);
size_t src_buffer_index = buffer_index(0u, y);
size_t dest_buffer_index = buffer_index(0u, y + height + offset - 1u);
size_t src_buffer_index = buffer_index(0u, y + height - 1u);
memcpy32(&m_buffer1[dest_buffer_index],
&m_buffer1[src_buffer_index],
(m_stride * height));
@@ -199,6 +262,21 @@ struct Fb
(m_stride * height));
}
/**
* Scale a color value by an alpha amount.
*
* @param color Color value.
* @param alpha Alpha amount.
*
* @return Scaled color value.
*/
private static uint scale_color(uint color, ubyte alpha)
{
return ((((color & 0xFFu) * alpha) >> 8u) & 0xFFu) |
((((color & 0xFF00u) * alpha) >> 8u) & 0xFF00u) |
((((color & 0xFF0000u) * alpha) >> 8u) & 0xFF0000u);
}
/**
* Return the buffer index for the given X and Y coordinates.
*
@@ -209,6 +287,6 @@ struct Fb
*/
private static size_t buffer_index(size_t x, size_t y)
{
return y * m_stride + x;
return (m_height - y - 1u) * m_stride + x;
}
}
+1 -1
View File
@@ -5,7 +5,7 @@ module hulk.gdt;
import ldc.llvmasm;
struct Gdt
struct gdt
{
struct gdtr_t
{
+1 -1
View File
@@ -7,7 +7,7 @@
*/
module hulk.hippo;
struct Hippo
struct hippo
{
/**
* Linked list node entry for a physical page.
+18 -18
View File
@@ -21,7 +21,7 @@ import hulk.pic;
import hulk.acpi;
import hulk.apic;
import hulk.rtc;
import hulk.serial;
import hulk.pit;
extern extern(C) __gshared ubyte _hulk_bss_size;
@@ -30,9 +30,9 @@ private __gshared HulkHeader hulk_header = {
&_hulk_bss_size, /* hulk_bss_size */
&hulk_start, /* entry */
16u * 1024u, /* stack_size */
Hurl.HULK_BASE, /* virt_base */
Hurl.HULK_STACK_TOP, /* virt_stack_top */
Hurl.HULK_FRAMEBUFFER, /* virt_fb_buffer */
HULK_VIRTUAL_BASE_ADDRESS, /* virt_base */
HULK_VIRTUAL_STACK_TOP_ADDRESS, /* virt_stack_top */
HULK_VIRTUAL_FRAMEBUFFER_ADDRESS, /* virt_fb_buffer */
};
private void initialize_cpu()
@@ -57,26 +57,26 @@ void hulk_start()
{
cli();
initialize_cpu();
Serial.initialize();
Gdt.initialize();
Idt.initialize();
Fb.initialize(cast(uint *)Hurl.HULK_FRAMEBUFFER,
gdt.initialize();
idt.initialize();
fb.initialize(cast(uint *)HULK_VIRTUAL_FRAMEBUFFER_ADDRESS,
cast(uint *)hulk_header.bootinfo.fb_buffer1_phys,
hulk_header.bootinfo.fb.width,
hulk_header.bootinfo.fb.height,
hulk_header.bootinfo.fb.stride);
Console.initialize();
Console.clear();
Klog.initialize();
console.initialize();
console.clear();
klog.initialize();
Klog.writefln("Welcome to HULK, the HOS UltraLight Kernel!");
klog.writefln("Welcome to HULK, the HOS UltraLight Kernel!");
Hurl.initialize(&hulk_header);
Pic.initialize();
Acpi.initialize(hulk_header.bootinfo.acpi_xsdt_phys);
Apic.initialize();
Rtc.initialize();
Pci.initialize();
hurl.initialize(&hulk_header);
pci.initialize();
pic.initialize();
acpi.initialize(hulk_header.bootinfo.acpi_xsdt_phys);
apic.initialize();
rtc.initialize();
pit.initialize();
sti();
for (;;)
+1 -5
View File
@@ -6,7 +6,7 @@ SECTIONS
.hulk_header :
{
KEEP(*(.hulk_header))
*(.hulk_header)
}
. = ALIGN(4K);
@@ -16,7 +16,6 @@ SECTIONS
.text :
{
*(.text)
*(.text.*)
}
. = ALIGN(4K);
@@ -26,7 +25,6 @@ SECTIONS
.rodata :
{
*(.rodata)
*(.rodata.*)
}
. = ALIGN(4K);
@@ -37,7 +35,6 @@ SECTIONS
.data :
{
*(.data)
*(.data.*)
}
. = ALIGN(4K);
@@ -49,7 +46,6 @@ SECTIONS
{
*(COMMON)
*(.bss)
*(.bss.*)
}
. = ALIGN(4K);
+26 -45
View File
@@ -3,7 +3,7 @@
*
* HURL provides virtual memory management for HULK.
*/
module hulk.hurl.hurl;
module hulk.hurl;
public import hulk.pagetable;
import hulk.cpu;
@@ -13,22 +13,18 @@ import hulk.klog;
import hulk.bootinfo;
import hulk.header;
import hulk.linker_addresses;
import hulk.util;
struct Hurl
/** HULK virtual base address. */
enum ulong HULK_VIRTUAL_BASE_ADDRESS = 0xFFFF_8000_0000_0000u;
/** HULK virtual stack top address. */
enum ulong HULK_VIRTUAL_STACK_TOP_ADDRESS = 0xFFFF_A000_0000_0000u;
/** HULK virtual framebuffer address. */
enum ulong HULK_VIRTUAL_FRAMEBUFFER_ADDRESS = 0xFFFF_A000_0000_0000u;
struct hurl
{
/** HULK base address. */
enum ulong HULK_BASE = 0xFFFF_8000_0000_0000u;
/** HULK stack top address. */
enum ulong HULK_STACK_TOP = 0xFFFF_8001_0000_0000u;
/** HULK framebuffer address. */
enum ulong HULK_FRAMEBUFFER = 0xFFFF_8001_0000_0000u;
/** A1 allocator range base address. */
enum ulong A1_BASE = 0xFFFF_8002_0000_0000u;
/**
* Pointer to the base page table.
*/
@@ -49,7 +45,7 @@ struct Hurl
physical_address_limit,
PT_WRITABLE | PT_NO_EXECUTE);
ulong phys_address = header.bootinfo.hulk_phys;
ulong virt_address = HULK_BASE;
ulong virt_address = HULK_VIRTUAL_BASE_ADDRESS;
/* Map HULK header region. */
map_range(virt_address,
phys_address,
@@ -83,12 +79,12 @@ struct Hurl
LinkerAddresses.hulk_bss_size,
PT_WRITABLE | PT_NO_EXECUTE);
/* Map HULK stack. */
map_range(HULK_STACK_TOP - header.stack_size,
map_range(HULK_VIRTUAL_STACK_TOP_ADDRESS - header.stack_size,
header.bootinfo.stack_phys,
header.stack_size,
PT_WRITABLE | PT_NO_EXECUTE);
/* Map device framebuffer. */
map_range(HULK_FRAMEBUFFER,
map_range(HULK_VIRTUAL_FRAMEBUFFER_ADDRESS,
cast(ulong)header.bootinfo.fb.buffer,
header.bootinfo.fb.height * header.bootinfo.fb.stride * 4u,
PT_WRITABLE | PT_NO_EXECUTE);
@@ -125,7 +121,7 @@ struct Hurl
reclaimed_pages += reclaim_bootloader_page_table_pages(pte.follow(), level + 1u);
}
}
Hippo.free_page(pt);
hippo.free_page(pt);
reclaimed_pages++;
return reclaimed_pages;
}
@@ -156,7 +152,7 @@ struct Hurl
*/
size_t usable_memory;
size_t physical_address_limit;
const(size_t) fb_size = round_up_power_2(header.bootinfo.fb.height * header.bootinfo.fb.stride * 4u, PAGE_SIZE);
const(size_t) fb_size = (header.bootinfo.fb.height * header.bootinfo.fb.stride * 4u + PAGE_SIZE - 1u) & ~(PAGE_SIZE - 1u);
ulong[2][2] reserved = [
[header.bootinfo.hulk_phys, LinkerAddresses.hulk_binary_size],
[cast(ulong)header.bootinfo.fb.buffer, fb_size],
@@ -190,7 +186,7 @@ struct Hurl
}
if (!is_reserved)
{
Hippo.free_page(phys);
hippo.free_page(phys);
}
phys += PAGE_SIZE;
}
@@ -217,11 +213,11 @@ struct Hurl
usable_memory += LinkerAddresses.hulk_bss_size;
usable_memory += header.stack_size;
usable_memory += fb_size;
Klog.writefln("Usable memory: %uKB", usable_memory >> 10u);
Klog.writefln("Kernel size: %uKB", (LinkerAddresses.hulk_binary_size + LinkerAddresses.hulk_bss_size + header.stack_size) >> 10u);
klog.writefln("Usable memory: %uKB", usable_memory >> 10u);
klog.writefln("Kernel size: %uKB", (LinkerAddresses.hulk_binary_size + LinkerAddresses.hulk_bss_size + header.stack_size) >> 10u);
}
public static void map(ulong virtual, ulong physical, ulong flags)
public static void map(T, U)(T virtual, U physical, ulong flags)
{
PageTable * pt = m_pt_base;
for (size_t level = 0; level < 4u; level++)
@@ -248,12 +244,7 @@ struct Hurl
}
}
public static void map(T, U)(T virtual, U physical, ulong flags)
{
map(cast(ulong)virtual, cast(ulong)physical, flags);
}
public static void map_range(ulong virtual, ulong physical, size_t length, ulong flags)
public static void map_range(size_t virtual, size_t physical, size_t length, ulong flags)
{
size_t end = virtual + length;
while (virtual < end)
@@ -264,33 +255,23 @@ struct Hurl
}
}
public static void map_range(T, U)(T virtual, U physical, size_t length, ulong flags)
{
map_range(cast(ulong)virtual, cast(ulong)physical, length, flags);
}
public static void identity_map_range(ulong address, size_t length, ulong flags)
public static void identity_map_range(size_t address, size_t length, ulong flags)
{
size_t end = address + length;
for (size_t page = address & 0xFFFF_FFFF_FFFF_F000u; page < end; page += PAGE_SIZE)
for (size_t page = address & ~0xFFFu; page < end; page += PAGE_SIZE)
{
map(page, page, flags);
}
}
public static void identity_map_range(T)(T address, size_t length, ulong flags)
{
identity_map_range(cast(ulong)address, length, flags);
}
public static void debug_lookup(void * address)
{
Klog.writefln("Debugging page table lookup of 0x%x", address);
klog.writefln("Debugging page table lookup of 0x%x", address);
PageTable * pt = m_pt_base;
for (size_t level = 0; level < 4u; level++)
{
PageTableEntry pte = *pt.entry(address, level);
Klog.writefln("Level %u, index %u, entry = 0x%x", level, pt.index(address, level), pte);
klog.writefln("Level %u, index %u, entry = 0x%x", level, pt.index(address, level), pte);
if (pte.present)
{
pt = pte.follow();
@@ -308,7 +289,7 @@ struct Hurl
private static PageTable * allocate_pt()
{
PageTable * pt = cast(PageTable *)Hippo.allocate_page();
PageTable * pt = cast(PageTable *)hippo.allocate_page();
memset64(pt, 0u, PAGE_SIZE / 8u);
return pt;
}
-64
View File
@@ -1,64 +0,0 @@
/**
* A1 memory allocator.
*/
module hulk.hurl.a1;
import hulk.hurl;
import hulk.hippo;
import hulk.util;
import hulk.pagetable;
/**
* The A1 memory allocator is a one-shot memory allocator for kernel memory
* that is allocated but never freed.
*/
struct A1
{
/**
* Number of bytes allocated in the A1 region so far.
*/
private static __gshared size_t allocated;
/**
* Allocate memory.
*
* @param size
* Size of memory to allocate.
*
* @return Address of allocated memory. This address will always be aligned
* to a multiple of 16 bytes.
*/
public static void * allocate(size_t size)
{
/* Round size up to a multiple of 16. */
size = round_up_power_2(size, 16u);
ulong address = Hurl.A1_BASE + allocated;
ulong current_limit = round_up_power_2(address, PAGE_SIZE);
allocated += size;
ulong desired_limit = round_up_power_2(Hurl.A1_BASE + allocated, PAGE_SIZE);
while (desired_limit > current_limit)
{
void * page = Hippo.allocate_page();
Hurl.map(current_limit, page, PT_WRITABLE);
current_limit += PAGE_SIZE;
}
return cast(void *)address;
}
/**
* Allocate memory to store an instance of a given type.
*
* @return Address of allocated memory. This address will always be aligned
* to a multiple of 16 bytes.
*/
public static T * allocate(T)()
{
return cast(T *)allocate(T.sizeof);
}
}
-3
View File
@@ -1,3 +0,0 @@
module hulk.hurl;
public import hulk.hurl.hurl;
+25 -30
View File
@@ -9,17 +9,16 @@ import hulk.fb;
import hulk.console;
import hulk.klog;
import hulk.apic;
import hulk.rtc;
struct Idt
struct idt
{
/* The I/O APIC is configured to map IRQ 0 to interrupt 64 (0x40). */
public static enum ulong INT_APIC_BASE = 0x40u; /* IRQ 0 */
public static enum ulong INT_APIC_COUNT = 24u;
public static enum ulong INT_RTC = 0x48u; /* IRQ 8 */
public static enum ulong INT_APIC_TIMER = 0x70u;
public static enum ulong INT_APIC_LINT0 = 0x71u;
public static enum ulong INT_APIC_LINT1 = 0x72u;
public static enum ulong INT_APIC_SPURIOUS = 0xFFu;
public static enum ulong INT_LAPIC_TIMER = 0x70u;
public static enum ulong INT_LAPIC_LINT0 = 0x71u;
public static enum ulong INT_LAPIC_LINT1 = 0x72u;
struct idtr_t
{
@@ -96,7 +95,7 @@ struct Idt
((offset & 0xFFFF_0000u) << 32u) |
(dpl << 45u) |
((trap ? 1uL : 0uL) << 40u) |
(Gdt.SELECTOR_KERNEL_CODE << 16u) |
(gdt.SELECTOR_KERNEL_CODE << 16u) |
(offset & 0xFFFFu);
idt[index][1] = offset >> 32u;
}
@@ -104,30 +103,26 @@ struct Idt
public extern(C) void isr(ulong vector, ulong arg)
{
if ((vector >= Idt.INT_APIC_BASE) && (vector < (Idt.INT_APIC_BASE + Idt.INT_APIC_COUNT)))
switch (vector)
{
Apic.isr(vector);
}
else
{
switch (vector)
{
case Idt.INT_APIC_TIMER:
case Idt.INT_APIC_LINT0:
case Idt.INT_APIC_LINT1:
case Idt.INT_APIC_SPURIOUS:
Apic.isr(vector);
break;
case idt.INT_RTC:
rtc.isr();
break;
default:
Console.clear();
Fb.clear(0xFF8000u);
Klog.writefln("ISR %u, 0x%x", vector, arg);
__asm("cli", "");
for (;;)
{
__asm("hlt", "");
}
case idt.INT_LAPIC_TIMER:
case idt.INT_LAPIC_LINT0:
case idt.INT_LAPIC_LINT1:
apic.isr(vector);
break;
default:
console.clear();
fb.clear(0xFF8000u);
klog.writefln("ISR %u, 0x%x", vector, arg);
__asm("cli", "");
for (;;)
{
__asm("hlt", "");
}
}
}
+3 -17
View File
@@ -6,9 +6,8 @@ module hulk.klog;
import core.stdc.stdarg;
import hulk.console;
static import hulk.writef;
import hulk.cpu;
struct Klog
struct klog
{
/**
* Kernel buffer size log.
@@ -41,7 +40,7 @@ struct Klog
public static void writef(string s, va_list args)
{
hulk.writef.writef(s, args, function void(ubyte ch) {
Console.write(ch);
console.write(ch);
});
}
@@ -59,7 +58,7 @@ struct Klog
}
/**
* Write a formatted string and newline to the kernel log.
* Write a formatted string and newline to the console.
*
* @param s Format string.
*/
@@ -71,17 +70,4 @@ struct Klog
writef("\n", args);
va_end(args);
}
/**
* Print a fatal kernel error and loop forever.
*/
public static void fatal_error(T...)(T args)
{
writef("FATAL ERROR: ");
writefln(args);
cli();
for (;;)
{
}
}
}
+2 -2
View File
@@ -31,7 +31,7 @@ enum ulong MTRRPHYSBASE_TYPE_MASK = 0xFFu;
enum ulong MTRRPHYSMASK_PHYSMASK_MASK = 0x000F_FFFF_FFFF_F000u;
enum ulong MTRRPHYSMASK_VALID = 0x800u;
struct Mtrr
struct mtrr
{
public static void initialize()
{
@@ -41,7 +41,7 @@ struct Mtrr
cpuid1(&ebx, &ecx, &edx);
if ((edx & CPUID_1_EDX_MTRR) == 0u)
{
Klog.writefln("CPU does not support MTRR");
klog.writefln("CPU does not support MTRR");
return;
}
const(ulong) mtrrcap = rdmsr(MSR_MTRRCAP);
-8
View File
@@ -183,11 +183,3 @@ struct PageTable
}
}
static assert(PageTable.sizeof == 4096u);
/**
* Get the base address of the page containing the given address.
*/
T page_address(T)(T address)
{
return cast(T)(cast(ulong)address & ~(PAGE_SIZE - 1u));
}
+18 -384
View File
@@ -2,13 +2,8 @@ module hulk.pci;
import hulk.cpu;
import hulk.klog;
import hulk.hurl;
import hulk.hurl.a1;
import hulk.range;
import hulk.usb.xhci;
import hulk.acpi;
struct Pci
struct pci
{
/* IO address for PCI configuration address. */
enum IO_ADDR_CONFIG_ADDRESS = 0xCF8u;
@@ -16,399 +11,38 @@ struct Pci
/* IO address for PCI configuration data. */
enum IO_ADDR_CONFIG_DATA = 0xCFCu;
enum MAX_DEVICES_PER_BUS = 32;
enum MAX_FUNCTIONS_PER_DEVICE = 8;
struct Address
private static ulong read_config_register(ulong bus_id, ulong device_id, ulong register_id)
{
/** Bus number (0-255). */
ubyte bus_nr;
/** Device number (0-31). */
ubyte device_nr;
/** Function number (0-7). */
ubyte function_nr;
}
struct Device
{
Address address;
ushort vendor_id;
ushort device_id;
ubyte class_id;
ubyte subclass_id;
ubyte if_id;
bool multifunction;
ubyte header_type;
Range[6] memory_ranges;
void initialize(Address address, ushort vendor_id, ushort device_id)
{
this.address = address;
this.vendor_id = vendor_id;
this.device_id = device_id;
uint reg2 = read_config_register(address, 2u);
class_id = (reg2 >> 24u) & 0xFFu;
subclass_id = (reg2 >> 16u) & 0xFFu;
if_id = (reg2 >> 8u) & 0xFFu;
Klog.writefln("Found PCI device %04x:%04x (%02x:%02x:%02x) at %02u:%02u.%u",
vendor_id, device_id,
class_id, subclass_id, if_id,
address.bus_nr, address.device_nr, address.function_nr);
uint reg3 = read_config_register(address, 3u);
header_type = (reg3 >> 16u) & 0x7Fu;
multifunction = (address.function_nr == 0u) && ((reg3 & (1u << 23u)) != 0u);
if (header_type == 0u)
{
map_memory_regions();
}
spawn_device_instance();
}
private void map_memory_regions()
{
size_t range_index;
uint[2] r;
uint[2] s;
for (uint reg_no = 4u; reg_no <= 9u; reg_no++)
{
/* Read the BAR. */
r[0] = read_config_register(address, reg_no);
/* Skip zeroed BARs. */
if (r[0] == 0u)
{
continue;
}
/* Skip I/O BARs. */
if ((r[0] & 1u) != 0u)
{
continue;
}
bool is_64bit;
uint bar_type = (r[0] >> 1u) & 0x3u;
if (bar_type == 0u)
{
/* 32-bit region. */
r[1] = 0u;
}
else if ((bar_type == 2u) && (reg_no < 9u))
{
/* 64-bit region. */
is_64bit = true;
r[1] = read_config_register(address, reg_no + 1);
}
else
{
continue;
}
/* Determine the region length. */
write_config_register(address, reg_no, 0xFFFF_FFFFu);
s[0] = read_config_register(address, reg_no);
write_config_register(address, reg_no, r[0]);
if (is_64bit)
{
write_config_register(address, reg_no + 1, 0xFFFF_FFFFu);
s[1] = read_config_register(address, reg_no + 1);
write_config_register(address, reg_no + 1, r[1]);
}
else
{
s[1] = 0xFFFF_FFFFu;
}
ulong mm_region_address = (cast(ulong)r[0] & 0xFFFF_FFF0u) | (cast(ulong)r[1] << 32u);
ulong length = ~((cast(ulong)s[0] & 0xFFFF_FFF0u) | (cast(ulong)s[1] << 32u)) + 1u;
ulong flags = (r[0] & 0x8) != 0u ? PT_WRITE_THROUGH : 0u;
Hurl.identity_map_range(mm_region_address, length, flags);
memory_ranges[range_index].address = mm_region_address;
memory_ranges[range_index].length = length;
range_index++;
if (is_64bit)
{
reg_no++;
}
}
}
private void spawn_device_instance()
{
switch (class_id)
{
case SerialBusController.ID:
switch (subclass_id)
{
case SerialBusController.USBController.ID:
switch (if_id)
{
case SerialBusController.USBController.XHCIController.ID:
XHCI.build(&this);
break;
default:
break;
}
break;
default:
break;
}
break;
default:
break;
}
}
}
struct SerialBusController
{
enum ID = 0x0Cu;
struct USBController
{
enum ID = 0x03u;
struct XHCIController
{
enum ID = 0x30u;
}
}
}
private static uint read_config_register(Address address, uint register_id)
{
uint cfg_addr = 0x8000_0000u |
(address.bus_nr << 16u) |
(address.device_nr << 11u) |
(address.function_nr << 8u) |
(register_id << 2u);
out32(IO_ADDR_CONFIG_ADDRESS, cfg_addr);
ulong addr = 0x8000_0000u | (bus_id << 16u) | (device_id << 11u) | (register_id << 2u);
out32(IO_ADDR_CONFIG_ADDRESS, addr);
return in32(IO_ADDR_CONFIG_DATA);
}
private static void write_config_register(Address address, uint register_id, uint value)
private static void scan(ulong bus_id, ulong device_id)
{
uint cfg_addr = 0x8000_0000u |
(address.bus_nr << 16u) |
(address.device_nr << 11u) |
(address.function_nr << 8u) |
(register_id << 2u);
out32(IO_ADDR_CONFIG_ADDRESS, cfg_addr);
out32(IO_ADDR_CONFIG_DATA, value);
}
private static void scan(Address address)
{
ulong reg0 = read_config_register(address, 0u);
ulong reg0 = read_config_register(bus_id, device_id, 0u);
if (reg0 != 0xFFFFFFFFu)
{
ushort vendor_id = reg0 & 0xFFFFu;
ushort device_id = (reg0 >> 16u) & 0xFFFFu;
Device * device = A1.allocate!Device();
device.initialize(address, vendor_id, device_id);
if (device.multifunction)
{
for (address.function_nr = 1u; address.function_nr < MAX_FUNCTIONS_PER_DEVICE; address.function_nr++)
{
scan(address);
}
}
}
}
static struct Configuration
{
static struct HeaderType0
{
ushort vendor_id;
ushort device_id;
ushort command;
ushort status;
ubyte revision_id;
ubyte interface_id;
ubyte subclass_id;
ubyte class_id;
ubyte cache_line_size;
ubyte latency_timer;
ubyte header_type;
ubyte bist;
uint[6] base_addresses;
uint cardbus_cis_pointer;
ushort subsystem_vendor_id;
ushort subsystem_id;
uint expansion_rom_base_address;
ubyte capabilities_pointer;
ubyte[7] _reserved;
ubyte interrupt_line;
ubyte interrupt_pin;
ubyte min_grant;
ubyte max_latency;
}
/**
* PCI configuration format for header type 1 (PCI-to-PCI bridge).
*/
static struct HeaderType1
{
ushort vendor_id;
ushort device_id;
ushort command;
ushort status;
ubyte revision_id;
ubyte interface_id;
ubyte subclass_id;
ubyte class_id;
ubyte cache_line_size;
ubyte latency_timer;
ubyte header_type;
ubyte bist;
uint[2] base_addresses;
ubyte primary_bus_nr;
ubyte secondary_bus_nr;
ubyte subordinate_bus_nr;
ubyte secondary_latency_timer;
ubyte io_base;
ubyte io_limit;
ushort secondary_status;
ushort memory_base;
ushort memory_limit;
ushort prefetchable_memory_base;
ushort prefetchable_memory_limit;
uint prefetchable_base_high;
uint prefetchable_limit_high;
ushort io_base_high;
ushort io_limit_high;
ubyte capability_pointer;
ubyte[3] _reserved;
uint expansion_rom_base_address;
ubyte interrupt_line;
ubyte interrupt_pin;
ushort bridge_control;
}
/**
* PCI configuration format for header type 2 (PCI-to-CardBus bridge).
*/
static struct HeaderType2
{
ushort vendor_id;
ushort device_id;
ushort command;
ushort status;
ubyte revision_id;
ubyte interface_id;
ubyte subclass_id;
ubyte class_id;
ubyte cache_line_size;
ubyte latency_timer;
ubyte header_type;
ubyte bist;
uint cardbus_base_address;
ubyte capability_list_offset;
ubyte _reserved;
ushort secondary_status;
ubyte pci_bus_nr;
ubyte cardbus_bus_nr;
ubyte subordinate_bus_nr;
ubyte cardbus_latency_timer;
uint base_address_0;
uint memory_limit_0;
uint base_address_1;
uint memory_limit_1;
uint io_base_address_0;
uint io_limit_0;
uint io_base_address_1;
uint io_limit_1;
ubyte interrupt_line;
ubyte interrupt_pin;
ushort bridge_control;
ushort subsystem_device_id;
ushort subsystem_vendor_id;
uint legacy_base_address;
}
union
{
struct
{
ushort vendor_id;
ushort device_id;
ushort command;
ushort status;
ubyte revision_id;
ubyte interface_id;
ubyte subclass_id;
ubyte class_id;
ubyte cache_line_size;
ubyte latency_timer;
ubyte header_type;
ubyte bist;
}
HeaderType0 header0;
HeaderType1 header1;
HeaderType2 header2;
}
}
private static void scan(ubyte bus_nr, ubyte device_nr, ubyte function_nr, ulong config_address)
{
Configuration * config = cast(Configuration *)config_address;
if (config.vendor_id != 0xFFFFu)
{
Klog.writefln("Found PCI device %04x:%04x (%02x:%02x:%02x) at %02u:%02u.%u (%p)",
config.vendor_id, config.device_id,
config.class_id, config.subclass_id, config.interface_id,
bus_nr, device_nr, function_nr, config_address);
if (function_nr == 0 && (config.header_type & 0x80u) != 0u)
{
for (function_nr = 1u; function_nr < MAX_FUNCTIONS_PER_DEVICE; function_nr++)
{
config_address += PAGE_SIZE;
scan(bus_nr, device_nr, function_nr, config_address);
}
}
ulong reg2 = read_config_register(bus_id, device_id, 2u);
klog.writefln("Found PCI device %04x:%04x (%02x:%02x:%02x) at %02u:%02u",
(reg0 & 0xFFFFu), (reg0 >> 16u),
(reg2 >> 24u) & 0xFFu,
(reg2 >> 16u) & 0xFFu,
(reg2 >> 8u) & 0xFFu,
bus_id, device_id);
}
}
public static void initialize()
{
Klog.writefln("Scanning PCI devices...");
for (uint bus_nr = 0u; bus_nr < 256u; bus_nr++)
klog.writefln("Scanning PCI devices...");
for (ulong bus_id = 0u; bus_id < 256u; bus_id++)
{
for (ubyte device_nr = 0u; device_nr < MAX_DEVICES_PER_BUS; device_nr++)
for (ulong device_id = 0u; device_id < 32u; device_id++)
{
scan(Address(cast(ubyte)bus_nr, device_nr, 0u));
scan(bus_id, device_id);
}
}
Klog.writefln("PCI scan complete.");
Klog.writefln("MCFG PCI scan...");
size_t n_sgma_descs = Acpi.mcfg.n_sgma_descs;
for (size_t i = 0u; i < n_sgma_descs; i++)
{
Acpi.MCFG.SGMADesc * sgma_desc = &Acpi.mcfg.sgma_descs[i];
ulong base_address = sgma_desc.base_address;
uint start_pci_bus = sgma_desc.start_pci_bus_number;
uint end_pci_bus = sgma_desc.end_pci_bus_number;
ulong n_buses = (end_pci_bus - start_pci_bus) + 1u;
ulong map_length = PAGE_SIZE * MAX_FUNCTIONS_PER_DEVICE * MAX_DEVICES_PER_BUS * n_buses;
Hurl.identity_map_range(base_address, map_length, PT_DISABLE_CACHE | PT_NO_EXECUTE);
for (uint bus_nr = start_pci_bus; bus_nr <= end_pci_bus; bus_nr++)
{
for (ubyte device_nr = 0u; device_nr < MAX_DEVICES_PER_BUS; device_nr++)
{
ulong device_address = base_address + ((bus_nr - start_pci_bus) * (MAX_DEVICES_PER_BUS * MAX_FUNCTIONS_PER_DEVICE) + device_nr * MAX_FUNCTIONS_PER_DEVICE) * PAGE_SIZE;
scan(cast(ubyte)bus_nr, device_nr, 0u, device_address);
}
}
}
Klog.writefln("PCI scan 2 complete.");
klog.writefln("PCI scan complete.");
}
}
+1 -1
View File
@@ -5,7 +5,7 @@ module hulk.pic;
import hulk.cpu;
struct Pic
struct pic
{
public static void initialize()
{
+2 -2
View File
@@ -6,7 +6,7 @@ module hulk.pit;
import hulk.cpu;
import hulk.klog;
struct Pit
struct pit
{
/** PIT input frequency in 1/1000 Hz. */
private enum ulong PIT_FREQUENCY_1000HZ = 1_193_181_667u;
@@ -37,6 +37,6 @@ struct Pit
public static void isr()
{
Klog.writefln("PIT ISR");
klog.writefln("PIT ISR");
}
}
-27
View File
@@ -1,27 +0,0 @@
module hulk.range;
/**
* Representation of a memory range.
*/
struct Range
{
/** Range base address. */
void * _address;
/** Range length. */
size_t length;
/** Set the range address. */
@property void * address(T)(T a)
{
static assert(T.sizeof == size_t.sizeof);
_address = cast(void *)a;
return _address;
}
/** Get the range address. */
@property void * address()
{
return _address;
}
}
+15 -106
View File
@@ -5,77 +5,41 @@ module hulk.rtc;
import hulk.cpu;
import hulk.klog;
import hulk.apic;
struct Rtc
struct rtc
{
private enum ubyte PORT_SELECT = 0x70u;
private enum ubyte PORT_DATA = 0x71u;
private enum ubyte DISABLE_NMI = 0x80u;
private enum ubyte REG_RTC_SECONDS = 0x0u;
private enum ubyte REG_RTC_MINUTES = 0x2u;
private enum ubyte REG_RTC_HOURS = 0x4u;
private enum ubyte REG_RTC_DAY = 0x7u;
private enum ubyte REG_RTC_MONTH = 0x8u;
private enum ubyte REG_RTC_YEAR = 0x9u;
private enum ubyte REG_SR_A = 0xAu;
private enum ubyte REG_SR_B = 0xBu;
private enum ubyte REG_SR_C = 0xCu;
private enum ubyte SR_A = 0xAu;
private enum ubyte SR_B = 0xBu;
private enum ubyte SR_C = 0xCu;
private enum ubyte SR_A_RTC_UPDATE_IN_PROGRESS = 0x80u;
private enum ubyte SR_B_24HOUR = 0x02u;
private enum ubyte SR_B_BINARY = 0x04u;
private enum ubyte SR_B_ENABLE_IRQ = 0x40u;
private static __gshared bool rtc_24hour_mode;
private static __gshared bool rtc_binary_mode;
static struct time
{
public ubyte year;
public ubyte month;
public ubyte day;
public ubyte hour;
public ubyte minute;
public ubyte second;
}
public static void initialize()
{
/* Enable IRQ 8 to receive RTC interrupts. */
ubyte sr_b = read_register(REG_SR_B, true);
write_register(REG_SR_B, sr_b | SR_B_ENABLE_IRQ, true);
out8(PORT_SELECT, DISABLE_NMI | SR_B);
ubyte sr_b = in8(PORT_DATA);
out8(PORT_SELECT, DISABLE_NMI | SR_B);
out8(PORT_DATA, sr_b | SR_B_ENABLE_IRQ);
/* Record RTC mode flags from status register B. */
rtc_24hour_mode = (sr_b & SR_B_24HOUR) != 0u;
rtc_binary_mode = (sr_b & SR_B_BINARY) != 0u;
/* Read the current system time. */
time t = read_rtc_time();
Klog.writefln("System time is 20%02u-%02u-%02u %02u:%02u:%02u",
t.year, t.month, t.day, t.hour, t.minute, t.second);
out8(PORT_SELECT, DISABLE_NMI | SR_A);
klog.writefln("SR_A = 0x%x", in8(PORT_DATA));
/* Send EOI to enable more RTC interrupts and re-enable NMIs. */
eoi();
}
private static ubyte read_register(ubyte register, bool disable_nmi = false)
{
out8(PORT_SELECT, register | (disable_nmi ? DISABLE_NMI : 0u));
return in8(PORT_DATA);
}
private static void write_register(ubyte register, ubyte value, bool disable_nmi = false)
{
out8(PORT_SELECT, register | (disable_nmi ? DISABLE_NMI : 0u));
out8(PORT_DATA, value);
}
private static void eoi()
{
/* Read from status register C to clear the interrupt. */
read_register(REG_SR_C);
out8(PORT_SELECT, SR_C);
in8(PORT_DATA);
}
public static void isr()
@@ -86,64 +50,9 @@ struct Rtc
if ((count % 1024) == 0u)
{
seconds++;
klog.writefln("Seconds: %u", seconds);
}
eoi();
}
private static time read_rtc_time()
{
time[2] times;
size_t reads;
do
{
times[reads & 1] = read_rtc_time_unsafe();
reads++;
} while ((reads < 2u) || (times[0] != times[1]));
return times[0];
}
private static time read_rtc_time_unsafe()
{
time t;
while ((read_register(REG_SR_A) & SR_A_RTC_UPDATE_IN_PROGRESS) != 0u)
{
}
t.year = read_rtc_time_register(REG_RTC_YEAR);
t.month = read_rtc_time_register(REG_RTC_MONTH);
t.day = read_rtc_time_register(REG_RTC_DAY);
t.minute = read_rtc_time_register(REG_RTC_MINUTES);
t.second = read_rtc_time_register(REG_RTC_SECONDS);
/* Hour field is treated differently because it might have 'PM' flag
* in highest bit if we're in 24-hour mode. */
ubyte hour = read_register(REG_RTC_HOURS);
ubyte pm = hour >> 7u;
hour &= 0x7Fu;
if (!rtc_binary_mode)
{
/* Hour is in BCD format; convert to binary. */
hour = bcd_to_binary(hour);
}
if (!rtc_24hour_mode)
{
/* Hour is in 12-hour format; convert to 24-hour format. */
hour = cast(ubyte)((hour % 12u) + pm * 12u);
}
t.hour = hour;
return t;
}
private static ubyte read_rtc_time_register(ubyte register)
{
ubyte value = read_register(register);
if (!rtc_binary_mode)
{
value = bcd_to_binary(value);
}
return value;
}
private static ubyte bcd_to_binary(ubyte bcd)
{
return (bcd & 0xFu) + ((bcd & 0xF0u) >> 4u) * 10u;
apic.eoi();
}
}
-74
View File
@@ -1,74 +0,0 @@
/**
* Serial port access.
*/
module hulk.serial;
import hulk.cpu;
import core.stdc.stdarg;
static import hulk.writef;
struct Serial
{
enum BASE_PORT = 0x3F8;
/**
* Initialize the serial module.
*/
static void initialize()
{
}
/**
* Write a character to the serial port.
*
* @param ch Character to write.
*/
static void write(ubyte ch)
{
if (ch == '\n')
{
out8(BASE_PORT, '\r');
}
out8(BASE_PORT, ch);
}
/**
* Write a formatted string to the serial port.
*
* @param s Format string.
* @param args Variable arguments structure.
*/
public static void writef(string s, va_list args)
{
hulk.writef.writef(s, args, function void(ubyte ch) {
Serial.write(ch);
});
}
/**
* Write a formatted string to the serial port.
*
* @param s Format string.
*/
public static extern (C) void writef(string s, ...)
{
va_list args;
va_start(args, s);
writef(s, args);
va_end(args);
}
/**
* Write a formatted string and newline to the serial port.
*
* @param s Format string.
*/
public static extern (C) void writefln(string s, ...)
{
va_list args;
va_start(args, s);
writef(s, args);
writef("\n", args);
va_end(args);
}
}
-104
View File
@@ -1,104 +0,0 @@
/**
* eXtensible Host Controller Interface for Universal Serial Bus
*
* Documentation:
* - https://wiki.osdev.org/EXtensible_Host_Controller_Interface
* - https://www.intel.com/content/dam/www/public/us/en/documents/technical-specifications/extensible-host-controler-interface-usb-xhci.pdf
*/
module hulk.usb.xhci;
import hulk.pci;
import hulk.hurl.a1;
import hulk.klog;
struct XHCI
{
/**
* Located at PCI base address.
*/
struct CapabilityRegisters
{
ubyte capability_length;
ubyte _reserved01;
ushort hci_version;
uint[3] hcs_params;
uint hcc_params1;
uint doorbell_offset;
uint rts_offset;
uint hcc_params2;
}
static assert(CapabilityRegisters.sizeof == 0x20u);
/**
* Located at offset capability_length from PCI base address.
*/
struct OperationalRegisters
{
uint usb_command;
uint usb_status;
uint page_size;
uint[2] _reserved01;
uint dn_ctrl;
ulong cr_ctrl;
uint[4] _reserved02;
ulong dcbaap;
uint config;
uint _reserved03;
}
static assert(OperationalRegisters.sizeof == 0x40u);
/**
* Located at offset 0x400 from start of Operational Registers.
*/
struct PortRegisters
{
uint portsc;
uint portpmsc;
uint portli;
uint porthlpmc;
}
static assert(PortRegisters.sizeof == 0x10u);
struct RuntimeRegisters
{
uint mfindex;
uint[7] _reserved01;
uint ir;
}
struct DoorbellRegister
{
ubyte target;
ubyte _reserved01;
ushort task_id;
}
static assert(DoorbellRegister.sizeof == 4u);
private CapabilityRegisters * m_capability_registers;
private OperationalRegisters * m_operational_registers;
private PortRegisters * m_port_registers;
private RuntimeRegisters * m_runtime_registers;
private DoorbellRegister * m_doorbell_registers;
void initialize(Pci.Device * pci_device)
{
void * base_address = pci_device.memory_ranges[0].address;
Klog.writefln("Found XHCI controller at address %p", base_address);
m_capability_registers = cast(CapabilityRegisters *)base_address;
m_operational_registers = cast(OperationalRegisters *)(base_address + m_capability_registers.capability_length);
/* TODO: confirm if 0x400 offset is from m_operation_registers or base_address. */
m_port_registers = cast(PortRegisters *)(cast(void *)m_operational_registers + 0x400);
m_runtime_registers = cast(RuntimeRegisters *)(base_address + m_capability_registers.rts_offset);
m_doorbell_registers = cast(DoorbellRegister *)(base_address + m_capability_registers.doorbell_offset);
}
static void build(Pci.Device * pci_device)
{
if (pci_device.memory_ranges[0].address != null)
{
XHCI * xhci = A1.allocate!XHCI();
xhci.initialize(pci_device);
}
}
}
-17
View File
@@ -1,17 +0,0 @@
/**
* HULK utility functions.
*/
module hulk.util;
/**
* Round a value up to the next power of 2.
*
* @param v Value to round up.
* @param p Power of 2 to round up to.
*
* @return Rounded up value.
*/
ulong round_up_power_2(ulong v, ulong p)
{
return (v + p - 1u) & ~(p - 1u);
}
+13 -36
View File
@@ -26,33 +26,18 @@ size_t writef(string s, va_list args, ch_out_fn ch_out)
{
if (escape)
{
if (c == 'c')
{
ulong ch;
va_arg(args, ch);
ch_out(cast(ubyte)ch);
length_written++;
escape = false;
}
else if (c == 'p')
if (c == 'x')
{
ulong v;
va_arg(args, v);
length_written += write_hex(v, true, true, pad, width, ch_out);
escape = false;
}
else if (c == 'x')
{
ulong v;
va_arg(args, v);
length_written += write_hex(v, false, false, pad, width, ch_out);
length_written += write_hex(v, false, pad, width, ch_out);
escape = false;
}
else if (c == 'X')
{
ulong v;
va_arg(args, v);
length_written += write_hex(v, true, false, pad, width, ch_out);
length_written += write_hex(v, true, pad, width, ch_out);
escape = false;
}
else if (c == 'u')
@@ -95,35 +80,27 @@ size_t writef(string s, va_list args, ch_out_fn ch_out)
*
* @param v Value to format.
* @param upper Whether to use uppercase letters.
* @param pointer Whether to format as a pointer.
* @param pad Pad character to use.
* @param width Field width.
* @param ch_out Character output function.
*
* @return Number of characters written.
*/
private size_t write_hex(ulong v, bool upper, bool pointer, char pad, size_t width, ch_out_fn ch_out)
private size_t write_hex(ulong v, bool upper, char pad, size_t width, ch_out_fn ch_out)
{
static __gshared const(char)[16] hex_chars_lower = "0123456789abcdef";
static __gshared const(char)[16] hex_chars_upper = "0123456789ABCDEF";
char[19] buf;
size_t digit;
size_t buf_idx;
char[16] buf;
size_t i;
do
{
ulong n = v & 0xFu;
buf[buf_idx] = upper ? hex_chars_upper[n] : hex_chars_lower[n];
buf[i] = upper ? hex_chars_upper[n] : hex_chars_lower[n];
v >>= 4u;
buf_idx++;
digit++;
if (pointer && ((digit % 4) == 0) && (v != 0u))
{
buf[buf_idx] = '_';
buf_idx++;
}
i++;
} while (v != 0u);
size_t length_written = buf_idx;
while (width > buf_idx)
size_t length_written = i;
while (width > i)
{
ch_out(pad);
width--;
@@ -131,9 +108,9 @@ private size_t write_hex(ulong v, bool upper, bool pointer, char pad, size_t wid
}
do
{
buf_idx--;
ch_out(buf[buf_idx]);
} while (buf_idx != 0u);
i--;
ch_out(buf[i]);
} while (i != 0u);
return length_written;
}
-9
View File
@@ -21,30 +21,23 @@ end
default do
unless Dir.exist?(install_path)
puts "Building cross compiler toolchain..."
# Download archives.
puts "Downloading binutils..."
download "https://ftp.gnu.org/gnu/binutils/binutils-#{binutils_version}.tar.xz",
"#{build_dir}/binutils-#{binutils_version}.tar.xz",
sha256sum: binutils_checksum
puts "Downloading gcc..."
download "https://ftp.gnu.org/gnu/gcc/gcc-#{gcc_version}/gcc-#{gcc_version}.tar.xz",
"#{build_dir}/gcc-#{gcc_version}.tar.xz",
sha256sum: gcc_checksum
# Extract archives.
puts "Extracting binutils..."
sh "tar", "xJf", "binutils-#{binutils_version}.tar.xz",
chdir: build_dir
puts "Extracting gcc..."
sh "tar", "xJf", "gcc-#{gcc_version}.tar.xz",
chdir: build_dir
# Build binutils.
puts "Building binutils..."
rm_rf "#{build_dir}/build-binutils"
mkdir_p "#{build_dir}/build-binutils"
cd "#{build_dir}/build-binutils" do
@@ -56,7 +49,6 @@ default do
end
# Build gcc.
puts "Building gcc..."
rm_rf "#{build_dir}/build-gcc"
mkdir_p "#{build_dir}/build-gcc"
cd "#{build_dir}/build-gcc" do
@@ -70,7 +62,6 @@ default do
end
# Remove archives and build directories if everything succeeded.
puts "Cleaning up..."
rm_f "#{build_dir}/binutils-#{binutils_version}.tar.xz"
rm_rf "#{build_dir}/binutils-#{binutils_version}"
rm_rf "#{build_dir}/build-binutils"