412 Commits
Author SHA1 Message Date
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
josh 2a66443a49 Add DoorbellRegister comment 2024-02-09 13:02:05 -05:00
josh 9874802ee4 Add new threads to runnable threads list
More safely handle nested interrupts.
Switch to newly created thread immediately.
2023-12-08 12:16:35 -05:00
josh 44a305721e Allow use of {suspend,resume}_interrupts() from within an ISR
Move functions from hulk.cpu to hulk.him.
2023-12-01 07:54:37 -05:00
josh 73f4d6b728 Rename hulk.idt to hulk.him 2023-12-01 07:49:52 -05:00
josh 0efe8af5aa Commonize ISR handling as much as possible 2023-11-30 20:32:06 -05:00
josh edc9b2c3ff Remove thread test 2023-11-28 10:47:44 -05:00
josh c8a9fcf0d5 idt: add INT_KERNEL_SWINT 2023-11-28 10:30:16 -05:00
josh dc231741b7 cpu: add swint() 2023-11-28 10:30:03 -05:00
josh fbaf9df59f Add kernel threading test
Kernel multithreading is working!
Threads cannot exit for now.
Scheduling is round-robin for now.
2023-11-27 20:07:08 -05:00
josh 58a74e4859 Fix PCI device list 2023-11-27 19:37:14 -05:00
josh cc1753a75d Move system time display to Rtc.initialize() 2023-11-27 19:36:04 -05:00
josh 3c8587acf5 Redesign List as a mixin template 2023-11-27 15:30:09 -05:00
josh db2814596b Move PIT test to test module 2023-11-25 21:01:46 -05:00
josh 8cfa7bc009 Add hulk.thread module 2023-11-25 20:58:11 -05:00
josh d100ab53a8 Add read_rflags() 2023-11-25 13:02:27 -05:00
josh 35e5aa2ee5 Add hulk.test module to test kernel functionality 2023-11-22 20:47:21 -05:00
josh cd9a3a7284 Rework List to allow removing nodes 2023-11-22 20:46:48 -05:00
josh 294500fb70 Squelch linker warning about a RWX segment 2023-11-21 12:13:29 -05:00
josh bb4404df23 Add suspend_interrupts() and resume_interrupts() 2023-11-21 11:36:22 -05:00
josh aa5ca83889 Disable the red zone
This fixes the interrupt handler from clobbering local variables.
2023-11-20 16:18:41 -05:00
josh f2839cdd0f Handle all APIC IRQ redirects specified in MADT 2023-11-07 17:19:56 -05:00
josh 31bf82e2ae Store all registers in interrupt stack frame
Do not clear console when printing interrupt stack frame
2023-11-02 16:32:42 -04:00
josh 4f9206af91 Build with debugging symbols 2023-11-02 11:54:08 -04:00
josh 2eec448653 Update gcc and binutils 2023-11-02 11:53:35 -04:00
josh 9932b92963 Change orange screen of death to red bar 2023-11-02 10:34:29 -04:00
josh 5d8343ed40 Preserve registers and align stack in interrupt handlers 2023-11-02 10:29:27 -04:00
josh 2fa4193517 Pass exception stack frame pointer to exception handler
Show exception stack frame contents on exception
2023-11-01 21:22:54 -04:00
josh 01c73f8474 Add check that PIT ISR is firing 2023-11-01 14:45:43 -04:00
josh 7264a31ff3 Rework scanning MADT table entries
Get I/O APIC address from MADT entry.
Add DEBUG flag for APIC.
Show number of CPUs found.
2023-10-31 13:29:23 -04:00
josh c0a00b528e Run in QEMU with 4 CPUs by default 2023-10-31 11:56:39 -04:00
josh 9f8a4ea100 Add hulk.time and msleep() 2023-10-26 16:18:26 -04:00
josh 6251fee3ff Store item in List rather than pointer to item 2023-10-25 21:28:27 -04:00
josh f5c6a35cef Move MCFG ACPI table processing from ACPI to PCI 2023-10-25 21:18:36 -04:00
josh e32282f6f0 Move MADT table processing from ACPI to APIC 2023-10-25 21:11:21 -04:00
josh 2b87792c67 Store ACPI table pointers in list 2023-10-25 19:13:36 -04:00
josh e480bd0ed0 Enable PIT ISR to count milliseconds 2023-10-25 12:02:44 -04:00
josh e357f2ba44 Initialize USB controllers from Usb instead of Pci 2023-10-24 10:44:48 -04:00
josh f8f9b72588 Store PCI addresses and types as 32-bit uints 2023-10-24 10:25:16 -04:00
josh d86bf47211 Store a List of discovered PCI devices 2023-10-24 08:49:11 -04:00
josh 757f8f8c65 Make A1.allocate() zero returned memory 2023-10-24 08:48:26 -04:00
josh 8303451929 Add List class 2023-10-24 08:48:00 -04:00
josh 1c6c922b45 Add Pci.Type struct 2023-10-22 21:30:36 -04:00
josh 7632445d43 Add console escape sequences to draw headings 2023-10-21 22:13:20 -04:00
josh 601ea50e4b Console: delay newline rendering until non newline character 2023-10-21 21:21:46 -04:00
josh 722494af44 Console: do not index nonexistent character codes 2023-10-21 21:04:18 -04:00
josh e1f38bd5ea Initialize RTC after APIC 2023-10-21 20:47:15 -04:00
josh bcf1bd3bde HELLO: Zero HULK BSS region after mapping it 2023-10-21 20:46:27 -04:00
josh f7dde241ad Split console into two pages 2023-10-21 20:15:11 -04:00
josh 8638840cd8 Add console header line 2023-10-21 17:08:45 -04:00
josh 4273c703e9 writef: split into writef() and writefv() 2023-10-21 16:45:41 -04:00
josh b2597fb5da Add hulk.ver module 2023-10-18 19:33:43 -04:00
josh 291ba2bc1c Remove xHCI TODO 2023-10-13 14:17:34 -04:00
josh 71bc3543a1 fontgen: show more error info for invalid character metrics 2023-09-26 12:00:22 -04:00
josh a87d24d417 Reduce kernel console font size slightly 2023-09-26 09:59:22 -04:00
josh 6fcc6da022 Remove APIC debug outputs 2023-09-24 11:03:21 -04:00
josh dc07fd0255 Document xHCI runtime registers and interrupter registers 2023-09-23 19:48:14 -04:00
josh eb0a4b2a4d Document xHCI port registers 2023-09-23 19:28:35 -04:00
josh 0ae3c6c96d Document xHCI operational registers 2023-09-23 11:59:20 -04:00
josh 4814b51daf Dump xHCI extended capabilities 2023-09-19 11:07:18 -04:00
josh 14bb3adf37 Document xHCI capability registers 2023-09-19 11:07:02 -04:00
josh cda45b205d Remove legacy PCI bus scanning 2023-09-17 16:13:37 -04:00
josh cfd42550fc Add struct definitions for all PCI header types 2023-09-17 15:22:58 -04:00
josh 673ce8f097 Scan PCI devices via MCFG table 2023-09-17 14:49:02 -04:00
josh ba0befa21b Check that needed ACPI tables are found 2023-09-17 13:40:26 -04:00
josh fa4de31aa4 Store pertinent ACPI table pointers 2023-09-17 11:22:58 -04:00
josh 3412d9ece9 Add Klog.fatal_error() 2023-09-17 11:15:02 -04:00
josh e8978c73f2 Move PCI initialization after ACPI/APIC/RTC 2023-09-17 11:00:48 -04:00
josh f79b0098c5 Map ACPI tables as disable cache + no execute 2023-09-17 09:12:20 -04:00
josh 10d7e7f0c6 Move parsing of ACPI tables into table structures
Move mapping ACPI table memory into common location
2023-09-17 09:08:01 -04:00
josh e088f942d1 Use Acpi.Header in ACPI table structures 2023-09-17 08:53:34 -04:00
josh 6514af8e94 Begin parsing MCFG ACPI table 2023-09-17 08:41:08 -04:00
josh 602a7525d2 Add %p format specifier for printing pointers 2023-09-16 17:09:55 -04:00
josh 617b861524 Size to hulk.elf.size 2023-09-15 13:38:25 -04:00
josh 2f968de7ed Disassemble to hulk.elf.txt 2023-09-15 13:37:48 -04:00
josh 68e85999fb Drop unused sections when linking HULK 2023-09-15 13:37:00 -04:00
josh 6b1445935c Update mk-vmdk task to have a file template since VBoxManage createmedium command was failing 2023-09-15 11:04:36 -04:00
josh 665d8aef80 Update qemu command to change machine to q35
This enables PCIe
2023-09-15 11:04:12 -04:00
josh af5ad73cf7 Update instructions for VirtualBox to change machine chipset
This enables PCIe
2023-09-15 11:03:39 -04:00
josh 4c67faaad4 Rework Kfont to store glyph top as offset from top of text row 2023-09-13 13:48:11 -04:00
josh 4fcea6a283 Reverse framebuffer vertical coordinates to start with 0 at top 2023-09-13 11:57:47 -04:00
josh c958b9ffcc Remove alpha-blending framebuffer functions 2023-09-13 10:57:45 -04:00
josh 3d911ab191 Adjust console text height by font baseline offset
This fixes having leftover pixels on screen bottom when scrolling the
console up.
2023-09-13 10:52:24 -04:00
josh d04c5444c7 fontgen: put character number before character data 2023-09-13 08:54:09 -04:00
josh 209658ee09 Use cache to mkdir_p for HulkBinObj builder 2023-09-10 09:48:07 -04:00
josh f3f45445b3 Determine XHCI controller addresses 2023-09-07 14:04:30 -04:00
josh 459d5c36aa Set alignment of XSDT table pointers to 4 instead of 8 2023-09-07 12:57:26 -04:00
josh 22c9891c4f Add page_address() 2023-09-07 12:51:41 -04:00
josh 2a832bfb8b Print progress messages for cross compiler toolchain installation 2023-09-06 22:58:18 -04:00
josh 496445e533 Fix linker script section placement 2023-09-06 16:40:17 -04:00
josh 156642293f Debug output HULK memory range end addresses 2023-09-04 21:20:10 -04:00
josh 4e46b98efc Capture QEMU serial port output 2023-09-04 21:13:35 -04:00
josh ce3e2c55df Store QEMU files in local qemu directory 2023-09-04 21:12:36 -04:00
josh cb24d00e5f Document running in QEMU in README 2023-09-04 21:04:30 -04:00
josh 4500f3cbca Write HELLO memory map debug data to serial port 2023-09-04 20:59:38 -04:00
josh 0781962e9f Rework HELLO console module to use hulk.writef 2023-09-04 16:17:47 -04:00
josh e25d28ebc7 Add serial module 2023-09-04 14:56:12 -04:00
josh 93a4065dea Add path to OVMF.fd for Arch 2023-09-04 14:07:05 -04:00
josh 5b017fb810 Add some xHCI register structures 2023-06-11 17:22:50 -04:00
josh 37814b4f86 Start on XHCI struct 2023-06-10 22:55:08 -04:00
josh 238659e94b Store PCI device mapped memory ranges 2023-06-10 22:22:09 -04:00
josh c16aa0e9c3 Add hulk.range 2023-06-10 22:21:55 -04:00
josh 2935903bae Map PCI device memory regions 2023-06-10 20:12:46 -04:00
josh 5179b5881b Read PCI device header type 2023-06-10 12:01:06 -04:00
josh a0c62937ff Remove Pci.init_device() for now 2023-06-10 11:28:51 -04:00
josh 657287c160 Move Pci.scan() recursion into scan() itself 2023-06-10 11:20:50 -04:00
josh d600e089e5 Add Pci.Device class 2023-06-10 11:16:27 -04:00
josh dd07a08388 Fix A1 allocator to map the correct pages 2023-06-10 11:06:41 -04:00
josh 63fbbc9051 Use ulong for round_up_power_2() 2023-06-10 10:59:46 -04:00
josh 3e32802862 Add A1.allocate() template to allocate struct/class instances 2023-06-10 10:30:56 -04:00
josh 40ff805f7d Add Pci.Address struct 2023-06-10 09:35:52 -04:00
josh 9ac69c9003 Add Pci.write_config_register() 2023-06-10 09:19:58 -04:00
josh 7aa28da1ef Allow pointers or integers for Hurl.*map_range() 2023-06-09 23:38:52 -04:00
josh 222a1efea4 Fix address calculation in Hurl.identity_map_range() 2023-06-09 23:27:20 -04:00
josh 7a4edf38f0 Scan for multi-function PCI devices 2023-06-08 20:28:32 -04:00
josh dda1b6379f Fix in32()/out32() to use uint instead of ulong 2023-06-08 16:07:44 -04:00
josh 98134957e7 Print APIC table signatures found 2023-06-08 13:21:43 -04:00
josh 22463e729b writef: add %c format specifier support 2023-06-08 13:21:24 -04:00
josh 8de86dd647 Add Pci.init_device() skeleton 2023-06-07 16:49:54 -04:00
josh f6fde01b06 Fix build error -- import hulk.util 2023-04-05 01:08:55 -04:00
josh ea6f485bd9 Add hulk.util and round_up_power_2() 2023-02-24 21:15:33 -05:00
josh 2ab388f2e9 Remove seconds counter printout 2023-02-24 20:58:11 -05:00
josh cc891f6d4d Assign PCI header fields to named variables 2023-02-24 20:53:46 -05:00
josh f5e5c40c12 Reduce Hurl.map() template overhead 2023-01-02 20:46:12 -05:00
josh 7b09c9beed Add A1 memory allocator 2023-01-01 22:02:48 -05:00
josh 103205bff2 Move address constants into Hurl struct 2023-01-01 21:04:29 -05:00
josh 25ee1775f0 Capitalize namespacing structs
This helps to avoid name clashes when breaking up modules into packages.
2023-01-01 17:34:41 -05:00
josh a423cdf1b1 Fix RTC clock reading in 24-hour mode 2022-12-19 11:32:08 -05:00
josh 7c8744d1e0 Read RTC date and time 2022-12-18 22:29:12 -05:00
josh 4081a220ef Route I/O APIC interrupts, enable RTC tick interrupt 2022-12-16 00:32:49 -05:00
josh 9adc248225 Initialize rtc module 2022-12-15 20:41:44 -05:00
josh 676fd17bf5 Add pit and rtc modules 2022-12-15 20:41:15 -05:00
josh b1a8f8d348 Handle local APIC exceptions 2022-12-07 23:24:01 -05:00
josh 9b52ae58e8 Get local APIC timer ready to run 2022-12-07 23:13:51 -05:00
josh 5799f94efe Configure local APIC interrupt vectors 2022-12-06 22:06:57 -05:00
josh 400a7b22db Enable local APIC interrupts 2022-12-06 21:22:56 -05:00
josh 2bba0dfca4 Add hulk.mtrr module 2022-11-08 21:49:41 -05:00
josh edba40b2c6 Implement frame buffer double-buffering
This slowed down drawing to video in QEMU/VirtualBox but greatly sped up
doing so on real hardware (no longer reading from video memory).
Despite the speed-up, it is still quite slow though.
2022-11-08 06:19:03 -05:00
josh 55604468c8 Allocate framebuffer buffer1 in HELLO 2022-11-07 21:27:52 -05:00
josh 71c30fa932 Reclaim bootloader page table pages 2022-11-06 21:59:42 -05:00
josh b3fb599b25 Move EFER initialization to initialize_cpu() 2022-11-05 22:49:57 -04:00
josh d357aada75 Map HULK regions separately 2022-11-05 22:45:35 -04:00
josh 1fef8ada29 Define acpi structs as static 2022-11-05 22:26:21 -04:00
josh 5231930543 Clean up ApicRegister 2022-11-05 22:22:09 -04:00
josh 95b9e4558a Move hulk.writef buffer variables to stack
Previously ldc2 was emitting AVX/SSE instructions to initialize these
buffers.
2022-11-05 22:06:18 -04:00
josh 354555d7f1 Disable AVX and SSE instruction generation for HULK 2022-11-05 22:03:13 -04:00
josh 1b69810e8f Turn on OSXSAVE 2022-11-05 21:17:30 -04:00
josh 64190b04cb Add initialize_cpu() 2022-11-05 20:27:48 -04:00
josh d7b12c7896 Run qemu with maximum supported host CPU features 2022-11-05 20:15:30 -04:00
josh 11f922da33 Add write_cr0() 2022-11-05 19:58:10 -04:00
josh 59e084c234 Add cpuid1() and output bit enums 2022-11-04 19:28:34 -04:00
josh f21ee0d149 Add enums for a few CPU register bits 2022-11-04 00:08:40 -04:00
josh 2a7c783bba Add write_cr4() 2022-11-03 23:31:55 -04:00
josh 1f2a2bea48 Add xgetbv()/xsetbv() 2022-11-03 22:45:35 -04:00
josh 8eedf4e267 Switch klog buffer to ubyte array to move it to bss section 2022-11-03 16:34:03 -04:00
josh ae49c29c75 Fail build if thread-local data is found 2022-11-03 16:17:42 -04:00
josh 4d88810fc1 Move hulk.writef hex character strings out of data section 2022-11-03 16:03:12 -04:00
josh ba9cf30e67 Clean up linker script symbols 2022-11-03 15:41:14 -04:00
josh b9675019e7 Rename BOOTX64.EFI -> HOS.EFI 2022-11-03 13:54:42 -04:00
josh aa9809e0ed README: add building instructions 2022-11-03 13:34:21 -04:00
josh 07202b902b README: fix headings 2022-11-03 13:30:09 -04:00
josh 08501e86bb README: Add HOS System Requirements 2022-11-03 13:29:05 -04:00
josh 10a2d63e08 Add instructions to run HOS from GRUB 2022-11-03 13:27:24 -04:00
josh 8aa01ba122 Build HELLO page tables from unused memory instead of scratch buffer 2022-11-02 22:49:42 -04:00
josh 0b326e2e36 Move PAGE_SIZE from hulk.hippo to hulk.pagetable 2022-11-01 22:23:26 -04:00
josh e49c27cbbc Increase scratch space to 10MB 2022-10-30 21:29:19 -04:00
josh 49677c8499 PageTableEntry improvements
- fix alias this
- add properties for dirty/accessed
- add opIndex for direct indexing
2022-10-29 22:07:38 -04:00
josh 1e1c389caf Turn on EFER NXE bit to allow no-execute pages 2022-10-27 23:42:18 -04:00
josh 7b531e36ea Fix HELLO check that HULK bss and stack region could be found 2022-10-26 23:26:25 -04:00
josh 7540d4302e Add a couple more page table flags 2022-10-26 23:18:08 -04:00
josh ba7c2996d5 Add MSR_EFER and rdmsr() 2022-10-26 22:45:09 -04:00
josh 707d42bec4 Remove PageTable.opIndex and .opIndexAssign, use .entry 2022-10-26 21:58:22 -04:00
josh 476ae7d6fd Move hos.* modules to hulk.* 2022-10-26 00:16:07 -04:00
josh 4a431f7d93 Use hulk.pagetable from hello 2022-10-26 00:05:49 -04:00
josh 555ec9b627 Split PageTable struct out from hulk.hurl to hulk.pagetable 2022-10-25 23:30:17 -04:00
josh c11361d40f Build new page tables in HULK 2022-10-19 23:59:11 -04:00
josh c8a81b1101 Add PAGE_SIZE constant 2022-10-18 21:53:38 -04:00
josh 41531cf4d2 Rename Hurl to hurl for consistency 2022-10-18 20:59:13 -04:00
josh edbe33bcfa Add ApicRegisters structure 2022-10-18 20:48:46 -04:00
josh 747e824dae Fix calcuation of reserved HULK binary pages 2022-10-18 16:23:13 -04:00
josh b1be5b888f Add apic module that does not do anything yet 2022-10-18 12:56:02 -04:00
josh dba58b2277 acpi: show APIC address found 2022-10-18 12:55:41 -04:00
josh 72b83b0c3c Hurl.debug_lookup(): show page table entry index 2022-10-18 12:54:27 -04:00
josh 90711adada Actually calling Hurl.initialize() helps a lot 2022-10-18 12:51:08 -04:00
josh 4f98c469b7 Add Hurl.debug_lookup() 2022-10-18 11:18:19 -04:00
josh 7d2b535df5 Add hulk.acpi module 2022-10-18 00:48:56 -04:00
josh 2f1a12be81 Add Hurl.map_range() 2022-10-18 00:48:40 -04:00
josh 5ca95a5662 memcpy*() should take const src ptr 2022-10-18 00:47:46 -04:00
josh 7471a846ec Locate the ACPI XSDT 2022-10-17 21:48:43 -04:00
josh 2ee920fdd2 Reset console position on OSOD 2022-10-14 17:10:32 -04:00
josh d24eafbd63 Tweak VirtualBox instructions 2022-10-14 16:05:35 -04:00
josh 6f94bc3ddd Add VirtualBox instructions and task to create a VMDK 2022-10-14 15:57:26 -04:00
josh 777820d471 Tell rscons the map files are side-effect files 2022-10-14 15:28:38 -04:00
josh b3ca9af48a Disable PIC 2022-09-06 22:35:41 -04:00
josh 43d945b5e8 Enable interrupts and halt CPU 2022-09-04 23:03:20 -04:00
josh bc7fd3f2fc Add idt module and set up IDT 2022-09-04 22:25:46 -04:00
josh b72c69ef1c Clear interrupts on HULK startup just in case 2022-09-01 15:50:59 -04:00
josh 66bd51ffb0 Add hulk.gdt module and create our own GDT 2022-09-01 15:43:00 -04:00
josh 16143a727a Avoid using SSE instructions in writef functions 2022-08-23 22:48:52 -04:00
josh 63e6fd4bb5 Add run-vb task 2022-08-20 19:57:10 -04:00
josh b4a4638a82 Create HOS.img with a GPT partition table and EFI partition 2022-08-20 19:01:25 -04:00
josh 93763917c1 Rename hos.img -> HOS.img 2022-08-18 23:03:16 -04:00
josh 743cf9ffef Update to rscons 3.1.0 2022-08-11 15:08:49 -04:00
josh b9f051017c Rename max_physical_address -> physical_address_limit 2022-05-03 19:46:46 -04:00
josh 59890868c1 Fix efibootmgr command to install HOS to physical machine 2022-05-03 16:18:47 -04:00
josh 6b715c9051 Add README.md with installation instructions 2022-05-01 16:17:11 -04:00
josh 89f7d2120f Add Hurl struct with map() method 2022-05-01 09:26:33 -04:00
josh 7515ebdf1c Fix hippo.allocate_page() 2022-05-01 09:20:41 -04:00
josh b0e59b3e26 Add hippo.allocate_page() 2022-04-26 21:45:17 -04:00
josh 153a8d43f1 Add hulk.linker_addresses module 2022-04-26 19:37:05 -04:00
josh bf9a005dbc Launch qemu with a USB XHCI controller and USB tablet device 2022-04-13 21:55:06 -04:00
josh 53e2e52bbe Scan for PCI devices 2022-04-13 21:54:28 -04:00
josh 12067b8e1a Remove src-old 2022-04-13 17:12:16 -04:00
josh 8278c4211b Add HIPPO module and starting tracking free physical pages 2022-03-29 22:24:14 -04:00
josh 3bdc5bccdd Pass page table address range to HULK on boot 2022-03-28 21:22:10 -04:00
josh f904ec2b48 Convert hello.console to use a namespacing struct 2022-03-28 15:18:31 -04:00
josh bcec23ef89 Update hello.scratch to use namespacing struct 2022-03-28 15:17:07 -04:00
josh d86745d91d Move bootinfo into HULK header 2022-03-27 16:14:54 -04:00
josh cf5956dcd3 Rename Header to HulkHeader 2022-03-27 09:45:09 -04:00
josh 8498de6b62 Add HURL; relocate kernel virtual regions 2022-03-26 10:41:53 -04:00
josh f761d0a445 Jump to HULK from assembly 2022-03-26 00:36:23 -04:00
josh f29bd9d00c Allocate HULK stack region from HELLO, translate memory region types 2022-03-26 00:29:19 -04:00
josh f236a64b21 HELLO: Be more welcoming 2022-03-25 13:17:22 -04:00
josh 1225e98276 Pass HULK physical memory info to kernel from HELLO 2022-03-25 13:16:36 -04:00
josh cb31e36e90 Clean up console 2022-03-25 12:37:18 -04:00
josh 0568a813f2 HELLO: Zero out HULK bss section 2022-03-25 11:53:01 -04:00
josh 37d5621e41 HULK console: clear last row when shifting rows up 2022-03-25 10:51:52 -04:00
josh 98e992aad0 Convert fb, console, klog to "static instance" namespacing structs 2022-03-25 10:48:32 -04:00
josh 06242a0c9f Add console, klog, and writef modules.
They are not complete, but adding to checkpoint progress.
2022-03-24 17:52:39 -04:00
josh e214a9c3de Fix call to fb.blend_alpha_bitmap() 2022-03-24 09:52:26 -04:00
josh c259ae4cee Add Framebuffer.copy_rows_up() 2022-03-23 22:12:38 -04:00
josh b4d8707243 Rename blending blit methods to blend 2022-03-22 22:32:45 -04:00
josh 6b7b14d954 Add Framebuffer.character() 2022-03-22 22:11:12 -04:00
josh 9e7c3ee676 Add Framebuffer.rect(), .hline(), .vline() 2022-03-22 21:55:25 -04:00
josh 2d7bf5197f Drawing text working using Framebuffer.blit_alpha_bitmap() 2022-03-22 20:01:08 -04:00
josh 7562be585f Add Framebuffer.blit_alpha_bitmap() 2022-03-22 20:00:32 -04:00
josh 3d04eec427 Compile HULK with large code model 2022-03-22 19:29:30 -04:00
josh 5c97acba5f Update fontgen to output D instead of C 2022-03-22 13:01:20 -04:00
josh c3ead56582 Add Framebuffer object 2022-03-21 16:32:11 -04:00
josh 15559b0a56 Add HULK header; map virtual memory for HULK bss section 2022-03-21 16:31:01 -04:00
josh c58284761a Comment hulk.hulk module a bit 2022-03-20 23:05:10 -04:00
josh bd99e429a9 Comment hulk.bootinfo a bit 2022-03-20 22:58:25 -04:00
josh d0acf5a718 Comment hello.hello module a bit better 2022-03-20 22:38:42 -04:00
josh b40151055c Rework scratch module and use qualified names for function calls 2022-03-20 22:21:10 -04:00
josh 1e00d7a9e9 Rename hello.output to hello.console 2022-03-20 22:12:46 -04:00
josh 79b34477ed Reorganize D modules a bit 2022-03-19 22:39:12 -04:00
josh 163ef9f79e Increase scratch buffer size 2022-03-19 22:08:35 -04:00
josh 3c549f0838 Write size file for HULK/HELLO 2022-03-19 22:07:37 -04:00
josh d8c85ad045 Map all memory regions and graphics framebuffer 2022-03-19 21:54:30 -04:00
josh 7c5af33ace Fix receiving correct argument to hulk_start() 2022-03-19 20:02:49 -04:00
josh 6f3521c576 Make sure to rebuild HELLO properly when HULK changes 2022-03-19 00:27:10 -04:00
josh 5a5d60abae Fix HULK virtual start address to be addressable 2022-03-19 00:04:59 -04:00
josh 9182a83ef2 HELLO: Make sure scratch area is page-aligned 2022-03-18 23:43:05 -04:00
josh 195b7496f4 HELLO: Include EfiLoaderCode and EfiLoaderData memory regions in memory map 2022-03-18 23:33:42 -04:00
josh b1042fd649 Jump to HULK
Unfortunately, crashes... :(
2022-03-18 23:16:07 -04:00
josh 6beb7da4cd Map HULK virtual address space 2022-03-18 23:04:09 -04:00
josh f27851def9 Bundle HULK in HELLO 2022-03-18 22:43:37 -04:00
josh 18f1bfc88f Build HELLO after HULK 2022-03-18 22:02:07 -04:00
josh cd6983e2cd Generate HULK binary 2022-03-18 22:01:27 -04:00
josh 8df1646c61 Add initial HULK source and linker script 2022-03-18 21:55:38 -04:00
josh 3e25ab6ae4 HELLO: Zero out page tables after allocating, before using 2022-03-18 21:21:00 -04:00
josh 05cc2da2e3 HULK: Add virtual start address 2022-03-18 21:19:06 -04:00
josh a54536660b HELLO: Create page tables to identity map available RAM prior to jumping to kernel 2022-03-18 21:15:58 -04:00
josh 9e3d9b18ea Add write_cr3() 2022-03-18 16:40:46 -04:00
josh ef01239468 HELLO: Add scratch module 2022-03-18 16:03:50 -04:00
josh 372b7265f1 Add src/common/hos/cpu.d 2022-03-18 10:51:35 -04:00
josh 1bc8722098 Add hos.memory module in src/common 2022-03-18 00:07:10 -04:00
josh cd2f3f9a84 Rename kernel to hulk 2022-03-17 16:57:18 -04:00
josh 08a35e40d4 Rename HEL -> HELLO 2022-03-16 16:11:26 -04:00
josh a855702214 Fix checking for EFI_INVALID_PARAMETER 2022-03-16 14:37:46 -04:00
josh 706f2c1c5d HEL: Call ExitBootServices 2022-03-16 01:12:07 -04:00
josh 704fd15f7b Get memory map; remove heap 2022-03-15 23:58:37 -04:00
josh f054bab5cc Set bootinfo framebuffer fields 2022-03-15 23:03:28 -04:00
josh 3fa8e4a24b Set maximum resolution for running in qemu 2022-03-15 22:52:56 -04:00
josh a38f95a7b8 Set graphics mode 2022-03-14 22:26:55 -04:00
josh dd57a31d38 HEL: Add heap module; locate GOP handle 2022-03-14 21:43:40 -04:00
josh 406f17c1db HEL: format hex, decimal, and CHAR16 strings in output module 2022-03-14 15:09:02 -04:00
josh 0be1b113aa Add output module for console output routines 2022-03-14 13:53:02 -04:00
josh d782b59768 Write map file 2022-03-14 01:35:28 -04:00
josh c3a6139f83 Run image from temporary copy to avoid modified disk image file 2022-03-14 00:57:24 -04:00
josh 3d3a433800 Update to rscons 3.0.2 2022-03-14 00:51:54 -04:00
josh 54451bcf5b Add initial HOS EFI Loader sources 2022-03-13 23:16:37 -04:00
josh 1fc2dd34e5 Update build system for 64-bit, EFI, and D 2022-03-13 22:46:59 -04:00
josh cb6bd3914c Remove HOS v0.16 sources 2022-02-28 15:10:25 -05:00
josh 56c3be9207 Update to rscons 3.0.0 2022-02-28 13:40:08 -05:00
josh c6ae200a54 Update to rscons 2.3.0
Move cross compiler to i686-elf-gcc directory.
Automatically build cross compiler using rscons subsidiary script.
2021-12-08 11:33:03 -05:00
josh 6b1de7c9d4 Explicitly check page boundaries when adding bootloader-provided memory regions 2021-08-16 17:35:11 -04:00
josh ebfeca47b5 Use size_t rather than uint32_t 2021-08-16 14:01:39 -04:00
josh 43f4a1f4b1 Show kernel size/address 2021-08-16 13:59:39 -04:00
josh 0f73efbdc3 add mm module to manage free physical page regions 2020-10-26 20:17:08 -04:00
josh a084ab296c define _hos_mem_start and _hos_mem_end symbols 2020-10-25 17:08:07 -04:00
josh aa28284187 build kernel .size file on build 2020-10-25 17:06:56 -04:00
josh 87c135b010 set up a GDT to stop using the one GRUB set up 2020-10-25 16:49:09 -04:00
josh 3d30025d3b write a map file when linking 2020-10-25 16:48:42 -04:00
josh 556b0f0c4d add gdt.h 2020-10-23 00:48:40 -04:00
josh bffd652c16 walk multiboot2 memory map 2020-10-23 00:47:19 -04:00
josh cbd427b14b add 64-bit formatting support 2020-10-23 00:46:40 -04:00
josh fa4ff5facf load some multiboot2 info after the framebuffer is initialized 2020-10-22 22:03:43 -04:00
josh db16e69d5d add klog module to print kernel messages 2020-10-20 21:44:21 -04:00
josh 1d3b0a5621 make fb_clear() public 2020-10-20 20:24:48 -04:00
josh d03a34ab3e fb: store fb.pitch in words, not bytes 2020-10-20 20:07:51 -04:00
josh 494ef6de81 add fb_width(), fb_height() 2020-10-20 20:06:54 -04:00
josh 784009ba6c hos_printf: handle field width, zero-padding, and left-justifiying conversion specifiers 2020-10-20 19:56:30 -04:00
josh 9bddf11ee4 stream: use char instead of uint8_t 2020-10-20 19:47:15 -04:00
josh 313b86fdc7 provide an implementation for memcpy() 2020-10-20 19:31:26 -04:00
josh 75491dd36b add hos_printf and stream modules 2020-10-20 19:30:23 -04:00
josh c8db9fe905 add string.h 2020-10-20 17:55:31 -04:00
josh d0cbaba4d1 add memcpy(), memmove(), memset() 2020-10-20 17:47:40 -04:00
josh 1f22d0c900 add a few multiboot2 info structures 2020-10-20 17:34:08 -04:00
josh a474368435 increase kernel font size a little 2020-10-20 17:28:43 -04:00
josh fb88595dec add fb_clear(), just clear to solid bluish color for now 2020-10-20 17:28:16 -04:00
josh 70b4db9dbb fix fb_text_render_char() to use given color 2020-10-20 17:23:51 -04:00
josh 9fde638b6e build with -O2 2020-10-20 15:09:00 -04:00
josh b4b77dd52c add mem.h and memset32() 2020-10-20 15:08:12 -04:00
josh 79951bd0f1 add cross/clean.sh 2020-10-20 14:15:28 -04:00
josh 41152cb4ca add fb_fill() 2020-10-20 14:01:14 -04:00
josh dba3d28bbf draw a character 2020-10-20 13:34:02 -04:00
josh 610f30fae9 generate a built-in kernel font 2020-10-20 00:34:53 -04:00
josh e22b90b768 configure GRUB to boot HOS automatically after 1s 2020-10-20 00:17:05 -04:00
josh 08fc9a5445 rename target run-bios -> run 2020-10-20 00:11:12 -04:00
josh a66df19edc add fb_ready() 2020-10-20 00:09:09 -04:00
josh 5bc844649b set desired framebuffer size to 1600x900x32 2020-10-19 23:57:54 -04:00
josh 0d390465f6 simplify boot.S 2020-10-19 23:42:02 -04:00
josh 04d29fdb71 add mbinfo module to parse multiboot2 boot info 2020-10-19 23:34:42 -04:00
josh e9f426894c rename kernel_main.c -> hos_main.c 2020-10-19 22:40:55 -04:00
josh c8810e4701 rename _start -> hos_start 2020-10-19 22:26:12 -04:00
josh b202eca0cc define startup stack in linker script, not assembly 2020-10-19 22:23:39 -04:00
josh 05de14800b remove hard tabs! 2020-10-19 22:12:34 -04:00
josh 8ae84716d6 rename kernel_main() to hos_main() 2020-10-19 22:12:17 -04:00
josh bb495eceec add "fb" module for framebuffer control 2020-10-19 22:09:33 -04:00
josh 67b90a482f add "clean" target 2020-10-19 21:59:54 -04:00
josh 85e5b76aa3 Move multiboot2 header from assembly to C. 2020-10-19 21:44:27 -04:00
josh 412925a790 switch from multiboot to multiboot2 2020-10-18 14:25:06 -04:00
josh 21afa93c4b fill in framebuffer with more exciting pattern - working in qemu BIOS but lost graphics in qemu EFI 2020-10-18 13:47:35 -04:00
josh d08d54ecbf make run tasks depend on all 2020-10-18 13:29:56 -04:00
josh 06644a02f9 draw pixels to screen to verify framebuffer access and multiboot info 2020-10-18 13:25:26 -04:00
josh 8f9881889b build both BIOS and EFI images 2020-10-18 13:16:02 -04:00
josh a91ea8d620 update Makefile to wrap rscons and add run target 2020-10-15 20:05:58 -04:00
josh a9a2f6dcaf fix GRUB config to add a HOS menu entry 2020-10-15 20:01:40 -04:00
josh 9befd553eb always disassemble kernel when building 2020-10-15 19:47:20 -04:00
josh 6053745ee9 build kernel as 32-bit ELF for now so GRUB can recognize it as multiboot 2020-10-15 19:46:53 -04:00
josh 0adc6e395c Add more modern build script for kernel and disk image based on osdev Bare Bones template
GRUB is not identifying the kernel as multiboot compatible. Possibly
because I am using x86_64 instead of i686. Need to investigate further.
2020-10-14 21:20:41 -04:00
josh bbf212d5a2 add configure script 2020-10-13 19:53:14 -04:00
josh 94ed9078df update rscons 2020-10-13 19:20:19 -04:00
josh e97e76da7b add cross compiler build script and configure script 2020-10-06 20:06:19 -04:00
josh 1f5e3507ba change nasm output format to elf32 2020-10-02 10:21:10 -04:00
josh a9a6f6f4d4 avoid make jobserver warnings 2020-10-02 10:17:32 -04:00
josh 2d009273a1 add readme.txt 2017-07-26 13:51:58 -04:00
josh 2b936758ff add .gitignore 2017-07-26 13:42:21 -04:00
josh 509009d134 get HOS building again on Ubuntu 17.04 with GCC 6 2017-07-26 13:41:23 -04:00
josh 0aaf5db5ad Import backup from 2006-01-02 2017-07-25 22:23:52 -04:00
josh 89d962e33a Import backup from 2005-12-31 2017-07-25 22:23:52 -04:00
josh 712337c485 Import backup from 2005-12-30 2017-07-25 22:23:52 -04:00
josh 761e3f0483 Import backup from 2005-12-26 2017-07-25 22:23:51 -04:00
josh 98abfc2af0 Import backup from 2005-12-19 2017-07-25 22:23:51 -04:00
josh 677551fba5 Import backup from 2005-11-03 2017-07-25 22:23:51 -04:00
josh 7daa1c5336 Import backup from 2005-11-01 2017-07-25 22:23:51 -04:00
josh 79ca453f66 Import backup from 2005-09-13 2017-07-25 22:23:51 -04:00
josh 0521733e20 Import backup from 2005-09-11 2017-07-25 22:23:51 -04:00
josh 396c5f3452 Import backup from 2005-09-01 2017-07-25 22:23:51 -04:00
josh 9e03bfc8b6 Import backup from 2005-08-30 2017-07-25 22:23:51 -04:00
josh 2b67ff6f49 Import backup from 2005-08-29 2017-07-25 22:23:51 -04:00
josh daa29212d0 Import backup from 2005-08-27 2017-07-25 22:23:50 -04:00
josh 83a5b032f8 Import backup from 2005-08-25 2017-07-25 22:23:50 -04:00
josh 345ef6c9f3 Import backup from 2005-08-18 2017-07-25 22:23:50 -04:00
josh e1682a2fe7 Import backup from 2005-08-17 2017-07-25 22:23:50 -04:00
josh 2cefd9441c Import backup from 2005-06-21 2017-07-25 22:23:50 -04:00
josh da90bcc164 Import backup from 2005-06-20 2017-07-25 22:23:50 -04:00
josh 4689c11cc8 Import backup from 2005-06-13 2017-07-25 22:23:50 -04:00
josh 692cf2fc08 Import backup from 2005-06-02 2017-07-25 22:23:50 -04:00
josh b0132c866e Import backup from 2005-05-12 2017-07-25 22:23:50 -04:00
josh 14792ef954 Import backup from 2005-03-21 2017-07-25 22:23:50 -04:00
josh bb8ff09e3f Import backup from 2005-03-11 2017-07-25 22:23:50 -04:00
josh dfeabc39aa Import backup from 2005-02-23 2017-07-25 22:23:50 -04:00
josh 14148e4d80 Import backup from 2005-02-15 2017-07-25 22:23:49 -04:00
josh 80774c48fe Import backup from 2005-02-07 2017-07-25 22:23:49 -04:00
josh 862b36b37b Import backup from 2005-02-01 2017-07-25 22:23:49 -04:00
josh 4638656aaf Import backup from 2005-01-31 2017-07-25 22:23:49 -04:00
josh 3381041a8f Import backup from 2005-01-26 2017-07-25 22:23:49 -04:00
josh f09ed66826 Import backup from 2005-01-18 2017-07-25 22:23:49 -04:00
josh ba5906c7a3 Import backup from 2005-01-14 2017-07-25 22:23:49 -04:00
josh 05183a3949 Import backup from 2005-01-05 2017-07-25 22:23:49 -04:00
josh d8580a9393 Import backup from 2005-01-04 2017-07-25 22:23:49 -04:00
josh 50285aa33b Import backup from 2005-01-01 2017-07-25 22:23:49 -04:00
josh ee63a84c0e Import backup from 2004-12-31 2017-07-25 22:23:49 -04:00
josh 76a243d894 Import backup from 2004-12-30 2017-07-25 22:23:49 -04:00
josh 6bad3f2b96 Import backup from 2004-12-29 2017-07-25 22:23:49 -04:00
josh 51948ce081 Import backup from 2004-12-24 2017-07-25 22:23:49 -04:00
josh b40a68f581 Import backup from 2004-12-23 2017-07-25 22:23:49 -04:00
josh 55b7429d4e Import backup from 2004-12-22 2017-07-25 22:23:49 -04:00
josh 7b805f2495 Import backup from 2004-12-21 2017-07-25 22:23:48 -04:00
josh 2445034e43 Import backup from 2004-12-20 2017-07-25 22:23:48 -04:00
josh 3c531f3b7b Import backup from 2004-12-17 2017-07-25 22:23:48 -04:00
josh 11cc0c87f3 Import backup from 2004-12-16 2017-07-25 22:23:48 -04:00
josh bad7f79ed1 Import backup from 2004-09-21 2017-07-25 22:23:48 -04:00
josh 78272f6bc3 Import backup from 2004-08-20 2017-07-25 22:23:48 -04:00
josh 396d5015d2 Import backup from 2004-08-19 2017-07-25 22:23:48 -04:00
josh 1bf14ddefa Import backup from 2004-08-17 2017-07-25 22:23:48 -04:00
josh c0dd3b529e Import backup from 2004-08-16 2017-07-25 22:23:48 -04:00
josh 8a8f56decb Import backup from 2004-08-15 2017-07-25 22:23:48 -04:00
josh b9c77827bd Import backup from 2004-08-06 2017-07-25 22:23:48 -04:00
josh cd02211b21 Import backup from 2004-08-03 2017-07-25 22:23:48 -04:00
josh a50c2a1233 Import backup from 2004-08-02 2017-07-25 22:23:48 -04:00
josh 07e8a0f4cf Import backup from 2004-07-31 2017-07-25 22:23:48 -04:00
josh 6d23c76e84 Import backup from 2004-07-29 2017-07-25 22:23:48 -04:00
josh 11da8cb162 Import backup from 2004-07-25 2017-07-25 22:23:48 -04:00
josh 1063a68a21 Import backup from 2004-07-20 2017-07-25 22:23:47 -04:00
josh 286b5e9ae1 Import backup from 2004-07-17 2017-07-25 22:23:47 -04:00
josh d4aadbea38 Import backup from 2004-07-15 2017-07-25 22:23:47 -04:00
josh dfb71cc759 Import backup from 2004-07-12 2017-07-25 22:23:47 -04:00
64 changed files with 6261 additions and 779 deletions

No files matched your search

-43
View File
@@ -1,43 +0,0 @@
# configuration file generated by Bochs
config_interface: textconfig
display_library: x
megs: 32
romimage: file=/usr/share/bochs/BIOS-bochs-latest, address=0xf0000
vgaromimage: /usr/share/bochs/VGABIOS-lgpl-latest
boot: floppy
floppya: 1_44="hos.flp", status=inserted
# no floppyb
ata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14
ata1: enabled=0
ata2: enabled=0
ata3: enabled=0
parport1: enabled=1, file=""
com1: enabled=1, dev=""
usb1: enabled=1, ioaddr=0xff80, irq=10
# no sb16
floppy_bootsig_check: disabled=0
vga_update_interval: 30000
keyboard_serial_delay: 20000
keyboard_paste_delay: 100000
floppy_command_delay: 50000
ips: 500000
text_snapshot_check: 0
mouse: enabled=0
private_colormap: enabled=0
i440fxsupport: enabled=0
clock: sync=none, time0=local
# no ne2k
newharddrivesupport: enabled=1
# no loader
log: -
logprefix: %t%e%d
debugger_log: -
panic: action=ask
error: action=report
info: action=report
debug: action=ignore
pass: action=fatal
keyboard_mapping: enabled=0, map=
keyboard_type: mf
user_shortcut: keys=none
# no cmosimage
+4
View File
@@ -0,0 +1,4 @@
.rscons*
/x86_64-elf-gcc/
/build/
/qemu/
+3
View File
@@ -0,0 +1,3 @@
[submodule "uefi-d"]
path = uefi-d
url = git://github.com/kubasz/uefi-d
-48
View File
@@ -1,48 +0,0 @@
# Makefile for HOS
# Josh Holtrop
# Created: 07/09/04
FLOPPY=/dev/fd0
FLOPPY_MOUNT=./mnt_flp
FLOPPY_IMAGE=hos.flp
GRUB_IMAGE=grub.flp
all:
make -C kernel
# make -C rmmod
clean:
make -C kernel clean
make -C include clean
# make -C rmmod clean
- rm *~ hos.flp
grub:
- mkdir $(FLOPPY_MOUNT)
mke2fs $(FLOPPY)
mount -t ext2 $(FLOPPY) $(FLOPPY_MOUNT)
grub-install --root-directory=$(FLOPPY_MOUNT) fd0
umount $(FLOPPY_MOUNT)
- rmdir $(FLOPPY_MOUNT)
grub_image:
dd if=$(FLOPPY) of=$(GRUB_IMAGE)
install:
- mkdir $(FLOPPY_MOUNT)
mount -t ext2 $(FLOPPY) $(FLOPPY_MOUNT)
cp kernel/kernel.bin $(FLOPPY_MOUNT)
cp menu.lst $(FLOPPY_MOUNT)/boot/grub
umount $(FLOPPY_MOUNT)
- rmdir $(FLOPPY_MOUNT)
install_img:
- mkdir $(FLOPPY_MOUNT)
cp grub.flp $(FLOPPY_IMAGE)
mount -t ext2 -o loop $(FLOPPY_IMAGE) $(FLOPPY_MOUNT)
cp kernel/kernel.bin $(FLOPPY_MOUNT)
cp menu.lst $(FLOPPY_MOUNT)/boot/grub
umount $(FLOPPY_MOUNT)
- rmdir $(FLOPPY_MOUNT)
+81
View File
@@ -0,0 +1,81 @@
# HOS System Requirements
HOS requires:
* A 64-bit CPU.
* A UEFI system.
* 128MB of RAM.
# Building HOS
From the top level of the repository, run:
./rscons
If you get errors about missing packages, install the packages and then re-run
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:
1. Copy build/hello/HOS.EFI to EFI partition EFI/HOS.EFI. For example, from Linux:
sudo cp build/hello/HOS.EFI /boot/efi/EFI/HOS.EFI
2. Register EFI loader for HOS (one time only) with command:
efibootmgr -c -d /dev/nvme1n1 -p 2 -l '\EFI\HOS.EFI' -L HOS
(Update the -d device parameter and -p partition parameter as appropriate)
3. Set boot order to desired boot order. Exact order will be system dependent. Example:
efibootmgr -o 2,0,6,5
At this point you should be able to boot HOS from your EFI boot selection menu.
If you use GRUB, you can optionally create a GRUB boot entry to load HOS.EFI
with an entry like this:
menuentry 'HOS' {
insmod part_gpt
insmod chain
set root='(hd0,gpt1)'
chainloader /EFI/HOS.EFI
}
Just update the root setting for the correction location to your system's EFI
partition.
## VirtualBox
To create a VM in VirtualBox:
1. Build HOS ("./rscons").
2. In VirtualBox, select Machine -> New.
3. Set name to HOS.
4. Set Type to Other.
5. Set Version to Other/Unknown (64-bit).
6. Click Next.
7. Set memory size to 512 MB.
8. Click Next.
9. Select Do not add a virtual hard disk.
10. Click Create.
11. From the HOS repository, create a VirtualBox VMDK image with "./rscons mk-vmdk".
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.
+246
View File
@@ -0,0 +1,246 @@
require "tmpdir"
project_name "HOS"
path_prepend "x86_64-elf-gcc/bin"
configure do
rscons "x86_64-elf-gcc.rb", "-b", "#{build_dir}/x86_64-elf-gcc"
check_d_compiler "ldc2", use: "ldc2"
check_c_compiler "x86_64-w64-mingw32-gcc", use: "x86_64-w64-mingw32-gcc"
check_c_compiler "x86_64-elf-gcc", use: "x86_64-elf-gcc"
check_c_compiler
check_program "mformat", on_fail: "Install the mtools package"
check_program "parted"
check_cfg package: "freetype2", on_fail: "Install libfreetype-dev", use: "freetype"
sh %w[git submodule update --init]
end
# Kernel default font size.
KFONT_SIZE = 16
# One kilobyte.
KB = 1024
# One megabyte.
MB = 1024 * 1024
class HulkBinObj < Builder
def run(options)
@cache.mkdir_p(File.dirname(@target))
File.write(@target, <<EOF)
.section ".rodata"
.balign 4096
.global _hulk_bin_start
_hulk_bin_start:
.incbin "#{@sources.first}"
.balign 4096
.global _hulk_bin_end
_hulk_bin_end:
EOF
unless @cache.up_to_date?(@target, nil, @sources, @env)
print_run_message("Creating HULK binary object <target>#{@target}<reset>", nil)
@cache.register_build(@target, nil, @sources, @env)
end
true
end
end
# Create a GPT disk image with an EFI partition containing the EFI image.
class Image < Builder
def run(options)
unless @cache.up_to_date?(@target, nil, @sources, @env)
print_run_message("Creating disk image <target>#{@target}<reset>", nil)
efi_image_size = File.stat(@sources.first).size
efi_image_size_mb = (efi_image_size + MB - 1) / MB
partition_size_mb = efi_image_size_mb + 1
empty_mb = "\0".b * MB
File.binwrite(@target, empty_mb * partition_size_mb)
system(*%W[mformat -i #{@target} ::])
system(*%W[mmd -i #{@target} ::/EFI])
system(*%W[mmd -i #{@target} ::/EFI/BOOT])
system(*%W[mcopy -i #{@target} #{@sources.first} ::/EFI/BOOT/BOOTX64.EFI])
partition_contents = File.binread(@target)
disk_image = empty_mb + partition_contents + empty_mb
File.binwrite(@target, disk_image)
system(*%W[parted --script #{@target} mklabel gpt mkpart HOS fat32 1MiB #{partition_size_mb + 1}MiB])
@cache.register_build(@target, nil, @sources, @env)
end
true
end
end
class CheckThreadLocal < Builder
def run(options)
map_file = File.binread(@sources.first)
if map_file =~ /\.(tdata|tbss)\b/
$stderr.puts "Error: found thread-local data in #{@sources.first}"
false
else
true
end
end
end
class FontGen < Builder
def run(options)
if @command
finalize_command
else
fontgen = @vars["fontgen"]
@sources += [fontgen]
command = %W[#{fontgen} #{@sources.first} #{KFONT_SIZE} #{@target}]
standard_command("FontGen <target>#{@target}<reset>", command, {})
end
end
end
fontgen_env = env "fontgen", use: "freetype" do |env|
env.Program("^/fontgen", glob("src/fontgen/**/*.c"))
end
hulk_env = env "hulk", use: %w[ldc2 x86_64-elf-gcc] do |env|
env.add_builder(FontGen)
env.add_builder(CheckThreadLocal)
env.FontGen("^/src/hulk/kfont.d", "font/Hack-Regular.ttf",
"fontgen" => fontgen_env.expand("^/fontgen"))
env["sources"] = glob("src/hulk/**/*.d")
env["sources"] << "^/src/hulk/kfont.d"
cpu_attrs = %w[
-avx
-avx2
-avx512bf16
-avx512bitalg
-avx512bw
-avx512cd
-avx512dq
-avx512er
-avx512f
-avx512ifma
-avx512pf
-avx512vbmi
-avx512vbmi2
-avx512vl
-avx512vnni
-avx512vp2intersect
-avx512vpopcntdq
-sse
-sse-unaligned-mem
-sse2
-sse3
-sse4.1
-sse4.2
-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["D_IMPORT_PATH"] += %w[src]
env["D_IMPORT_PATH"] << env.expand("^/src")
env["LD"] = "x86_64-elf-gcc"
env["LDFLAGS"] += %w[-g -nostdlib -Tsrc/hulk/hulk.ld -Wl,--gc-sections -Wl,-Map,${_TARGET}.map -Wl,--no-warn-rwx-segments]
env["LDCMD"] = %w[${LD} -o ${_TARGET} ${LDFLAGS} ${_SOURCES} ${LIBDIRPREFIX}${LIBPATH} ${LIBLINKPREFIX}${LIBS}]
env["OBJDUMP"] = "x86_64-elf-objdump"
env["OBJCOPY"] = "x86_64-elf-objcopy"
env.Program("^/hulk.elf", "${sources}")
env.produces("^/hulk.elf", "^/hulk.elf.map")
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.Command("^/hulk.bin", "^/hulk.elf",
"CMD" => %W[${OBJCOPY} -O binary ${_SOURCES} ${_TARGET}],
"CMD_DESC" => "Convert ELF to binary:")
env.add_build_hook do |builder|
if builder.target.end_with?(".o")
env.Disassemble("#{builder.target}.txt", builder.target)
end
end
end
hello_env = env "hello", use: %w[ldc2 x86_64-w64-mingw32-gcc] do |env|
env.add_builder(Image)
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")
env.depends("^/hulk_bin.o", hulk_env.expand("^/hulk.bin"))
env["sources"] << "^/hulk_bin.o"
env["DFLAGS"] += %w[-g -mtriple=x86_64-unknown-windows-coff --betterC -release -O3 --wi --enable-cross-module-inlining --disable-red-zone]
env["D_IMPORT_PATH"] += %w[src uefi-d/source]
env["LD"] = "x86_64-w64-mingw32-gcc"
env["LDFLAGS"] += %w[-g -nostdlib -Wl,-dll -shared -Wl,--subsystem,10 -e efi_main -Wl,-Map,${_TARGET}.map]
env["LDCMD"] = %w[${LD} -o ${_TARGET} ${LDFLAGS} ${_SOURCES} ${LIBDIRPREFIX}${LIBPATH} ${LIBLINKPREFIX}${LIBS}]
env["OBJDUMP"] = "x86_64-w64-mingw32-objdump"
env.Program("^/HOS.EFI", "${sources}")
env.produces("^/HOS.EFI", "^/HOS.EFI.map")
env.CheckThreadLocal(:hos_map_check, "^/HOS.EFI.map")
env["SIZE"] = "x86_64-w64-mingw32-size"
env.Size("^/HOS.size", "^/HOS.EFI")
env.Disassemble("^/HOS.txt", "^/HOS.EFI")
env.Image("^/HOS.img", "^/HOS.EFI")
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"
end
sh %W[
qemu-system-x86_64
-machine q35
-cpu max
-smp cpus=4
-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"))}]
end
# See README.md for how to set up VirtualBox for HOS.
task "run-vb", desc: "Run HOS in VirtualBox" do
sh %W[VBoxManage startvm HOS]
end
Binary file not shown.
BIN
View File
Binary file not shown.
-2
View File
@@ -1,2 +0,0 @@
clean:
- rm *~
-23
View File
@@ -1,23 +0,0 @@
#ifndef __HOS_KERNEL_H__
#define __HOS_KERNEL_H__ __HOS_KERNEL_H__
#include "multiboot.h"
#define VIRT_OFFSET 0xC0000000
#define MAX_MODULES 16
#define MAX_MMAP 16
typedef unsigned int u32_t;
typedef unsigned short u16_t;
typedef unsigned char u8_t;
/* returns true to callee if we should jump to a real mode module */
int k_mbsave(mb_info_t *mbinfo, unsigned int mb_magic);
void k_init();
void isr();
#endif
-16
View File
@@ -1,16 +0,0 @@
#ifndef __HOS_MODULE_H__
#define __HOS_MODULE_H__ __HOS_MODULE_H__
#define MOD_REAL_MODE 1
#define MOD_KERNEL 2
typedef struct {
unsigned int mod_magic; // "HOSM" = 0x484F534D
unsigned int mod_type; // module type
void (*init) (); // address of void initialization function
unsigned int reserved;
} hos_module_header_t;
#endif
-144
View File
@@ -1,144 +0,0 @@
#ifndef __HOS_MULTIBOOT_H__
#define __HOS_MULTIBOOT_H__ __HOS_MULTIBOOT_H__
/* The magic number for the Multiboot header. */
#define MULTIBOOT_HEADER_MAGIC 0x1BADB002
#define MB_HEADER_ALIGN_MODULES 0x01
#define MB_HEADER_MEM_INFO 0x02
#define MB_HEADER_VIDEO_INFO 0x04
#define MB_HEADER_KLUDGE_OFFSETS 0x10000
/* The magic number passed by a Multiboot-compliant boot loader. */
#define MULTIBOOT_BOOTLOADER_MAGIC 0x2BADB002
#define MB_BOOTLOADER_MEM_INFO 0x01
#define MB_BOOTLOADER_BOOT_DEVICE 0x02
#define MB_BOOTLOADER_COMMAND_LINE 0x04
#define MB_BOOTLOADER_MODS 0x08
#define MB_BOOTLOADER_AOUT 0x10
#define MB_BOOTLOADER_ELF 0x20
#define MB_BOOTLOADER_MMAP 0x40
#define MB_BOOTLOADER_DRIVES 0x80
#define MB_BOOTLOADER_CONFIG 0x0100
#define MB_BOOTLOADER_APM 0x0200
#define MB_BOOTLOADER_GRAPHICS 0x0400
#define MB_DRIVE_MODE_CHS 0
#define MB_DRIVE_MODE_LBA 1
/* The Multiboot header. */
typedef struct
{
unsigned int magic;
unsigned int flags;
unsigned int checksum;
unsigned int header_addr;
unsigned int load_addr;
unsigned int load_end_addr;
unsigned int bss_end_addr;
unsigned int entry_addr;
} mb_header_t;
/* The symbol table for a.out. */
typedef struct
{
unsigned int tabsize;
unsigned int strsize;
unsigned int addr;
unsigned int reserved;
} mb_aout_symbol_table_t;
/* The section header table for ELF. */
typedef struct
{
unsigned int num;
unsigned int size;
unsigned int addr;
unsigned int shndx;
} mb_elf_section_header_table_t;
/* The Multiboot information. */
typedef struct
{
unsigned int flags;
unsigned int mem_lower; // present if flags[0] is set
unsigned int mem_upper;
unsigned int boot_device; // 1
unsigned int cmdline; // 2
unsigned int mods_count; // 3
unsigned int mods_addr;
union
{
mb_aout_symbol_table_t aout_sym; // 4
mb_elf_section_header_table_t elf_sec; // 5
};
unsigned int mmap_length; // 6
unsigned int mmap_addr;
unsigned int drives_length; // 7
unsigned int drives_addr;
unsigned int config_table; // 8
unsigned int bootloader_name; // 9
unsigned int apm_table; // 10
unsigned int vbe_control_info; // 11
unsigned int vbe_mode_info;
unsigned short vbe_mode;
unsigned short vbe_interface_seg;
unsigned short vbe_interface_off;
unsigned short vbe_interface_len;
} mb_info_t;
/* The module structure. */
typedef struct
{
unsigned int mod_start;
unsigned int mod_end;
unsigned int string;
unsigned int reserved;
} mb_module_t;
/* The memory map. Be careful that the offset 0 is base_addr_low, not size. */
typedef struct
{
unsigned int size; //offset -4
unsigned int base_addr_low; //offset 0
unsigned int base_addr_high;
unsigned int length_low;
unsigned int length_high;
unsigned int type;
} mb_mmap_t;
/* The drive structure */
typedef struct
{
unsigned int size;
unsigned char drive_number;
unsigned char drive_mode;
unsigned char drive_cylinders;
unsigned char drive_heads;
unsigned char drive_sectors;
unsigned short drive_ports[1];
} mb_drive_t;
/* APM table structure */
typedef struct
{
unsigned short version;
unsigned short cseg;
unsigned int offset;
unsigned short cseg_16;
unsigned short dseg;
unsigned short flags;
unsigned short cseg_len;
unsigned short cseg_16_len;
unsigned short dseg_len;
} mb_apm_t;
#endif
-33
View File
@@ -1,33 +0,0 @@
# Makefile for HOS
# Josh Holtrop
# Created: 07/08/04
# Modified: 07/09/04
# Assembler Information:
NASM=nasm
NASM_FLAGS=-f aout
# C Information:
CC=gcc
CC_FLAGS=-fleading-underscore -fno-builtin -nostdlib -nostartfiles -nodefaultlibs -I. -I../include -Wall
# Linker Information:
LD=ld
LD_FLAGS=-nodefaultlibs -nostdlib --no-demangle -T link.ld
all: Asm_Kernel C_Kernel
$(LD) $(LD_FLAGS) -Map boot.map boot.o kernel.o -o kernel.bin
Asm_Kernel:
$(NASM) $(NASM_FLAGS) -l boot.lst boot.asm -o boot.o
C_Kernel:
$(CC) $(CC_FLAGS) -c kernel.c -o kernel.o
#################################################
# Clean up the source directory of any binaries #
#################################################
clean:
- rm *.s *.S *.o *.bin *~ *.map *.lst
-196
View File
@@ -1,196 +0,0 @@
;boot.asm
;Author: Josh Holtrop
;Date: 07/08/04
;Modified: 07/10/04
%define MULTIBOOT_MAGIC 0x1BADB002
%define MULTIBOOT_FLAGS 0x00010003
%define VIRT_OFFSET 0xC0000000 ;3gb virtual address
%define PHYS_START 0x00100000 ;1mb physical address
%define VIRT_STACK_TOP 0xCFFFFFFC ;3gb+256mb virtual address
%define GDT_P PHYS_START ;1mb physical - Global Descriptor Table space
%define GDT_V GDT_P+VIRT_OFFSET
%define IDT_P PHYS_START+0x2000 ;1mb+8kb - Interrupt Descriptor Table space
%define IDT_V IDT_P+VIRT_OFFSET
%define PDBR_P PHYS_START+0x4000 ;1mb+16kb - Page Directory Base Register (first PD)
%define PDBR_V PDBR_P+VIRT_OFFSET
%define LOPT_P PHYS_START+0x5000 ;1mb+20kb - LOw Page Table for mapping first 4mb
%define LOPT_V LOPT_P+VIRT_OFFSET
%define PT_STACK_P PHYS_START+0x6000 ;1mb+24kb - page table for initial kernel stack pages (under 0xD0000000)
%define PT_STACK_V PT_STACK_P+VIRT_OFFSET
%define STACK_P PHYS_START+0x7000 ;1mb+28kb - initial 4kb kernel stack page
%define STACK_V STACK_P+VIRT_OFFSET
%define KERNEL_P PHYS_START+0x8000 ;1mb+32kb - the kernel's physical address
%define KERNEL_V KERNEL_P+VIRT_OFFSET ;3gb+1mb+32kb, the virtual address of the kernel
extern _k_init, _isr, _k_mbsave, _end
[bits 32]
[global _start]
_start:
multiboot_header:
dd MULTIBOOT_MAGIC ;magic
dd MULTIBOOT_FLAGS ;flags
dd -(MULTIBOOT_MAGIC + MULTIBOOT_FLAGS) ;checksum
dd multiboot_header-VIRT_OFFSET ;header_addr
dd _start-VIRT_OFFSET ;load_addr
dd 0 ;load_end_addr
dd _end-VIRT_OFFSET ;bss_end_addr
dd multiboot_entry-VIRT_OFFSET ;entry_addr
; dd 1 ;mode_type
; dd 80 ;width
; dd 25 ;height
; dd 0 ;depth
[global multiboot_entry]
multiboot_entry:
;This is where the kernel begins execution from the bootloader.
;At this point, a temporary gdt is set up to "map" 0xC000_0000 to 0x0.
cli ;should already be off...
lgdt [gdtrbs32-VIRT_OFFSET]
jmp KERNEL_CODE_BS32:segmented_start
segmented_start:
mov ax, KERNEL_DATA_BS32
mov ss, ax
mov ds, ax
mov es, ax
mov gs, ax
mov fs, ax
mov esp, STACK_V+0x1000 ;ok, now we can access our data
;aloop:
; inc dword [0xC00B8000]
; jmp aloop
;Then the multiboot info structures are saved to local data variables.
add ebx, VIRT_OFFSET
push eax
push ebx ;pointer to multiboot info structure
call _k_mbsave ;save multiboot info structures
add esp, 8
cmp eax, 0
jz pm_return
;go back to real mode to initialize video mode
mov ebx, pm_return
;Next we enable paging with the first 4mb mapped 1:1 virtual:physical
; and with the 4mb starting at 0xC000_0000 mapped to the first 4mb physical.
pm_return:
xor eax, eax
mov edi, PDBR_V
mov ecx, 1024 ;clear the PDBR
rep stosd
mov edi, PT_STACK_V
mov ecx, 1024 ;clear the PT_STACK
rep stosd
mov [PDBR_V], dword LOPT_P|0x03 ;store the physical address of the LOw Page Table | (read/write, present)
mov [PDBR_V+0xC00], dword LOPT_P|0x03 ;store the physical address of the LOw Page Table | (read/write, present)
mov [PDBR_V+0xCFC], dword PT_STACK_P|0x03 ;store the physical address of the initial stack page page table | (read/write, present)
mov [PT_STACK_V+0xFFC], dword STACK_P|0x03 ;store the physical address of the initial stack page | (read/write, present)
mov edi, LOPT_V
mov ecx, 1024
mov eax, 0x03 ;starting physical address = 0x0 | (read/write, present flags)
fill_lopt_loop: ;fill the page table
stosd
add eax, 4096 ;increment next phsyical address by 4kb
loop fill_lopt_loop
mov eax, PDBR_P
mov cr3, eax ;store the Page Directory Base Address
mov eax, cr0
or eax, 0x80000000 ;set Page Enable bit
mov cr0, eax ;now paging is active!
mov edi, GDT_V
mov esi, gdt
mov ecx, gdt_end-gdt
rep movsb
mov edi, IDT_V ;destination
mov esi, isr_0 ;address of isr0
mov edx, isr_1-isr_0 ;distance between isr labels
mov ecx, 50 ;number of isrlabels
fill_idt:
mov ebx, esi
mov ax, si
stosw ;0 offset 15:0
mov ax, KERNEL_CODE
stosw ;2 selector 15:0
mov ax, 0x8E00
stosw ;4 [P][DPL][0][TYPE][0][0][0][0][0][0][0][0]
shr esi, 16
mov ax, si
stosw ;6 offset 31:16
mov esi, ebx
add esi, edx
loop fill_idt
mov word [IDT_V+0x30*8+4], 0xEE00 ;interrupt 0x30 has user priviledges
;Then we can start using our "real" gdt, then unmap the lower 4mb.
lgdt [gdtr] ;load gdt
jmp KERNEL_CODE:newgdtcontinue
newgdtcontinue:
mov ax, KERNEL_DATA
mov es, ax
mov ds, ax
mov gs, ax
mov fs, ax
mov ss, ax
mov esp, VIRT_STACK_TOP ;stack just under 3gb+256mb, moves downward
lidt [idtr] ;load idt
mov [PDBR_V], dword 0 ;unmap 0x0, we are running completely paged at 0xC000_0000
call _k_init ;C kernel initialization
idle_loop:
; sti
hlt
jmp idle_loop
;-------------------------------------------------------
gdtrbs32:
dw gdt_endbs32-gdtbs32-1
dd gdtbs32-VIRT_OFFSET
gdtbs32: ;null descriptor
dd 0
dd 0
;a base of 0x4000_0000, when added to 0xC000_0000 will produce 0x0000_0000 physical before paging in effect
KERNEL_CODE_BS32 equ $-gdtbs32
db 0xff ;limit 7:0
db 0xff ;limit 15:8
db 0x00 ;base 7:0
db 0x00 ;base 15:8
db 0x00 ;base 23:16
db 0x9a ;access
db 0xcf ;flags / limit 19:16
db 0x40 ;base 31:24
KERNEL_DATA_BS32 equ $-gdtbs32
db 0xff ;limit 7:0
db 0xff ;limit 15:8
db 0x00 ;base 7:0
db 0x00 ;base 15:8
db 0x00 ;base 23:16
db 0x92 ;access
db 0xcf ;flags / limit 19:16
db 0x40 ;base 31:24
gdt_endbs32:
%include "gdt.inc"
%include "idt.inc"
-71
View File
@@ -1,71 +0,0 @@
;gdt.inc
;Author: Josh Holtrop
;Date: 10/30/03
;Modified: 03/02/04
gdtr:
dw gdt_end-gdt-1
dd GDT_V
gdt:
dd 0
dd 0
KERNEL_CODE equ $-gdt
dw 0xffff ;limit 15:0
dw 0x0000 ;base 15:0
db 0x00 ;base 23:16
db 0x9A ;access ([P][DPL][1][Executable][Direction/Conforming][Writable/Readable][A])
db 0xCF ;flags ([G][D/B][0][0]) / limit 19:16
db 0x00 ;base 31:24
KERNEL_DATA equ $-gdt
dw 0xffff ;limit 15:0
dw 0x0000 ;base 15:0
db 0x00 ;base 23:16
db 0x92 ;access ([P][DPL][1][Executable][Direction/Conforming][Writable/Readable][A])
db 0xCF ;flags ([G][D/B][0][0]) / limit 19:16
db 0x00 ;base 31:24
USER_CODE equ $-gdt
dw 0xffff ;limit 15:0
dw 0x0000 ;base 15:0
db 0x00 ;base 23:16
db 0xFA ;access ([P][DPL][1][Executable][Direction/Conforming][Writable/Readable][A])
db 0xCF ;flags ([G][D/B][0][0]) / limit 19:16
db 0x00 ;base 31:24
USER_DATA equ $-gdt
dw 0xffff ;limit 15:0
dw 0x0000 ;base 15:0
db 0x00 ;base 23:16
db 0xF2 ;access ([P][DPL][1][Executable][Direction/Conforming][Writable/Readable][A])
db 0xCF ;flags ([G][D/B][0][0]) / limit 19:16
db 0x00 ;base 31:24
VESA_CODE equ $-gdt
dw 0xffff ;limit 15:0
dw 0x0000 ;base 15:0
db 0x00 ;base 23:16
db 0x9A ;access ([P][DPL][1][Executable][Direction/Conforming][Writable/Readable][A])
db 0x40 ;flags ([G][D/B][0][0]) / limit 19:16
db 0x00 ;base 31:24
VESA_DATA equ $-gdt
dw 0xffff ;limit 15:0
dw 0x0000 ;base 15:0
db 0x00 ;base 23:16
db 0x92 ;access ([P][DPL][1][Executable][Direction/Conforming][Writable/Readable][A])
db 0x40 ;flags ([G][D/B][0][0]) / limit 19:16
db 0x00 ;base 31:24
VIDEO_TEXT equ $-gdt
dw 0x7FFF ;limit 15:0
dw 0x8000 ;base 15:0
db 0x0B ;base 23:16
db 0x92 ;access ([P][DPL][1][Executable][Direction/Conforming][Writable/Readable][A])
db 0x40 ;flags ([G][D/B][0][0]) / limit 19:16
db 0x00 ;base 31:24
VIDEO_GRAPHICS equ $-gdt
dw 0xFFFF ;limit 15:0
dw 0x0000 ;base 15:0
db 0x0A ;base 23:16
db 0x92 ;access ([P][DPL][1][Executable][Direction/Conforming][Writable/Readable][A])
db 0x40 ;flags ([G][D/B][0][0]) / limit 19:16
db 0x00 ;base 31:24
gdt_end:
-92
View File
@@ -1,92 +0,0 @@
;idt.inc
;Author: Josh Holtrop
;Date: 10/30/03
;Modified: 07/06/04
idtr:
dw 50*8-1 ;size of idt
dd IDT_V ;address of idt
%macro isr_label 1
isr_%1:
push eax
mov eax, %1
jmp isr_main
%endmacro
isr_label 0
isr_label 1
isr_label 2
isr_label 3
isr_label 4
isr_label 5
isr_label 6
isr_label 7
isr_label 8
isr_label 9
isr_label 10
isr_label 11
isr_label 12
isr_label 13
isr_label 14
isr_label 15
isr_label 16
isr_label 17
isr_label 18
isr_label 19
isr_label 20
isr_label 21
isr_label 22
isr_label 23
isr_label 24
isr_label 25
isr_label 26
isr_label 27
isr_label 28
isr_label 29
isr_label 30
isr_label 31
isr_label 32
isr_label 33
isr_label 34
isr_label 35
isr_label 36
isr_label 37
isr_label 38
isr_label 39
isr_label 40
isr_label 41
isr_label 42
isr_label 43
isr_label 44
isr_label 45
isr_label 46
isr_label 47
isr_label 48
isr_label 49
isr_main:
pusha
push ds
push es
push eax ;interrupt number
call _isr
add esp, 4
pop es
pop ds
popa
pop eax ;original saved eax
iret
-76
View File
@@ -1,76 +0,0 @@
#include "kernel.h"
#include "multiboot.h"
#include "module.h"
mb_info_t mb_info_block;
mb_mmap_t mb_mmap[MAX_MMAP];
mb_module_t mb_modules[MAX_MODULES];
mb_apm_t mb_apm_table;
char mb_cmdline[256];
/* This function runs in segmented memory - 0xC000_0000 is mapped to 0x0 but 0x0
itself is an invalid linear address. Therefore, the multiboot information addresses
must be manually adjusted by VIRT_OFFSET to become valid linear addresses. */
int k_mbsave(mb_info_t *mbinfo, unsigned int mb_magic)
{
if (mb_magic != MULTIBOOT_BOOTLOADER_MAGIC)
{
char *msg = "Bad multiboot magic identifier!";
char *dest = (char *) 0xC00B8000;
while (*msg)
{
*dest++ = *msg++;
*dest++ = 0x04; //red error message
}
for (;;) ;
}
mb_info_block = *mbinfo;
if (mb_info_block.flags & MB_BOOTLOADER_COMMAND_LINE)
{
mb_info_block.cmdline += VIRT_OFFSET;
memcpy(mb_cmdline, mb_info_block.cmdline, 256);
mb_cmdline[255] = 0;
}
if (mb_info_block.flags & MB_BOOTLOADER_MODS)
{
mb_info_block.mods_addr += VIRT_OFFSET;
int i;
for (i = 0; i < mb_info_block.mods_count && i < MAX_MODULES; i++)
{
mb_modules[i] = ((mb_module_t *)mb_info_block.mods_addr)[i];
}
}
if (mb_info_block.flags & MB_BOOTLOADER_MMAP)
{
mb_info_block.mmap_addr += VIRT_OFFSET - 4; //-4 to get to size field, not base_addr_low field
mb_mmap_t *mmap = (mb_mmap_t *)mb_info_block.mmap_addr;
int i, sz = 0;
for (i = 0; sz < mb_info_block.mmap_length && i < MAX_MMAP; i++)
{
sz += mmap->size;
mb_mmap[i] = *mmap;
mmap = (mb_mmap_t *)(((u32_t) mmap) + mmap->size);
}
}
if (mb_info_block.flags & MB_BOOTLOADER_APM)
{
mb_info_block.apm_table += VIRT_OFFSET;
mb_apm_table = *(mb_apm_t *)mb_info_block.apm_table;
}
return 0;
}
void k_init()
{
for (;;)
{
(*(char*)0xC00B8000)++;
}
}
void isr()
{
for (;;) ;
}
-26
View File
@@ -1,26 +0,0 @@
OUTPUT_FORMAT("binary")
ENTRY(_start)
SECTIONS
{
.text 0xC0108000 : {
code = .; _code = .; __code = .;
*(.text)
. = ALIGN(4096);
}
.data : {
data = .; _data = .; __data = .;
*(.data)
/* . = ALIGN(4096); */
}
.rodata : {
rodata = .; _rodata = .; __rodata = .;
*(.rodata)
. = ALIGN(4096);
}
.bss : {
bss = .; _bss = .; __bss = .;
*(.bss)
. = ALIGN(4096);
}
end = .; _end = .; __end = .;
}
-9
View File
@@ -1,9 +0,0 @@
timeout 10
default 0
title HOS 0.15
root (fd0)
kernel /kernel.bin
+89
View File
@@ -0,0 +1,89 @@
HOS - Holtrop's Operating System
--------------------------------
HOS is (in the process of becoming) a 32-bit, protected mode, graphical, multitasking operating system.
It was written by me, Josh Holtrop, with help from a few others along the way.
Goals: (A = accomplished, P = in progress, T = todo)
----------------------------------------------------
(A) Custom bootloader to load kernel from FAT-formatted boot media, options for video mode/ram disk
(A) Multiboot compliance - kernel can be loaded by GRUB
(A) 32-bit protected mode environment
(A) VESA Support for graphics modes
(A) PS/2 keyboard & mouse drivers
(A) Utilize x86's paging architecture for virtual memory management
(P) Console Manager
(P) VFS abstraction layer for a single file system
(P) ram disk driver
(P) devfs file system driver
(P) ext2 file system support
(T) vfat file system support
(T) Multitasking support
(T) HASH command shell
(T) Window Manager
(T) Various other utilities/applications
(T) Hard Drive (ATA) driver
(T) cdrom (ATAPI) driver
Change Log
----------
0.16
12/16/04 - initrd going to be loaded as a gzipped ext2 image (kernel module) - faster loading!
0.15
07/10/04 - Multiboot support added, loadable by GRUB
0.14
05/21/04 - C++ support in kernel, can use classes & templates
04/04/04 - video_line function for diagonal lines
03/16/04 - new VFS design with support for a loop device
03/01/04 - Thanks to Ben Meyer for helping me get a Makefile working and building on linux to work!
0.13
01/26/04 - functions added to read/write CMOS clock date and time
01/19/04 - fixed bug GDTR/IDTR pointing to physical rather than linear table base address
01/07/04 - fixed bug not reading sectors correctly from floppy
12/28/03 - fixed bug not storing eax on interrupt
12/25/03 - fixed bug in mm_palloc()
12/25/03 - incorporated output functions as regular functions rather than as part of a linked library
12/23/03 - re-written physical memory manager using bitmap instead of stack
12/22/03 - kernel relocated to 3gb linear / 1mb+24kb physical to allow for app. address space
0.12
12/21/03 - sample bmp loader tested, works (tests loading a kernel of size ~ 932kb)
12/20/03 - GDT/IDT now located at 1mb physical, before kernel
10/30/03 - turns floppy motor off
10/30/03 - keyboard LEDs working
10/29/03 - paging functions working
10/15/03 - physical memory management page allocators working
0.11
10/09/03 - PS/2 mouse driver
0.10
09/11/03 - Rewritten C and assembly kernel with VESA GUI mode support, keyboard driver
0.05
05/14/03 - HGUI24/HGUI32 commands finished for testing GUI on both 24bpp and 32bpp graphics cards
05/14/03 - first web release!
0.04
03/09/03 - added VM shortcut command
03/09/03 - press up to fill retrieve last inputted command for Nate Scholten
03/08/03 - press clear to clear console input
03/07/03 - added "shortcut" commands PC, IC, ? for Nate Scholten
03/06/03 - added PROMPTC, INPUTC commands
0.03
12/30/02 - Command Line Interface working, accepting basic commands
0.02
12/11/02 - Assembly bootsector can load stage2 ("console")
0.01
12/01/02 - Real mode assembly bootsector boots from floppy disk successfully
View File
Whitespace-only changes.
View File
Whitespace-only changes.
Executable
+46
View File
@@ -0,0 +1,46 @@
#!/usr/bin/env ruby
# Copyright (c) 2013-2022 Josh Holtrop
#
# MIT License
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
script = File.join(File.dirname(__FILE__), ".rscons-3.1.0-4892f95d56c30bbe9aa0c9964062ec5b.rb")
unless File.exist?(script)
if File.read(__FILE__, mode: "rb") =~ /^#==>(.*)/
require "zlib"
require "base64"
encoded_compressed = $1
unescaped_compressed = Base64.decode64(encoded_compressed)
inflated = Zlib::Inflate.inflate(unescaped_compressed)
File.open(script, "wb") do |fh|
fh.write(inflated)
end
else
raise "Could not decompress."
end
end
load script
if __FILE__ == $0
Rscons::Cli.new.run(ARGV)
end
#==>eJztff13GzeS4O/5K9ptJyZlirIzN7PvMVYkW5IT7cmWT5KznqUZDkU2pR6T3dxuUrJW5v7thyp8VQHoJiXbuey+87yJ2PgoAIVCoVAoVD18sLUoi63zNNtKsquoWJzffFck/7FIiySKs2S+dTmfz2KbNEovknIefzfNR4tJEp2Uwzwrv4si9f0iK1PxFUXDyaAso+fPozKZjDElik4OTg/Oou0o/pB0n05jlTpKxtF1kc6TRpq3oo1pUpaDi6SpckV+3h/mk7wQFWVr7cFsNkmHg3maZ22ROxBtyiKmTjo21dpZOtkxGQycqrsjGrbNJdnI/M4Xc+huHIJLQA4XRZFkc9tNGCdtMikF7kaV+WrI7WQwvBTwo8/TzyQXW52207I/2Gmczos0u2iy7CiapFlSCsDTdikwM2/EH7K4FW0+C5bDZvrX6fyyn2aj5BO2CDmtKP3sVMC2IS96wPDA8vnwRUE23kAdidgn6xR0UbuqBp09rzkYiJcbqiEGlUbPFbrK9D+TaDN6tubg3cn1elFdYBUdrTVImPs1BummJJPSxc1wUCbR1Em8vkyyqCOm4Cea6lI4rvCf/vJs6nZFVr8okiT7aWX1Hyuq3ySTSX7906rqf6mofj5ZJLT3FdX/V0X1qViq2Xzw04rqf62oPrwZZGu0/reK6teXglOuRt2/VI09n4zo5IWqP6ueOKhOJ6+ietXEQXU6eRXVKydOVKeTV1G9auKgOp28iupVEwfV6eRVVK+aOKhOJ6+iet3ErSKbqlkrkjKZ19BMiM94/IF986/12GAF+6OgHCb0xfuianK65kjo7zRvS6FEwNBgbf6sSK8Gc91XkGCCsoTo4Mm7l3/vvz16cfbq+OR1tP1f0dZUdPT687S8KbdIPxoHb37rxmcHJ6/jXrQt5vPTPCmmcTP64Yfo++vuOB3n0fByUAyGIv10lgzTwaTXTrPhZDFKoNV2OR/M2+P5zYzITg5CRan5/GYnMGD9S/6F/8L/jdQn6McX+aSI98IKYwhhMJ8X/SIZjJIi6ojepldJ/2pQpINsXtoCg+FQTK4glc75Ip2M+qO0CGX60p1TIOvPL6Gx0m+7HBbpbB6qVKYTSavZOL1YFEmozFVSnOcKeTC/QlZK5wLnQhhQKNt1wYiVNC8WJtsMTKTj5J6c7h2/Oe2/fHd4tN/fPzwRE/35cxRjOb1wRcH2KJkkgvD88nped82oBeh383QiqgC1CHGlzxEiyirc9y+KfDGDCt0emWk5uPmg/NhPPiXDBUxjf3Ypdn5NJbuhTA9CscgaBRIGYr2FIMXKzEb9mSDaadmKysv8uo/JrWgwmeifSTY4nwhmpGlED3JPLPpEELgg62yYdOPxIJ0gz5pOBdQSVokeiuokbQ7mwknSRd0GRVE36TuzfP3CIAfDonzgwreLMTYkETNeMIQh9QPtu2PV9XFV9UeD+SDudWO3YtwjSzs0rHB7NasfiBrnT1Q+xR/tLLm22BBTuBA0PckHoz5ZXqRiG/IoJdCDFfTD7YZtWsJXJGJqYZIEJXMahnYs6CKZL4oseurBhJPiDZZWk9QYDwRLbNbRNl/G6dgjpHYynVEuKpA8FPCLHHiHQPdVWuTZNKGoFlDOBJQ2gurGYsUMFpM5m0DIJzltCVX2LQnNGWXtfhf1lokjzAZTcbqTWZ/dNk2JNdo0v556HCA8vYtsIpAS7Zp0TY4UNT7tuqfN5JPYScTEPGgE6Fzsqb83Pjz5vNncogJAYEF4lfV5uRXTmiVsr+OU171d1sC2+OZo4PIKz6Md32m0N5qPtkKlR2kJf1uRZuQwVaI/j561okc/shp+v7u0Us9wOg0U8bzJEM2FI9AU6O7C6ILDgoXrtWy5oUrpdrAProhmchVKoZPV41BAehxRkxI4NZDIGsCRAdxDIPRJmDMKW1atohDbpQsGORvsaloCiSJnjwvsDN4uGK4Z1PGoTKbmAX2dEnQflfOREHZbeLpvRfErBBmpWlHj4W0aPYmeLbce3rqtgYpk2ezELXXWaKEWwk61At2eLcRSQoFFVe3P837ZUB+umE2RNZwkg0zjF3Di4YZmCj5bXCRzze0pN4R0O3xZukimuZBSZWZD/rGdfyXGCn0u28W0P3ayyawjKCHuJcN5XqSJaVyIk/Po9vOgFZ1/js6lOun59s/RQKLNdk7Xvanon8lvmF+2l1nyaa65LfTY9ORmJ1RcLJjGflq0xS6FfbVFos2o+7j9uBU9brcf95ruZhdFUK2Yigq0kpj24SKJsnRSu23I8SC9eVMseNJ8/Wl2C7YhRWsE2ZQV44aVxZs+ZeFq5WeBkOAAS93Oes1et54wZxocESkA9kIlRw0W8xzKEMS7faw+v9GR1cglZnNWZcSSDkovBzax26Nb3RXdCMRnWwGqYKDhZsJslA3EGbjpt0UiacUmcsiAQCAnnX08A+G2sevKqefJRZqRcekZMXAFv6KiJxK+PBQfFAUoVH6OEjZtgjbFUZKLnlh3kApxMzSd/vFn3SNBSMr5zusKJ2Yf44sMW57o1XwHlougv4zjerws+SR4w45XDreT+ARgpdlF9PBWFljGsJDoAR7+3ZuNywH9T+PiHu5M3TD6vh3fV1TakIeUfAYELgVuPVBgiyFNEvx78MDNao+FyCOmSsuqEZcd4QQPP7Q4z85R0BJXmPiYY/nBtWvHoH61R6SkSjPdwd74uURk1VDGyXx42eioM2IroquY1PyY3ARqidQWNmVruEOdDEqBJY3HHtzeKiA1rELDUP018n6ftrX6IJGOA/NEQVG+KY/7nnRfS4JW7g/1HjHQ2BBMoWxFP5xP8uFHQn2QLMiqKOcV6mZ1JsNy5SQdJg8aT33eYunCAgQVoDlauso6OwHtaSL4Fa6RTiRXip6nTtTtkb5i3+1mBl9GTRaaPzwkaFgNb+iVC09uXjGrLtZ5luVzsYWKXxM4PUB2mkUDkXqZFLwx2bnYQ9PqRbh+21GWG0TBcNMsGQVanCdF/+oCZmYymJ6PBkijMlVVZpTKcuReIKjV7XRpdcU4uQ4mRWMcjjgGzfgZls9eBRDGe/nZ1ulR1+93j6x3u4dVHfOrVxzHI29InBr1+d09ua9x8vZnqdvtcRU2vY2xgm+FFOSRljNomf6Z9ESCGeYL0NlwjkGxJwtUoG8dXsUUzqq5baPUhH/qQgyu+94Qutb6iLEQPjWTxe5RzU46druObJbNh4YPZgRCJAiVB+FvJnb/ZbXWSK5OIhGjnO3Z9dQfXuiOcc+Zq5ypOjq/SZPJKOINr+rrGjpqKW6BvrXsaMyh9rWHkmVQXws/GduBhPYokS2JXQH2DtOSK9t9343EFJZibWTzcSP+fvPHfyljCVRuzUsUmDnEJaUHzHT1yfhNFcqcSYiNrT8HIRYUi5sPb23xJb+bFsPBPHFu+JiIPbW4cHiJgQTEuE0htRczME1xALoX1gYJLhr+CmiIH97qBpYxokL2pgoXq3iTPpLW71t3pWBNNx+y3+iyDq/MaEcs2sfhvOXjOOpEcbzsUKTda4HoPkWWQehGSIKRXqFTDfXVVJ2oYh31q8xXyeSZSDDHcnaps/IyhMCxo1OzyOHCZZ+piBpze73nrBavQW+1CJY2WSTexop5Ys24FzISXteCcXdct0KZzPukoUZFB7gWPmD7Febh8bvsY5ZfZxIU3DlHbGHqvQF3IuiVYjGKATRrFuz6dFB5CamOBXAqQhmy/t7OKX1vrZ2Cg8cLPJD77YqjVykO5N9fd42OUyowrZ7FPaIbvRU3yAibYLwclOmQKOkMqqzNQiN0rgZ2JAhGpAn2cprgZW9Dwu509g9evXh3dNYHG4Szk3d7Z4fHb/q/vTg5fPHy6OBUg8BZ8HH1QLfHytklInd2wRPKB978dnsNgTCnj1041HpFLwS1i/xA+baXxZvYbuB5WCyGUEMo5k1CHEh8NnAFlW6DgUwmz3yaAUWIwkUybsg/LZE6LwaQqAR5DVSmMLnQlHQNmlUH6s4A0D95gLRgQoKYPPzAZoyGIkl21UH7bTxsioMm/LdHutgOj4qA4YgQpDgo+4JxXOYjbfljbqU6DJhB3Ay63x9PBhdlA/9LDqf4Le9RHzg3qCpLcItkMmk8euafxosreqt7nRd44XYK5fFD3Q2zNsuP6cy5Q5RlQ/dtkMMu2+CiVAAgkxOAB/9ADRg8IEgi48dUgS8kZLqpFFdw4gL7ImIkQzOeWAp327gUkzBJVreBB4oJUmOEB4+JrysDMpkIUIikLt4f8h1MIYCp6QPmhQAFLiHhgF/RkERNF3sq/jvprRbfEDR0Da16NgfF8NI7MdX2XrUZ7+29Onrxy6mQK7sKDGKrFy59tL+6NMdACEvy1lv2HhbAw1vN8uK9t28F9357cvDq8L0Qbj3bAjnDXVXu8M0B9OURGRuFDZhRd/lfATka0peOGHtV3pRFns+/Rrc0qLXnrabGF83d4Zu9tSbu7YuzX2tmzYF6dPjy6PDN/14NWRSsIwYf7P7hyVpQV/QX5nOa5ZvDm4vrlD1gCMwXVGEYD8yQU8ZrS7Qyyq/LUEvrQ5lJW8tv213A+ea/DVoedjWYF6cazKNnxKCpDtqkGprt1NrQZtXQBKWuDQ4smIs57qI7jXiTHRdWo7UKzpM7wllzepJQBbl4vNIBfUFx5UmIRNB5wKUOLctUikIo24Uy8MNrqb64lGVmg7TArV/LyVyMEUIhE7HVvciLohjcNHGrhm2aJlKWKGpLOdsVQzhebbkqaSV0PhwtplrEkqJv/3JQXkbbRhKe5/1LvwCe0lAZ1z+/afzQAcukJtOEMM1iv5wXUhusr4Rupuf5pBntyDR5Eo5QZjb1gtZW8KakpUESCyqwI0CNiu4hSm7mjE0MrEJYWPdgJtXC6xshQ2FusaKuI/UpBv50475OjZ2VRTQrtFcUSPgtpmjJ3HAuSqYIQQJrsFwyc+LT07eINNZfB2B9X3Xlr6POqG6HtpHqVcuwjEkLine truncated
+235
View File
@@ -0,0 +1,235 @@
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <ft2build.h>
#include <stdio.h>
#include FT_FREETYPE_H
#include <string.h>
#include <strings.h>
#include <ctype.h>
#define N_CHARS 128
#define round_up_26_6(val) (((val) + 63) >> 6u)
int max_advance;
int max_top = -9999;
int min_bottom = 9999;
int line_height;
int baseline_offset;
typedef struct {
int width;
int height;
int top;
int left;
uint8_t * bitmap;
} char_info_t;
static char_info_t char_infos[N_CHARS];
static void load_char(FT_Face face, int char_code)
{
if (FT_Load_Char(face, char_code, FT_LOAD_RENDER) != 0)
{
return;
}
int advance = round_up_26_6(face->glyph->advance.x);
if (advance > max_advance)
{
max_advance = advance;
}
if ((face->glyph->bitmap.width == 0) ||
(face->glyph->bitmap.rows == 0))
{
return;
}
char_infos[char_code].width = face->glyph->bitmap.width;
char_infos[char_code].height = face->glyph->bitmap.rows;
char_infos[char_code].top = face->glyph->bitmap_top;
if (char_infos[char_code].top > max_top)
{
max_top = char_infos[char_code].top;
}
int bottom = char_infos[char_code].top - char_infos[char_code].height;
if (bottom < min_bottom)
{
min_bottom = bottom;
}
char_infos[char_code].left = face->glyph->bitmap_left;
char_infos[char_code].bitmap = malloc(char_infos[char_code].width * char_infos[char_code].height);
memcpy(char_infos[char_code].bitmap,
face->glyph->bitmap.buffer,
char_infos[char_code].width * char_infos[char_code].height);
}
static void generate_bytes(FILE * file, const uint8_t * bytes, int count)
{
for (int i = 0; i < count; i++)
{
if (i % 8 == 0)
{
fprintf(file, " ");
}
fprintf(file, "0x%02xu,", bytes[i]);
if ((i + 1) % 8 == 0)
{
fprintf(file, "\n");
}
else if (i < (count - 1))
{
fprintf(file, " ");
}
}
if (count % 8 != 0)
{
fprintf(file, "\n");
}
}
static bool 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, " 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, " const CharInfo[] chars;\n");
fprintf(fh, "};\n");
fprintf(fh, "/** Kernel font data. */\n");
fprintf(fh, "__gshared const FontInfo Kfont = {\n");
fprintf(fh, " %du,\n", line_height);
fprintf(fh, " %du,\n", max_advance);
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);
if (char_infos[i].width > 0)
{
fprintf(fh, " [\n");
generate_bytes(fh, char_infos[i].bitmap, char_infos[i].width * char_infos[i].height);
fprintf(fh, " ]\n");
}
else
{
fprintf(fh, " []\n");
}
fprintf(fh, " ),\n");
}
fprintf(fh, " ],\n");
fprintf(fh, "};\n");
fclose(fh);
return true;
}
int main(int argc, char * argv[])
{
/* Expect: font file, size, out file */
if (argc != 4)
{
fprintf(stderr, "Incorrect arguments\n");
return 1;
}
const char * font_file = argv[1];
int size = atoi(argv[2]);
const char * out_file = argv[3];
FT_Library ft_library;
if (FT_Init_FreeType(&ft_library) != 0)
{
fprintf(stderr, "Could not initialize freetype\n");
return 2;
}
FT_Face face;
if (FT_New_Face(ft_library, font_file, 0, &face) != 0)
{
fprintf(stderr, "Could not open %s\n", font_file);
return 3;
}
FT_Set_Pixel_Sizes(face, 0, size);
for (int i = 0; i < N_CHARS; i++)
{
load_char(face, i);
}
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 (max advance %d)\n", i, char_infos[i].width, max_advance);
return false;
}
if ((char_infos[i].height < 0) || (char_infos[i].height > line_height))
{
fprintf(stderr, "Error: invalid character %d height: %d (line height %d)\n", i, char_infos[i].height, line_height);
return false;
}
if ((char_infos[i].left < 0) || (char_infos[i].left >= max_advance))
{
fprintf(stderr, "Error: invalid character %d left: %d (max advance %d)\n", i, char_infos[i].left, max_advance);
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 (line height %d)\n", i, char_infos[i].top, line_height);
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;
}
return 0;
}
+88
View File
@@ -0,0 +1,88 @@
/**
* HELLO console support.
*/
module hello.console;
import uefi;
import hello.hello;
import core.stdc.stdarg;
import hulk.writef;
struct Console
{
/**
* Write a character to the console.
*
* @param ch Character to write.
*/
public static void write(ubyte ch)
{
if (ch == '\n')
{
write('\r');
}
CHAR16[2] s16 = [ch, 0];
st.ConOut.OutputString(st.ConOut, &s16[0]);
}
/**
* Write a formatted string to the console.
*
* @param s Format string.
* @param args Variable arguments structure.
*/
public static void writef(string s, va_list args)
{
hulk.writef.writefv(function void(ubyte ch) {
Console.write(ch);
}, s, args);
}
/**
* Write a formatted string to the console.
*
* @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 console.
*
* @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);
}
/**
* Write a message to press any key and wait for a key to be pressed.
*/
public static void wait_key()
{
writefln("Press any key...");
st.ConIn.Reset(st.ConIn, FALSE);
EFI_INPUT_KEY key;
while (st.ConIn.ReadKeyStroke(st.ConIn, &key) == EFI_NOT_READY)
{
}
}
/**
* Clear the console.
*/
public static void clear()
{
st.ConOut.ClearScreen(st.ConOut);
}
}
+579
View File
@@ -0,0 +1,579 @@
/**
* HELLO, the HOS EFI Lightweight LOader.
*/
module hello.hello;
import uefi;
import hello.console;
import hulk.bootinfo;
import hulk.header;
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. */
extern extern(C) __gshared ubyte _hulk_bin_start;
/** HULK binary end address, 4KB-aligned. */
extern extern(C) __gshared ubyte _hulk_bin_end;
private align(4096) __gshared ubyte[1024 * 1024] scratch_buffer;
/** Index to the memory map region being used to allocate page tables. */
private __gshared size_t memory_map_page_table_alloc_index;
private HulkHeader * hulk_header()
{
return cast(HulkHeader *)&_hulk_bin_start;
}
private BootInfo * bootinfo()
{
return &hulk_header().bootinfo;
}
private ulong hulk_bin_phys()
{
return cast(ulong)&_hulk_bin_start;
}
private ulong hulk_bin_size()
{
return cast(ulong)&_hulk_bin_end - cast(ulong)&_hulk_bin_start;
}
private ulong hulk_bss_size()
{
return cast(ulong)hulk_header().hulk_bss_size;
}
private ulong hulk_stack_size()
{
return hulk_header().stack_size;
}
private ulong hulk_virt_base_address()
{
return hulk_header().virt_base;
}
private ulong hulk_virt_stack_top()
{
return hulk_header().virt_stack_top;
}
private ulong hulk_virt_framebuffer_address()
{
return hulk_header().virt_fb_buffer;
}
/**
* Detect if we're running in QEMU.
*/
private bool in_qemu()
{
ulong * firmware_vendor = cast(ulong *) st.FirmwareVendor;
ulong fv1 = firmware_vendor[0];
return fv1 ==
((cast(ulong)'E') |
(cast(ulong)'D' << 16) |
(cast(ulong)'K' << 32) |
(cast(ulong)' ' << 48));
}
/**
* Set a graphics mode.
*/
private bool set_graphics_mode()
{
uint max_horizontal_resolution = in_qemu() ? 1920u : 0xFFFFFFFFu;
UINTN buffer_size = scratch_buffer.sizeof;
EFI_GUID gop_guid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
EFI_HANDLE * handles = cast(EFI_HANDLE *)&scratch_buffer[0];
EFI_STATUS status = st.BootServices.LocateHandle(ByProtocol,
&gop_guid, null, &buffer_size, handles);
if (status != EFI_SUCCESS)
{
Console.writefln("LocateHandle: error %x", status);
return false;
}
EFI_HANDLE gop_handle = handles[0];
EFI_HANDLE gop_interface;
status = st.BootServices.HandleProtocol(gop_handle,
&gop_guid, &gop_interface);
if (status != EFI_SUCCESS)
{
Console.writefln("HandleProtocol: error %x", status);
return false;
}
if (gop_interface == null)
{
Console.writefln("null interface from HandleProtocol");
return false;
}
EFI_GRAPHICS_OUTPUT_PROTOCOL * gop = cast(EFI_GRAPHICS_OUTPUT_PROTOCOL *)gop_interface;
UINTN info_size;
EFI_GRAPHICS_OUTPUT_MODE_INFORMATION * info;
uint best_width;
uint best_mode_number;
for (uint mode_number = 0u;
(status = gop.QueryMode(gop, mode_number, &info_size, &info)) == EFI_SUCCESS;
mode_number++)
{
if ((info.HorizontalResolution > best_width) &&
(info.HorizontalResolution <= max_horizontal_resolution))
{
best_width = info.HorizontalResolution;
best_mode_number = mode_number;
}
st.BootServices.FreePool(info);
}
if ((status = gop.SetMode(gop, best_mode_number)) != EFI_SUCCESS)
{
Console.writefln("SetMode: Error %x\n", status);
return false;
}
bootinfo().fb.buffer = cast(uint *)gop.Mode.FrameBufferBase;
bootinfo().fb.width = gop.Mode.Info.HorizontalResolution;
bootinfo().fb.height = gop.Mode.Info.VerticalResolution;
bootinfo().fb.stride = gop.Mode.Info.PixelsPerScanLine;
bootinfo().fb.format = gop.Mode.Info.PixelFormat;
return true;
}
/**
* Walk the EFI memory map and translate it to the HULK bootinfo format.
*/
private void get_memory_map(ulong * physical_address_limit, UINTN * memory_map_key)
{
immutable static ubyte[] efi_to_hulk_memory_map_type = [
BootInfo.MemoryRegion.Type.Reserved, // EfiReservedMemoryType
BootInfo.MemoryRegion.Type.Bootloader, // EfiLoaderCode
BootInfo.MemoryRegion.Type.Bootloader, // EfiLoaderData
BootInfo.MemoryRegion.Type.Bootloader, // EfiBootServicesCode
BootInfo.MemoryRegion.Type.Bootloader, // EfiBootServicesData
BootInfo.MemoryRegion.Type.Reserved, // EfiRuntimeServicesCode
BootInfo.MemoryRegion.Type.Reserved, // EfiRuntimeServicesData
BootInfo.MemoryRegion.Type.Conventional, // EfiConventionalMemory
BootInfo.MemoryRegion.Type.Unusable, // EfiUnusableMemory
BootInfo.MemoryRegion.Type.ACPIReclaim, // EfiACPIReclaimMemory
BootInfo.MemoryRegion.Type.ACPINVS, // EfiACPIMemoryNVS
BootInfo.MemoryRegion.Type.MemoryMappedIO, // EfiMemoryMappedIO
BootInfo.MemoryRegion.Type.MemoryMappedIOPortSpace, // EfiMemoryMappedIOPortSpace
BootInfo.MemoryRegion.Type.PalCode, // EfiPalCode
];
*physical_address_limit = 0u;
UINTN memory_map_size = scratch_buffer.sizeof;
UINTN descriptor_size;
UINT32 descriptor_version;
ubyte * scratch_base = cast(ubyte *)&scratch_buffer[0];
UINTN status = st.BootServices.GetMemoryMap(
&memory_map_size,
cast(EFI_MEMORY_DESCRIPTOR *)scratch_base,
memory_map_key,
&descriptor_size,
&descriptor_version);
if (status != EFI_SUCCESS)
{
Console.writefln("GetMemoryMap: Error %x", status);
for (;;) {}
}
size_t n_entries = memory_map_size / descriptor_size;
size_t count;
bool found_bss;
bool found_stack;
bool found_fb_buffer1;
const(size_t) fb_size = (bootinfo().fb.stride * bootinfo().fb.height * 4u + PAGE_SIZE - 1u) & ~(PAGE_SIZE - 1u);
for (count = 0u; count < n_entries; count++)
{
if (count > bootinfo().memory_map.length)
{
Console.writefln("Memory map too large");
for (;;) {}
}
EFI_MEMORY_DESCRIPTOR * descriptor = cast(EFI_MEMORY_DESCRIPTOR *)&scratch_base[count * descriptor_size];
ulong end_address = descriptor.PhysicalStart + descriptor.NumberOfPages * 4096u;
if ((end_address > *physical_address_limit) &&
((descriptor.Type == EfiLoaderCode) ||
(descriptor.Type == EfiLoaderData) ||
(descriptor.Type == EfiBootServicesCode) ||
(descriptor.Type == EfiBootServicesData) ||
(descriptor.Type == EfiRuntimeServicesCode) ||
(descriptor.Type == EfiRuntimeServicesData) ||
(descriptor.Type == EfiConventionalMemory)))
{
*physical_address_limit = end_address;
}
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;
bootinfo().memory_map[count].size = descriptor.NumberOfPages * 4096u;
bootinfo().memory_map[count].type = efi_to_hulk_memory_map_type[descriptor.Type];
if ((!found_bss) &&
(descriptor.Type == EfiConventionalMemory) &&
(bootinfo().memory_map[count].size >= hulk_bss_size()))
{
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) &&
(descriptor.Type == EfiConventionalMemory) &&
(bootinfo().memory_map[count].size >= hulk_stack_size()))
{
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) &&
(descriptor.Type == EfiConventionalMemory) &&
(bootinfo().memory_map[count].size >= fb_size))
{
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))
{
for (;;) {}
}
}
private void * alloc_pt_page()
{
BootInfo.MemoryRegion * regions = &bootinfo().memory_map[0];
for (;;)
{
BootInfo.MemoryRegion * region = &bootinfo().memory_map[memory_map_page_table_alloc_index];
if ((region.type == BootInfo.MemoryRegion.Type.Conventional) && (region.size >= PAGE_SIZE))
{
void * addr = cast(void *)region.base;
region.base += PAGE_SIZE;
region.size -= PAGE_SIZE;
return addr;
}
memory_map_page_table_alloc_index++;
if (memory_map_page_table_alloc_index >= bootinfo().memory_map_count)
{
return null;
}
}
}
/**
* Allocate a new page table.
*/
private PageTable * new_page_table()
{
PageTable * pt = cast(PageTable *)alloc_pt_page();
if (pt == null)
{
return null;
}
memset64(pt, 0u, 512);
return pt;
}
/**
* Map a virtual address to a physical address using 4KB pages.
*
* @param source_page Source page address.
* @param dest_page Destination page address.
* @param pt_base Page table base address.
*/
private bool map4k(ulong source_page, ulong dest_page, PageTable * pt_base)
{
PageTable * pt = pt_base;
for (size_t level = 0; level < 4u; level++)
{
PageTableEntry * ppte = pt.entry(source_page, level);
PageTableEntry pte = *ppte;
if (pte.present)
{
pt = pte.follow();
}
else
{
PageTable * next_pt;
ulong addr;
if (level < 3u)
{
next_pt = new_page_table();
if (next_pt == null)
{
return false;
}
addr = cast(ulong)next_pt;
}
else
{
addr = dest_page;
}
*ppte = PageTableEntry(addr, PT_WRITABLE | PT_PRESENT);
pt = next_pt;
}
}
return true;
}
/**
* Map a virtual region to a physical region using 4KB pages.
*
* @param source Source address.
* @param dest Destination address.
* @param size Region size.
* @param pt_base Page table base address.
*/
private bool map4kregion(ulong source, ulong dest, size_t size, PageTable * pt_base)
{
ulong end = source + size;
while (source < end)
{
if (!map4k(source, dest, pt_base))
{
return false;
}
source += 4096u;
dest += 4096u;
}
return true;
}
/**
* Map a virtual address to a physical address using 2MB pages.
*
* @param source_page Source page address.
* @param dest_page Destination page address.
* @param pt_base Page table base address.
*/
private bool map2m(ulong source_page, ulong dest_page, PageTable * pt_base)
{
PageTable * pt = pt_base;
for (size_t level = 0; level < 3u; level++)
{
PageTableEntry * ppte = pt.entry(source_page, level);
PageTableEntry pte = *ppte;
if (pte.present)
{
pt = pte.follow();
}
else
{
PageTable * next_pt;
if (level < 2u)
{
next_pt = new_page_table();
if (next_pt == null)
{
return false;
}
*ppte = PageTableEntry(next_pt, PT_WRITABLE | PT_PRESENT);
}
else
{
*ppte = PageTableEntry(dest_page, PT_HUGE_PAGE | PT_WRITABLE | PT_PRESENT);
}
pt = next_pt;
}
}
return true;
}
/**
* Map HULK virtual addresses to physical kernel location.
*
* @param pt_base Page table base address.
*/
private bool map_hulk(PageTable * pt_base)
{
/* Map HULK bin region. */
ulong virt = hulk_virt_base_address();
if (!map4kregion(virt, hulk_bin_phys(), hulk_bin_size(), pt_base))
{
return false;
}
/* Map HULK bss region. */
virt += hulk_bin_size();
if (!map4kregion(virt, bootinfo().bss_phys, hulk_bss_size(), pt_base))
{
return false;
}
/* Zero BSS region. */
memset64(cast(void *)bootinfo().bss_phys, 0u, hulk_bss_size() / 8);
/* Map HULK stack. */
virt = hulk_virt_stack_top() - hulk_stack_size();
if (!map4kregion(virt, bootinfo().stack_phys, hulk_stack_size(), pt_base))
{
return false;
}
return true;
}
/**
* Build page tables in preparation to jump to HULK.
*
* @param physical_address_limit Maximum physical address to identity map.
*/
private bool build_page_tables(ulong physical_address_limit)
{
PageTable * pt_base = new_page_table();
if (pt_base == null)
{
return false;
}
/* Map physical RAM. */
for (size_t addr = 0u; addr < physical_address_limit; addr += (2u * 1024u * 1024u))
{
if (!map2m(addr, addr, pt_base))
{
return false;
}
}
/* Map any memory regions that are outside physical RAM. */
for (size_t i = 0u; i < bootinfo().memory_map_count; i++)
{
ulong addr = bootinfo().memory_map[i].base;
if (addr >= physical_address_limit)
{
if (!map4kregion(addr, addr, bootinfo().memory_map[i].size, pt_base))
{
return false;
}
}
}
/* Map graphics framebuffer. */
ulong framebuffer_size = bootinfo().fb.height * bootinfo().fb.stride * 4u;
ulong fb_phys = cast(ulong)bootinfo().fb.buffer;
ulong fb_virt = hulk_virt_framebuffer_address();
if (!map4kregion(fb_virt, fb_phys, framebuffer_size, pt_base))
{
return false;
}
/* Map HULK regions. */
if (!map_hulk(pt_base))
{
return false;
}
/* Switch to the new page table. */
write_cr3(cast(ulong)pt_base);
return true;
}
/**
* Jump to HULK entry point.
*/
private void jump_to_hulk()
{
__asm(
"jmpq *$0",
"r,{rsp}",
hulk_header().entry, hulk_virt_stack_top());
}
/**
* Find the ACPI XSDT.
*
* @return Whether it was found.
*/
private bool find_acpi_xsdt()
{
for (size_t i = 0u; i < st.NumberOfTableEntries; i++)
{
if ((st.ConfigurationTable[i].VendorGuid == EFI_ACPI_TABLE_GUID) ||
(st.ConfigurationTable[i].VendorGuid == ACPI_TABLE_GUID))
{
enum ulong rsdp_magic = 0x20525450_20445352u;
const(EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER) * rdsp = cast(const(EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER) *)st.ConfigurationTable[i].VendorTable;
if (rdsp.Signature == rsdp_magic)
{
if (rdsp.Revision >= EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER_REVISION)
{
bootinfo().acpi_xsdt_phys = rdsp.XsdtAddress;
return true;
}
}
}
}
return false;
}
/**
* EFI application entry point.
*
* @param image_handle EFI application handle.
* @param st Pointer to EFI system table.
*/
extern (C) EFI_STATUS efi_main(EFI_HANDLE image_handle, EFI_SYSTEM_TABLE * st)
{
.st = st;
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);
if (!find_acpi_xsdt())
{
Console.writefln("Error: Could not locate ACPI XSDT");
Console.wait_key();
return EFI_SUCCESS;
}
if (!set_graphics_mode())
{
Console.wait_key();
return EFI_SUCCESS;
}
ulong physical_address_limit;
UINTN memory_map_key;
for (;;)
{
get_memory_map(&physical_address_limit, &memory_map_key);
EFI_STATUS status = st.BootServices.ExitBootServices(image_handle, memory_map_key);
if (status == EFI_INVALID_PARAMETER)
{
continue;
}
if (status == EFI_SUCCESS)
{
break;
}
Console.writefln("ExitBootServices: Error %x", status);
Console.wait_key();
return EFI_SUCCESS;
}
if (!build_page_tables(physical_address_limit))
{
return EFI_SUCCESS;
}
bootinfo().hulk_phys = hulk_bin_phys();
jump_to_hulk();
return EFI_SUCCESS;
}
+126
View File
@@ -0,0 +1,126 @@
/**
* ACPI (Advanced Configuration and Power Interface) functionality.
*/
module hulk.acpi;
import hulk.hurl;
import hulk.klog;
import hulk.memory;
import hulk.hurl.a1;
struct Acpi
{
/**
* List of ACPI tables.
*/
private static __gshared Header *[] tables;
enum uint XSDT_SIGNATURE = signature("XSDT");
/**
* ACPI table header structure.
*/
public static struct Header
{
uint signature;
uint length;
ubyte revision;
ubyte checksum;
char[6] oemid;
char[8] oemtableid;
uint oem_revision;
uint creator_id;
uint creator_revision;
}
/**
* XSDT table.
*/
static struct XSDT
{
Header header;
/* Table pointers are not ulong-aligned! They begin at offset 36. */
align(4) ulong[1] tables;
}
static assert(XSDT.tables.offsetof == 36);
/**
* Initialize ACPI.
*/
public static void initialize(ulong acpi_xsdt_phys)
{
Klog.writefln("\a3Initializing ACPI");
/* Map the XSDT header. */
map_table(acpi_xsdt_phys, PAGE_SIZE);
const(XSDT) * xsdt = cast(const(XSDT) *)acpi_xsdt_phys;
if (xsdt.header.signature != XSDT_SIGNATURE)
{
Klog.fatal_error("XSDT signature invalid");
return;
}
/* Map the entire XSDT. */
if (xsdt.header.length > PAGE_SIZE)
{
map_table(acpi_xsdt_phys, xsdt.header.length);
}
size_t n_entries = (xsdt.header.length - xsdt.header.sizeof) / xsdt.tables[0].sizeof;
Header ** table_pointers = cast(Header **)A1.allocate(n_entries * (Header *).sizeof);
tables = table_pointers[0..n_entries];
for (size_t i = 0u; i < n_entries; i++)
{
ulong address = xsdt.tables[i];
map_table(address, PAGE_SIZE);
Header * header = cast(Header *)address;
uint length = header.length;
if (length > PAGE_SIZE)
{
map_table(address, length);
}
tables[i] = header;
uint signature = header.signature;
Klog.writefln("Found ACPI table '%c%c%c%c' at %p",
signature & 0xFFu,
(signature >> 8u) & 0xFFu,
(signature >> 16u) & 0xFFu,
(signature >> 24u) & 0xFFu,
address);
}
}
/**
* Get pointer to ACPI table by name.
*
* @param name
* Table name.
*/
public static Header * get_table(string name)
{
uint signature = signature(name);
foreach (table; tables)
{
if (table.signature == signature)
{
return table;
}
}
Klog.fatal_error("Could not find requested ACPI table");
return null;
}
/**
* Map an ACPI table.
*/
private static void map_table(ulong address, ulong length)
{
Hurl.identity_map_range(address, length, PT_WRITABLE | PT_DISABLE_CACHE | PT_NO_EXECUTE);
}
/**
* Convert table signature from string to 32-bit unsigned integer.
*/
private static uint signature(string s)
{
return s[0] | (s[1] << 8) | (s[2] << 16) | (s[3] << 24);
}
}
+382
View File
@@ -0,0 +1,382 @@
/**
* APIC (Advanced Programmable Interrupt Controller) functionality.
*/
module hulk.apic;
import hulk.hurl;
import hulk.acpi;
import hulk.him;
import hulk.rtc;
import hulk.pit;
import hulk.klog;
import hulk.memory;
struct Apic
{
private enum DEBUG = false;
private enum DEFAULT_IO_APIC_ADDRESS = 0xFEC0_0000u;
private enum uint PERIODIC_MODE = 0x2_0000u;
private enum ulong IRQ_PIT = 0u;
private enum ulong IRQ_RTC = 8u;
/**
* MADT ACPI table structure.
*/
static struct MADT
{
/**
* MADT table entry header.
*/
static struct Entry
{
enum PROCESSOR_LOCAL_APIC = 0;
enum IO_APIC = 1;
enum IO_APIC_INTERRUPT_SOURCE_OVERRIDE = 2;
enum IO_APIC_NMI_SOURCE = 3;
enum LOCAL_APIC_NMI = 4;
enum LOCAL_APIC_ADDRESS_OVERRIDE = 5;
enum PROCESSOR_LOCAL_X2APIC = 9;
ubyte type;
ubyte length;
}
/**
* Processor Local APIC.
*/
static struct Entry0
{
Entry header;
ubyte acpi_processor_id;
ubyte apic_id;
uint flags;
}
static assert(Entry0.sizeof == 8);
/**
* I/O APIC.
*/
static struct Entry1
{
Entry header;
ubyte io_apic_id;
ubyte _reserved;
uint io_apic_address;
uint global_system_interrupt_base;
}
static assert(Entry1.sizeof == 12);
/**
* IO/APIC Interrupt Source Override.
*/
static struct Entry2
{
Entry header;
ubyte bus_source;
ubyte irq_source;
uint global_system_interrupt;
ushort flags;
ushort _reserved;
}
static assert(Entry2.sizeof == 12);
/**
* IO/APIC Non-maskable interrupt source.
*/
static struct Entry3
{
Entry header;
ubyte nmi_source;
ubyte _reserved;
ushort flags;
ubyte[4] global_system_interrupt;
}
static assert(Entry3.sizeof == 10);
/**
* Local APIC Non-maskable interrupts.
*/
static struct Entry4
{
Entry header;
ubyte acpi_processor_id;
ubyte[2] flags;
ubyte lint_nr;
}
static assert(Entry4.sizeof == 6);
/**
* Local APIC Address Override.
*/
static struct Entry5
{
Entry header;
ushort _reserved;
ubyte[8] local_apic_address;
}
static assert(Entry5.sizeof == 12);
/**
* Processor Local x2APIC.
*/
static struct Entry9
{
Entry header;
ushort _reserved;
uint local_x2apic_id;
uint flags;
uint acpi_id;
}
static assert(Entry9.sizeof == 16);
Acpi.Header header;
uint local_apic_address;
uint flags;
static assert(MADT.sizeof == 0x2C);
/**
* Scan the MADT table.
*/
public void scan()
{
apic_registers = cast(ApicRegisters *)local_apic_address;
const(void) * end = cast(const(void) *)(&this) + header.length;
const(Entry) * entry = cast(const(Entry) *)(cast(ulong)&this + MADT.sizeof);
bool first_io_apic = true;
size_t n_cpus = 0u;
while (entry < end)
{
if (DEBUG)
{
Klog.writefln("MADT entry type %u, length %u", entry.type, entry.length);
}
switch (entry.type)
{
case Entry.PROCESSOR_LOCAL_APIC:
Entry0 * e = cast(Entry0 *)entry;
n_cpus++;
if (DEBUG)
{
Klog.writefln(" ACPI processor ID: %u, APIC ID: %u, Flags: 0x%x",
e.acpi_processor_id, e.apic_id, e.flags);
}
break;
case Entry.IO_APIC:
Entry1 * e = cast(Entry1 *)entry;
if (first_io_apic)
{
io_apic_registers = cast(IoApicRegisters *)e.io_apic_address;
first_io_apic = false;
}
if (DEBUG)
{
Klog.writefln(" I/O APIC ID: %u, I/O APIC Address: 0x%x, GSIB: %u",
e.io_apic_id, e.io_apic_address, e.global_system_interrupt_base);
}
break;
case Entry.IO_APIC_INTERRUPT_SOURCE_OVERRIDE:
Entry2 * e = cast(Entry2 *)entry;
if (e.global_system_interrupt < INT_APIC_COUNT)
{
irq_redirects[e.irq_source] = cast(ubyte)e.global_system_interrupt;
}
else
{
Klog.writefln("Warning: unexpected interrupt source override global system interrupt value: %u", e.global_system_interrupt);
}
if (DEBUG)
{
Klog.writefln(" Bus %u IRQ %u GSI %u Flags: 0x%x",
e.bus_source, e.irq_source, e.global_system_interrupt, e.flags);
}
break;
case Entry.IO_APIC_NMI_SOURCE:
Entry3 * e = cast(Entry3 *)entry;
if (DEBUG)
{
uint global_system_interrupt;
memcpy(&global_system_interrupt, &e.global_system_interrupt, 4u);
Klog.writefln(" NMI Source: %u, Flags: 0x%x, GSI: %u",
e.nmi_source, e.flags, global_system_interrupt);
}
break;
case Entry.LOCAL_APIC_NMI:
Entry4 * e = cast(Entry4 *)entry;
if (DEBUG)
{
ushort flags;
memcpy(&flags, &e.flags, 2u);
Klog.writefln(" ACPI Processor ID: %u, Flags: 0x%x, LINT#: %u",
e.acpi_processor_id, flags, e.lint_nr);
}
break;
case Entry.LOCAL_APIC_ADDRESS_OVERRIDE:
Entry5 * e = cast(Entry5 *)entry;
if (DEBUG)
{
memcpy(&apic_registers, &e.local_apic_address, 8u);
Klog.writefln(" Local APIC Address: 0x%x", apic_registers);
}
break;
case Entry.PROCESSOR_LOCAL_X2APIC:
Entry9 * e = cast(Entry9 *)entry;
if (DEBUG)
{
Klog.writefln(" x2APIC ID: %u, Flags: 0x%x, ACPI ID: %u",
e.local_x2apic_id, e.flags, e.acpi_id);
}
break;
default:
break;
}
/* Move to next entry. */
entry = cast(const(Entry) *)(cast(size_t)entry + entry.length);
}
if (n_cpus > 0u)
{
Klog.writefln("%u CPU(s) found", n_cpus);
}
}
}
/**
* APIC register structure.
*/
static struct ApicRegister
{
public uint value;
alias value this;
private ubyte[12] _padding;
}
/**
* APIC registers.
*/
static struct ApicRegisters
{
ApicRegister[2] _reserved0;
ApicRegister lapic_id;
ApicRegister lapic_version;
ApicRegister[4] _reserved1;
ApicRegister task_priority;
ApicRegister arbitration_priority;
ApicRegister processor_priority;
ApicRegister eoi;
ApicRegister remote_read;
ApicRegister logical_destination;
ApicRegister destination_format;
ApicRegister spurious_interrupt_vector;
ApicRegister[8] in_service;
ApicRegister[8] trigger_mode;
ApicRegister[8] interrupt_request;
ApicRegister error_status;
ApicRegister[6] _reserved2;
ApicRegister lvt_cmci;
ApicRegister[2] interrupt_command;
ApicRegister lvt_timer;
ApicRegister lvt_thermal_sensor;
ApicRegister lvt_performance_monitoring_counters;
ApicRegister[2] lvt_lint;
ApicRegister lvt_error;
ApicRegister initial_count;
ApicRegister current_count;
ApicRegister[4] _reserved3;
ApicRegister divide_configuration;
}
/**
* I/O APIC registers.
*/
static struct IoApicRegisters
{
ApicRegister address;
ApicRegister data;
}
alias ISRHandler = void function();
private static __gshared ApicRegisters * apic_registers;
private static __gshared IoApicRegisters * io_apic_registers;
private static __gshared ISRHandler[INT_APIC_COUNT] irq_handlers;
private static __gshared ubyte[INT_APIC_COUNT] irq_redirects;
/**
* Initialize APIC.
*/
public static void initialize()
{
Klog.writefln("\a3Initializing APIC");
io_apic_registers = cast(IoApicRegisters *)DEFAULT_IO_APIC_ADDRESS;
for (ubyte i = 0u; i < INT_APIC_COUNT; i++)
{
irq_redirects[i] = i;
}
MADT * madt = cast(MADT *)Acpi.get_table("APIC");
madt.scan();
Klog.writefln("APIC found at %p", apic_registers);
Klog.writefln("I/O APIC found at %p", io_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,
PT_WRITABLE | PT_WRITE_THROUGH | PT_DISABLE_CACHE | PT_NO_EXECUTE);
/* Enable local APIC to receive interrupts and set spurious interrupt
* vector to 0xFF. */
apic_registers.spurious_interrupt_vector.value = 0x100u | INT_APIC_SPURIOUS;
apic_registers.lvt_timer.value = INT_APIC_TIMER;
apic_registers.lvt_lint[0].value = INT_APIC_LINT0;
apic_registers.lvt_lint[1].value = INT_APIC_LINT1;
/* Enable PIT interrupt. */
configure_io_apic_irq(IRQ_PIT, &Pit.isr);
/* Enable RTC interrupt. */
configure_io_apic_irq(IRQ_RTC, &Rtc.isr);
}
/**
* Configure routing for an I/O APIC IRQ.
*/
private static void configure_io_apic_irq(size_t orig_irq, ISRHandler isr_handler)
{
size_t io_apic_irq = irq_redirects[orig_irq];
ulong entry = INT_APIC_BASE + io_apic_irq;
io_apic_registers.address.value = cast(uint)(0x10u + io_apic_irq * 2u);
io_apic_registers.data.value = entry & 0xFFFF_FFFFu;
io_apic_registers.address.value = cast(uint)(0x10u + io_apic_irq * 2u + 1u);
io_apic_registers.data.value = entry >> 32u;
irq_handlers[io_apic_irq] = isr_handler;
}
/**
* Signal APIC end of interrupt.
*/
public static void eoi()
{
apic_registers.eoi.value = 0u;
}
/**
* APIC interrupt handler.
*/
public static void isr(ulong vector)
{
ulong io_apic_irq = vector - INT_APIC_BASE;
if ((io_apic_irq < INT_APIC_COUNT) && (irq_handlers[io_apic_irq] != null))
{
irq_handlers[io_apic_irq]();
}
else
{
Klog.writefln("Unhandled APIC ISR %u", vector);
}
eoi();
}
}
+77
View File
@@ -0,0 +1,77 @@
/**
* HULK boot information.
*/
module hulk.bootinfo;
/**
* HULK boot information structure.
*/
struct BootInfo
{
/**
* Framebuffer description structure.
*/
struct Framebuffer
{
/** Framebuffer physical base address. */
uint * buffer;
/** Horizontal resolution. */
uint width;
/** Vertical resolution. */
uint height;
/** Number of pixels per scan line. */
uint stride;
/** Pixel format. */
uint format;
}
/**
* Memory map entry description structure.
*/
struct MemoryRegion
{
enum Type
{
Reserved,
Bootloader,
Conventional,
Unusable,
ACPIReclaim,
ACPINVS,
MemoryMappedIO,
MemoryMappedIOPortSpace,
PalCode,
}
/** Base address of the memory region. */
ulong base;
/** Size in bytes of the memory region. */
size_t size;
/** Type of the memory region. */
ubyte type;
}
/* Framebuffer parameters. */
Framebuffer fb;
/* Memory map. */
MemoryRegion[1000] memory_map;
/* Number of memory map entries. */
size_t memory_map_count;
/* Physical address of HULK. */
ulong hulk_phys;
/* Physical address used for HULK bss section. */
ulong bss_phys;
/* Physical address of stack while jumping to HULK. */
ulong stack_phys;
/* Physical address of framebuffer buffer1. */
ulong fb_buffer1_phys;
/* Physical address of ACPI XSDT table. */
ulong acpi_xsdt_phys;
}
+276
View File
@@ -0,0 +1,276 @@
/**
* HULK Console functionality.
*/
module hulk.console;
import hulk.fb;
import hulk.kfont;
import hulk.ver;
import hulk.rtc;
import hulk.writef;
/**
* Represent the HULK console.
*
* Coordinate (0,0) is the top-left console position.
*/
struct Console
{
/** Border color. */
private enum BORDER_COLOR = 0xFF8000u;
/** Heading color. */
private enum HEADING_COLOR = 0x0066FFu;
/** Console page width in text columns. */
private static __gshared size_t m_width;
/** Console page height in text rows. */
private static __gshared size_t m_height;
/** Current console page. */
private static __gshared size_t m_page;
/** Current page cursor X position. */
private static __gshared size_t m_x;
/** Current page cursor Y position. */
private static __gshared size_t m_y;
/** Number of delayed newline characters. */
private static __gshared size_t m_newlines;
/** Active console escape code. */
private static __gshared char m_escape_code;
/** Flag to indicate the previous character was an escape character. */
private static __gshared bool m_escape;
/**
* Initialize the console.
*/
public static void initialize()
{
size_t fb_console_height = Fb.height - Kfont.line_height - 1;
m_width = (Fb.width - 1) / 2 / Kfont.advance;
m_height = fb_console_height / Kfont.line_height;
}
/**
* Clear the console.
*/
public static void clear()
{
Fb.clear();
m_page = 0u;
m_x = 0u;
m_y = 0u;
draw();
}
/**
* Write a character to the console (buffer newlines).
*
* @param ch Character to write.
*/
public static void write(char ch)
{
if (ch == '\n')
{
render_heading_end();
m_escape_code = 0u;
m_newlines++;
}
else
{
dowrite(ch);
}
}
private static void render_heading_start()
{
if ('0' <= m_escape_code && m_escape_code <= '9' && m_x < (m_width - 1))
{
size_t heading_level = m_escape_code - ('0' - 1);
size_t nx = m_x + heading_level;
if (nx >= m_width)
{
nx = m_width - 1;
}
size_t hx = fb_x(m_page, m_x);
size_t hy = fb_y(m_y) + Kfont.line_height / 2 - 1;
size_t hwidth = (nx - m_x - 1) * Kfont.advance + Kfont.advance / 2 - 1;
Fb.rect(hx, hy, hwidth, 2, HEADING_COLOR);
Fb.rect(hx + hwidth, fb_y(m_y) + Kfont.line_height / 8,
2, Kfont.line_height * 3 / 4, HEADING_COLOR);
m_x = nx;
}
}
private static void render_heading_end()
{
if ('0' <= m_escape_code && m_escape_code <= '9' && m_x < (m_width - 1))
{
size_t heading_level = m_escape_code - ('0' - 1);
size_t nx = m_x + heading_level;
if (nx >= m_width)
{
nx = m_width - 1;
}
size_t hwidth = (nx - m_x - 1) * Kfont.advance + Kfont.advance / 2 - 1;
size_t hx = fb_x(m_page, nx) - hwidth;
size_t hy = fb_y(m_y) + Kfont.line_height / 2 - 1;
Fb.rect(hx, hy, hwidth, 2, HEADING_COLOR);
Fb.rect(hx - 2, fb_y(m_y) + Kfont.line_height / 8,
2, Kfont.line_height * 3 / 4, HEADING_COLOR);
m_x = nx;
}
}
/**
* Write a character to the console (no newline buffering).
*
* @param ch Character to write.
*/
private static void dowrite(char ch)
{
if (m_newlines != 0u)
{
size_t newlines = m_newlines;
m_newlines = 0u;
for (size_t i = 0u; i < newlines; i++)
{
dowrite('\n');
}
}
if (m_escape)
{
m_escape_code = ch;
render_heading_start();
m_escape = false;
return;
}
if (ch == '\a')
{
m_escape = true;
return;
}
if (ch == '\n')
{
m_x = 0u;
m_y++;
}
else
{
render_char(fb_x(m_page, m_x), fb_y(m_y), ch);
m_x++;
if (m_x == m_width)
{
m_x = 0u;
m_y++;
}
}
if (m_y == m_height)
{
if (m_page == 0u)
{
m_page = 1u;
m_x = 0u;
m_y = 0u;
}
else
{
m_y--;
shift_rows();
}
}
}
/**
* Shift console rows.
*/
private static void shift_rows()
{
/* Shift up page 0 */
Fb.copy_rect(fb_x(0u, 0u), fb_y(1u),
m_width * Kfont.advance, (m_height - 1u) * Kfont.line_height,
fb_x(0u, 0u), fb_y(0u));
/* Copy page 1 first row to page 0 last row. */
Fb.copy_rect(fb_x(1u, 0u), fb_y(0u),
m_width * Kfont.advance, Kfont.line_height,
fb_x(0u, 0u), fb_y(m_height - 1u));
/* Shift up page 1 */
Fb.copy_rect(fb_x(1u, 0u), fb_y(1u),
m_width * Kfont.advance, (m_height - 1u) * Kfont.line_height,
fb_x(1u, 0u), fb_y(0u));
/* Erase page 1 last row. */
Fb.rect(fb_x(1u, 0u), fb_y(m_height - 1u),
m_width * Kfont.advance, Kfont.line_height, 0u);
}
/**
* Render a character.
*
* @param x X position.
* @param y Y position.
* @param ch Character to render.
*/
private static void render_char(size_t x, size_t y, char ch)
{
if (ch > 127)
{
ch = 0u;
}
const(CharInfo) * ci = &Kfont.chars[ch];
Fb.blit_alpha_bitmap(x + ci.left, y + ci.top, ci.bitmap, ci.width, ci.height);
}
/**
* Get the framebuffer X coordinate corresponding to the console page X position.
*/
private static size_t fb_x(size_t page, size_t x)
{
return x * Kfont.advance + page * (m_width * Kfont.advance + 1);
}
/**
* Get the framebuffer Y coordinate corresponding to the console page Y position.
*/
private static size_t fb_y(size_t y)
{
return (y + 1) * Kfont.line_height + 1;
}
/**
* Draw console.
*/
private static draw()
{
static __gshared string header_text = "Welcome to HOS v" ~ VERSION ~ "!";
Fb.rect(0u, Kfont.line_height, Fb.width, 1, BORDER_COLOR);
Fb.rect(m_width * Kfont.advance, Kfont.line_height, 1, Fb.height - Kfont.line_height, BORDER_COLOR);
size_t x = 0;
foreach (c; header_text)
{
render_char(x, 0, c);
x += Kfont.advance;
}
update_header();
}
/**
* Update console header.
*/
public static update_header()
{
__gshared uint x;
x = Fb.width - 8 * Kfont.advance;
Fb.rect(x - 1, 0, 1, Kfont.line_height, BORDER_COLOR);
Fb.rect(x, 0, Fb.width - x, Kfont.line_height, 0);
Rtc.time rtc_time = Rtc.read_rtc_time();
writef(function(ubyte ch) {
render_char(x, 0, ch);
x += Kfont.advance;
}, "%02u:%02u:%02u", rtc_time.hour, rtc_time.minute, rtc_time.second);
}
}
+260
View File
@@ -0,0 +1,260 @@
/**
* CPU functionality.
*/
module hulk.cpu;
import ldc.llvmasm;
/** CR0 bits. @{ */
enum ulong CR0_PE = 0x1u;
enum ulong CR0_MP = 0x2u;
enum ulong CR0_EM = 0x4u;
enum ulong CR0_TS = 0x8u;
enum ulong CR0_ET = 0x10u;
enum ulong CR0_NE = 0x20u;
enum ulong CR0_WP = 0x1_0000u;
enum ulong CR0_AM = 0x4_0000u;
enum ulong CR0_NW = 0x2000_0000u;
enum ulong CR0_CD = 0x4000_0000u;
enum ulong CR0_PG = 0x8000_0000u;
/** @} */
/** CR4 bits. @{ */
enum ulong CR4_VME = 0x1u;
enum ulong CR4_PVI = 0x2u;
enum ulong CR4_TSD = 0x4u;
enum ulong CR4_DE = 0x8u;
enum ulong CR4_PSE = 0x10u;
enum ulong CR4_PAE = 0x20u;
enum ulong CR4_MCE = 0x40u;
enum ulong CR4_PGE = 0x80u;
enum ulong CR4_PCE = 0x100u;
enum ulong CR4_OSFXSR = 0x200u;
enum ulong CR4_OSXMMEXCPT = 0x400u;
enum ulong CR4_UMIP = 0x800u;
enum ulong CR4_VMXE = 0x2000u;
enum ulong CR4_SMXE = 0x4000u;
enum ulong CR4_FSGSBASE = 0x1_0000u;
enum ulong CR4_PCIDE = 0x2_0000u;
enum ulong CR4_OSXSAVE = 0x4_0000u;
enum ulong CR4_SMEP = 0x10_0000u;
enum ulong CR4_SMAP = 0x20_0000u;
enum ulong CR4_PKE = 0x40_0000u;
enum ulong CR4_CET = 0x80_0000u;
enum ulong CR4_PKS = 0x100_0000u;
/** @} */
/** XCR0 bits. @{ */
enum ulong XCR0_X87 = 0x1u;
enum ulong XCR0_SSE = 0x2u;
enum ulong XCR0_AVX = 0x4u;
enum ulong XCR0_BNDREG = 0x8u;
enum ulong XCR0_BNDSCR = 0x10u;
enum ulong XCR0_OPMASK = 0x20u;
enum ulong XCR0_ZMM_HI256 = 0x40u;
enum ulong XCR0_HI16_ZMM = 0x80u;
enum ulong XCR0_PKRU = 0x100u;
/** @} */
/** MSR register numbers. @{ */
enum uint MSR_EFER = 0xC000_0080u;
/** @} */
/** EFER flags. @{ */
enum uint EFER_SCE = 0x1u;
enum uint EFER_LME = 0x100u;
enum uint EFER_LMA = 0x400u;
enum uint EFER_NXE = 0x800u;
enum uint EFER_SVME = 0x1000u;
enum uint EFER_LMSLE = 0x2000u;
enum uint EFER_FFXSR = 0x4000u;
enum uint EFER_TCE = 0x8000u;
/** @} */
/** CPUID 1 bits. @{ */
enum uint CPUID_1_EDX_FPU = 0x1u;
enum uint CPUID_1_EDX_VME = 0x2u;
enum uint CPUID_1_EDX_DE = 0x4u;
enum uint CPUID_1_EDX_PSE = 0x8u;
enum uint CPUID_1_EDX_TSC = 0x10u;
enum uint CPUID_1_EDX_MSR = 0x20u;
enum uint CPUID_1_EDX_PAE = 0x40u;
enum uint CPUID_1_EDX_MCE = 0x80u;
enum uint CPUID_1_EDX_CX8 = 0x100u;
enum uint CPUID_1_EDX_APIC = 0x200u;
enum uint CPUID_1_EDX_SEP = 0x800u;
enum uint CPUID_1_EDX_MTRR = 0x1000u;
enum uint CPUID_1_EDX_PGE = 0x2000u;
enum uint CPUID_1_EDX_MCA = 0x4000u;
enum uint CPUID_1_EDX_CMOV = 0x8000u;
enum uint CPUID_1_EDX_PAT = 0x1_0000u;
enum uint CPUID_1_EDX_PSE36 = 0x2_0000u;
enum uint CPUID_1_EDX_PSN = 0x4_0000u;
enum uint CPUID_1_EDX_CLFSH = 0x8_0000u;
enum uint CPUID_1_EDX_DS = 0x20_0000u;
enum uint CPUID_1_EDX_ACPI = 0x40_0000u;
enum uint CPUID_1_EDX_MMX = 0x80_0000u;
enum uint CPUID_1_EDX_FXSR = 0x100_0000u;
enum uint CPUID_1_EDX_SSE = 0x200_0000u;
enum uint CPUID_1_EDX_SSE2 = 0x400_0000u;
enum uint CPUID_1_EDX_SS = 0x800_0000u;
enum uint CPUID_1_EDX_HTT = 0x1000_0000u;
enum uint CPUID_1_EDX_TM = 0x2000_0000u;
enum uint CPUID_1_EDX_IA64 = 0x4000_0000u;
enum uint CPUID_1_EDX_PBE = 0x8000_0000u;
enum uint CPUID_1_ECX_SSE3 = 0x1u;
enum uint CPUID_1_ECX_PCLMULQDQ = 0x2u;
enum uint CPUID_1_ECX_DTES64 = 0x4u;
enum uint CPUID_1_ECX_MONITOR = 0x8u;
enum uint CPUID_1_ECX_DSCPL = 0x10u;
enum uint CPUID_1_ECX_VMX = 0x20u;
enum uint CPUID_1_ECX_SMX = 0x40u;
enum uint CPUID_1_ECX_EST = 0x80u;
enum uint CPUID_1_ECX_TM2 = 0x100u;
enum uint CPUID_1_ECX_SSSE3 = 0x200u;
enum uint CPUID_1_ECX_CNXTID = 0x400u;
enum uint CPUID_1_ECX_SDBG = 0x800u;
enum uint CPUID_1_ECX_FMA = 0x1000u;
enum uint CPUID_1_ECX_CX16 = 0x2000u;
enum uint CPUID_1_ECX_XTPR = 0x4000u;
enum uint CPUID_1_ECX_PDCM = 0x8000u;
enum uint CPUID_1_ECX_PCID = 0x2_0000u;
enum uint CPUID_1_ECX_DCA = 0x4_0000u;
enum uint CPUID_1_ECX_SSE41 = 0x8_0000u;
enum uint CPUID_1_ECX_SSE42 = 0x10_0000u;
enum uint CPUID_1_ECX_X2APIC = 0x20_0000u;
enum uint CPUID_1_ECX_MOVBE = 0x40_0000u;
enum uint CPUID_1_ECX_POPCNT = 0x80_0000u;
enum uint CPUID_1_ECX_TSCDEADLINE = 0x100_0000u;
enum uint CPUID_1_ECX_AES = 0x200_0000u;
enum uint CPUID_1_ECX_XSAVE = 0x400_0000u;
enum uint CPUID_1_ECX_OSXSAVE = 0x800_0000u;
enum uint CPUID_1_ECX_AVX = 0x1000_0000u;
enum uint CPUID_1_ECX_F16C = 0x2000_0000u;
enum uint CPUID_1_ECX_RDRND = 0x4000_0000u;
enum uint CPUID_1_ECX_HYPERVISOR = 0x8000_0000u;
/** @} */
void cli()
{
__asm("cli", "");
}
void sti()
{
__asm("sti", "");
}
void hlt()
{
__asm("hlt", "");
}
ulong read_cr0()
{
return __asm!ulong("mov %cr0, %rax", "={rax}");
}
void write_cr0(ulong v)
{
__asm("mov $0, %cr0", "r", v);
}
ulong read_cr2()
{
return __asm!ulong("mov %cr2, %rax", "={rax}");
}
ulong read_cr3()
{
return __asm!ulong("mov %cr3, %rax", "={rax}");
}
void write_cr3(ulong v)
{
__asm("mov $0, %cr3", "r", v);
}
ulong read_cr4()
{
return __asm!ulong("mov %cr4, %rax", "={rax}");
}
void write_cr4(ulong v)
{
__asm("mov $0, %cr4", "r", v);
}
ulong read_rflags()
{
return __asm!ulong(`
pushf
mov (%rsp), %rax
add $$8, %rsp`, "={rax}");
}
ulong rdmsr(uint msr)
{
return __asm!ulong(`
rdmsr
shl $$32, %rdx
or %rdx, %rax`, "={rax},{ecx},~{rdx}", msr);
}
void wrmsr(uint msr, ulong value)
{
__asm(`wrmsr`, "{ecx},{edx},{eax}", msr, value >> 32u, value);
}
ulong xgetbv(uint xcr)
{
return __asm!ulong(`
xgetbv
shl $$32, %rdx
or %rdx, %rax`, "={rax},{ecx},~{rdx}", xcr);
}
void xsetbv(uint xcr, ulong value)
{
__asm(`xsetbv`, "{ecx},{edx},{eax}", xcr, value >> 32u, value);
}
ubyte in8(ushort ioaddr)
{
return __asm!ubyte("inb %dx, %al", "={al},{dx}", ioaddr);
}
ushort in16(ushort ioaddr)
{
return __asm!ushort("inw %dx, %ax", "={ax},{dx}", ioaddr);
}
uint in32(ushort ioaddr)
{
return __asm!uint("inl %dx, %eax", "={eax},{dx}", ioaddr);
}
void out8(ushort ioaddr, ubyte v)
{
__asm("outb %al, %dx", "{dx},{al}", ioaddr, v);
}
void out16(ushort ioaddr, ushort v)
{
__asm("outw %ax, %dx", "{dx},{ax}", ioaddr, v);
}
void out32(ushort ioaddr, uint v)
{
__asm("outl %eax, %dx", "{dx},{eax}", ioaddr, v);
}
void cpuid1(uint * ebx, uint * ecx, uint * edx)
{
__asm("cpuid", "=*{ebx},=*{ecx},=*{edx},{eax}", ebx, ecx, edx, 1u);
}
void swint(ubyte swint_id)()
{
mixin(`__asm("int $$`, cast(int)cast(uint)swint_id, `", "");`);
}
+242
View File
@@ -0,0 +1,242 @@
/**
* HULK Framebuffer support.
*/
module hulk.fb;
import hulk.memory;
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
{
/** Device frame buffer base address. */
private __gshared static uint * m_device_buffer;
/** Frame buffer 1 base address. */
private __gshared static uint * m_buffer1;
/** Frame buffer width. */
private __gshared static uint m_width;
/** Frame buffer height. */
private __gshared static uint m_height;
/** Frame buffer stride. */
private __gshared static uint m_stride;
/** Number of pixels in the frame buffer (whether visible or not). */
private __gshared static uint m_buffer_size;
/**
* Get the framebuffer width.
*/
public static @property uint width()
{
return m_width;
}
/**
* Get the framebuffer height.
*/
public static @property uint height()
{
return m_height;
}
/**
* Initialize a frame buffer.
*
* @param device_buffer Device frame buffer base address.
* @param buffer1 Frame buffer 1 base address.
* @param width Frame buffer width.
* @param height Frame buffer height.
* @param stride Frame buffer stride.
*/
static void initialize(uint * device_buffer, uint * buffer1, uint width, uint height, uint stride)
{
m_device_buffer = device_buffer;
m_buffer1 = buffer1;
m_width = width;
m_height = height;
m_stride = stride;
m_buffer_size = stride * height;
}
/**
* Clear the frame buffer to the given color.
*
* @param color Color to clear to.
*/
static void clear(uint color = 0u)
{
memset32(m_buffer1, color, m_buffer_size);
memset32(m_device_buffer, color, m_buffer_size);
}
/**
* Draw a solid rectangle on the framebuffer.
*
* @param x X coordinate of left of rectangle.
* @param y Y coordinate of top of rectangle.
* @param width Width of rectangle.
* @param height Height of rectangle.
* @param color Color of rectangle.
*/
static void rect(size_t x, size_t y, size_t width, size_t height, uint color)
{
for (size_t iy = 0u; iy < height; iy++)
{
size_t buffer_index = buffer_index(x, y);
memset32(&m_buffer1[buffer_index], color, width);
memset32(&m_device_buffer[buffer_index], color, width);
y++;
}
}
/**
* Draw a horizontal line.
*
* @param x X coordinate of left of line.
* @param y Y coordinate of line.
* @param width Width of line.
* @param color Color of line.
*/
static void hline(size_t x, size_t y, size_t width, uint color)
{
size_t buffer_index = buffer_index(x, y);
memset32(&m_buffer1[buffer_index], color, width);
memset32(&m_device_buffer[buffer_index], color, width);
}
/**
* Draw a vertical line.
*
* @param x X coordinate of line.
* @param y Y coordinate of top of line.
* @param height Height of line.
* @param color Color of line.
*/
static void vline(size_t x, size_t y, size_t height, uint color)
{
size_t buffer_index = buffer_index(x, y);
for (size_t iy = 0u; iy < height; iy++)
{
m_buffer1[buffer_index] = color;
m_device_buffer[buffer_index] = color;
buffer_index += m_stride;
}
}
/**
* 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 alpha_bitmap 8-bit alpha-channel bitmap.
* @param width Bitmap width.
* @param height Bitmap height.
*/
static void blit_alpha_bitmap(size_t x, size_t y, const(ubyte) * alpha_bitmap,
size_t width, size_t height)
{
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];
m_buffer1[buffer_index] = (alpha << 16u) | (alpha << 8u) | alpha;
bitmap_index++;
}
memcpy32(&m_device_buffer[row_buffer_index], &m_buffer1[row_buffer_index], width);
y++;
}
}
/**
* 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 alpha_bitmap 8-bit alpha-channel bitmap.
* @param width Bitmap width.
* @param height Bitmap height.
*/
static void blit_alpha_bitmap(size_t x, size_t y, const(ubyte)[] alpha_bitmap,
size_t width, size_t height)
{
blit_alpha_bitmap(x, y, alpha_bitmap.ptr, width, height);
}
/**
* Copy framebuffer rows up in the framebuffer.
*
* @param y Y coordinate of top 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);
memcpy32(&m_buffer1[dest_buffer_index],
&m_buffer1[src_buffer_index],
(m_stride * height));
memcpy32(&m_device_buffer[dest_buffer_index],
&m_buffer1[dest_buffer_index],
(m_stride * height));
}
/**
* Copy a rectangle in the framebuffer.
*
* @param sx X coordinate of left of source rectangle.
* @param sy Y coordinate of top of source rectangle.
* @param width Width of rectangle to copy.
* @param height Height of rectangle to copy.
* @param dx X coordinate of left of destination rectangle.
* @param dy Y coordinate of top of destination rectangle.
*/
static void copy_rect(size_t sx, size_t sy, size_t width, size_t height,
size_t dx, size_t dy)
{
size_t dest_buffer_index = buffer_index(dx, dy);
size_t src_buffer_index = buffer_index(sx, sy);
for (size_t y = 0u; y < height; y++)
{
memcpy32(&m_buffer1[dest_buffer_index],
&m_buffer1[src_buffer_index],
width);
memcpy32(&m_device_buffer[dest_buffer_index],
&m_buffer1[dest_buffer_index],
width);
dest_buffer_index += m_stride;
src_buffer_index += m_stride;
}
}
/**
* Return the buffer index for the given X and Y coordinates.
*
* @param x X coordinate from left side of framebuffer.
* @param y Y coordinate from bottom side of framebuffer.
*
* @return Buffer index for the given X and Y coordinates.
*/
private static size_t buffer_index(size_t x, size_t y)
{
return y * m_stride + x;
}
}
+58
View File
@@ -0,0 +1,58 @@
/**
* GDT (Global Descriptor Table) functionality.
*/
module hulk.gdt;
import ldc.llvmasm;
struct Gdt
{
struct gdtr_t
{
ushort limit;
align(2) ulong offset;
}
static assert(gdtr_t.sizeof == 10u);
public enum size_t SELECTOR_NULL = 0x00u;
public enum size_t SELECTOR_KERNEL_CODE = 0x08u;
public enum size_t SELECTOR_KERNEL_DATA = 0x10u;
public enum size_t SELECTOR_COUNT = 3u;
static __gshared ulong[SELECTOR_COUNT] gdt;
static __gshared gdtr_t gdtr;
public static void initialize()
{
gdt[SELECTOR_KERNEL_CODE / ulong.sizeof] = 0x00_A_F_9A_000000_0000u;
gdt[SELECTOR_KERNEL_DATA / ulong.sizeof] = 0x00_C_F_92_000000_0000u;
gdtr.limit = gdt.sizeof - 1u;
gdtr.offset = cast(ulong)&gdt;
lgdt(&gdtr);
load_data_selectors(SELECTOR_KERNEL_DATA);
load_code_selector(SELECTOR_KERNEL_CODE);
}
private static void lgdt(gdtr_t * gdtr)
{
__asm("lgdt $0", "*m", gdtr);
}
private static void load_data_selectors(ulong selector)
{
__asm(`mov %ax, %ds
mov %ax, %es
mov %ax, %fs
mov %ax, %gs
mov %ax, %ss`, "{rax}", selector);
}
private static void load_code_selector(ulong selector)
{
__asm(`push %rax
movabs $$1f, %rax
push %rax
lretq
1:`, "{rax}", selector);
}
}
+40
View File
@@ -0,0 +1,40 @@
/**
* HULK image header.
*/
module hulk.header;
import hulk.bootinfo;
/**
* Header describing the HULK image.
*/
struct HulkHeader
{
/**
* HULK BSS size.
*
* The OS loader must map memory to a zeroed range of this size.
*
* This value is really an integer, but is stored as a pointer because it
* is provided by the linker and LDC does not like us to cast it.
*/
void * hulk_bss_size;
/** Entry point. */
void * entry;
/** Stack size. */
ulong stack_size;
/** Virtual base address. */
ulong virt_base;
/** Stack top virtual address. */
ulong virt_stack_top;
/** Framebuffer virtual address. */
ulong virt_fb_buffer;
/** HULK boot information. */
BootInfo bootinfo;
}
+329
View File
@@ -0,0 +1,329 @@
/**
* HULK Interrupt Manager.
*/
module hulk.him;
import hulk.gdt;
import ldc.llvmasm;
import hulk.fb;
import hulk.console;
import hulk.klog;
import hulk.apic;
import hulk.cpu;
import hulk.kfont;
import hulk.thread;
/** Number if Interrupt Service Routines. */
private enum N_ISRS = 256;
/** Interrupt stack frame indices. */
public static enum
{
ISF_RBP,
ISF_R15,
ISF_R14,
ISF_R13,
ISF_R12,
ISF_R11,
ISF_R10,
ISF_R9,
ISF_R8,
ISF_RDI,
ISF_RSI,
ISF_RDX,
ISF_RCX,
ISF_RBX,
ISF_RAX,
ISF_ERROR_CODE,
ISF_RIP,
ISF_CS,
ISF_RFLAGS,
ISF_RSP,
ISF_SS,
ISF_COUNT,
}
private static __gshared string[ISF_COUNT] ISF_NAMES = [
"RBP",
"R15",
"R14",
"R13",
"R12",
"R11",
"R10",
"R9",
"R8",
"RDI",
"RSI",
"RDX",
"RCX",
"RBX",
"RAX",
"Error Code",
"RIP",
"CS",
"RFLAGS",
"RSP",
"SS",
];
/** Interrupt IDs. @{ */
public enum ulong INT_PAGE_FAULT = 0x0Eu;
/* The I/O APIC is configured to map IRQ 0 to interrupt 64 (0x40). */
public enum ulong INT_APIC_BASE = 0x40u; /* IRQ 0 */
public enum ulong INT_APIC_COUNT = 24u;
public enum ulong INT_APIC_TIMER = 0x70u;
public enum ulong INT_APIC_LINT0 = 0x71u;
public enum ulong INT_APIC_LINT1 = 0x72u;
public enum ulong INT_KERNEL_SWINT = 0x80u;
public enum ulong INT_APIC_SPURIOUS = 0xFFu;
/** @} */
static foreach(isr; 0 .. N_ISRS)
{
mixin(`private extern(C) void isr_`, isr, `();`);
}
private string isrs_list(int index = 0)()
{
static if (index < 256)
{
return "&isr_" ~ index.stringof ~ ",\n" ~ isrs_list!(index + 1)();
}
else
{
return "";
}
}
mixin(`private static __gshared extern(C) void function()[N_ISRS] isrs = [`,
isrs_list(),
`];`);
/** Interrupt suspend level (0 when interrupts are enabled). */
private __gshared size_t interrupt_suspend_level;
/** Interrupt nest level (0 when not in an interrupt handler). */
private __gshared size_t interrupt_level;
/**
* Suspend interrupts.
*
* This function disables interrupts. Calls can be nested and interrupts will
* be enabled only when the outermost pair of
* suspend_interrupts()/resume_interrupts() is complete.
*/
void suspend_interrupts()
{
if (interrupt_level == 0)
{
cli();
interrupt_suspend_level++;
}
}
/**
* Resume interrupts.
*
* Calls can be nested and interrupts will be enabled only when the outermost
* pair of suspend_interrupts()/resume_interrupts() is complete.
*/
void resume_interrupts()
{
if (interrupt_level == 0)
{
interrupt_suspend_level--;
if (interrupt_suspend_level == 0)
{
sti();
}
}
}
struct Him
{
/**
* IDT descriptor entry type.
*/
struct descriptor_t
{
ulong[2] descriptor;
this(T)(size_t index, ulong dpl, bool trap, T offset)
{
descriptor[0] =
0x0000_8E_00_0000_0000u |
((cast(ulong)offset & 0xFFFF_0000u) << 32u) |
(dpl << 45u) |
((trap ? 1uL : 0uL) << 40u) |
(Gdt.SELECTOR_KERNEL_CODE << 16u) |
(cast(ulong)offset & 0xFFFFu);
descriptor[1] = cast(ulong)offset >> 32u;
}
}
/**
* IDTR register format.
*/
struct idtr_t
{
ushort limit;
align(2) ulong offset;
}
static assert(idtr_t.sizeof == 10u);
private static __gshared idtr_t idtr;
private static __gshared align(0x10) descriptor_t[N_ISRS] idt;
static assert(idt.sizeof == (N_ISRS * 16u));
public static void initialize()
{
set_isrs();
idtr.limit = idt.sizeof - 1u;
idtr.offset = cast(ulong)&idt;
lidt(&idtr);
}
private static void lidt(idtr_t * idtr)
{
__asm("lidt $0", "*m", idtr);
}
private static void set_isrs()
{
static bool isr_has_error_code(size_t isr)
{
return (isr == 8) ||
((10 <= isr) && (isr <= 14)) ||
(isr == 17) ||
(isr == 21) ||
(isr == 29) ||
(isr == 30);
}
static bool isr_is_trap(size_t isr)
{
return (isr < 32u) && (isr != 2u);
}
__asm("jmp 1f", "");
static foreach(isr; 0 .. N_ISRS)
{
mixin("__asm(`isr_", isr, ":
" ~ (isr_has_error_code(isr) ? "" : "pushq $$0") ~ "
pushq %rax
mov $$", isr, ", %rax
jmp isr_common`, ``);");
}
__asm(`isr_common:
pushq %rbx
pushq %rcx
pushq %rdx
pushq %rsi
pushq %rdi
pushq %r8
pushq %r9
pushq %r10
pushq %r11
pushq %r12
pushq %r13
pushq %r14
pushq %r15
pushq %rbp
mov %rsp, %rbp
mov %rsp, %rsi
and $$0xFFFFFFFFFFFFFFF0, %rsp
mov %rsp, %rdx
mov %rax, %rdi
movabs $$isr, %rax
callq *%rax
mov %rax, %rsp
popq %rbp
popq %r15
popq %r14
popq %r13
popq %r12
popq %r11
popq %r10
popq %r9
popq %r8
popq %rdi
popq %rsi
popq %rdx
popq %rcx
popq %rbx
popq %rax
add $$8, %rsp
iretq
1:`, ``);
for (size_t isr = 0; isr < N_ISRS; isr++)
{
idt[isr] = descriptor_t(isr, 0u, isr_is_trap(isr), isrs[isr]);
}
}
}
/**
* Interrupt service routine.
*
* This function returns the stack pointer of the thread to execute when
* returning from this function.
*/
public extern(C) ulong * isr(ulong vector, ulong * stack_frame, ulong * rsp)
{
interrupt_level++;
if (interrupt_level == 1)
{
Thread.current_thread.stack_pointer = stack_frame;
}
if ((vector >= INT_APIC_BASE) && (vector < (INT_APIC_BASE + INT_APIC_COUNT)))
{
Apic.isr(vector);
}
else
{
switch (vector)
{
case INT_APIC_TIMER:
case INT_APIC_LINT0:
case INT_APIC_LINT1:
case INT_APIC_SPURIOUS:
Apic.isr(vector);
break;
case INT_KERNEL_SWINT:
Thread.handle_swint(stack_frame);
break;
default:
Fb.rect(0, 0, Fb.width, Kfont.line_height, 0xCC0000u);
Klog.writefln("\n **** Unhandled ISR %u ****", vector);
for (size_t i = 0u; i < ISF_COUNT; i++)
{
Klog.writef(ISF_NAMES[i]);
Klog.writefln(" = 0x%x", stack_frame[i]);
}
Klog.writefln("CR2 = 0x%p", read_cr2());
__asm("cli", "");
for (;;)
{
__asm("hlt", "");
}
}
}
Thread.current_thread = Thread.current_thread.list_next;
interrupt_level--;
if (interrupt_level == 0)
{
return Thread.current_thread.stack_pointer;
}
else
{
return rsp;
}
}
+69
View File
@@ -0,0 +1,69 @@
/**
* HIPPO, the HOS In-place Physical Page Organizer.
*
* HIPPO maintains a list of free physical pages "in place", meaning that the
* available page itself is used as the linked list entry so separate memory
* is not needed to keep track of the available pages.
*/
module hulk.hippo;
struct Hippo
{
/**
* Linked list node entry for a physical page.
*/
private static struct PhysicalPage
{
PhysicalPage * next;
}
/**
* Linked list of free physical pages.
*/
private static __gshared PhysicalPage * free_pages;
/**
* Number of free physical pages.
*/
private static __gshared size_t m_n_free_pages;
/**
* Free a physical page.
*
* @param phys Physical page address.
*/
public static void free_page(T)(T phys)
{
PhysicalPage * pp = cast(PhysicalPage *)phys;
pp.next = free_pages;
free_pages = pp;
m_n_free_pages++;
}
/**
* Allocate a physical page.
*
* @return Page address, or null if no pages are available.
*/
public static void * allocate_page()
{
PhysicalPage * pp;
if (free_pages != null)
{
pp = free_pages;
free_pages = free_pages.next;
m_n_free_pages--;
}
return cast(void *)pp;
}
/**
* Get the number of free pages.
*
* @return The number of free pages.
*/
public @property size_t n_free_pages() const
{
return m_n_free_pages;
}
}
+114
View File
@@ -0,0 +1,114 @@
/**
* HULK, the HOS Ultra Light Kernel.
*/
module hulk.hulk;
import hulk.header;
import hulk.fb;
import hulk.console;
import hulk.memory;
import ldc.attributes;
import hulk.kfont;
import hulk.klog;
import hulk.hurl;
import hulk.hippo;
import hulk.pci;
import hulk.gdt;
import hulk.him;
import hulk.cpu;
import ldc.llvmasm;
import hulk.pic;
import hulk.acpi;
import hulk.apic;
import hulk.rtc;
import hulk.serial;
import hulk.usb;
import hulk.pit;
import hulk.time;
import hulk.test;
import hulk.thread;
extern extern(C) __gshared ubyte _hulk_bss_size;
@(ldc.attributes.section(".hulk_header"))
private __gshared HulkHeader hulk_header = {
&_hulk_bss_size, /* hulk_bss_size */
&hulk_start, /* entry */
Thread.STACK_SIZE, /* stack_size */
Hurl.HULK_BASE, /* virt_base */
Hurl.HULK_STACK_TOP, /* virt_stack_top */
Hurl.HULK_FRAMEBUFFER, /* virt_fb_buffer */
};
private void initialize_cpu()
{
/* Enable SSE. */
/* Turn off CR0.EM and turn on CR0.MP. */
write_cr0((read_cr0() & ~CR0_EM) | CR0_MP);
/* Set CR4.OSFXSR and CR4.OSXMMEXCPT. */
write_cr4(read_cr4() | CR4_OSFXSR | CR4_OSXMMEXCPT);
/* Enable OSXSAVE. */
write_cr4(read_cr4() | CR4_OSXSAVE);
/* Turn on NXE (no execute enable) flag in the EFER MSR. */
wrmsr(MSR_EFER, rdmsr(MSR_EFER) | EFER_NXE);
}
/**
* HULK entry point.
*/
void hulk_start()
{
suspend_interrupts();
initialize_cpu();
Serial.initialize();
Gdt.initialize();
Him.initialize();
Fb.initialize(cast(uint *)Hurl.HULK_FRAMEBUFFER,
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();
Klog.writefln("\a5Welcome to HULK, the HOS UltraLight Kernel!");
Hurl.initialize(&hulk_header);
Pic.initialize();
Acpi.initialize(hulk_header.bootinfo.acpi_xsdt_phys);
Apic.initialize();
Rtc.initialize();
Pit.initialize();
Pci.initialize();
Thread.initialize();
resume_interrupts();
Usb.initialize();
/* Run kernel tests. */
Test.run();
Klog.writefln("\a5HULK Initialization Complete!");
Thread.start(&th);
/* Idle loop. */
Time.msleep(1);
Time.msleep(500);
Klog.writefln("Main thread!");
for (;;)
{
hlt();
}
}
void th()
{
for (;;)
{
Klog.writefln("Hello from thread.");
Time.msleep(1000);
}
}
+65
View File
@@ -0,0 +1,65 @@
SECTIONS
{
. = 0xFFFF800000000000;
_hulk_mem_start = .;
_hulk_header_start = .;
.hulk_header :
{
KEEP(*(.hulk_header))
}
. = ALIGN(4K);
_hulk_header_end = .;
_hulk_text_start = .;
.text :
{
*(.text)
*(.text.*)
}
. = ALIGN(4K);
_hulk_text_end = .;
_hulk_rodata_start = .;
.rodata :
{
*(.rodata)
*(.rodata.*)
}
. = ALIGN(4K);
_hulk_rodata_end = .;
_hulk_data_start = .;
.data :
{
*(.data)
*(.data.*)
}
. = ALIGN(4K);
_hulk_data_end = .;
_hulk_binary_size = . - _hulk_mem_start;
_hulk_bss_start = .;
.bss :
{
*(COMMON)
*(.bss)
*(.bss.*)
}
. = ALIGN(4K);
_hulk_bss_end = .;
_hulk_mem_end = .;
_hulk_header_size = _hulk_header_end - _hulk_header_start;
_hulk_text_size = _hulk_text_end - _hulk_text_start;
_hulk_rodata_size = _hulk_rodata_end - _hulk_rodata_start;
_hulk_data_size = _hulk_data_end - _hulk_data_start;
_hulk_bss_size = _hulk_bss_end - _hulk_bss_start;
_hulk_mem_size = _hulk_mem_end - _hulk_mem_start;
}
+67
View File
@@ -0,0 +1,67 @@
/**
* A1 memory allocator.
*/
module hulk.hurl.a1;
import hulk.hurl;
import hulk.hippo;
import hulk.util;
import hulk.pagetable;
import hulk.memory;
/**
* 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;
}
memset64(cast(void *)address, 0, size / 8);
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);
}
}
+315
View File
@@ -0,0 +1,315 @@
/**
* HURL, the HOS Unreal Region Locator.
*
* HURL provides virtual memory management for HULK.
*/
module hulk.hurl.hurl;
public import hulk.pagetable;
import hulk.cpu;
import hulk.hippo;
import hulk.memory;
import hulk.klog;
import hulk.bootinfo;
import hulk.header;
import hulk.linker_addresses;
import hulk.util;
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.
*/
private static __gshared PageTable * m_pt_base;
/**
* Build HULK page tables.
*
* @param physical_address_limit
* Limit of physical memory.
*/
private static void build_page_tables(HulkHeader * header, size_t physical_address_limit)
{
m_pt_base = allocate_pt();
/* Identity map all physical RAM. */
map_range(0u,
0u,
physical_address_limit,
PT_WRITABLE | PT_NO_EXECUTE);
ulong phys_address = header.bootinfo.hulk_phys;
ulong virt_address = HULK_BASE;
/* Map HULK header region. */
map_range(virt_address,
phys_address,
LinkerAddresses.hulk_header_size,
PT_NO_EXECUTE);
phys_address += LinkerAddresses.hulk_header_size;
virt_address += LinkerAddresses.hulk_header_size;
/* Map HULK text region. */
map_range(virt_address,
phys_address,
LinkerAddresses.hulk_text_size,
0u);
phys_address += LinkerAddresses.hulk_text_size;
virt_address += LinkerAddresses.hulk_text_size;
/* Map HULK rodata region. */
map_range(virt_address,
phys_address,
LinkerAddresses.hulk_rodata_size,
PT_NO_EXECUTE);
phys_address += LinkerAddresses.hulk_rodata_size;
virt_address += LinkerAddresses.hulk_rodata_size;
/* Map HULK data region. */
map_range(virt_address,
phys_address,
LinkerAddresses.hulk_data_size,
PT_WRITABLE | PT_NO_EXECUTE);
virt_address += LinkerAddresses.hulk_data_size;
/* Map HULK BSS region. */
map_range(virt_address,
header.bootinfo.bss_phys,
LinkerAddresses.hulk_bss_size,
PT_WRITABLE | PT_NO_EXECUTE);
/* Map HULK stack. */
map_range(HULK_STACK_TOP - header.stack_size,
header.bootinfo.stack_phys,
header.stack_size,
PT_WRITABLE | PT_NO_EXECUTE);
/* Map device framebuffer. */
map_range(HULK_FRAMEBUFFER,
cast(ulong)header.bootinfo.fb.buffer,
header.bootinfo.fb.height * header.bootinfo.fb.stride * 4u,
PT_WRITABLE | PT_NO_EXECUTE);
/* Map framebuffer buffer1. */
map_range(cast(ulong)header.bootinfo.fb_buffer1_phys,
cast(ulong)header.bootinfo.fb_buffer1_phys,
header.bootinfo.fb.height * header.bootinfo.fb.stride * 4u,
PT_WRITABLE | PT_NO_EXECUTE);
write_cr3(cast(ulong)m_pt_base);
}
/**
* Reclaim the pages that were used for the bootloader page tables.
*
* @param pt
* The page table to reclaim pages from.
* @param level
* Page table level (internally used while recursing the page tables).
*
* @return Number of pages reclaimed.
*/
private static size_t reclaim_bootloader_page_table_pages(PageTable * pt, size_t level = 0u)
{
map(pt, pt, PT_WRITABLE | PT_NO_EXECUTE);
size_t reclaimed_pages;
for (size_t i = 0u; i < PageTable.N_ENTRIES; i++)
{
PageTableEntry pte = (*pt)[i];
if (pte.present && (level < 2u) && !pte.huge)
{
/* For the first two levels of page tables, first
* recurse and free pages from the lower level page
* tables before reclaiming this entry. */
reclaimed_pages += reclaim_bootloader_page_table_pages(pte.follow(), level + 1u);
}
}
Hippo.free_page(pt);
reclaimed_pages++;
return reclaimed_pages;
}
/**
* Initialize HURL.
*
* @param bootinfo HULK boot information structure.
*/
public static void initialize(HulkHeader * header)
{
PageTable * bootloader_pt_base = cast(PageTable *)read_cr3();
/*
* Ok, what we do here is iterate through all of the memory map regions
* in the bootinfo memory_map array and mark each page that is not in
* use in a reserved range as available. Within the available memory
* regions, we have to watch out for the following items:
* 1) HULK binary (header + text + rodata + data)
* 2) Framebuffer
* In addition to these ranges, there are also pages for the following
* purposes that are not represented in the memory map from the
* bootloader:
* 3) HULK BSS
* 4) HULK stack
* 5) bootloader page table pages
* 6) framebuffer buffer1
*/
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 = [
[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++)
{
reserved[ri][1] += reserved[ri][0];
}
for (size_t bii = 0u; bii < header.bootinfo.memory_map_count; bii++)
{
if ((header.bootinfo.memory_map[bii].type == BootInfo.MemoryRegion.Type.Bootloader) ||
(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;
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;
}
}
}
/*
* Now that we have available physical pages to allocate from, we can
* build new page tables to replace the bootloader page tables.
*/
build_page_tables(header, physical_address_limit);
/*
* After we have switched to the newly constructed page tables, we can
* iterate through and free the bootloader page tables. They are most
* likely already mapped because we just identity mapped every page up
* to the physical_address_limit determined above. But just in case the
* bootloader used the last pages of RAM for the page table pages, we
* will make sure to map them as we traverse them.
*/
size_t reclaimed_bootloader_page_table_memory = reclaim_bootloader_page_table_pages(bootloader_pt_base) << 10u;
usable_memory += reclaimed_bootloader_page_table_memory;
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);
}
public static void map(ulong virtual, ulong physical, ulong flags)
{
PageTable * pt = m_pt_base;
for (size_t level = 0; level < 4u; level++)
{
PageTableEntry * ppte = pt.entry(virtual, level);
if (level < 3u)
{
PageTableEntry pte = *ppte;
if (pte.present)
{
pt = pte.follow();
}
else
{
PageTable * next_pt = allocate_pt();
*ppte = PageTableEntry(next_pt, PT_WRITABLE | PT_PRESENT);
pt = next_pt;
}
}
else
{
*ppte = PageTableEntry(cast(ulong)physical, flags | PT_PRESENT);
}
}
}
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)
{
size_t end = virtual + length;
while (virtual < end)
{
map(virtual, physical, flags);
virtual += PAGE_SIZE;
physical += PAGE_SIZE;
}
}
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)
{
size_t end = address + length;
for (size_t page = address & 0xFFFF_FFFF_FFFF_F000u; 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);
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);
if (pte.present)
{
pt = pte.follow();
}
else
{
break;
}
if (pte.huge)
{
break;
}
}
}
private static PageTable * allocate_pt()
{
PageTable * pt = cast(PageTable *)Hippo.allocate_page();
memset64(pt, 0u, PAGE_SIZE / 8u);
return pt;
}
}
+3
View File
@@ -0,0 +1,3 @@
module hulk.hurl;
public import hulk.hurl.hurl;
+87
View File
@@ -0,0 +1,87 @@
/**
* HULK Kernel Log buffer.
*/
module hulk.klog;
import core.stdc.stdarg;
import hulk.console;
static import hulk.writef;
import hulk.cpu;
struct Klog
{
/**
* Kernel buffer size log.
* 16 gives a kernel buffer size of 64KB.
*/
private enum size_t KLOG_SIZE_LOG = 16u;
/** Kernel buffer size. */
private enum size_t KLOG_SIZE = 1u << KLOG_SIZE_LOG;
/** Kernel log buffer. */
private static __gshared align(4096) ubyte[KLOG_SIZE] klog_buffer;
/** Write index in the kernel log buffer. */
private static __gshared size_t klog_index;
/**
* Initialize the klog module.
*/
public static void initialize()
{
}
/**
* Write a formatted string to the kernel log.
*
* @param s Format string.
* @param args Variable arguments structure.
*/
public static void writef(string s, va_list args)
{
hulk.writef.writefv(function void(ubyte ch) {
Console.write(ch);
}, s, args);
}
/**
* Write a formatted string to the kernel log.
*
* @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 kernel log.
*
* @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);
}
/**
* Print a fatal kernel error and loop forever.
*/
public static void fatal_error(T...)(T args)
{
writef("FATAL ERROR: ");
writefln(args);
cli();
for (;;)
{
}
}
}
+139
View File
@@ -0,0 +1,139 @@
/**
* This module provides access to linker-defined symbols.
*/
module hulk.linker_addresses;
private extern extern(C) __gshared ubyte _hulk_header_start;
private extern extern(C) __gshared ubyte _hulk_header_end;
private extern extern(C) __gshared ubyte _hulk_header_size;
private extern extern(C) __gshared ubyte _hulk_text_start;
private extern extern(C) __gshared ubyte _hulk_text_end;
private extern extern(C) __gshared ubyte _hulk_text_size;
private extern extern(C) __gshared ubyte _hulk_rodata_start;
private extern extern(C) __gshared ubyte _hulk_rodata_end;
private extern extern(C) __gshared ubyte _hulk_rodata_size;
private extern extern(C) __gshared ubyte _hulk_data_start;
private extern extern(C) __gshared ubyte _hulk_data_end;
private extern extern(C) __gshared ubyte _hulk_data_size;
private extern extern(C) __gshared ubyte _hulk_bss_start;
private extern extern(C) __gshared ubyte _hulk_bss_end;
private extern extern(C) __gshared ubyte _hulk_bss_size;
/* hulk_binary includes header, text, rodata, and data */
private extern extern(C) __gshared ubyte _hulk_binary_size;
/* hulk_mem includes header, text, rodata, data, and bss */
private extern extern(C) __gshared ubyte _hulk_mem_start;
private extern extern(C) __gshared ubyte _hulk_mem_end;
private extern extern(C) __gshared ubyte _hulk_mem_size;
/**
* This struct provides access to linker-defined symbols.
*/
public struct LinkerAddresses
{
public static @property ulong hulk_header_start()
{
return cast(ulong)&_hulk_header_start;
}
public static @property ulong hulk_header_end()
{
return cast(ulong)&_hulk_header_end;
}
public static @property ulong hulk_header_size()
{
return cast(ulong)&_hulk_header_size;
}
public static @property ulong hulk_text_start()
{
return cast(ulong)&_hulk_text_start;
}
public static @property ulong hulk_text_end()
{
return cast(ulong)&_hulk_text_end;
}
public static @property ulong hulk_text_size()
{
return cast(ulong)&_hulk_text_size;
}
public static @property ulong hulk_rodata_start()
{
return cast(ulong)&_hulk_rodata_start;
}
public static @property ulong hulk_rodata_end()
{
return cast(ulong)&_hulk_rodata_end;
}
public static @property ulong hulk_rodata_size()
{
return cast(ulong)&_hulk_rodata_size;
}
public static @property ulong hulk_data_start()
{
return cast(ulong)&_hulk_data_start;
}
public static @property ulong hulk_data_end()
{
return cast(ulong)&_hulk_data_end;
}
public static @property ulong hulk_data_size()
{
return cast(ulong)&_hulk_data_size;
}
public static @property ulong hulk_bss_start()
{
return cast(ulong)&_hulk_bss_start;
}
public static @property ulong hulk_bss_end()
{
return cast(ulong)&_hulk_bss_end;
}
public static @property ulong hulk_bss_size()
{
return cast(ulong)&_hulk_bss_size;
}
public static @property ulong hulk_binary_size()
{
return cast(ulong)&_hulk_binary_size;
}
public static @property ulong hulk_mem_start()
{
return cast(ulong)&_hulk_mem_start;
}
public static @property ulong hulk_mem_end()
{
return cast(ulong)&_hulk_mem_end;
}
public static @property ulong hulk_mem_size()
{
return cast(ulong)&_hulk_mem_size;
}
}
+100
View File
@@ -0,0 +1,100 @@
/**
* Linked list functionality.
*/
module hulk.list;
/**
* Linked list mixin.
*/
mixin template List(T)
{
/**
* Next item in linked list.
*/
T * list_next;
/**
* Previous item in linked list.
*/
T * list_prev;
/**
* Initialize linked list fields.
*/
public void list_init()
{
list_next = &this;
list_prev = &this;
}
/**
* Add this item after another in a list.
*/
public void list_insert_after(T * item)
{
list_next = item.list_next;
list_prev = item;
item.list_next = &this;
list_next.list_prev = &this;
}
/**
* Add this item before another in a list.
*/
public void list_insert_before(T * item)
{
list_next = item;
list_prev = item.list_prev;
item.list_prev = &this;
list_prev.list_next = &this;
}
/**
* Remove this item from the list.
*/
public void list_remove()
{
list_next.list_prev = list_prev;
list_prev.list_next = list_next;
list_init();
}
/**
* Get the number of items in this list.
*/
public @property size_t list_count() const
{
size_t count = 1;
const(T) * item = &this;
while (item.list_next != &this)
{
count++;
item = item.list_next;
}
return count;
}
/**
* Allow foreach iteration through this linked list.
*/
public int opApply(scope int delegate(T *) dg)
{
T * item = &this;
T * last = item.list_prev;
for (;;)
{
T * next = item.list_next;
int result = dg(item);
if (result != 0)
{
return result;
}
if (item == last)
{
break;
}
item = next;
}
return 0;
}
}
+62
View File
@@ -0,0 +1,62 @@
/**
* Memory-related functions.
*/
module hulk.memory;
import ldc.llvmasm;
void memset(void * dest, ubyte v, size_t n)
{
__asm("rep stosb",
"{al},{rcx},{rdi},~{rcx},~{rdi},~{memory}",
v, n, dest);
}
void memset16(void * dest, ushort v, size_t n)
{
__asm("rep stosw",
"{ax},{rcx},{rdi},~{rcx},~{rdi},~{memory}",
v, n, dest);
}
void memset32(void * dest, uint v, size_t n)
{
__asm("rep stosl",
"{eax},{rcx},{rdi},~{rcx},~{rdi},~{memory}",
v, n, dest);
}
void memset64(void * dest, ulong v, size_t n)
{
__asm("rep stosq",
"{rax},{rcx},{rdi},~{rcx},~{rdi},~{memory}",
v, n, dest);
}
void memcpy(void * dest, const(void) * src, size_t n)
{
__asm("rep movsb",
"{rcx},{rsi},{rdi},~{rcx},~{rsi},~{rdi},~{memory}",
n, src, dest);
}
void memcpy16(void * dest, const(void) * src, size_t n)
{
__asm("rep movsw",
"{rcx},{rsi},{rdi},~{rcx},~{rsi},~{rdi},~{memory}",
n, src, dest);
}
void memcpy32(void * dest, const(void) * src, size_t n)
{
__asm("rep movsl",
"{rcx},{rsi},{rdi},~{rcx},~{rsi},~{rdi},~{memory}",
n, src, dest);
}
void memcpy64(void * dest, const(void) * src, size_t n)
{
__asm("rep movsq",
"{rcx},{rsi},{rdi},~{rcx},~{rsi},~{rdi},~{memory}",
n, src, dest);
}
+70
View File
@@ -0,0 +1,70 @@
/**
* MTRR (Memory Type Range Register) support for HULK.
*/
module hulk.mtrr;
import hulk.cpu;
import hulk.klog;
enum ulong MTRR_TYPE_UC = 0u; /* Uncacheable */
enum ulong MTRR_TYPE_WC = 1u; /* Write-Combining */
enum ulong MTRR_TYPE_WT = 4u; /* Writethrough */
enum ulong MTRR_TYPE_WP = 5u; /* Write-Protect */
enum ulong MTRR_TYPE_WB = 6u; /* Writeback */
enum uint MSR_MTRRCAP = 0xFEu;
enum uint MSR_MTRRDEFTYPE = 0x2FFu;
enum uint MSR_MTRRPHYSBASE0 = 0x200u;
enum uint MSR_MTRRPHYSMASK0 = 0x201u;
enum ulong MTRRCAP_WC = 0x400u;
enum ulong MTRRCAP_FIX = 0x100u;
enum ulong MTRRCAP_VCNT_MASK = 0xFFu;
enum ulong MTRRDEFTYPE_E = 0x800u;
enum ulong MTRRDEFTYPE_FE = 0x400u;
enum ulong MTRRDEFTYPE_TYPE_MASK = 0xFFu;
enum ulong MTRRPHYSBASE_PHYSBASE_MASK = 0x000F_FFFF_FFFF_F000u;
enum ulong MTRRPHYSBASE_TYPE_MASK = 0xFFu;
enum ulong MTRRPHYSMASK_PHYSMASK_MASK = 0x000F_FFFF_FFFF_F000u;
enum ulong MTRRPHYSMASK_VALID = 0x800u;
struct Mtrr
{
public static void initialize()
{
uint ebx;
uint ecx;
uint edx;
cpuid1(&ebx, &ecx, &edx);
if ((edx & CPUID_1_EDX_MTRR) == 0u)
{
Klog.writefln("CPU does not support MTRR");
return;
}
const(ulong) mtrrcap = rdmsr(MSR_MTRRCAP);
const(ulong) mtrrdeftype = rdmsr(MSR_MTRRDEFTYPE);
}
private static ulong get_phys_base(uint n)
{
return rdmsr(MSR_MTRRPHYSBASE0 + 2u * n);
}
private static void set_phys_base(uint n, ulong physbase)
{
wrmsr(MSR_MTRRPHYSBASE0 + 2u * n, physbase);
}
private static ulong get_phys_mask(uint n)
{
return rdmsr(MSR_MTRRPHYSMASK0 + 2u * n);
}
private static void set_phys_mask(uint n, ulong physmask)
{
wrmsr(MSR_MTRRPHYSMASK0 + 2u * n, physmask);
}
}
+193
View File
@@ -0,0 +1,193 @@
/**
* Page table structures.
*/
module hulk.pagetable;
/** Page table entry attributes. @{ */
enum ulong PT_PRESENT = 0x1u;
enum ulong PT_WRITABLE = 0x2u;
enum ulong PT_USER = 0x4u;
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_GLOBAL = 0x100u;
enum ulong PT_NO_EXECUTE = 0x8000_0000_0000_0000u;
/** @} */
/** Page size in bytes. */
enum ulong PAGE_SIZE = 4096u;
/**
* Structure that represents a page table entry.
*/
struct PageTableEntry
{
/** The raw page table entry is a 64-bit ulong. */
public ulong entry;
alias entry this;
/**
* Construct a page table entry.
*
* @param address
* Address pointed to by the page table entry (ulong or pointer).
* @param flags
* Page table flags (ORed set of PT_*).
*/
this(T)(T address, ulong flags = 0u)
{
entry = cast(ulong)address | flags;
}
/**
* Return whether the page is present.
*/
public @property bool present() const
{
return (entry & PT_PRESENT) != 0u;
}
/**
* Return whether the page is writable.
*/
public @property bool writable() const
{
return (entry & PT_WRITABLE) != 0u;
}
/**
* Return whether the page is a user page.
*/
public @property bool user() const
{
return (entry & PT_USER) != 0u;
}
/**
* Return whether the page is write-through.
*/
public @property bool write_through() const
{
return (entry & PT_WRITE_THROUGH) != 0u;
}
/**
* Return whether the page has disable cache set.
*/
public @property bool disable_cache() const
{
return (entry & PT_DISABLE_CACHE) != 0u;
}
/**
* Return whether the page is huge.
*/
public @property bool huge() const
{
return (entry & PT_HUGE_PAGE) != 0u;
}
/**
* Return whether the page is global.
*/
public @property bool global() const
{
return (entry & PT_GLOBAL) != 0u;
}
/**
* Return whether the page is no-execute.
*/
public @property bool no_execute() const
{
return (entry & PT_NO_EXECUTE) != 0u;
}
/**
* Return whether the page is dirty.
*/
public @property bool dirty() const
{
return (entry & PT_DIRTY) != 0u;
}
/**
* Return whether the page is accessed.
*/
public @property bool accessed() const
{
return (entry & PT_ACCESSED) != 0u;
}
/**
* Follow the page table entry to the next page table it points to.
*/
public PageTable * follow() const
{
return cast(PageTable *)(entry & 0x7FFF_FFFF_FFFF_F000u);
}
}
static assert(PageTableEntry.sizeof == 8u);
/**
* Structure that represents a page table.
*/
struct PageTable
{
/** Number of page table entries in a page table. */
enum size_t N_ENTRIES = 512u;
/** Page table entries. */
private PageTableEntry[N_ENTRIES] entries;
/**
* Access the PageTableEntry for the given address and page table level.
*
* @param address
* Address to look up the page table entry (ulong or pointer).
* @param level
* Page table level (0-4).
*/
public PageTableEntry * entry(T)(T address, ulong level)
{
return &entries[index(cast(ulong)address, level)];
}
/**
* Determine the index into the page table for the given address and page
* table level.
*
* @param address
* Address to look up the page table entry (ulong or pointer).
* @param level
* Page table level (0-4).
*/
public ulong index(T)(T address, ulong level)
{
return (cast(ulong)address >> (39u - (9u * level))) & 0x1FFu;
}
/**
* Access a page table entry by linear index.
*
* @param index
* Page table index (0-511).
*
* @return PageTableEntry at the given index.
*/
public PageTableEntry opIndex(size_t index)
{
return entries[index];
}
}
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));
}
+452
View File
@@ -0,0 +1,452 @@
/**
* PCI (Peripheral Component Interconnect) functionality.
*/
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;
import hulk.list;
struct Pci
{
/** IO address for PCI configuration address. */
enum IO_ADDR_CONFIG_ADDRESS = 0xCF8u;
/** IO address for PCI configuration data. */
enum IO_ADDR_CONFIG_DATA = 0xCFCu;
/** Maximum number of devices on a bus. */
enum MAX_DEVICES_PER_BUS = 32;
/** Maximum number of functions on a devices. */
enum MAX_FUNCTIONS_PER_DEVICE = 8;
/** XHCI controller device type. */
enum XHCI_CONTROLLER = Type(0x0Cu, 0x03u, 0x30u);
/**
* MCFG ACPI table structure.
*/
static struct MCFG
{
/* 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);
Acpi.Header header;
uint[2] _reserved;
SGMADesc[0] sgma_descs;
size_t n_sgma_descs()
{
return (header.length - MCFG.sgma_descs.offsetof) / MCFG.SGMADesc.sizeof;
}
}
/**
* PCI device address (bus number, device number, function number).
*/
struct Address
{
uint address;
alias address this;
this(ubyte bus_nr, ubyte device_nr, ubyte function_nr)
{
this.address = (bus_nr << 16u) | (device_nr << 8u) | function_nr;
}
/**
* Bus number (0-255).
*/
public @property ubyte bus_nr() const
{
return cast(ubyte)(address >> 16u);
}
/**
* Device number (0-31).
*/
public @property ubyte device_nr() const
{
return cast(ubyte)(address >> 8u);
}
/**
* Function number (0-7).
*/
public @property ubyte function_nr() const
{
return cast(ubyte)address;
}
}
/**
* PCI device type (class ID, subclass ID, interface ID).
*/
struct Type
{
uint type;
alias type this;
this(ubyte class_id, ubyte subclass_id, ubyte interface_id)
{
this.type = (class_id << 16u) | (subclass_id << 8u) | interface_id;
}
/**
* Class ID.
*/
public @property ubyte class_id() const
{
return cast(ubyte)(type >> 16u);
}
/**
* Subclass ID.
*/
public @property ubyte subclass_id() const
{
return cast(ubyte)(type >> 8u);
}
/**
* Interface ID.
*/
public @property ubyte interface_id() const
{
return cast(ubyte)type;
}
}
/**
* PCI device object.
*/
static struct Device
{
Configuration * config;
Address address;
Type type;
bool multifunction;
Range[6] memory_ranges;
mixin List!Device;
void initialize(Address address, Configuration * config)
{
list_init();
this.config = config;
this.address = address;
type = Type(config.class_id, config.subclass_id, config.interface_id);
Klog.writefln("Found PCI device %04x:%04x (%02x:%02x:%02x) at %02u:%02u.%u",
config.vendor_id, config.device_id,
type.class_id, type.subclass_id, type.interface_id,
address.bus_nr, address.device_nr, address.function_nr);
multifunction = (address.function_nr == 0u) && ((config.header_type & 0x80u) != 0u);
ubyte header_type = config.header_type & 0x7Fu;
if (header_type == 0u)
{
map_memory_regions();
}
}
private void map_memory_regions()
{
size_t range_index;
uint[2] r;
uint[2] s;
for (uint bar_idx = 0u; bar_idx < config.header0.base_addresses.length; bar_idx++)
{
/* Read the BAR. */
r[0] = config.header0.base_addresses[bar_idx];
/* 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) && (bar_idx < 5u))
{
/* 64-bit region. */
is_64bit = true;
r[1] = config.header0.base_addresses[bar_idx + 1];
}
else
{
continue;
}
/* Determine the region length. */
config.header0.base_addresses[bar_idx] = 0xFFFF_FFFFu;
s[0] = config.header0.base_addresses[bar_idx];
config.header0.base_addresses[bar_idx] = r[0];
if (is_64bit)
{
config.header0.base_addresses[bar_idx + 1] = 0xFFFF_FFFFu;
s[1] = config.header0.base_addresses[bar_idx + 1];
config.header0.base_addresses[bar_idx + 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, PT_WRITABLE | flags);
memory_ranges[range_index].address = mm_region_address;
memory_ranges[range_index].length = length;
range_index++;
if (is_64bit)
{
bar_idx++;
}
}
}
}
/**
* Device list.
*/
public static __gshared Device * devices;
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);
return in32(IO_ADDR_CONFIG_DATA);
}
private static void write_config_register(Address address, uint register_id, uint value)
{
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);
}
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)
{
Device * device = A1.allocate!Device();
if (devices == null)
{
devices = device;
}
else
{
device.list_insert_before(devices);
}
device.initialize(Address(bus_nr, device_nr, function_nr), config);
if (device.multifunction)
{
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);
}
}
}
}
public static void initialize()
{
Klog.writefln("\a3Initializing PCI");
MCFG * mcfg = cast(MCFG *)Acpi.get_table("MCFG");
size_t n_sgma_descs = mcfg.n_sgma_descs;
for (size_t i = 0u; i < n_sgma_descs; i++)
{
MCFG.SGMADesc * sgma_desc = &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_WRITABLE | 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);
}
}
}
}
}
+16
View File
@@ -0,0 +1,16 @@
/**
* PIC (Programmable Interrupt Controller) functionality.
*/
module hulk.pic;
import hulk.cpu;
struct Pic
{
public static void initialize()
{
/* Disable the PIC. */
out8(0xA1u, 0xFFu);
out8(0x21u, 0xFFu);
}
}
+45
View File
@@ -0,0 +1,45 @@
/**
* PIT (Programmable Interval Timer) functionality.
*/
module hulk.pit;
import hulk.cpu;
import hulk.klog;
import hulk.console;
import hulk.time;
struct Pit
{
/** PIT input frequency in 1/1000 Hz. */
private enum ulong PIT_FREQUENCY_1000HZ = 1_193_181_667u;
private enum ulong TARGET_INTERRUPT_HZ = 1000u;
private enum ulong TARGET_INTERRUPT_1000HZ = TARGET_INTERRUPT_HZ * 1000u;
private enum ulong PIT_DIVIDER = (PIT_FREQUENCY_1000HZ + TARGET_INTERRUPT_1000HZ / 2u) / TARGET_INTERRUPT_1000HZ;
/** PIT channel 0 I/O port. */
private enum ubyte PORT_CH_0 = 0x40u;
/** PIT channel 1 I/O port. */
private enum ubyte PORT_CH_1 = 0x41u;
/** PIT channel 2 I/O port. */
private enum ubyte PORT_CH_2 = 0x42u;
/** PIT mode/command register I/O port. */
private enum ubyte PORT_MC = 0x43u;
private enum ubyte MC_CH_0 = 0x00u;
private enum ubyte MC_LO_HI = 0x30u;
private enum ubyte MC_RATE_GENERATOR = 0x04u;
private enum ubyte MC_BINARY = 0x00u;
public static void initialize()
{
Klog.writefln("\a3Initializing PIT");
out8(PORT_MC, MC_CH_0 | MC_LO_HI | MC_RATE_GENERATOR | MC_BINARY);
out8(PORT_CH_0, PIT_DIVIDER & 0xFFu);
out8(PORT_CH_0, PIT_DIVIDER >> 8u);
}
public static void isr()
{
Time.ms_isr();
}
}
+27
View File
@@ -0,0 +1,27 @@
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;
}
}
+150
View File
@@ -0,0 +1,150 @@
/**
* RTC (Real-Time Clock) functionality.
*/
module hulk.rtc;
import hulk.cpu;
import hulk.klog;
import hulk.console;
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_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()
{
Klog.writefln("\a3Initializing RTC");
/* 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);
/* 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;
/* Send EOI to enable more RTC interrupts and re-enable NMIs. */
eoi();
time t = Rtc.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);
}
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);
}
public static void isr()
{
static __gshared ulong count;
count++;
if ((count % 1024) == 0u)
{
Console.update_header();
}
eoi();
}
public 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;
}
}
+74
View File
@@ -0,0 +1,74 @@
/**
* 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.writefv(function void(ubyte ch) {
Serial.write(ch);
}, s, args);
}
/**
* 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);
}
}
+139
View File
@@ -0,0 +1,139 @@
/**
* Kernel tests.
*/
module hulk.test;
import hulk.klog;
import hulk.list;
import hulk.time;
import hulk.hurl.a1;
import core.volatile;
struct Test
{
/**
* Run tests.
*/
public static void run()
{
Klog.writefln("\a3Running kernel tests");
test_pit();
test_list();
Klog.writefln("\a3Kernel tests complete");
}
private static void test_pit()
{
Klog.writefln("Testing PIT...");
/* Check that PIT millisecond interrupt is firing. */
size_t uptime = Time.uptime();
while (Time.uptime() <= uptime)
{
}
}
private static void test_list()
{
Klog.writefln("Testing list...");
struct S
{
size_t v;
mixin List!S;
void initialize()
{
list_init();
}
}
S * s1 = A1.allocate!S();
s1.initialize();
s1.v = 33;
assert_eq(1, s1.list_count);
S * s2 = A1.allocate!S();
s2.initialize();
s2.v = 42;
s2.list_insert_after(s1);
S * s3 = A1.allocate!S();
s3.initialize();
s3.v = 55;
s3.list_insert_before(s1);
size_t count;
assert_eq(3, s1.list_count);
assert_eq(3, s2.list_count);
assert_eq(3, s3.list_count);
foreach (entry; *s1)
{
switch (count)
{
case 0:
assert_eq(33, entry.v);
break;
case 1:
assert_eq(42, entry.v);
break;
case 2:
assert_eq(55, entry.v);
break;
case 3:
assert_eq(0, 1);
break;
default:
break;
}
count++;
}
foreach (entry; *s3)
{
if (entry.v == 33)
{
entry.list_remove();
}
}
assert_eq(2, s3.list_count);
count = 0;
foreach (entry; *s3)
{
switch (count)
{
case 0:
assert_eq(55, entry.v);
break;
case 1:
assert_eq(42, entry.v);
break;
case 2:
assert_eq(0, 1);
break;
default:
break;
}
count++;
}
foreach (entry; *s2)
{
if (entry.v == 42)
{
entry.list_remove();
}
}
assert_eq(1, s2.list_count);
assert_eq(1, s3.list_count);
}
private static void assert_eq(T)(T first, T second, size_t line_number = __LINE__)
{
if (first != second)
{
Klog.fatal_error("Assertion failed! %x != %x (line %u)", first, second, line_number);
}
}
private static void assert_neq(T)(T first, T second, size_t line_number = __LINE__)
{
if (first == second)
{
Klog.fatal_error("Assertion failed! %x == %x (line %u)", first, second, line_number);
}
}
}
+143
View File
@@ -0,0 +1,143 @@
/**
* Kernel thread functionality.
*/
module hulk.thread;
import hulk.hurl.a1;
import hulk.him;
import hulk.gdt;
import hulk.memory;
import hulk.list;
import hulk.cpu;
import hulk.hurl;
import ldc.llvmasm;
struct Thread
{
/* TODO: currently kernel thread stack size is fixed. */
enum STACK_SIZE = 16 * 1024;
enum ulong INT_TCTRL_YIELD = 0;
/** Interrupt stack template. */
static immutable __gshared ulong[ISF_COUNT] interrupt_stack_template = [
0x16161616_16161616u, /* RBP */
0x15151515_15151515u, /* R15 */
0x14141414_14141414u, /* R14 */
0x13131313_13131313u, /* R13 */
0x12121212_12121212u, /* R12 */
0x11111111_11111111u, /* R11 */
0x10101010_10101010u, /* R10 */
0x09090909_09090909u, /* R9 */
0x08080808_08080808u, /* R8 */
0x06060606_06060606u, /* RDI */
0x05050505_05050505u, /* RSI */
0x04040404_04040404u, /* RDX */
0x03030303_03030303u, /* RCX */
0x02020202_02020202u, /* RBX */
0x01010101_01010101u, /* RAX */
0u, /* Error Code */
0u, /* RIP */
Gdt.SELECTOR_KERNEL_CODE, /* CS */
0u, /* RFLAGS */
0u, /* RSP */
Gdt.SELECTOR_KERNEL_DATA, /* SS */
];
/** List of all runnable kernel threads. */
private static __gshared Thread * runnable_threads;
/** Currently executing kernel thread. */
static __gshared Thread * current_thread;
/** Current kernel thread stack pointer. */
ulong * stack_pointer;
static assert(stack_pointer.offsetof == 0);
/** Base address of kernel thread stack. */
void * stack_addr;
mixin List!Thread;
/**
* Initialize a kernel thread.
*/
public void initialize(void function() fn)
{
list_init();
suspend_interrupts();
list_insert_after(current_thread);
resume_interrupts();
stack_addr = A1.allocate(STACK_SIZE);
ulong * stack_top = cast(ulong *)(stack_addr + STACK_SIZE);
stack_pointer = stack_top - ISF_COUNT;
memcpy64(stack_pointer, &interrupt_stack_template[0], ISF_COUNT);
stack_pointer[ISF_RIP] = cast(ulong)fn;
stack_pointer[ISF_RFLAGS] = read_rflags();
stack_pointer[ISF_RSP] = cast(ulong)stack_top;
}
/**
* Initialize first kernel thread.
*/
public void initialize_first_thread()
{
list_init();
runnable_threads = &this;
stack_addr = cast(void *)(Hurl.HULK_STACK_TOP - STACK_SIZE);
}
/**
* Initialize kernel threading.
*/
public static void initialize()
{
Thread * thread = A1.allocate!Thread();
thread.initialize_first_thread();
current_thread = thread;
}
/**
* Create and start a kernel thread.
*
* TODO: fn must not return.
* TODO: threads are always runnable.
* TODO: threads cannot be destroyed.
*/
public static Thread * start(void function() fn)
{
Thread * thread = A1.allocate!Thread();
thread.initialize(fn);
swint(INT_TCTRL_YIELD);
return thread;
}
/**
* Trigger a thread management software interrupt.
*/
public static void swint(T1)(T1 v1)
{
mixin(`__asm("int $$`, cast(int)INT_KERNEL_SWINT, `", "{rax}", v1);`);
}
/**
* Handle a thread management software interrupt.
*
* This function is called in interrupt context.
*
* @param stack_frame
* Pointer to the stack frame.
*/
public static void handle_swint(ulong * stack_frame)
{
switch (stack_frame[ISF_RAX])
{
case INT_TCTRL_YIELD:
Thread.current_thread = Thread.current_thread.list_next;
break;
default:
break;
}
}
}
+42
View File
@@ -0,0 +1,42 @@
/**
* Time functionality.
*/
module hulk.time;
import core.volatile;
struct Time
{
/** System uptime (ms). */
private static __gshared ulong s_uptime;
/**
* Millisecond ISR.
*/
public static void ms_isr()
{
s_uptime++;
}
/**
* Get system uptime (ms).
*/
public static @property ulong uptime()
{
return volatileLoad(&s_uptime);
}
/**
* Sleep for the given amount of time (ms).
*
* @param count
* Number of milliseconds to sleep for.
*/
public static void msleep(ulong count)
{
ulong wait_for = uptime() + count + 1;
while (uptime() < wait_for)
{
}
}
}
+3
View File
@@ -0,0 +1,3 @@
module hulk.usb;
public import hulk.usb.usb;
+24
View File
@@ -0,0 +1,24 @@
/**
* USB (Universal Serial Bus) functionality.
*/
module hulk.usb.usb;
import hulk.klog;
import hulk.usb.xhci;
import hulk.pci;
struct Usb
{
public static void initialize()
{
Klog.writefln("\a3Initializing USB");
foreach (pci_device; *Pci.devices)
{
if (pci_device.type == Pci.XHCI_CONTROLLER)
{
XHCI.build(pci_device);
}
}
}
}
+404
View File
@@ -0,0 +1,404 @@
/**
* 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.
*
* All are read-only.
*/
struct CapabilityRegisters
{
/**
* Offset from beginning of capability registers to beginning of
* operational registers.
*/
ubyte capability_length;
ubyte _reserved01;
/**
* Interface version number supported (psuedo-BSD).
*/
ushort hci_version;
/**
* HCSPARAMS1.
* 7:0 number of device slots (MaxSlots)
* 18:8 number of interrupters (MaxIntrs)
* 23:19 reserved
* 31:24 number of ports (MaxPorts)
*/
uint hcs_params1;
/**
* 3:0 isochronous scheduling threshold (IST)
* 7:4 event ring segment table max (ERST Max)
* 20:8 reserved
* 25:21 max scratchpad buffers (high 5 bits; xHCI v1.1+)
* 26 scratchpad restore (SPR)
* 31:27 max scratchpad buffers (low 5 bits)
*/
uint hcs_params2;
/**
* 7:0 U1 device exit latency
* 15:8 reserved
* 31:16 U2 device exit latency
*/
uint hcs_params3;
/**
* 0 64-bit addressing capability (AC64)
* 1 BW negotiation capability (BNC)
* 2 context size (CSZ)
* 3 port power control (PPC)
* 4 port indicators (PIND)
* 5 light HC reset capability (LHRC)
* 6 latency tolerance messaging capability (LTC)
* 7 no secondary SID support (NSS)
* 8 parse all event data (PAE; xHCI v1.1+)
* 9 stopped - short packet capability (SPC; xHCI v1.1+)
* 10 stopped EDTLA capability (SEC; xHCI v1.1+)
* 11 continuous frame ID capability (CFC; xHCI v1.1+)
* 15:12 maximum primary stream array size (MaxPSASize)
* 31:16 xHCI extended capabilities pointer (xECP)
* offset in 32-bit words from base of capability registers to base
* of capabilities list
*/
uint hcc_params1;
/**
* 1:0 reserved
* 31:2 doorbell array offset in 32-bit words
* offset in 32-bit words from base of capability registers to the
* doorbell array
*/
uint doorbell_offset;
/**
* 4:0 reserved
* 31:5 runtime register space offset
*/
uint rts_offset;
/**
* 0 U3 entry capability (U3C)
* 1 ConfigEP command max exit latency too large (CMC)
* 2 force save context capability (FSC)
* 3 compliance transition capability (CTC)
* 4 large ESIT payload capability (LEC)
* 5 configuration information capability (CIC)
* 6 extended TBC capability (ETC)
* 7 extended TBC TRB status capability (ETC_TSC)
* 8 get/set extended property capability (GSC; xHCI v1.1+)
* 9 virtualization based trusted I/O capability (VTC; xHCI v1.2+)
* 31:10 reserved
*/
uint hcc_params2;
/**
* 11:0 reserved
* 31:12 VTIO register space offset (xHCI v1.2+)
*/
uint vtios_offset;
}
static assert(CapabilityRegisters.sizeof == 0x24u);
/**
* Located at offset capability_length from PCI base address.
*/
struct OperationalRegisters
{
/**
* 0 run/stop (RS)
* 1 host controller reset (HCRST)
* 2 interrupter enable (INTE)
* 3 host system error enable (HSEE)
* 6:4 reserved
* 7 light host controller reset (LHCRST)
* 8 controller save state (CSS)
* 9 controller restore state (CRS)
* 10 enable wrap event (EWE)
* 11 enable U3 MFINDEX stop (UE3S)
* 12 stopped short packet enable (SPE; xHCI v1.1+)
* 13 CEM enable (CME; xHCI v1.1+)
* 14 extended TBC enable (ETE; xHCI v1.2+)
* 15 extended TBC TRB status enable (TSC_EN; xHCI v1.2+)
* 16 VTIO enable (VTIOE; xHCI v1.2+)
* 31:17 reserved
*/
uint usb_command;
/**
* 0 HCHalted
* 1 reserved
* 2 Host System Error (HSE)
* 3 Event Interrupt (EINT)
* 4 Port Change Detected (PCD)
* 7:5 reserved
* 8 Save State Status (SSS)
* 9 Restore State Status (RSS)
* 10 Save/Restore Error (SRE)
* 11 Controller Not Ready (CNR)
* 12 Host Controller Error (HCE)
* 31:13 reserved
*/
uint usb_status;
/**
* 15:0 Page Size (actual page size is 2^(x+12))
* 31:16 reserved
*/
uint page_size;
uint[2] _reserved01;
/**
* 15:0 Notification Enable
* 31:16 reserved
*/
uint dn_ctrl;
/**
* 0 Ring Cycle State (RCS)
* 1 Command Stop (CS)
* 2 Command Abort (CA)
* 3 Command Ring Running (CRR)
* 5:4 reserved
* 63:6 Command Ring Pointer
*/
ulong cr_ctrl;
uint[4] _reserved02;
/**
* 5:0 reserved
* 63:6 Device Context Base Address Array Pointer
*/
ulong dcbaap;
/**
* 7:0 Max Device Slots Enabled (MaxSlotsEn)
* 8 U3 Entry Enable (U3E; xHCI v1.1+)
* 9 Configuration Information Enable (CIE; xHCI v1.1+)
* 31:10 reserved
*/
uint config;
uint _reserved03;
}
static assert(OperationalRegisters.sizeof == 0x40u);
/**
* Located at offset 0x400 from start of Operational Registers.
*
* There is one set of these registers for each port of the root hub.
*/
struct PortRegisters
{
/**
* Port Status and Control
*
* 0 Current Connect Status
* 1 Port Enabled/Disabled
* 2 reserved
* 3 Over-current active
* 4 Port Reset
* 8:5 Port Link State
* 9 Port Power
* 13:10 Port Speed
* 15:14 Port Indicator Control
* 16 Port Link State Write Strobe
* 17 Connect Status Change
* 18 Port Enable/Disable Change
* 19 Warm Port Reset Change
* 20 Over-current Change
* 21 Port Reset Change
* 22 Port Link State Change
* 23 Port Config Error Change
* 24 Cold Attach Status
* 25 Wake on Connect Enable
* 26 Wake on Disconnect Enable
* 27 Wake on Over-current Enable
* 29:28 reserved
* 30 Device Removable
* 31 Warm Port Reset
*/
uint portsc;
/**
* Port Power Management Status and Control
*/
uint portpmsc;
/**
* Port Link Info
*/
uint portli;
/**
* Port Hardware LPM Control (xHCI v1.1+)
*/
uint porthlpmc;
}
static assert(PortRegisters.sizeof == 0x10u);
/**
* Located at offset rts_offset from PCI base address.
*/
struct RuntimeRegisters
{
/**
* Microframe index. Incremented by controller each microframe.
*/
uint mfindex;
uint[7] _reserved01;
/**
* Interrupter register sets.
*/
InterrupterRegister[0] ir;
}
/**
* Interrupter register set.
*
* A copy of this register set is present for each interrupter.
*/
struct InterrupterRegister
{
/**
* Interrupter Management Register.
* 0 Interrupt Pending (IP)
* 1 Interrupt Enable
* 31:2 reserved
*/
uint imr;
/**
* Interrupter Moderation.
* 15:0 Interrupt Moderation Interval
* 31:16 Interrupt Moderation Counter
*/
uint im;
/**
* Event Ring Segment Table Size.
* 15:0 Event Ring Segment Table Size
* 31:16 reserved
*/
uint ersts;
uint reserved;
/**
* Event Ring Segment Table Base Address.
* 5:0 reserved
* 63:6 Event Ring Segment Table Base Address
*/
ulong erstba;
/**
* Event Ring Dequeue Pointer.
* 2:0 Dequeue ERST Segment Index
* 3 Event Handler Busy
* 63:4 Event Ring Dequeue Pointer
*/
ulong erdp;
}
/**
* Located at offset doorbell_offset from PCI base address.
*
* The number of these is given by HCSPARAMS1.MaxSlots + 1 (for the command
* ring).
*/
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);
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);
dump_extended_capabilities();
}
private void dump_extended_capabilities()
{
size_t ext_cap_off = (m_capability_registers.hcc_params1 >> 16u);
if (ext_cap_off != 0u)
{
Klog.writefln("Extended capabilities:");
uint * extended_capabilities = cast(uint *)m_capability_registers + ext_cap_off;
for (;;)
{
uint ec0 = extended_capabilities[0];
size_t next_offset = (ec0 >> 8u) & 0xFFu;
size_t len = next_offset;
if (len < 1u)
{
len = 1u;
}
ubyte type = ec0 & 0xFFu;
if (type == 2u)
{
len = 4u;
}
for (size_t i = 0u; i < len; i++)
{
uint ecv = extended_capabilities[i];
Klog.writef(" %02X %02X %02X %02X",
ecv & 0xFFu,
(ecv >> 8u) & 0xFFu,
(ecv >> 16u) & 0xFFu,
(ecv >> 24u) & 0xFFu);
}
Klog.writef("\n");
if (next_offset == 0u)
{
break;
}
extended_capabilities += next_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
@@ -0,0 +1,17 @@
/**
* 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);
}
+3
View File
@@ -0,0 +1,3 @@
module hulk.ver;
enum VERSION = "0.18.0";
+191
View File
@@ -0,0 +1,191 @@
/**
* HULK Formatted stream writing support.
*/
module hulk.writef;
import core.stdc.stdarg;
alias ch_out_fn = void function(ubyte);
/**
* Format a string and write characters to the given output function.
*
* @param ch_out Character output function.
* @param s Format string.
* @param args Variable arguments structure.
*
* @return Number of characters written.
*/
size_t writefv(ch_out_fn ch_out, string s, va_list args)
{
size_t length_written;
bool escape = false;
char pad = ' ';
size_t width;
foreach (char c; s)
{
if (escape)
{
if (c == 'c')
{
ulong ch;
va_arg(args, ch);
ch_out(cast(ubyte)ch);
length_written++;
escape = false;
}
else if (c == 'p')
{
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);
escape = false;
}
else if (c == 'X')
{
ulong v;
va_arg(args, v);
length_written += write_hex(v, true, false, pad, width, ch_out);
escape = false;
}
else if (c == 'u')
{
ulong v;
va_arg(args, v);
length_written += write_udec(v, pad, width, ch_out);
escape = false;
}
else if ((c == '0') && (width == 0u))
{
pad = '0';
}
else if (('0' <= c) && (c <= '9'))
{
width = (width * 10u) + (c - '0');
}
else
{
ch_out(c);
escape = false;
}
}
else if (c == '%')
{
escape = true;
pad = ' ';
width = 0u;
}
else
{
ch_out(c);
}
}
return length_written;
}
/**
* Format a string and write characters to the given output function.
*
* @param ch_out Character output function.
* @param s Format string.
*
* @return Number of characters written.
*/
extern(C) size_t writef(ch_out_fn ch_out, string s, ...)
{
va_list args;
va_start(args, s);
size_t rv = writefv(ch_out, s, args);
va_end(args);
return rv;
}
/**
* Format a value in hexadecimal to the given output function.
*
* @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)
{
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;
do
{
ulong n = v & 0xFu;
buf[buf_idx] = 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++;
}
} while (v != 0u);
size_t length_written = buf_idx;
while (width > buf_idx)
{
ch_out(pad);
width--;
length_written++;
}
do
{
buf_idx--;
ch_out(buf[buf_idx]);
} while (buf_idx != 0u);
return length_written;
}
/**
* Format a value in decimal to the given output function.
*
* @param v Value to format.
* @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_udec(ulong v, char pad, size_t width, ch_out_fn ch_out)
{
char[20] buf;
size_t i;
do
{
ulong d = v % 10u;
buf[i] = cast(char)(d + '0');
v /= 10u;
i++;
} while (v != 0u);
size_t length_written = i;
while (width > i)
{
ch_out(pad);
width--;
length_written++;
}
do
{
i--;
ch_out(buf[i]);
} while (i != 0u);
return length_written;
}
Submodule
+1
Submodule uefi-d added at e70959ce8a.
+85
View File
@@ -0,0 +1,85 @@
project_name "x86_64-elf-gcc"
binutils_version = "2.41"
binutils_checksum = "ae9a5789e23459e59606e6714723f2d3ffc31c03174191ef0d015bdf06007450"
gcc_version = "13.2.0"
gcc_checksum = "e275e76442a6067341a27f04c5c6b83d8613144004c0413528863dc6b5c743da"
install_path = File.expand_path("x86_64-elf-gcc")
target = "x86_64-elf"
path_prepend "#{install_path}/bin"
configure do
check_c_compiler "gcc"
check_program "make"
check_program "bison"
check_program "flex"
check_program "texi2any", on_fail: "Install the texinfo package"
check_program "wget"
check_lib "gmp", on_fail: "Install the libgmp-dev package"
check_lib "mpc", on_fail: "Install the libmpc-dev package"
check_lib "mpfr", on_fail: "Install the libmpfr-dev package"
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
sh %W[../binutils-#{binutils_version}/configure
--target=#{target} --prefix=#{install_path} --with-sysroot --disable-nls
--disable-werror]
sh "make"
sh "make install"
end
# Build gcc.
puts "Building gcc..."
rm_rf "#{build_dir}/build-gcc"
mkdir_p "#{build_dir}/build-gcc"
cd "#{build_dir}/build-gcc" do
sh %W[../gcc-#{gcc_version}/configure
--target=#{target} --prefix=#{install_path} --disable-nls
--enable-languages=c --without-headers]
sh "make all-gcc"
sh "make all-target-libgcc"
sh "make install-gcc"
sh "make install-target-libgcc"
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"
rm_f "#{build_dir}/gcc-#{gcc_version}.tar.xz"
rm_rf "#{build_dir}/gcc-#{gcc_version}"
rm_rf "#{build_dir}/build-gcc"
end
end
distclean do
rm_rf install_path
end