18 Commits
Author SHA1 Message Date
josh bb65def53c XHCI: set dcbaap 2025-05-23 10:16:49 -04:00
josh 0d970a6d25 XHCI: allocate scratchpad buffers 2025-05-23 10:13:54 -04:00
josh ea159db100 XHCI: allocate device context buffer for each slot 2025-05-23 09:21:48 -04:00
josh e3f27812ad Allocate memory regions for XHCI 2025-02-23 20:52:36 -05:00
josh d78669df9c Check for pkg-config 2025-02-23 20:46:31 -05:00
josh 7313b01732 Allow allocating arbitrarily aligned physical memory regions
This will be needed for USB (XHCI controller driver).
2025-02-21 15:31:48 -05:00
josh b2497d1ee0 HIPPO: store memory regions in addition to individual free pages 2025-02-21 12:31:03 -05:00
josh 30078417b6 Turn off test thread 2025-02-20 15:50:57 -05:00
josh c18cbf7be3 Remove unsupported avx CPU flags 2025-02-20 11:30:53 -05:00
josh 2d95371aa1 Add hulk.volatile 2024-12-03 00:18:45 -05:00
josh 13b6f39e1a Add OVMF search location 2024-12-02 10:54:02 -05:00
josh 30aedfc97b Map framebuffer with write-combining access mode to speed up physical hardware 2024-07-29 00:01:47 -04:00
josh 26bb071b4d Update base address to build with kernel code model 2024-07-28 23:14:24 -04:00
josh 3a75e0505f Prepare for future XHCI setup 2024-02-20 11:41:23 -05:00
josh a02df12924 Add XHCI.reset() 2024-02-20 11:23:12 -05:00
josh 699f53ac15 Initialize USB after enabling interrupts so Time can be used 2024-02-20 11:17:29 -05:00
josh 1119855215 Fix mapping PCI regions as writable 2024-02-20 11:17:01 -05:00
josh 0c82250bd2 Fix Time.msleep() when inlined in a loop 2024-02-20 11:16:34 -05:00
11 changed files with 437 additions and 73 deletions

No files matched your search

+5 -3
View File
@@ -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
+1
View File
@@ -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
View File
@@ -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 = &regions;
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 = &region.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
View File
@@ -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
View File
@@ -1,6 +1,6 @@
SECTIONS
{
. = 0xFFFF800000000000;
. = 0xFFFFFFFF80000000;
_hulk_mem_start = .;
_hulk_header_start = .;
+70 -26
View File
@@ -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)
+2 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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)
+35
View File
@@ -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;
}
}