Compare commits
18
Commits
2a66443a49
...
d
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bb65def53c | ||
|
|
0d970a6d25 | ||
|
|
ea159db100 | ||
|
|
e3f27812ad | ||
|
|
d78669df9c | ||
|
|
7313b01732 | ||
|
|
b2497d1ee0 | ||
|
|
30078417b6 | ||
|
|
c18cbf7be3 | ||
|
|
2d95371aa1 | ||
|
|
13b6f39e1a | ||
|
|
30aedfc97b | ||
|
|
26bb071b4d | ||
|
|
3a75e0505f | ||
|
|
a02df12924 | ||
|
|
699f53ac15 | ||
|
|
1119855215 | ||
|
|
0c82250bd2 |
No files matched your search
+5
-3
@@ -11,6 +11,7 @@ configure do
|
||||
check_c_compiler
|
||||
check_program "mformat", on_fail: "Install the mtools package"
|
||||
check_program "parted"
|
||||
check_program "pkg-config"
|
||||
check_cfg package: "freetype2", on_fail: "Install libfreetype-dev", use: "freetype"
|
||||
sh %w[git submodule update --init]
|
||||
end
|
||||
@@ -113,10 +114,8 @@ hulk_env = env "hulk", use: %w[ldc2 x86_64-elf-gcc] do |env|
|
||||
-avx512bw
|
||||
-avx512cd
|
||||
-avx512dq
|
||||
-avx512er
|
||||
-avx512f
|
||||
-avx512ifma
|
||||
-avx512pf
|
||||
-avx512vbmi
|
||||
-avx512vbmi2
|
||||
-avx512vl
|
||||
@@ -132,7 +131,7 @@ hulk_env = env "hulk", use: %w[ldc2 x86_64-elf-gcc] do |env|
|
||||
-sse4a
|
||||
-ssse3
|
||||
]
|
||||
env["DFLAGS"] += %W[-g -mtriple=x86_64-unknown-elf -mattr=#{cpu_attrs.join(",")} --betterC -release -O3 --wi --enable-cross-module-inlining -code-model=large --disable-red-zone]
|
||||
env["DFLAGS"] += %W[-g -mtriple=x86_64-unknown-elf -mattr=#{cpu_attrs.join(",")} --betterC -release -O3 --wi --enable-cross-module-inlining -code-model=kernel --disable-red-zone]
|
||||
env["D_IMPORT_PATH"] += %w[src]
|
||||
env["D_IMPORT_PATH"] << env.expand("^/src")
|
||||
env["LD"] = "x86_64-elf-gcc"
|
||||
@@ -194,10 +193,13 @@ task "run", desc: "Run HOS in QEMU" do
|
||||
ovmf = "OVMF.fd"
|
||||
if File.exist?("/usr/share/edk2/x64/OVMF.fd")
|
||||
ovmf = "/usr/share/edk2/x64/OVMF.fd"
|
||||
elsif File.exist?("/usr/share/edk2/x64/OVMF.4m.fd")
|
||||
ovmf = "/usr/share/edk2/x64/OVMF.4m.fd"
|
||||
end
|
||||
sh %W[
|
||||
qemu-system-x86_64
|
||||
-machine q35
|
||||
-m 128M
|
||||
-cpu max
|
||||
-smp cpus=4
|
||||
-serial file:qemu/serial.out
|
||||
|
||||
@@ -57,6 +57,7 @@ enum ulong XCR0_PKRU = 0x100u;
|
||||
/** @} */
|
||||
|
||||
/** MSR register numbers. @{ */
|
||||
enum uint MSR_PAT = 0x277u;
|
||||
enum uint MSR_EFER = 0xC000_0080u;
|
||||
/** @} */
|
||||
|
||||
|
||||
+152
-3
@@ -7,21 +7,38 @@
|
||||
*/
|
||||
module hulk.hippo;
|
||||
|
||||
import hulk.hurl;
|
||||
import hulk.klog;
|
||||
|
||||
struct Hippo
|
||||
{
|
||||
/**
|
||||
* Linked list node entry for a physical page.
|
||||
* Linked list node entry for a single page.
|
||||
*/
|
||||
private static struct PhysicalPage
|
||||
{
|
||||
PhysicalPage * next;
|
||||
}
|
||||
|
||||
/**
|
||||
* Linked list node entry for a region.
|
||||
*/
|
||||
private static struct Region
|
||||
{
|
||||
ulong size;
|
||||
Region * next;
|
||||
}
|
||||
|
||||
/**
|
||||
* Linked list of free physical pages.
|
||||
*/
|
||||
private static __gshared PhysicalPage * free_pages;
|
||||
|
||||
/**
|
||||
* Linked list of free regions.
|
||||
*/
|
||||
private static __gshared Region * regions;
|
||||
|
||||
/**
|
||||
* Number of free physical pages.
|
||||
*/
|
||||
@@ -48,22 +65,154 @@ struct Hippo
|
||||
public static void * allocate_page()
|
||||
{
|
||||
PhysicalPage * pp;
|
||||
if (free_pages != null)
|
||||
if (free_pages !is null)
|
||||
{
|
||||
pp = free_pages;
|
||||
free_pages = free_pages.next;
|
||||
m_n_free_pages--;
|
||||
}
|
||||
else if (regions !is null)
|
||||
{
|
||||
pp = cast(PhysicalPage *)(cast(ulong)regions + regions.size - PAGE_SIZE);
|
||||
regions.size -= PAGE_SIZE;
|
||||
if (regions.size == 0)
|
||||
{
|
||||
regions = regions.next;
|
||||
}
|
||||
m_n_free_pages--;
|
||||
}
|
||||
return cast(void *)pp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Free a physical memory region.
|
||||
*/
|
||||
public static void free_region(T)(T start, ulong size)
|
||||
{
|
||||
if (size == PAGE_SIZE)
|
||||
{
|
||||
free_page(start);
|
||||
return;
|
||||
}
|
||||
|
||||
if (regions is null)
|
||||
{
|
||||
/* The free regions list is empty. Append this new region. */
|
||||
regions = cast(Region *)start;
|
||||
regions.size = size;
|
||||
regions.next = null;
|
||||
}
|
||||
else if (size < regions.size)
|
||||
{
|
||||
/* The new region is smaller than the first one in the list.
|
||||
* Add the new region to the beginning of the list. */
|
||||
Region * new_region = cast(Region *)start;
|
||||
new_region.size = size;
|
||||
new_region.next = regions;
|
||||
regions = new_region;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Find the last free region that is smaller than this one. */
|
||||
Region * region = regions;
|
||||
while (region.next !is null && region.next.size < size)
|
||||
{
|
||||
region = region.next;
|
||||
}
|
||||
|
||||
/* Add the new region after this entry. */
|
||||
Region * new_region = cast(Region *)start;
|
||||
new_region.size = size;
|
||||
new_region.next = region.next;
|
||||
region.next = new_region;
|
||||
}
|
||||
|
||||
m_n_free_pages += size >> 12;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocate a region with the given size and alignment.
|
||||
*
|
||||
* @param size Region size.
|
||||
* @param alignment Region alignment.
|
||||
*/
|
||||
public static void * allocate_aligned_region(ulong size, ulong alignment)
|
||||
{
|
||||
Region ** regionp = ®ions;
|
||||
for (;;)
|
||||
{
|
||||
Region * region = *regionp;
|
||||
if (region is null)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
/* The size of the region must be large enough */
|
||||
if (region.size >= size)
|
||||
{
|
||||
/* The alignment contstraint must be satisfied. */
|
||||
if ((cast(ulong)region & (alignment - 1)) == 0)
|
||||
{
|
||||
/* The region start address happens to already be aligned. */
|
||||
if (region.size > size)
|
||||
{
|
||||
/* Region found is larger that needed. */
|
||||
Region * new_region = cast(Region *)(cast(ulong)region + size);
|
||||
new_region.size = region.size - size;
|
||||
new_region.next = region.next;
|
||||
*regionp = new_region;
|
||||
return region;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Region happens to be the size requested. */
|
||||
*regionp = region.next;
|
||||
return region;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* This region is large enough but not aligned. See if an
|
||||
* aligned subregion can be found at the end. */
|
||||
ulong start = (cast(ulong)region + region.size - size) & ~(alignment - 1);
|
||||
if (start > cast(ulong)region)
|
||||
{
|
||||
/* The aligned subregion does fit in this region. */
|
||||
region.size = (start - cast(ulong)region);
|
||||
ulong region_end = cast(ulong)region + region.size;
|
||||
if (region_end > (start + size))
|
||||
{
|
||||
/* There is another region following the aligned
|
||||
* subregion that we must reclaim. */
|
||||
free_region(start + size, region_end - (start + size));
|
||||
}
|
||||
return cast(void *)start;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
regionp = ®ion.next;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of free pages.
|
||||
*
|
||||
* @return The number of free pages.
|
||||
*/
|
||||
public @property size_t n_free_pages() const
|
||||
public static @property size_t n_free_pages()
|
||||
{
|
||||
return m_n_free_pages;
|
||||
}
|
||||
|
||||
public static void dump_regions()
|
||||
{
|
||||
Region * region = regions;
|
||||
while (region !is null)
|
||||
{
|
||||
Klog.writefln("HIPPO free region: %p %uKB", region, region.size >> 10);
|
||||
region = region.next;
|
||||
}
|
||||
}
|
||||
}
|
||||
+6
-5
@@ -84,19 +84,20 @@ void hulk_start()
|
||||
Rtc.initialize();
|
||||
Pit.initialize();
|
||||
Pci.initialize();
|
||||
Usb.initialize();
|
||||
Thread.initialize();
|
||||
|
||||
resume_interrupts();
|
||||
|
||||
Usb.initialize();
|
||||
|
||||
/* Run kernel tests. */
|
||||
Test.run();
|
||||
Klog.writefln("\a5HULK Initialization Complete!");
|
||||
Thread.start(&th);
|
||||
// Thread.start(&th);
|
||||
// Time.msleep(1);
|
||||
// Time.msleep(500);
|
||||
// Klog.writefln("Main thread!");
|
||||
/* Idle loop. */
|
||||
Time.msleep(1);
|
||||
Time.msleep(500);
|
||||
Klog.writefln("Main thread!");
|
||||
for (;;)
|
||||
{
|
||||
hlt();
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
SECTIONS
|
||||
{
|
||||
. = 0xFFFF800000000000;
|
||||
. = 0xFFFFFFFF80000000;
|
||||
_hulk_mem_start = .;
|
||||
_hulk_header_start = .;
|
||||
|
||||
|
||||
+70
-26
@@ -18,16 +18,16 @@ import hulk.util;
|
||||
struct Hurl
|
||||
{
|
||||
/** HULK base address. */
|
||||
enum ulong HULK_BASE = 0xFFFF_8000_0000_0000u;
|
||||
enum ulong HULK_BASE = 0xFFFF_FFFF_8000_0000u;
|
||||
|
||||
/** HULK stack top address. */
|
||||
enum ulong HULK_STACK_TOP = 0xFFFF_8001_0000_0000u;
|
||||
enum ulong HULK_STACK_TOP = 0xFFFF_FFFF_9000_0000u;
|
||||
|
||||
/** HULK framebuffer address. */
|
||||
enum ulong HULK_FRAMEBUFFER = 0xFFFF_8001_0000_0000u;
|
||||
enum ulong HULK_FRAMEBUFFER = 0xFFFF_FFFF_9000_0000u;
|
||||
|
||||
/** A1 allocator range base address. */
|
||||
enum ulong A1_BASE = 0xFFFF_8002_0000_0000u;
|
||||
enum ulong A1_BASE = 0xFFFF_FFFF_A000_0000u;
|
||||
|
||||
/**
|
||||
* Pointer to the base page table.
|
||||
@@ -91,7 +91,7 @@ struct Hurl
|
||||
map_range(HULK_FRAMEBUFFER,
|
||||
cast(ulong)header.bootinfo.fb.buffer,
|
||||
header.bootinfo.fb.height * header.bootinfo.fb.stride * 4u,
|
||||
PT_WRITABLE | PT_NO_EXECUTE);
|
||||
PT_PAT | PT_WRITABLE | PT_NO_EXECUTE);
|
||||
/* Map framebuffer buffer1. */
|
||||
map_range(cast(ulong)header.bootinfo.fb_buffer1_phys,
|
||||
cast(ulong)header.bootinfo.fb_buffer1_phys,
|
||||
@@ -157,13 +157,14 @@ 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);
|
||||
ulong[2][2] reserved = [
|
||||
ulong[2][2] reserved_regions = [
|
||||
[header.bootinfo.hulk_phys, LinkerAddresses.hulk_binary_size],
|
||||
[cast(ulong)header.bootinfo.fb.buffer, fb_size],
|
||||
];
|
||||
for (size_t ri = 0u; ri < reserved.length; ri++)
|
||||
for (size_t ri = 0u; ri < reserved_regions.length; ri++)
|
||||
{
|
||||
reserved[ri][1] += reserved[ri][0];
|
||||
Klog.writefln("Reserved region %p %uKB", reserved_regions[ri][0], reserved_regions[ri][1] >> 10);
|
||||
reserved_regions[ri][1] += reserved_regions[ri][0];
|
||||
}
|
||||
for (size_t bii = 0u; bii < header.bootinfo.memory_map_count; bii++)
|
||||
{
|
||||
@@ -171,32 +172,21 @@ struct Hurl
|
||||
(header.bootinfo.memory_map[bii].type == BootInfo.MemoryRegion.Type.Conventional))
|
||||
{
|
||||
ulong phys = header.bootinfo.memory_map[bii].base;
|
||||
ulong phys_end = phys + header.bootinfo.memory_map[bii].size;
|
||||
ulong size = header.bootinfo.memory_map[bii].size;
|
||||
ulong phys_end = phys + size;
|
||||
if (phys_end > physical_address_limit)
|
||||
{
|
||||
physical_address_limit = phys_end;
|
||||
}
|
||||
usable_memory += header.bootinfo.memory_map[bii].size;
|
||||
while (phys < phys_end)
|
||||
{
|
||||
bool is_reserved = false;
|
||||
for (size_t ri = 0u; ri < reserved.length; ri++)
|
||||
{
|
||||
if ((reserved[ri][0] <= phys) && (phys < reserved[ri][1]))
|
||||
{
|
||||
is_reserved = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!is_reserved)
|
||||
{
|
||||
Hippo.free_page(phys);
|
||||
}
|
||||
phys += PAGE_SIZE;
|
||||
}
|
||||
add_region(phys, size, reserved_regions);
|
||||
}
|
||||
}
|
||||
|
||||
/* Set PAT4 to indicate Write Combining so we can set the PAT bit in a
|
||||
* page table entry to use Write Combining for that page. */
|
||||
wrmsr(MSR_PAT, (rdmsr(MSR_PAT) & 0xFFFF_FF00_FFFF_FFFFu) | 0x0000_0001_0000_0000u);
|
||||
|
||||
/*
|
||||
* Now that we have available physical pages to allocate from, we can
|
||||
* build new page tables to replace the bootloader page tables.
|
||||
@@ -219,6 +209,60 @@ struct Hurl
|
||||
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("Free pages: %u", Hippo.n_free_pages);
|
||||
// Hippo.dump_regions();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a region of available physical memory.
|
||||
*
|
||||
* @param start Start address of region.
|
||||
* @param size Size of region.
|
||||
* @param reserved_regions List of reserved regions to exclude.
|
||||
*/
|
||||
private static void add_region(ulong start, ulong size, ulong[2][] reserved_regions)
|
||||
{
|
||||
ulong end = start + size;
|
||||
bool split;
|
||||
|
||||
/* Skip empty regions. */
|
||||
if (size == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (size_t rri = 0; rri < reserved_regions.length; rri++)
|
||||
{
|
||||
/* Skip this region if it is entirely within a reserved region. */
|
||||
if (reserved_regions[rri][0] <= start && reserved_regions[rri][1] >= end)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* Check if the region is partly reserved but the beginning is free. */
|
||||
if (reserved_regions[rri][0] > start && reserved_regions[rri][0] < end)
|
||||
{
|
||||
split = true;
|
||||
add_region(start, reserved_regions[rri][0] - start, reserved_regions);
|
||||
}
|
||||
|
||||
/* Check if the region is partly reserved but the end is free. */
|
||||
if (reserved_regions[rri][1] > start && reserved_regions[rri][1] < end)
|
||||
{
|
||||
split = true;
|
||||
add_region(reserved_regions[rri][1], end - reserved_regions[rri][1], reserved_regions);
|
||||
}
|
||||
|
||||
if (split)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* If a region makes it here, it did not overlap with any reserved
|
||||
* region, so the entire region can be used. */
|
||||
// Klog.writefln("HURL: freeing region %p %uKB", start, size >> 10);
|
||||
Hippo.free_region(start, size);
|
||||
}
|
||||
|
||||
public static void map(ulong virtual, ulong physical, ulong flags)
|
||||
|
||||
@@ -11,7 +11,8 @@ enum ulong PT_WRITE_THROUGH = 0x8u;
|
||||
enum ulong PT_DISABLE_CACHE = 0x10u;
|
||||
enum ulong PT_ACCESSED = 0x20u;
|
||||
enum ulong PT_DIRTY = 0x40u;
|
||||
enum ulong PT_HUGE_PAGE = 0x80u;
|
||||
enum ulong PT_PAT = 0x80u; /* Page table entry bit. */
|
||||
enum ulong PT_HUGE_PAGE = 0x80u; /* Page directory entry bit. */
|
||||
enum ulong PT_GLOBAL = 0x100u;
|
||||
enum ulong PT_NO_EXECUTE = 0x8000_0000_0000_0000u;
|
||||
/** @} */
|
||||
|
||||
+1
-1
@@ -223,7 +223,7 @@ struct Pci
|
||||
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);
|
||||
Hurl.identity_map_range(mm_region_address, length, PT_WRITABLE | flags);
|
||||
memory_ranges[range_index].address = mm_region_address;
|
||||
memory_ranges[range_index].length = length;
|
||||
range_index++;
|
||||
|
||||
+4
-4
@@ -3,12 +3,12 @@
|
||||
*/
|
||||
module hulk.time;
|
||||
|
||||
import core.volatile;
|
||||
import hulk.volatile;
|
||||
|
||||
struct Time
|
||||
{
|
||||
/** System uptime (ms). */
|
||||
private static __gshared ulong s_uptime;
|
||||
private static __gshared Volatile!ulong s_uptime;
|
||||
|
||||
/**
|
||||
* Millisecond ISR.
|
||||
@@ -23,7 +23,7 @@ struct Time
|
||||
*/
|
||||
public static @property ulong uptime()
|
||||
{
|
||||
return volatileLoad(&s_uptime);
|
||||
return s_uptime;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -34,7 +34,7 @@ struct Time
|
||||
*/
|
||||
public static void msleep(ulong count)
|
||||
{
|
||||
ulong wait_for = s_uptime + count + 1;
|
||||
ulong wait_for = uptime() + count + 1;
|
||||
while (uptime() < wait_for)
|
||||
{
|
||||
}
|
||||
|
||||
+160
-29
@@ -9,8 +9,12 @@
|
||||
module hulk.usb.xhci;
|
||||
|
||||
import hulk.pci;
|
||||
import hulk.hurl;
|
||||
import hulk.hurl.a1;
|
||||
import hulk.hippo;
|
||||
import hulk.klog;
|
||||
import hulk.time;
|
||||
import hulk.volatile;
|
||||
|
||||
struct XHCI
|
||||
{
|
||||
@@ -25,14 +29,14 @@ struct XHCI
|
||||
* Offset from beginning of capability registers to beginning of
|
||||
* operational registers.
|
||||
*/
|
||||
ubyte capability_length;
|
||||
Volatile!ubyte capability_length;
|
||||
|
||||
ubyte _reserved01;
|
||||
|
||||
/**
|
||||
* Interface version number supported (psuedo-BSD).
|
||||
*/
|
||||
ushort hci_version;
|
||||
Volatile!ushort hci_version;
|
||||
|
||||
/**
|
||||
* HCSPARAMS1.
|
||||
@@ -41,7 +45,12 @@ struct XHCI
|
||||
* 23:19 reserved
|
||||
* 31:24 number of ports (MaxPorts)
|
||||
*/
|
||||
uint hcs_params1;
|
||||
Volatile!uint hcs_params1;
|
||||
|
||||
@property ubyte max_slots()
|
||||
{
|
||||
return this.hcs_params1 & 0xFFu;
|
||||
}
|
||||
|
||||
/**
|
||||
* 3:0 isochronous scheduling threshold (IST)
|
||||
@@ -51,14 +60,20 @@ struct XHCI
|
||||
* 26 scratchpad restore (SPR)
|
||||
* 31:27 max scratchpad buffers (low 5 bits)
|
||||
*/
|
||||
uint hcs_params2;
|
||||
Volatile!uint hcs_params2;
|
||||
|
||||
@property size_t max_scratchpad_buffers()
|
||||
{
|
||||
uint v = this.hcs_params2;
|
||||
return (v >> 27u) | ((v >> (21 - 5)) & 0x3E0u);
|
||||
}
|
||||
|
||||
/**
|
||||
* 7:0 U1 device exit latency
|
||||
* 15:8 reserved
|
||||
* 31:16 U2 device exit latency
|
||||
*/
|
||||
uint hcs_params3;
|
||||
Volatile!uint hcs_params3;
|
||||
|
||||
/**
|
||||
* 0 64-bit addressing capability (AC64)
|
||||
@@ -78,7 +93,7 @@ struct XHCI
|
||||
* offset in 32-bit words from base of capability registers to base
|
||||
* of capabilities list
|
||||
*/
|
||||
uint hcc_params1;
|
||||
Volatile!uint hcc_params1;
|
||||
|
||||
/**
|
||||
* 1:0 reserved
|
||||
@@ -86,13 +101,13 @@ struct XHCI
|
||||
* offset in 32-bit words from base of capability registers to the
|
||||
* doorbell array
|
||||
*/
|
||||
uint doorbell_offset;
|
||||
Volatile!uint doorbell_offset;
|
||||
|
||||
/**
|
||||
* 4:0 reserved
|
||||
* 31:5 runtime register space offset
|
||||
*/
|
||||
uint rts_offset;
|
||||
Volatile!uint rts_offset;
|
||||
|
||||
/**
|
||||
* 0 U3 entry capability (U3C)
|
||||
@@ -107,13 +122,13 @@ struct XHCI
|
||||
* 9 virtualization based trusted I/O capability (VTC; xHCI v1.2+)
|
||||
* 31:10 reserved
|
||||
*/
|
||||
uint hcc_params2;
|
||||
Volatile!uint hcc_params2;
|
||||
|
||||
/**
|
||||
* 11:0 reserved
|
||||
* 31:12 VTIO register space offset (xHCI v1.2+)
|
||||
*/
|
||||
uint vtios_offset;
|
||||
Volatile!uint vtios_offset;
|
||||
}
|
||||
static assert(CapabilityRegisters.sizeof == 0x24u);
|
||||
|
||||
@@ -140,7 +155,7 @@ struct XHCI
|
||||
* 16 VTIO enable (VTIOE; xHCI v1.2+)
|
||||
* 31:17 reserved
|
||||
*/
|
||||
uint usb_command;
|
||||
Volatile!uint usb_command;
|
||||
|
||||
/**
|
||||
* 0 HCHalted
|
||||
@@ -156,13 +171,13 @@ struct XHCI
|
||||
* 12 Host Controller Error (HCE)
|
||||
* 31:13 reserved
|
||||
*/
|
||||
uint usb_status;
|
||||
Volatile!uint usb_status;
|
||||
|
||||
/**
|
||||
* 15:0 Page Size (actual page size is 2^(x+12))
|
||||
* 31:16 reserved
|
||||
*/
|
||||
uint page_size;
|
||||
Volatile!uint page_size;
|
||||
|
||||
uint[2] _reserved01;
|
||||
|
||||
@@ -170,7 +185,7 @@ struct XHCI
|
||||
* 15:0 Notification Enable
|
||||
* 31:16 reserved
|
||||
*/
|
||||
uint dn_ctrl;
|
||||
Volatile!uint dn_ctrl;
|
||||
|
||||
/**
|
||||
* 0 Ring Cycle State (RCS)
|
||||
@@ -180,7 +195,7 @@ struct XHCI
|
||||
* 5:4 reserved
|
||||
* 63:6 Command Ring Pointer
|
||||
*/
|
||||
ulong cr_ctrl;
|
||||
Volatile!ulong cr_ctrl;
|
||||
|
||||
uint[4] _reserved02;
|
||||
|
||||
@@ -188,7 +203,7 @@ struct XHCI
|
||||
* 5:0 reserved
|
||||
* 63:6 Device Context Base Address Array Pointer
|
||||
*/
|
||||
ulong dcbaap;
|
||||
Volatile!ulong dcbaap;
|
||||
|
||||
/**
|
||||
* 7:0 Max Device Slots Enabled (MaxSlotsEn)
|
||||
@@ -196,7 +211,7 @@ struct XHCI
|
||||
* 9 Configuration Information Enable (CIE; xHCI v1.1+)
|
||||
* 31:10 reserved
|
||||
*/
|
||||
uint config;
|
||||
Volatile!uint config;
|
||||
|
||||
uint _reserved03;
|
||||
}
|
||||
@@ -237,22 +252,22 @@ struct XHCI
|
||||
* 30 Device Removable
|
||||
* 31 Warm Port Reset
|
||||
*/
|
||||
uint portsc;
|
||||
Volatile!uint portsc;
|
||||
|
||||
/**
|
||||
* Port Power Management Status and Control
|
||||
*/
|
||||
uint portpmsc;
|
||||
Volatile!uint portpmsc;
|
||||
|
||||
/**
|
||||
* Port Link Info
|
||||
*/
|
||||
uint portli;
|
||||
Volatile!uint portli;
|
||||
|
||||
/**
|
||||
* Port Hardware LPM Control (xHCI v1.1+)
|
||||
*/
|
||||
uint porthlpmc;
|
||||
Volatile!uint porthlpmc;
|
||||
}
|
||||
static assert(PortRegisters.sizeof == 0x10u);
|
||||
|
||||
@@ -264,7 +279,7 @@ struct XHCI
|
||||
/**
|
||||
* Microframe index. Incremented by controller each microframe.
|
||||
*/
|
||||
uint mfindex;
|
||||
Volatile!uint mfindex;
|
||||
|
||||
uint[7] _reserved01;
|
||||
|
||||
@@ -287,21 +302,21 @@ struct XHCI
|
||||
* 1 Interrupt Enable
|
||||
* 31:2 reserved
|
||||
*/
|
||||
uint imr;
|
||||
Volatile!uint imr;
|
||||
|
||||
/**
|
||||
* Interrupter Moderation.
|
||||
* 15:0 Interrupt Moderation Interval
|
||||
* 31:16 Interrupt Moderation Counter
|
||||
*/
|
||||
uint im;
|
||||
Volatile!uint im;
|
||||
|
||||
/**
|
||||
* Event Ring Segment Table Size.
|
||||
* 15:0 Event Ring Segment Table Size
|
||||
* 31:16 reserved
|
||||
*/
|
||||
uint ersts;
|
||||
Volatile!uint ersts;
|
||||
|
||||
uint reserved;
|
||||
|
||||
@@ -310,7 +325,7 @@ struct XHCI
|
||||
* 5:0 reserved
|
||||
* 63:6 Event Ring Segment Table Base Address
|
||||
*/
|
||||
ulong erstba;
|
||||
Volatile!ulong erstba;
|
||||
|
||||
/**
|
||||
* Event Ring Dequeue Pointer.
|
||||
@@ -318,7 +333,7 @@ struct XHCI
|
||||
* 3 Event Handler Busy
|
||||
* 63:4 Event Ring Dequeue Pointer
|
||||
*/
|
||||
ulong erdp;
|
||||
Volatile!ulong erdp;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -329,9 +344,9 @@ struct XHCI
|
||||
*/
|
||||
struct DoorbellRegister
|
||||
{
|
||||
ubyte target;
|
||||
Volatile!ubyte target;
|
||||
ubyte _reserved01;
|
||||
ushort task_id;
|
||||
Volatile!ushort task_id;
|
||||
}
|
||||
static assert(DoorbellRegister.sizeof == 4u);
|
||||
|
||||
@@ -351,6 +366,72 @@ struct XHCI
|
||||
m_runtime_registers = cast(RuntimeRegisters *)(base_address + m_capability_registers.rts_offset);
|
||||
m_doorbell_registers = cast(DoorbellRegister *)(base_address + m_capability_registers.doorbell_offset);
|
||||
dump_extended_capabilities();
|
||||
if (!reset())
|
||||
{
|
||||
Klog.writefln("XHCI controller failed to initialize");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Allocate memory for various controller data structures. */
|
||||
ubyte * page = cast(ubyte *)Hippo.allocate_page();
|
||||
/* Device Context Index: 2K */
|
||||
void ** device_context_index = cast(void **)page;
|
||||
/* Input Control Context: 64 bytes */
|
||||
void * input_control_context = &page[2048];
|
||||
/* Slot Context: 64 bytes */
|
||||
void * slot_context = &page[2048 + 64];
|
||||
/* Endpoint Context: 64 bytes */
|
||||
void * endpoint_context = &page[2048 + 64 + 64];
|
||||
/* Stream Context: 16 bytes */
|
||||
void * stream_context = &page[2048 + 64 + 64 + 64];
|
||||
/* Stream Array (Linear): 1M */
|
||||
void * stream_array_linear = Hippo.allocate_aligned_region(1024 * 1024, PAGE_SIZE);
|
||||
/* Stream Array (Pri/Sec): 4K */
|
||||
void * stream_array_pri_sec = Hippo.allocate_page();
|
||||
/* Transfer Ring Segments: 64K */
|
||||
void * transfer_ring_segments = Hippo.allocate_aligned_region(64 * 1024, 64 * 1024);
|
||||
/* Command Ring Segments: 64K */
|
||||
void * command_ring_segments = Hippo.allocate_aligned_region(64 * 1024, 64 * 1024);
|
||||
/* Event Ring Segments: 64K */
|
||||
void * event_ring_segments = Hippo.allocate_aligned_region(64 * 1024, 64 * 1024);
|
||||
/* Event Ring Segment Table: 512K */
|
||||
void * event_ring_segment_table = Hippo.allocate_aligned_region(512 * 1024, PAGE_SIZE);
|
||||
/* Scratchpad Buffer Array: 248 bytes */
|
||||
void ** scratchpad_buffer_array = cast(void **)Hippo.allocate_aligned_region(2 * PAGE_SIZE, PAGE_SIZE);
|
||||
|
||||
size_t n_scratchpad_buffers = m_capability_registers.max_scratchpad_buffers;
|
||||
for (size_t i = 0u; i < n_scratchpad_buffers; i++)
|
||||
{
|
||||
void * scratchpad_buffer = Hippo.allocate_page();
|
||||
scratchpad_buffer_array[i] = scratchpad_buffer;
|
||||
}
|
||||
|
||||
device_context_index[0] = scratchpad_buffer_array;
|
||||
|
||||
size_t max_slots = m_capability_registers.max_slots;
|
||||
for (size_t i = 0u; i < max_slots; i++)
|
||||
{
|
||||
void * addr;
|
||||
if ((i & 1) == 0)
|
||||
{
|
||||
page = cast(ubyte *)Hippo.allocate_page();
|
||||
addr = page;
|
||||
}
|
||||
else
|
||||
{
|
||||
addr = &page[2048];
|
||||
}
|
||||
device_context_index[1 + i] = addr;
|
||||
}
|
||||
|
||||
m_operational_registers.dcbaap = cast(ulong)device_context_index;
|
||||
/* TODO: write cr_ctrl. */
|
||||
/+ TODO:
|
||||
m_operational_registers.config = m_capability_registers.hcs_params1 & 0xFu;
|
||||
m_operational_registers.dn_ctrl = 1u << 1u;
|
||||
+/
|
||||
/* TODO: set up interrupt register set. */
|
||||
Klog.writefln("XHCI controller initialization successful");
|
||||
}
|
||||
|
||||
private void dump_extended_capabilities()
|
||||
@@ -393,6 +474,56 @@ struct XHCI
|
||||
}
|
||||
}
|
||||
|
||||
private bool reset()
|
||||
{
|
||||
/* Clear run/stop bit. */
|
||||
m_operational_registers.usb_command &= ~0x1u;
|
||||
|
||||
/* Wait for HCHalted bit to be set. */
|
||||
enum halt_timeout = 40u;
|
||||
for (size_t halt_timeout_counter = 0u;;)
|
||||
{
|
||||
Time.msleep(1u);
|
||||
|
||||
if ((m_operational_registers.usb_status & 1u) != 0u)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
halt_timeout_counter++;
|
||||
if (halt_timeout_counter >= halt_timeout)
|
||||
{
|
||||
Klog.writefln("XHCI controller failed to halt");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* Set HC reset bit. */
|
||||
m_operational_registers.usb_command |= (1u << 1u);
|
||||
|
||||
/* Wait for controller to be ready. */
|
||||
enum reset_timeout = 100u;
|
||||
for (size_t reset_timeout_counter = 0u;;)
|
||||
{
|
||||
Time.msleep(1u);
|
||||
|
||||
if (((m_operational_registers.usb_command & (1u << 1u)) == 0u) &&
|
||||
((m_operational_registers.usb_status & (1u << 11u)) == 0u))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
reset_timeout_counter++;
|
||||
if (reset_timeout_counter >= reset_timeout)
|
||||
{
|
||||
Klog.writefln("XHCI controller failed to reset");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void build(Pci.Device * pci_device)
|
||||
{
|
||||
if (pci_device.memory_ranges[0].address != null)
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
module hulk.volatile;
|
||||
|
||||
import core.volatile;
|
||||
|
||||
struct Volatile(T)
|
||||
{
|
||||
private T value;
|
||||
|
||||
public @property T read()
|
||||
{
|
||||
return volatileLoad(&value);
|
||||
}
|
||||
alias read this;
|
||||
|
||||
public void opAssign(T value)
|
||||
{
|
||||
volatileStore(&this.value, value);
|
||||
}
|
||||
|
||||
public T opUnary(string s)()
|
||||
{
|
||||
T v = read();
|
||||
mixin(s ~ "v;");
|
||||
volatileStore(&this.value, v);
|
||||
return v;
|
||||
}
|
||||
|
||||
public T opOpAssign(string s)(T rhs)
|
||||
{
|
||||
T v = read();
|
||||
mixin("v " ~ s ~ "= rhs;");
|
||||
volatileStore(&this.value, v);
|
||||
return v;
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user