93 Commits
Author SHA1 Message Date
josh f51426f73f fixed memory barrier bug in IDT initialization -- kernel still crashing when interrupts enabled but i think the memory management initialization is correct
git-svn-id: svn://anubis/hos/trunk@102 5b3e749e-e535-0410-8002-a9bb6afbdfca
2010-02-01 05:24:40 +00:00
josh 4b688a3ce0 fixed bug that mapping PAGE_DIR_SELF_REF would incorrectly allocate a new physical page
git-svn-id: svn://anubis/hos/trunk@101 5b3e749e-e535-0410-8002-a9bb6afbdfca
2010-02-01 05:04:39 +00:00
josh 563758b1bd added PAGE_DIR_SELF_REF2 to fix bug in page directory self-referencing
git-svn-id: svn://anubis/hos/trunk@100 5b3e749e-e535-0410-8002-a9bb6afbdfca
2010-02-01 04:21:29 +00:00
josh ae5dc7df6f in the middle of clearing page tables allocated during mm_map() and mm_early_map()
git-svn-id: svn://anubis/hos/trunk@99 5b3e749e-e535-0410-8002-a9bb6afbdfca
2010-02-01 01:47:19 +00:00
josh d41ffbbedc added mm_early_vpage_alloc(); kernel still crashing...
git-svn-id: svn://anubis/hos/trunk@98 5b3e749e-e535-0410-8002-a9bb6afbdfca
2010-01-28 04:22:02 +00:00
josh 5ac343a2e8 fixed mm bug, now crashing because IDT isn't mapped via paging
git-svn-id: svn://anubis/hos/trunk@97 5b3e749e-e535-0410-8002-a9bb6afbdfca
2010-01-27 05:25:05 +00:00
josh 1027b8c346 compiling again after updating mm_early_map() and mm_map() for new page allocation scheme
git-svn-id: svn://anubis/hos/trunk@96 5b3e749e-e535-0410-8002-a9bb6afbdfca
2010-01-27 05:06:12 +00:00
josh 08491bace9 still reworking physical page allocator
git-svn-id: svn://anubis/hos/trunk@95 5b3e749e-e535-0410-8002-a9bb6afbdfca
2010-01-26 05:25:46 +00:00
josh 96ba9fabb1 reworking memory management... again
git-svn-id: svn://anubis/hos/trunk@94 5b3e749e-e535-0410-8002-a9bb6afbdfca
2010-01-25 23:03:23 +00:00
josh 24485b8143 fixed line endings on text files
git-svn-id: svn://anubis/hos/trunk@93 5b3e749e-e535-0410-8002-a9bb6afbdfca
2010-01-25 16:04:08 +00:00
josh ca82cc32ac cleaned up a few page allocation page issues, still crashing
git-svn-id: svn://anubis/hos/trunk@92 5b3e749e-e535-0410-8002-a9bb6afbdfca
2010-01-25 15:59:27 +00:00
josh 4816102139 kernel compiling with new page allocation mechanism but crashing
git-svn-id: svn://anubis/hos/trunk@91 5b3e749e-e535-0410-8002-a9bb6afbdfca
2010-01-25 05:56:40 +00:00
josh 0bc304328d kernel now keeping track of total/free number of physical pages instead of free/used
git-svn-id: svn://anubis/hos/trunk@90 5b3e749e-e535-0410-8002-a9bb6afbdfca
2010-01-22 20:51:34 +00:00
josh dccecb054b fixed BUILD_BUG_ON() to work in C++
git-svn-id: svn://anubis/hos/trunk@89 5b3e749e-e535-0410-8002-a9bb6afbdfca
2010-01-22 20:48:41 +00:00
josh 0c78e21e14 added STACK_INITIAL_SIZE to control the number of initial stack pages; added BUILD_BUG_ON() macro to catch compile-time errors
git-svn-id: svn://anubis/hos/trunk@88 5b3e749e-e535-0410-8002-a9bb6afbdfca
2010-01-22 19:35:43 +00:00
josh 53407d7b59 rearranged slightly
git-svn-id: svn://anubis/hos/trunk@87 5b3e749e-e535-0410-8002-a9bb6afbdfca
2010-01-22 18:19:20 +00:00
josh cdea1602d5 added bochs target to Makefile
git-svn-id: svn://anubis/hos/trunk@86 5b3e749e-e535-0410-8002-a9bb6afbdfca
2010-01-22 18:19:17 +00:00
josh b6bebfd9b4 removed debug print
git-svn-id: svn://anubis/hos/trunk@85 5b3e749e-e535-0410-8002-a9bb6afbdfca
2010-01-14 15:54:16 +00:00
josh 1be6e37961 thanks to bug found by Nick - fixed mmap traversal and size calculation
git-svn-id: svn://anubis/hos/trunk@84 5b3e749e-e535-0410-8002-a9bb6afbdfca
2010-01-14 15:43:49 +00:00
josh 85c5a26631 removed erroneous offset by four when calculating address of mmap structure from bootloader
git-svn-id: svn://anubis/hos/trunk@83 5b3e749e-e535-0410-8002-a9bb6afbdfca
2010-01-14 04:23:26 +00:00
josh eb2dd3b1ad updated start symbol comment
git-svn-id: svn://anubis/hos/trunk@82 5b3e749e-e535-0410-8002-a9bb6afbdfca
2010-01-07 19:14:34 +00:00
josh 6cd78f195f changed kernel stack top to 0x40000000 (1GB) virtual
git-svn-id: svn://anubis/hos/trunk@81 5b3e749e-e535-0410-8002-a9bb6afbdfca
2010-01-07 15:56:53 +00:00
josh e4701b8d96 merged in removing-assembly branch to do more in C
git-svn-id: svn://anubis/hos/trunk@80 5b3e749e-e535-0410-8002-a9bb6afbdfca
2010-01-07 15:38:15 +00:00
josh 76ac4f88a4 set virtual offset to 0x0, kernel now runs in qemu / VirtualBox
git-svn-id: svn://anubis/hos/trunk@73 5b3e749e-e535-0410-8002-a9bb6afbdfca
2010-01-06 05:37:04 +00:00
josh f6e71b9891 minor Makefile improvements
git-svn-id: svn://anubis/hos/trunk@72 5b3e749e-e535-0410-8002-a9bb6afbdfca
2010-01-06 05:04:59 +00:00
josh cf7287d368 removed multiboot kludge; using ELF kernel with different virtual and load addresses
git-svn-id: svn://anubis/hos/trunk@71 5b3e749e-e535-0410-8002-a9bb6afbdfca
2010-01-06 05:02:32 +00:00
josh 44c6bac2af added util folder with build script for i586-elf target cross-compiler
git-svn-id: svn://anubis/hos/trunk@70 5b3e749e-e535-0410-8002-a9bb6afbdfca
2010-01-02 02:10:20 +00:00
josh bc7064e92a got interrupts working, added sys/{pic,timer,cpu} modules, ready to work on multitasking
git-svn-id: svn://anubis/hos/trunk@69 5b3e749e-e535-0410-8002-a9bb6afbdfca
2009-07-29 22:30:52 +00:00
josh 2c5a5d7093 moved gdtr_t definition from mm.h to hos_types.h
git-svn-id: svn://anubis/hos/trunk@68 5b3e749e-e535-0410-8002-a9bb6afbdfca
2009-07-24 17:05:11 +00:00
josh ddd8c9fd71 split mm_map() and mm_page_alloc() into regular and "early" versions (mm_early_map() and mm_early_page_alloc()); removed mm_use_virtual_offset flag
git-svn-id: svn://anubis/hos/trunk@67 5b3e749e-e535-0410-8002-a9bb6afbdfca
2009-07-24 14:51:23 +00:00
josh d7be0159c9 created /kernel/isr subdir, moved isr.asm from boot to isr module, added interrupts.cc for isr() main function and isr_bootstrap() routine
git-svn-id: svn://anubis/hos/trunk@66 5b3e749e-e535-0410-8002-a9bb6afbdfca
2009-07-24 14:19:31 +00:00
josh d352afd079 added int_stack_t type in hos_types.h for interrupt stack access
git-svn-id: svn://anubis/hos/trunk@65 5b3e749e-e535-0410-8002-a9bb6afbdfca
2009-07-24 14:02:11 +00:00
josh 1105e6e203 optimized isr.asm a bit
git-svn-id: svn://anubis/hos/trunk@64 5b3e749e-e535-0410-8002-a9bb6afbdfca
2009-07-24 13:50:29 +00:00
josh 339eef5976 build process generating assembly list files for .asm sources; ignoring .lst files in /kernel/boot
git-svn-id: svn://anubis/hos/trunk@63 5b3e749e-e535-0410-8002-a9bb6afbdfca
2009-07-23 22:03:57 +00:00
josh 6a75fdfc10 Added isr.asm with 50 isr_%d labels defined, ready to call isr()
git-svn-id: svn://anubis/hos/trunk@62 5b3e749e-e535-0410-8002-a9bb6afbdfca
2009-07-23 22:02:11 +00:00
josh 2f810cc2ec Reduced grub timeout in menu.lst
git-svn-id: svn://anubis/hos/trunk@61 5b3e749e-e535-0410-8002-a9bb6afbdfca
2009-07-22 21:00:18 +00:00
josh 63289deade updated include/portio.h to not use gcc-specific "statement blocks" but instead have inportX() be static inline functions. Verified that the compiler does in fact inline them
git-svn-id: svn://anubis/hos/trunk@60 5b3e749e-e535-0410-8002-a9bb6afbdfca
2009-07-20 19:21:20 +00:00
josh e70b1a5213 removed special cases for formatting of lowest signed values due to Corrin' rationale; fixed formatting routines to handle formatting "0" values
git-svn-id: svn://anubis/hos/trunk@59 5b3e749e-e535-0410-8002-a9bb6afbdfca
2009-07-20 19:10:54 +00:00
josh c21caccb1f printing memory map, used pages, and free pages on boot
git-svn-id: svn://anubis/hos/trunk@58 5b3e749e-e535-0410-8002-a9bb6afbdfca
2009-07-16 00:05:44 +00:00
josh fd02ee26e1 added kputs_pad(); implemented padding in kprintf(); put some padding tests in k_main()
git-svn-id: svn://anubis/hos/trunk@57 5b3e749e-e535-0410-8002-a9bb6afbdfca
2009-07-15 14:53:58 +00:00
josh ecd74fe35b starting kio change
git-svn-id: svn://anubis/hos/trunk@56 5b3e749e-e535-0410-8002-a9bb6afbdfca
2009-07-15 02:47:46 +00:00
josh 08af04897c added include/portio.h; using it to update cursor position in kputc()
git-svn-id: svn://anubis/hos/trunk@55 5b3e749e-e535-0410-8002-a9bb6afbdfca
2009-07-14 20:37:10 +00:00
josh 1dd8250048 moved call to stack_bootstrap() into mm_bootstrap() since stack_bootstrap() relies on calling mm_map() and mm_use_virtual_offset was getting unset at the end of mm_bootstrap(); calling k_main() now works!
git-svn-id: svn://anubis/hos/trunk@54 5b3e749e-e535-0410-8002-a9bb6afbdfca
2009-07-14 16:08:06 +00:00
josh 118021a0f6 added Makefile commands to build a binary and an ELF kernel and do disassemble the ELF version
git-svn-id: svn://anubis/hos/trunk@53 5b3e749e-e535-0410-8002-a9bb6afbdfca
2009-07-14 13:50:29 +00:00
josh bf9c7d74eb added mm/stack module; initializing "permanent" stack for kernel use while paging, crashing when calling k_main() though...
git-svn-id: svn://anubis/hos/trunk@52 5b3e749e-e535-0410-8002-a9bb6afbdfca
2009-07-14 13:31:08 +00:00
josh cf2d28f5ce added k_main.cc, need to set up a stack before calling k_main()
git-svn-id: svn://anubis/hos/trunk@51 5b3e749e-e535-0410-8002-a9bb6afbdfca
2009-07-14 03:34:16 +00:00
josh 594625b0fa changed lgdt instruction to load from linear address instead of physical address for [mm_gdtr]
git-svn-id: svn://anubis/hos/trunk@50 5b3e749e-e535-0410-8002-a9bb6afbdfca
2009-07-14 00:26:40 +00:00
josh df719b4281 added code to reset segmentation and enable paging; added fmt_xl2a() in kio; added debug prints in k_bootstrap() since kernel is crashing when trying to enable paging
git-svn-id: svn://anubis/hos/trunk@49 5b3e749e-e535-0410-8002-a9bb6afbdfca
2009-07-13 22:58:48 +00:00
josh 0fb590a407 changed kio routines to accept const char *; added MAKE_DESCRIPTOR() macro to mm
git-svn-id: svn://anubis/hos/trunk@48 5b3e749e-e535-0410-8002-a9bb6afbdfca
2009-07-13 22:38:53 +00:00
josh 5b9651299e fixed a few formatting and string bugs, kprintf() working when called during bootstrapping!
git-svn-id: svn://anubis/hos/trunk@47 5b3e749e-e535-0410-8002-a9bb6afbdfca
2009-07-13 21:54:27 +00:00
josh a4d497544e added memcpy{,w,d}(), memset{,w,d}(); filled in kputc()
git-svn-id: svn://anubis/hos/trunk@46 5b3e749e-e535-0410-8002-a9bb6afbdfca
2009-07-13 21:42:18 +00:00
josh 6a69fd06ec filled in a few more formatting routines; linking with libgcc.a to work with 64-bit unsigned integer division/modulus
git-svn-id: svn://anubis/hos/trunk@45 5b3e749e-e535-0410-8002-a9bb6afbdfca
2009-07-13 20:08:16 +00:00
josh 6a8c7431ff hos_defines.h should include hos_types.h first
git-svn-id: svn://anubis/hos/trunk@44 5b3e749e-e535-0410-8002-a9bb6afbdfca
2009-07-13 17:15:39 +00:00
josh be17cde305 added devices and lang directories, added skeleton kio and string modules
git-svn-id: svn://anubis/hos/trunk@43 5b3e749e-e535-0410-8002-a9bb6afbdfca
2009-07-13 15:34:39 +00:00
josh 1aace858da Moved page_directory from an allocated object to a pointer to a run-time allocated page of RAM
git-svn-id: svn://anubis/hos/trunk@42 5b3e749e-e535-0410-8002-a9bb6afbdfca
2009-07-06 21:48:04 +00:00
josh 784978b131 boot.asm comments
git-svn-id: svn://anubis/hos/trunk@41 5b3e749e-e535-0410-8002-a9bb6afbdfca
2009-07-05 16:38:47 +00:00
josh 54b42c0226 added set_cr3() macro and called it to set the PDBR
git-svn-id: svn://anubis/hos/trunk@40 5b3e749e-e535-0410-8002-a9bb6afbdfca
2009-07-04 00:22:18 +00:00
josh e55f2cdfc4 mapping in kernel virtual address space
git-svn-id: svn://anubis/hos/trunk@39 5b3e749e-e535-0410-8002-a9bb6afbdfca
2009-07-03 20:48:51 +00:00
josh edb1a6426d minor mm.cc comment changes
git-svn-id: svn://anubis/hos/trunk@38 5b3e749e-e535-0410-8002-a9bb6afbdfca
2009-07-02 19:26:52 +00:00
josh f07e34c849 updated link script to pack things better
git-svn-id: svn://anubis/hos/trunk@37 5b3e749e-e535-0410-8002-a9bb6afbdfca
2009-07-02 03:43:44 +00:00
josh e907902ca0 changed mm functions to C++ linkage
git-svn-id: svn://anubis/hos/trunk@36 5b3e749e-e535-0410-8002-a9bb6afbdfca
2009-07-02 03:35:24 +00:00
josh a8947f8aa3 added mm_map() to map addresses and mm_page_alloc() to allocate physical pages
git-svn-id: svn://anubis/hos/trunk@35 5b3e749e-e535-0410-8002-a9bb6afbdfca
2009-07-02 03:28:25 +00:00
josh 2bddc1d428 filled out more of mm_bootstrap() including initializing the free page linked list
git-svn-id: svn://anubis/hos/trunk@34 5b3e749e-e535-0410-8002-a9bb6afbdfca
2009-07-02 01:09:09 +00:00
josh bfb4f3bdd0 changed k_bootstrap from C to C++ source file
git-svn-id: svn://anubis/hos/trunk@33 5b3e749e-e535-0410-8002-a9bb6afbdfca
2009-07-01 21:17:24 +00:00
josh db192f6d36 added CXXFLAGS to disable rtti and exceptions; added C++ support to header files; moved mm.c to mm.cc to use C++ functionality
git-svn-id: svn://anubis/hos/trunk@32 5b3e749e-e535-0410-8002-a9bb6afbdfca
2009-07-01 19:52:18 +00:00
josh 2faa2cc8d6 added mm_bootstrap() skeleton function
git-svn-id: svn://anubis/hos/trunk@31 5b3e749e-e535-0410-8002-a9bb6afbdfca
2009-07-01 17:34:52 +00:00
josh 02c2b25ded added DEPS definition in subdir.mak so dependency files are automatically generated again
git-svn-id: svn://anubis/hos/trunk@30 5b3e749e-e535-0410-8002-a9bb6afbdfca
2009-07-01 12:39:43 +00:00
josh 39ea3f231b added bootstrap_stack so the temporary stack is not in the same place as the page directory
git-svn-id: svn://anubis/hos/trunk@29 5b3e749e-e535-0410-8002-a9bb6afbdfca
2009-07-01 01:53:43 +00:00
josh 981a01ba9b added linker script symbols and address macros to hos_defines.h
git-svn-id: svn://anubis/hos/trunk@28 5b3e749e-e535-0410-8002-a9bb6afbdfca
2009-07-01 01:51:02 +00:00
josh 3eea1b4fd3 building in linux with i586-elf cross-compiler as well
git-svn-id: svn://anubis/hos/trunk@27 5b3e749e-e535-0410-8002-a9bb6afbdfca
2009-06-30 23:31:30 +00:00
josh be8d6015ff Added mm_record_mmap_entry() and calls to it in k_bootstrap().
git-svn-id: svn://anubis/hos/trunk@26 5b3e749e-e535-0410-8002-a9bb6afbdfca
2009-06-30 21:29:44 +00:00
josh 6ea8fe1a27 Added k_bootstrap.c, k_early_panic.[ch]
Calling k_bootstrap() from boot.asm in segmented mode

git-svn-id: svn://anubis/hos/trunk@25 5b3e749e-e535-0410-8002-a9bb6afbdfca
2009-06-30 20:12:39 +00:00
josh d4f5a0b244 Added multiboot.h
git-svn-id: svn://anubis/hos/trunk@24 5b3e749e-e535-0410-8002-a9bb6afbdfca
2009-06-30 18:17:20 +00:00
josh 1548e7327a added SUBDIRS support to subdir.mak for recursive building
git-svn-id: svn://anubis/hos/trunk@23 5b3e749e-e535-0410-8002-a9bb6afbdfca
2009-06-30 17:54:09 +00:00
josh 90e03d4f95 Added include folder with hos_types.h and hos_defines.h
Added mm build subdir with mm.c
Updated subdir.mak to build $(subdir)_all.o instead of $(subdir).o
Updated main Makefile to pass SUBDIR in to subdirectory builds, add $(HOS_TOPLEVEL)/include to compiler include path, and made the linker write a map file
Updated boot.asm to use the page_directory symbol from the .bss section defined in mm.o as its temporary stack area

git-svn-id: svn://anubis/hos/trunk@22 5b3e749e-e535-0410-8002-a9bb6afbdfca
2009-06-29 19:55:50 +00:00
josh fb807847bf fixed SUBDIRS_clean definition in Makefile
git-svn-id: svn://anubis/hos/trunk@21 5b3e749e-e535-0410-8002-a9bb6afbdfca
2009-06-29 13:40:33 +00:00
josh d8f7e731e1 moved boot.asm into kernel/boot, added kernel/boot/Makefile using new subdir.mak
git-svn-id: svn://anubis/hos/trunk@20 5b3e749e-e535-0410-8002-a9bb6afbdfca
2009-06-25 21:57:50 +00:00
josh a5ca4348d9 changing Makefile system a bit, again
git-svn-id: svn://anubis/hos/trunk@19 5b3e749e-e535-0410-8002-a9bb6afbdfca
2009-06-25 19:46:49 +00:00
josh 8fe8d78051 realigned assembly a bit
git-svn-id: svn://anubis/hos/trunk@18 5b3e749e-e535-0410-8002-a9bb6afbdfca
2009-06-25 19:12:25 +00:00
josh 1b0da72e5a moved PLATFORM and associated definitions from Makefile to kernel/Makefile so the kernel can be built by itself
git-svn-id: svn://anubis/hos/trunk@17 5b3e749e-e535-0410-8002-a9bb6afbdfca
2009-06-25 18:03:39 +00:00
josh 8493002072 removed jump at start symbol since the bootloader starts after the multiboot header anyway; added diagnostic characters "a", "b"
git-svn-id: svn://anubis/hos/trunk@16 5b3e749e-e535-0410-8002-a9bb6afbdfca
2009-06-25 15:16:01 +00:00
josh 1ba82ac77f added svn:ignore to a few directories; kernel linked to virtual address 0xE000_0000 and running there in segmented mode
git-svn-id: svn://anubis/hos/trunk@15 5b3e749e-e535-0410-8002-a9bb6afbdfca
2009-06-25 15:02:46 +00:00
josh 13f467ca47 i guess genisoimage likes to modify iso/boot/grub/stage2_eltorito
git-svn-id: svn://anubis/hos/trunk@14 5b3e749e-e535-0410-8002-a9bb6afbdfca
2009-06-25 13:17:48 +00:00
josh 81a56c9fcf build system works using i586-elf cross-compiler in cygwin
git-svn-id: svn://anubis/hos/trunk@13 5b3e749e-e535-0410-8002-a9bb6afbdfca
2009-06-25 13:16:22 +00:00
josh 788597b6f4 added linker script
git-svn-id: svn://anubis/hos/trunk@12 5b3e749e-e535-0410-8002-a9bb6afbdfca
2009-06-24 21:53:32 +00:00
josh 09fb19df15 little Makefile change
git-svn-id: svn://anubis/hos/trunk@11 5b3e749e-e535-0410-8002-a9bb6afbdfca
2009-06-24 18:30:57 +00:00
josh af529606e9 load address changed to 1MB
git-svn-id: svn://anubis/hos/trunk@7 5b3e749e-e535-0410-8002-a9bb6afbdfca
2007-07-25 03:30:16 +00:00
josh f58228c559 fixed sample boot.asm, changed Makefile target to $(ISO)
git-svn-id: svn://anubis/hos/trunk@6 5b3e749e-e535-0410-8002-a9bb6afbdfca
2007-07-25 03:16:59 +00:00
josh 8f00324b30 bootable with small multiboot kernel
git-svn-id: svn://anubis/hos/trunk@5 5b3e749e-e535-0410-8002-a9bb6afbdfca
2007-07-25 03:00:58 +00:00
josh bdf4ce8ae8 added clean target
git-svn-id: svn://anubis/hos/trunk@4 5b3e749e-e535-0410-8002-a9bb6afbdfca
2007-07-25 01:18:24 +00:00
josh e124ac5b1b Makefiles created, added initial iso directory
git-svn-id: svn://anubis/hos/trunk@3 5b3e749e-e535-0410-8002-a9bb6afbdfca
2007-07-25 01:08:19 +00:00
josh fba9e3ea54 created kernel directory
git-svn-id: svn://anubis/hos/trunk@2 5b3e749e-e535-0410-8002-a9bb6afbdfca
2007-07-23 03:32:19 +00:00
josh 43d1ca0e18 initial creation of trunk directory
git-svn-id: svn://anubis/hos/trunk@1 5b3e749e-e535-0410-8002-a9bb6afbdfca
2007-07-23 03:11:24 +00:00
75 changed files with 2155 additions and 3912 deletions

No files matched your search

-3
View File
@@ -1,3 +0,0 @@
.rscons*
/x86_64-elf-gcc/
/build/
-3
View File
@@ -1,3 +0,0 @@
[submodule "uefi-d"]
path = uefi-d
url = git://github.com/kubasz/uefi-d
+37
View File
@@ -0,0 +1,37 @@
KERNEL_FILE := hos.gz
MKISOFS := genisoimage
ISO := hos.iso
QEMU := qemu-system-x86_64
BOCHS := bochs
# default target: build the kernel and ISO image
all: kernel iso
# build the kernel
.PHONY: kernel
kernel:
$(MAKE) -C $@
# build the ISO image
.PHONY: iso
iso: $(ISO) kernel
$(ISO): kernel
cp kernel/$(KERNEL_FILE) iso/boot
-rm -f $(ISO)
$(MKISOFS) -R -b boot/grub/stage2_eltorito -no-emul-boot \
-boot-load-size 4 -boot-info-table -o $(ISO) iso
.PHONY: qemu
qemu: iso
$(QEMU) -cdrom $(ISO) -boot d -m 384 -localtime
.PHONY: bochs
bochs: iso
-$(BOCHS)
.PHONY: clean
clean:
$(MAKE) -C kernel clean
-rm -f $(ISO) iso/boot/$(KERNEL_FILE)
-71
View File
@@ -1,71 +0,0 @@
# 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
## 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 Storage, add a hard disk and browse to select the HOS.vmdk file.
16. To run HOS, either start the VM through VirtualBox or with "./rscons run-vb".
-201
View File
@@ -1,201 +0,0 @@
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 = 18
# One kilobyte.
KB = 1024
# One megabyte.
MB = 1024 * 1024
class HulkBinObj < Builder
def run(options)
FileUtils.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[-mtriple=x86_64-unknown-elf -mattr=#{cpu_attrs.join(",")} --betterC -release -O3 --wi --enable-cross-module-inlining -code-model=large]
env["D_IMPORT_PATH"] += %w[src]
env["D_IMPORT_PATH"] << env.expand("^/src")
env["LD"] = "x86_64-elf-gcc"
env["LDFLAGS"] += %w[-nostdlib -Tsrc/hulk/hulk.ld -Wl,-Map,${_TARGET}.map]
env["LDCMD"] = %w[${LD} -o ${_TARGET} ${LDFLAGS} ${_SOURCES} ${LIBDIRPREFIX}${LIBPATH} ${LIBLINKPREFIX}${LIBS}]
env["OBJDUMP"] = "x86_64-elf-objdump"
env["OBJCOPY"] = "x86_64-elf-objcopy"
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.size", "^/hulk.elf")
env.Disassemble("^/hulk.txt", "^/hulk.elf")
env.Command("^/hulk.bin", "^/hulk.elf",
"CMD" => %W[${OBJCOPY} -O binary ${_SOURCES} ${_TARGET}],
"CMD_DESC" => "Convert ELF to binary:")
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"] += 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[-mtriple=x86_64-unknown-windows-coff --betterC -release -O3 --wi --enable-cross-module-inlining]
env["D_IMPORT_PATH"] += %w[src uefi-d/source]
env["LD"] = "x86_64-w64-mingw32-gcc"
env["LDFLAGS"] += %w[-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
Dir.mktmpdir do |tmpdir|
img = hello_env.expand("^/HOS.img")
FileUtils.cp(img, tmpdir)
sh %W[qemu-system-x86_64 -cpu max -bios OVMF.fd -drive file=#{tmpdir}/HOS.img,format=raw -device qemu-xhci -device usb-tablet]
end
end
# See README.md for how to set up VirtualBox for HOS.
task "mk-vmdk", desc: "Create VirtualBox VMDK virtual drive for HOS" do
sh %W[VBoxManage internalcommands createrawvmdk -filename HOS.vmdk -rawdisk #{File.expand_path(hello_env.expand("^/HOS.img"))}]
end
# See README.md for how to set up VirtualBox for HOS.
task "run-vb", desc: "Run HOS in VirtualBox" do
sh %W[VBoxManage startvm HOS]
end
+52
View File
@@ -0,0 +1,52 @@
# configuration file generated by Bochs
plugin_ctrl: unmapped=1, biosdev=1, speaker=1, extfpuirq=1, gameport=1, pci_ide=1, acpi=1, ioapic=1
config_interface: textconfig
display_library: sdl
megs: 32
romimage: file="/usr/share/bochs/BIOS-bochs-latest"
vgaromimage: file="/usr/share/bochs/VGABIOS-lgpl-latest"
boot: cdrom
floppy_bootsig_check: disabled=0
# no floppya
# no floppyb
ata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14
ata0-master: type=cdrom, path="hos.iso", status=inserted, biosdetect=auto, model="Generic 1234"
ata1: enabled=1, ioaddr1=0x170, ioaddr2=0x370, irq=15
ata2: enabled=0
ata3: enabled=0
parport1: enabled=1, file=""
parport2: enabled=0
com1: enabled=1, mode=null, dev=""
com2: enabled=0
com3: enabled=0
com4: enabled=0
usb_uhci: enabled=0
usb_ohci: enabled=0
i440fxsupport: enabled=1
vga_update_interval: 50000
vga: extension=vbe
cpu: count=1, ips=4000000, reset_on_triple_fault=1, cpuid_limit_winnt=0
print_timestamps: enabled=0
# no gdb stub
port_e9_hack: enabled=0
text_snapshot_check: enabled=0
private_colormap: enabled=0
clock: sync=none, time0=local
# no cmosimage
ne2k: enabled=0
pnic: enabled=0
sb16: enabled=0
# no loader
log: -
logprefix: %t%e%d
panic: action=ask
error: action=report
info: action=report
debug: action=ignore
pass: action=fatal
keyboard_type: mf
keyboard_serial_delay: 250
keyboard_paste_delay: 100000
keyboard_mapping: enabled=0, map=
user_shortcut: keys=none
mouse: enabled=0, type=ps2
Binary file not shown.
+6
View File
@@ -0,0 +1,6 @@
timeout 2
default 0
title HOS
kernel /boot/hos.gz
Binary file not shown.
+45
View File
@@ -0,0 +1,45 @@
CROSS_COMPILE := i586-elf-
export LD := $(CROSS_COMPILE)ld
export CC := $(CROSS_COMPILE)gcc
export CXX := $(CROSS_COMPILE)g++
export OBJDUMP := $(CROSS_COMPILE)objdump
export NASM := nasm
export HOS_TOPLEVEL := $(shell pwd)
LDSCRIPT := link.ld
KERNEL := hos
export CPPFLAGS := -I$(HOS_TOPLEVEL) -I$(HOS_TOPLEVEL)/include
export CFLAGS := -Wall -O2 -g
export CXXFLAGS := -Wall -O2 -fno-rtti -fno-exceptions -g
export LDFLAGS := -T $(LDSCRIPT) -Map $(KERNEL).map
export LDLIBS := `$(CC) -print-libgcc-file-name`
SUBDIRS := boot mm lang isr sys
SUBDIRS_clean := $(SUBDIRS:%=%.clean)
.PHONY: all
all: $(KERNEL).gz
$(KERNEL).gz: $(KERNEL)
gzip -c $< > $@
$(KERNEL): $(KERNEL).o
$(LD) $(LDFLAGS) -o $@ $<
$(OBJDUMP) --disassemble --source $@ > $@.dump
# strip $@
$(KERNEL).o: $(SUBDIRS)
$(LD) -r -o $@ $(foreach subdir,$(SUBDIRS),$(subdir)/$(subdir)_all.o) $(LDLIBS)
.PHONY: $(SUBDIRS)
$(SUBDIRS):
$(MAKE) -C $@ SUBDIR=$@
.PHONY: clean
clean: $(SUBDIRS_clean)
-rm -f *~ $(KERNEL) $(KERNEL).{gz,o,elf,dump,map}
%.clean:
$(MAKE) -C $* clean clean=1
+2
View File
@@ -0,0 +1,2 @@
include $(HOS_TOPLEVEL)/subdir.mak
+23
View File
@@ -0,0 +1,23 @@
; boot.asm
; Author: Josh Holtrop
; Date: 2009-06-25
; Adapted from HOS 0.16 source
%define CONSOLE_MEMORY 0xB8000
; Symbols from C
extern k_bootstrap, bootstrap_stack
;**************************************************************************
;* This is the entry point for the kernel. *
;**************************************************************************
[global start]
start:
mov cx, 0x0700 + 'a'
mov [CONSOLE_MEMORY+160*8+0*2], cx
mov esp, bootstrap_stack+4096 ; set up temporary stack space
push eax ; multiboot bootloader magic value
push ebx ; pointer to multiboot info struct
call k_bootstrap
+85
View File
@@ -0,0 +1,85 @@
#include "k_bootstrap.h"
#include "k_main.h"
#include "hos_types.h"
#include "hos_defines.h"
#include "multiboot.h"
#include "sys/cpu.h"
#include "k_early_panic.h"
#include "mm/mm.h"
#include "mm/stack.h"
#include "lang/kio.h"
#include "isr/interrupts.h"
#define DEBUG_LETTER(col,chr) *(u16_t *)(KERNEL_OFFSET + CONSOLE_MEMORY \
+ 160 * 8 + (col) * 2) \
= 0x0700 | (chr)
extern "C" {
u8_t bootstrap_stack[4096];
/**************************************************************************
* Multiboot header data block *
*************************************************************************/
u32_t mb_header[] __attribute__ ((section (".multiboot_header") )) = {
MB_HEADER_MAGIC, /* magic */
MB_HEADER_FLAGS, /* flags */
-(MB_HEADER_MAGIC + MB_HEADER_FLAGS) /* checksum */
};
/**************************************************************************
* This function is invoked to bootstrap the kernel. *
*************************************************************************/
void k_bootstrap(mb_info_t * mb_info, u32_t mb_magic)
{
DEBUG_LETTER(1, 'b');
if (mb_magic != MB_BOOTLOADER_MAGIC)
{
k_early_panic("Bad multiboot magic identifier!");
}
if ( ! (mb_info->flags & MB_BOOTLOADER_MMAP) )
{
k_early_panic("No memory map provided by bootloader!");
}
for (mb_mmap_t * mmap = (mb_mmap_t *) (mb_info->mmap_addr + KERNEL_OFFSET),
* end = (mb_mmap_t *) ((u32_t)mmap + mb_info->mmap_length);
mmap < end;
mmap = (mb_mmap_t *) (((u32_t)mmap) + mmap->size + 4))
{
// kprintf(" ** size: %d, type: %d ", mmap->size, mmap->type);
mm_record_mmap_entry(mmap);
}
DEBUG_LETTER(2, 'c');
/*
* These functions could destroy the multiboot information block and
* associated structures, so we must be finished reading those structures
* before calling them.
*/
mm_bootstrap();
DEBUG_LETTER(3, 'd');
interrupts_bootstrap();
DEBUG_LETTER(4, 'e');
kio_bootstrap();
DEBUG_LETTER(5, 'f');
/* begin using the permanent stack */
write_esp(KERNEL_STACK_TOP);
k_main();
idle_loop();
}
void idle_loop()
{
for (;;)
{
__asm__ __volatile__ ("hlt");
}
}
} /* extern "C" */
+17
View File
@@ -0,0 +1,17 @@
#ifndef K_BOOTSTRAP_H
#define K_BOOTSTRAP_H
#include "hos_types.h"
#include "multiboot.h"
extern "C" {
void k_bootstrap(mb_info_t * mb_info, u32_t mb_magic)
__attribute__ ((noreturn));
void idle_loop()
__attribute__ ((noreturn));
}
#endif
+18
View File
@@ -0,0 +1,18 @@
#include "hos_types.h"
#include "hos_defines.h"
#include "k_early_panic.h"
void k_early_panic(const char * msg)
{
char * dest = (char *) (CONSOLE_MEMORY + KERNEL_OFFSET);
while (*msg)
{
*dest++ = *msg++;
*dest++ = 0x04; /* red error message */
}
/* infinite loop */
for (;;)
;
}
+15
View File
@@ -0,0 +1,15 @@
#ifndef K_EARLY_PANIC_H
#define K_EARLY_PANIC_H
#ifdef __cplusplus
extern "C" {
#endif
void k_early_panic(const char * msg);
#ifdef __cplusplus
}
#endif
#endif
+28
View File
@@ -0,0 +1,28 @@
#include "k_main.h"
#include "lang/kio.h"
#include "mm/mm.h"
#include "sys/timer.h"
#include "sys/pic.h"
#include "isr/interrupts.h"
extern "C" {
void k_main()
{
kprintf("Kernel load address: 0x%08x\n", KERNEL_CODE);
kprintf("Kernel code size: %d KB (%d bytes)\n",
(KERNEL_DATA - KERNEL_CODE) >> 10, KERNEL_DATA - KERNEL_CODE);
kprintf("Kernel data size: %d KB (%d bytes)\n",
(KERNEL_BSS - KERNEL_DATA) >> 10, KERNEL_BSS - KERNEL_DATA);
kprintf("Kernel bss size: %d KB (%d bytes)\n",
(KERNEL_END - KERNEL_BSS) >> 10, KERNEL_END - KERNEL_BSS);
mm_print_memory_map();
timer_init(KERNEL_TIMER_FREQ);
pic_remap(0x20, 0x28);
pic_mask1(0x0);
pic_mask2(0x0);
interrupts_enable();
}
} /* extern "C" */
+11
View File
@@ -0,0 +1,11 @@
#ifndef K_MAIN_H
#define K_MAIN_H
extern "C" {
void k_main();
}
#endif
+47
View File
@@ -0,0 +1,47 @@
#ifndef HOS_DEFINES_H
#define HOS_DEFINES_H
#include "hos_types.h"
#define KERNEL_OFFSET 0x00000000
#define PAGE_LOG_SIZE 12u
#define PAGE_SIZE (1 << PAGE_LOG_SIZE)
#define PAGE_HIGH_MASK (0xFFFFFFFFu << PAGE_LOG_SIZE)
#define PAGE_LOW_MASK (0xFFFFFFFFu >> (32 - PAGE_LOG_SIZE))
#define CONSOLE_MEMORY 0xB8000
#define KERNEL_CODE (&_code)
#define KERNEL_DATA (&_data)
#define KERNEL_BSS (&_bss)
#define KERNEL_END (&_end)
#define KERNEL_PHYSICAL_ADDRESS ((u32_t)(KERNEL_CODE - KERNEL_OFFSET))
#define KERNEL_VIRTUAL_ADDRESS ((u32_t)KERNEL_CODE)
#define KERNEL_SIZE ((u32_t)(KERNEL_END - KERNEL_CODE))
#define KERNEL_TIMER_FREQ 1000
#define BUILD_BUG_ON(condition) \
do { \
typedef struct { int negative_width_test : ((condition)?-1:1); } \
BUILD_BUG_ON_DUMMY_STRUCT; \
} \
while(0)
#ifdef __cplusplus
extern "C" {
#endif
extern u8_t _code;
extern u8_t _data;
extern u8_t _bss;
extern u8_t _end;
#ifdef __cplusplus
}
#endif
#endif
+55
View File
@@ -0,0 +1,55 @@
#ifndef HOS_TYPES_H
#define HOS_TYPES_H
#ifdef __cplusplus
extern "C" {
#endif
typedef unsigned char u8_t;
typedef signed char s8_t;
typedef unsigned short u16_t;
typedef signed short s16_t;
typedef unsigned int u32_t;
typedef signed int s32_t;
typedef unsigned long long u64_t;
typedef signed long long s64_t;
typedef struct
{
u32_t gs;
u32_t fs;
u32_t es;
u32_t ds;
u32_t edi;
u32_t esi;
u32_t ebp;
u32_t esp_junk; /* the esp value saved by 'pusha' */
u32_t ebx;
u32_t edx;
u32_t ecx;
u32_t eax;
u32_t error; /* valid on exceptions 8, 10-14 */
u32_t eip;
u32_t cs;
u32_t eflags;
u32_t esp; /* present if privilege transition */
u32_t ss;
} int_stack_t;
typedef struct
{
u16_t limit;
u32_t base;
} __attribute__ ((packed)) gdtr_t;
typedef gdtr_t idtr_t;
#ifdef __cplusplus
}
#endif
#endif
+154
View File
@@ -0,0 +1,154 @@
#ifndef MULTIBOOT_H
#define MULTIBOOT_H
#include "hos_types.h"
#ifdef __cplusplus
extern "C" {
#endif
/* The magic number for the Multiboot header. */
#define MB_HEADER_MAGIC 0x1BADB002
#define MB_HEADER_FLAGS 0x00000003
#define MB_HEADER_ALIGN_MODULES (1 << 0)
#define MB_HEADER_MEM_INFO (1 << 1)
#define MB_HEADER_VIDEO_INFO (1 << 2)
#define MB_HEADER_KLUDGE_OFFSETS (1 << 16)
/* The magic number passed by a Multiboot-compliant boot loader. */
#define MB_BOOTLOADER_MAGIC 0x2BADB002
#define MB_BOOTLOADER_MEM_INFO (1 << 0)
#define MB_BOOTLOADER_BOOT_DEVICE (1 << 1)
#define MB_BOOTLOADER_COMMAND_LINE (1 << 2)
#define MB_BOOTLOADER_MODS (1 << 3)
#define MB_BOOTLOADER_AOUT (1 << 4)
#define MB_BOOTLOADER_ELF (1 << 5)
#define MB_BOOTLOADER_MMAP (1 << 6)
#define MB_BOOTLOADER_DRIVES (1 << 7)
#define MB_BOOTLOADER_CONFIG (1 << 8)
#define MB_BOOTLOADER_APM (1 << 9)
#define MB_BOOTLOADER_GRAPHICS (1 << 10)
#define MB_DRIVE_MODE_CHS 0
#define MB_DRIVE_MODE_LBA 1
#define MB_MMAP_TYPE_RAM 1
/* The Multiboot header. */
typedef struct
{
u32_t magic;
u32_t flags;
u32_t checksum;
u32_t header_addr; // if flags[16]
u32_t load_addr; // if flags[16]
u32_t load_end_addr; // if flags[16]
u32_t bss_end_addr; // if flags[16]
u32_t entry_addr; // if flags[16]
u32_t mode_type; // if flags[2]
u32_t width; // if flags[2]
u32_t height; // if flags[2]
u32_t depth; // if flags[2]
} mb_header_t;
/* The symbol table for a.out. */
typedef struct
{
u32_t tabsize;
u32_t strsize;
u32_t addr;
u32_t reserved;
} mb_aout_symbol_table_t;
/* The section header table for ELF. */
typedef struct
{
u32_t num;
u32_t size;
u32_t addr;
u32_t shndx;
} mb_elf_section_header_table_t;
/* The Multiboot information. */
typedef struct
{
u32_t flags;
u32_t mem_lower; // present if flags[0] is set
u32_t mem_upper;
u32_t boot_device; // 1
u32_t cmdline; // 2
u32_t mods_count; // 3
u32_t mods_addr; // 3
union
{
mb_aout_symbol_table_t aout_sym; // 4
mb_elf_section_header_table_t elf_sec; // 5
};
u32_t mmap_length; // 6
u32_t mmap_addr; // 6
u32_t drives_length; // 7
u32_t drives_addr; // 7
u32_t config_table; // 8
u32_t bootloader_name; // 9
u32_t apm_table; // 10
u32_t vbe_control_info; // 11
u32_t vbe_mode_info; // 11
u16_t vbe_mode; // 11
u16_t vbe_interface_seg; // 11
u16_t vbe_interface_off; // 11
u16_t vbe_interface_len; // 11
} mb_info_t;
/* The module structure. */
typedef struct
{
u32_t mod_start;
u32_t mod_end;
u32_t string;
u32_t reserved;
} mb_module_t;
/* The memory map. Be careful that the offset 0 is base_addr_low, not size. */
typedef struct
{
u32_t size; // offset -4
u64_t base; // offset 0
u64_t length;
u32_t type;
} mb_mmap_t;
/* The drive structure */
typedef struct
{
u32_t size;
u8_t drive_number;
u8_t drive_mode;
u8_t drive_cylinders;
u8_t drive_heads;
u8_t drive_sectors;
u16_t drive_ports[1];
} mb_drive_t;
/* APM table structure */
typedef struct
{
u16_t version;
u16_t cseg;
u32_t offset;
u16_t cseg_16;
u16_t dseg;
u16_t flags;
u16_t cseg_len;
u16_t cseg_16_len;
u16_t dseg_len;
} mb_apm_t;
#ifdef __cplusplus
}
#endif
#endif
+37
View File
@@ -0,0 +1,37 @@
#ifndef PORTIO_H
#define PORTIO_H
#include "hos_types.h"
#define outportb(port, val) \
__asm__ __volatile__ ("outb %%al, %%dx" : : "a" (val), "d" (port));
#define outportw(port, val) \
__asm__ __volatile__ ("outw %%ax, %%dx" : : "a" (val), "d" (port));
#define outportd(port, val) \
__asm__ __volatile__ ("outl %%eax, %%dx" : : "a" (val), "d" (port));
static inline u8_t inportb(u16_t port)
{
u8_t val;
__asm__ __volatile__ ("inb %%dx, %%al" : "=a" (val) : "d" (port));
return val;
}
static inline u16_t inportw(u16_t port)
{
u16_t val;
__asm__ __volatile__ ("inw %%dx, %%al" : "=a" (val) : "d" (port));
return val;
}
static inline u32_t inportd(u16_t port)
{
u32_t val;
__asm__ __volatile__ ("inl %%dx, %%al" : "=a" (val) : "d" (port));
return val;
}
#endif
+2
View File
@@ -0,0 +1,2 @@
include $(HOS_TOPLEVEL)/subdir.mak
+110
View File
@@ -0,0 +1,110 @@
#include "hos_types.h"
#include "interrupts.h"
#include "mm/mm.h"
#include "lang/kio.h"
#include "sys/pic.h"
#include "sys/cpu.h"
extern "C" {
idtr_t idtr;
void isr(u8_t int_num, int_stack_t * istack)
{
switch (int_num)
{
case 0x20: /* timer interrupt */
(*(u16_t *)CONSOLE_MEMORY)++;
pic_eoi();
break;
case 0x21:
/* TODO: keyboard hook */
pic_eoi();
break;
default:
kputs("--------------------------------------------------------------------------------");
kprintf("Unhandled Interrupt #%d\n", int_num);
kprintf(" ds: 0x%08x es: 0x%08x fs: 0x%08x gs: 0x%08x\n",
istack->ds, istack->es, istack->fs, istack->gs);
kprintf(" eax: 0x%08x ebx: 0x%08x ecx: 0x%08x edx: 0x%08x\n",
istack->eax, istack->ebx, istack->ecx, istack->edx);
kprintf(" ebp: 0x%08x esi: 0x%08x edi: 0x%08x eflags: 0x%08x\n",
istack->ebp, istack->esi, istack->edi, istack->eflags);
kprintf(" cs: 0x%08x eip: 0x%08x ss: 0x%08x esp: 0x%08x\n",
istack->cs, istack->eip, istack->ss, istack->esp);
kprintf(" cr0: 0x%08x cr2: 0x%08x cr3: 0x%08x\n",
read_cr0(), read_cr2(), read_cr3());
kprintf(" Error: 0x%08x (%d)\n", istack->error, istack->error);
kputs("--------------------------------------------------------------------------------");
kprintf("Halting!\n");
for (;;)
;
break;
}
}
} /* extern "C" */
void interrupts_bootstrap()
{
u32_t idt_phys = mm_page_alloc();
u32_t idt_virt = mm_early_vpage_alloc();
mm_map(idt_virt, idt_phys, 0, 1);
u64_t * idt = (u64_t *) idt_virt;
idt[0] = MAKE_IDT_DESCRIPTOR(KERNEL_CODE_SEGMENT, isr_0, 0);
idt[1] = MAKE_IDT_DESCRIPTOR(KERNEL_CODE_SEGMENT, isr_1, 0);
idt[2] = MAKE_IDT_DESCRIPTOR(KERNEL_CODE_SEGMENT, isr_2, 0);
idt[3] = MAKE_IDT_DESCRIPTOR(KERNEL_CODE_SEGMENT, isr_3, 0);
idt[4] = MAKE_IDT_DESCRIPTOR(KERNEL_CODE_SEGMENT, isr_4, 0);
idt[5] = MAKE_IDT_DESCRIPTOR(KERNEL_CODE_SEGMENT, isr_5, 0);
idt[6] = MAKE_IDT_DESCRIPTOR(KERNEL_CODE_SEGMENT, isr_6, 0);
idt[7] = MAKE_IDT_DESCRIPTOR(KERNEL_CODE_SEGMENT, isr_7, 0);
idt[8] = MAKE_IDT_DESCRIPTOR(KERNEL_CODE_SEGMENT, isr_8, 0);
idt[9] = MAKE_IDT_DESCRIPTOR(KERNEL_CODE_SEGMENT, isr_9, 0);
idt[10] = MAKE_IDT_DESCRIPTOR(KERNEL_CODE_SEGMENT, isr_10, 0);
idt[11] = MAKE_IDT_DESCRIPTOR(KERNEL_CODE_SEGMENT, isr_11, 0);
idt[12] = MAKE_IDT_DESCRIPTOR(KERNEL_CODE_SEGMENT, isr_12, 0);
idt[13] = MAKE_IDT_DESCRIPTOR(KERNEL_CODE_SEGMENT, isr_13, 0);
idt[14] = MAKE_IDT_DESCRIPTOR(KERNEL_CODE_SEGMENT, isr_14, 0);
idt[15] = MAKE_IDT_DESCRIPTOR(KERNEL_CODE_SEGMENT, isr_15, 0);
idt[16] = MAKE_IDT_DESCRIPTOR(KERNEL_CODE_SEGMENT, isr_16, 0);
idt[17] = MAKE_IDT_DESCRIPTOR(KERNEL_CODE_SEGMENT, isr_17, 0);
idt[18] = MAKE_IDT_DESCRIPTOR(KERNEL_CODE_SEGMENT, isr_18, 0);
idt[19] = MAKE_IDT_DESCRIPTOR(KERNEL_CODE_SEGMENT, isr_19, 0);
idt[20] = MAKE_IDT_DESCRIPTOR(KERNEL_CODE_SEGMENT, isr_20, 0);
idt[21] = MAKE_IDT_DESCRIPTOR(KERNEL_CODE_SEGMENT, isr_21, 0);
idt[22] = MAKE_IDT_DESCRIPTOR(KERNEL_CODE_SEGMENT, isr_22, 0);
idt[23] = MAKE_IDT_DESCRIPTOR(KERNEL_CODE_SEGMENT, isr_23, 0);
idt[24] = MAKE_IDT_DESCRIPTOR(KERNEL_CODE_SEGMENT, isr_24, 0);
idt[25] = MAKE_IDT_DESCRIPTOR(KERNEL_CODE_SEGMENT, isr_25, 0);
idt[26] = MAKE_IDT_DESCRIPTOR(KERNEL_CODE_SEGMENT, isr_26, 0);
idt[27] = MAKE_IDT_DESCRIPTOR(KERNEL_CODE_SEGMENT, isr_27, 0);
idt[28] = MAKE_IDT_DESCRIPTOR(KERNEL_CODE_SEGMENT, isr_28, 0);
idt[29] = MAKE_IDT_DESCRIPTOR(KERNEL_CODE_SEGMENT, isr_29, 0);
idt[30] = MAKE_IDT_DESCRIPTOR(KERNEL_CODE_SEGMENT, isr_30, 0);
idt[31] = MAKE_IDT_DESCRIPTOR(KERNEL_CODE_SEGMENT, isr_31, 0);
idt[32] = MAKE_IDT_DESCRIPTOR(KERNEL_CODE_SEGMENT, isr_32, 0);
idt[33] = MAKE_IDT_DESCRIPTOR(KERNEL_CODE_SEGMENT, isr_33, 0);
idt[34] = MAKE_IDT_DESCRIPTOR(KERNEL_CODE_SEGMENT, isr_34, 0);
idt[35] = MAKE_IDT_DESCRIPTOR(KERNEL_CODE_SEGMENT, isr_35, 0);
idt[36] = MAKE_IDT_DESCRIPTOR(KERNEL_CODE_SEGMENT, isr_36, 0);
idt[37] = MAKE_IDT_DESCRIPTOR(KERNEL_CODE_SEGMENT, isr_37, 0);
idt[38] = MAKE_IDT_DESCRIPTOR(KERNEL_CODE_SEGMENT, isr_38, 0);
idt[39] = MAKE_IDT_DESCRIPTOR(KERNEL_CODE_SEGMENT, isr_39, 0);
idt[40] = MAKE_IDT_DESCRIPTOR(KERNEL_CODE_SEGMENT, isr_40, 0);
idt[41] = MAKE_IDT_DESCRIPTOR(KERNEL_CODE_SEGMENT, isr_41, 0);
idt[42] = MAKE_IDT_DESCRIPTOR(KERNEL_CODE_SEGMENT, isr_42, 0);
idt[43] = MAKE_IDT_DESCRIPTOR(KERNEL_CODE_SEGMENT, isr_43, 0);
idt[44] = MAKE_IDT_DESCRIPTOR(KERNEL_CODE_SEGMENT, isr_44, 0);
idt[45] = MAKE_IDT_DESCRIPTOR(KERNEL_CODE_SEGMENT, isr_45, 0);
idt[46] = MAKE_IDT_DESCRIPTOR(KERNEL_CODE_SEGMENT, isr_46, 0);
idt[47] = MAKE_IDT_DESCRIPTOR(KERNEL_CODE_SEGMENT, isr_47, 0);
idt[48] = MAKE_IDT_DESCRIPTOR(KERNEL_CODE_SEGMENT, isr_48, 0);
idt[49] = MAKE_IDT_DESCRIPTOR(KERNEL_CODE_SEGMENT, isr_49, 0);
idtr.base = idt_phys;
idtr.limit = 49 * sizeof(idt[0]) - 1;
__asm__ __volatile__ ("lidt (idtr)" : : : "memory");
}
+79
View File
@@ -0,0 +1,79 @@
#ifndef INTERRUPTS_H
#define INTERRUPTS_H
#ifdef __cplusplus
extern "C" {
#endif
void isr(u8_t int_num, int_stack_t * int_stack);
extern void isr_0();
extern void isr_1();
extern void isr_2();
extern void isr_3();
extern void isr_4();
extern void isr_5();
extern void isr_6();
extern void isr_7();
extern void isr_8();
extern void isr_9();
extern void isr_10();
extern void isr_11();
extern void isr_12();
extern void isr_13();
extern void isr_14();
extern void isr_15();
extern void isr_16();
extern void isr_17();
extern void isr_18();
extern void isr_19();
extern void isr_20();
extern void isr_21();
extern void isr_22();
extern void isr_23();
extern void isr_24();
extern void isr_25();
extern void isr_26();
extern void isr_27();
extern void isr_28();
extern void isr_29();
extern void isr_30();
extern void isr_31();
extern void isr_32();
extern void isr_33();
extern void isr_34();
extern void isr_35();
extern void isr_36();
extern void isr_37();
extern void isr_38();
extern void isr_39();
extern void isr_40();
extern void isr_41();
extern void isr_42();
extern void isr_43();
extern void isr_44();
extern void isr_45();
extern void isr_46();
extern void isr_47();
extern void isr_48();
extern void isr_49();
#ifdef __cplusplus
}
#endif
#define MAKE_IDT_DESCRIPTOR(selector, offset, dpl) \
(u64_t) ( ( (((u64_t) offset) & 0xFFFF0000ull) << 32 ) /* offset 31:16 */ \
| ( ( (u64_t) 0x1ull) << 47 ) /* present */ \
| ( (((u64_t) dpl) & 0x3) << 45 ) /* DPL */ \
| ( ( (u64_t) 0xEull) << 40 ) /* TODO: gate? */ \
| ( (((u64_t) selector) & 0xFFFFull) << 16 ) /* selector */ \
| ( (((u64_t) offset) & 0x0000FFFFull) ) ) /* offset 15:0 */
void interrupts_bootstrap();
#define interrupts_enable() __asm__ __volatile__ ("sti");
#define interrupts_disable() __asm__ __volatile__ ("cli");
#endif
+56
View File
@@ -0,0 +1,56 @@
; C ISR routine
[extern isr]
; Macro for creating a single ISR label
; We need to push a junk value on the stack first
; if the interrupt number is not 8 or 10-14.
; This is to properly align the stack for both exceptions
; having and not having error codes.
%macro isr_label 1
[global isr_%1]
isr_%1:
%if ( (%1 != 8) && (%1 < 10 || %1 > 14) )
push eax ; junk value to take error code stack space
%endif
pusha ; eax, ecx, edx, ebx, esp, ebp, esi, edi
mov al, %1 ; save interrupt number in al
%if ($ - isr_common) < 127 ; do a short jump and save 3 bytes if we can
jmp short isr_common
%else
jmp isr_common
%endif
%endmacro
; The common ISR routine
isr_common:
push ds
push es
push fs
push gs
push esp ; pointer to interrupt stack
push eax ; interrupt number
call isr
pop eax ; restore stack pointer (this is shorter
pop eax ; than "add esp, 8" and "lea esp, [esp+8]")
pop gs
pop fs
pop es
pop ds
popa ; edi, esi, ebp, <null>, ebx, edx, ecx, eax
lea esp, [esp+4] ; bypass error code
iret
; Loop to create all of our ISR entry points
%assign i 0
%rep 50
isr_label i
%assign i i+1
%endrep
+2
View File
@@ -0,0 +1,2 @@
include $(HOS_TOPLEVEL)/subdir.mak
+317
View File
@@ -0,0 +1,317 @@
#include "hos_types.h"
#include "hos_defines.h"
#include "kio.h"
#include "string.h"
#include "portio.h"
#include <limits.h>
#include <stdarg.h> /* va_*() */
static void fmt_d2a(char * buf, int val);
static void fmt_u2a(char * buf, unsigned int val);
static void fmt_ll2a(char * buf, long long val);
static void fmt_ull2a(char * buf, unsigned long long val);
static void fmt_x2a(char * buf, unsigned int val);
static void fmt_xl2a(char * buf, unsigned long long val);
static void fmt_o2a(char * buf, unsigned int val);
static int cursor_x, cursor_y;
static void writeCursorPosition(int x, int y)
{
u16_t pos = 80 * y + x;
outportb(0x3D4, 0x0E);
outportb(0x3D5, pos >> 8);
outportb(0x3D4, 0x0F);
outportb(0x3D5, pos);
}
extern "C" {
void kio_bootstrap()
{
cursor_x = 0;
cursor_y = 9;
writeCursorPosition(cursor_x, cursor_y);
}
void kprintf(const char * fmt, ...)
{
va_list args;
va_start(args, fmt);
kvprintf(fmt, args);
va_end(args);
}
void kvprintf(const char * fmt, va_list args)
{
char tmpbuf[25];
for ( ; *fmt; fmt++)
{
if (*fmt == '%')
{
fmt++;
if (*fmt)
{
int width = 0;
char pad_char = ' ';
bool pad_right = false;
if (*fmt == '0')
{
pad_char = '0';
fmt++;
}
else if (*fmt == '-')
{
pad_right = true;
fmt++;
}
for ( ; '0' <= *fmt && *fmt <= '9'; fmt++)
{
if (width == 0)
{
width = *fmt - '0';
}
else
{
width *= 10;
width += *fmt - '0';
}
}
switch (*fmt)
{
case 'c':
kputc(va_arg(args, int));
break;
case 'd':
fmt_d2a(tmpbuf, va_arg(args, int));
kputs_pad(tmpbuf, width, pad_char, pad_right);
break;
case 'l':
fmt_ll2a(tmpbuf, va_arg(args, long long));
kputs_pad(tmpbuf, width, pad_char, pad_right);
break;
case 'L':
fmt_ull2a(tmpbuf, va_arg(args, unsigned long long));
kputs_pad(tmpbuf, width, pad_char, pad_right);
break;
case 'o':
fmt_o2a(tmpbuf, va_arg(args, unsigned int));
kputs_pad(tmpbuf, width, pad_char, pad_right);
break;
case 's':
kputs_pad(va_arg(args, char *),
width, pad_char, pad_right);
break;
case 'u':
fmt_u2a(tmpbuf, va_arg(args, unsigned int));
kputs_pad(tmpbuf, width, pad_char, pad_right);
break;
case 'x':
fmt_x2a(tmpbuf, va_arg(args, unsigned int));
kputs_pad(tmpbuf, width, pad_char, pad_right);
break;
case 'X':
fmt_xl2a(tmpbuf, va_arg(args, unsigned long long));
kputs_pad(tmpbuf, width, pad_char, pad_right);
break;
case '%':
kputc('%');
break;
}
}
}
else
{
kputc(*fmt);
}
if (!*fmt)
{
break;
}
}
}
void kputc(char c)
{
u16_t * console_memory = (u16_t *) CONSOLE_MEMORY;
console_memory += 80 * cursor_y + cursor_x;
switch (c)
{
case '\t':
{
int to_advance = 8 - (cursor_x & 0x3);
while (to_advance--)
{
*console_memory++ = 0x0720;
}
}
break;
case '\n':
cursor_x = 0;
cursor_y++;
break;
default:
*console_memory = 0x0700 | (c & 0xFF);
cursor_x++;
break;
}
if (cursor_x >= 80)
{
cursor_x = 0;
cursor_y++;
}
if (cursor_y >= 25)
{
memcpy((u8_t *) CONSOLE_MEMORY,
(u8_t *) (CONSOLE_MEMORY + 80 * 2),
2 * 80 * 24);
memsetw((u16_t *) (CONSOLE_MEMORY + 2 * 80 * 24), 0x0720, 80);
cursor_y = 24;
}
writeCursorPosition(cursor_x, cursor_y);
}
void kputs(const char * s)
{
while (*s)
{
kputc(*s);
s++;
}
}
void kputs_pad(const char * s, int width, char pad_char, bool pad_right)
{
int len = strlen(s);
if (pad_right)
{
kputs(s);
}
int num_pad_chars = width - len;
for (int i = 0; i < num_pad_chars; i++)
{
kputc(pad_char);
}
if (!pad_right)
{
kputs(s);
}
}
} /* extern "C" */
static void fmt_d2a(char * buf, int val)
{
if (val < 0)
{
*buf++ = '-';
val = -val;
}
fmt_u2a(buf, (unsigned int) val);
}
static void fmt_u2a(char * buf, unsigned int val)
{
bool printing = false;
for (unsigned int div = 1000000000; div >= 1; div /= 10)
{
unsigned int n = val / div;
if (n || div == 1)
{
printing = true;
}
if (printing)
{
*buf++ = '0' + n;
}
val -= n * div;
}
*buf = '\0';
}
static void fmt_ll2a(char * buf, long long val)
{
if (val < 0)
{
*buf++ = '-';
val = -val;
}
fmt_ull2a(buf, (unsigned long long) val);
}
static void fmt_ull2a(char * buf, unsigned long long val)
{
bool printing = false;
for (unsigned long long div = 10000000000000000000ull; div >= 1; div /= 10)
{
unsigned long long n = val / div;
if (n || div == 1)
{
printing = true;
}
if (printing)
{
*buf++ = '0' + n;
}
val -= n * div;
}
*buf = '\0';
}
static void fmt_x2a(char * buf, unsigned int val)
{
bool printing = false;
for (int s = 28; s >= 0; s -= 4)
{
unsigned int n = (val >> s) & 0xF;
if (n || s == 0)
{
printing = true;
}
if (printing)
{
*buf++ = "0123456789abcdef"[n];
}
}
*buf = '\0';
}
static void fmt_xl2a(char * buf, unsigned long long val)
{
bool printing = false;
for (int s = 60; s >= 0; s -= 4)
{
unsigned int n = (val >> s) & 0xF;
if (n || s == 0)
{
printing = true;
}
if (printing)
{
*buf++ = "0123456789abcdef"[n];
}
}
*buf = '\0';
}
static void fmt_o2a(char * buf, unsigned int val)
{
bool printing = false;
for (int s = 30; s >= 0; s -= 3)
{
unsigned int n = (val >> s) & 0x7;
if (n || s == 0)
{
printing = true;
}
if (printing)
{
*buf++ = "01234567"[n];
}
}
*buf = '\0';
}
+27
View File
@@ -0,0 +1,27 @@
#ifndef KIO_H
#define KIO_H
#include <stdarg.h>
#ifdef __cplusplus
extern "C" {
#endif
void kio_bootstrap();
void kprintf(const char * fmt, ...);
void kvprintf(const char * fmt, va_list args);
void kputc(char c);
void kputs(const char * s);
void kputs_pad(const char * s, int width, char pad_char, bool pad_right);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif
+73
View File
@@ -0,0 +1,73 @@
#include "string.h"
extern "C" {
void strcpy(char * dst, const char * src)
{
while (*src)
{
*dst++ = *src++;
}
*dst = '\0';
}
u32_t strlen(const char * s)
{
u32_t len = 0;
while (*s++)
{
len++;
}
return len;
}
void memcpy(u8_t * dst, u8_t * src, u32_t size)
{
for (u32_t n = 0; n < size; n++)
{
*dst++ = *src++;
}
}
void memcpyw(u16_t * dst, u16_t * src, u32_t size)
{
for (u32_t n = 0; n < size; n++)
{
*dst++ = *src++;
}
}
void memcpyd(u32_t * dst, u32_t * src, u32_t size)
{
for (u32_t n = 0; n < size; n++)
{
*dst++ = *src++;
}
}
void memset(u8_t * dst, u8_t val, u32_t size)
{
for (u32_t n = 0; n < size; n++)
{
*dst++ = val;
}
}
void memsetw(u16_t * dst, u16_t val, u32_t size)
{
for (u32_t n = 0; n < size; n++)
{
*dst++ = val;
}
}
void memsetd(u32_t * dst, u32_t val, u32_t size)
{
for (u32_t n = 0; n < size; n++)
{
*dst++ = val;
}
}
} /* extern "C" */
+27
View File
@@ -0,0 +1,27 @@
#ifndef STRING_H
#define STRING_H
#include "hos_defines.h"
#ifdef __cplusplus
extern "C" {
#endif
void strcpy(char * dst, const char * src);
u32_t strlen(const char * s);
void memcpy(u8_t * dst, u8_t * src, u32_t size);
void memcpyw(u16_t * dst, u16_t * src, u32_t size);
void memcpyd(u32_t * dst, u32_t * src, u32_t size);
void memset(u8_t * dst, u8_t val, u32_t size);
void memsetw(u16_t * dst, u16_t val, u32_t size);
void memsetd(u32_t * dst, u32_t val, u32_t size);
#ifdef __cplusplus
}
#endif
#endif
+34
View File
@@ -0,0 +1,34 @@
OUTPUT_FORMAT(elf32-i386)
ENTRY(start)
virt = 0x00100000;
phys = 0x00100000;
SECTIONS
{
.text virt : AT(phys) {
code = .; _code = .; __code = .;
*(.multiboot_header*)
*(.text*)
*(.gnu.linkonce*)
. = ALIGN(4096);
}
.rodata : {
*(.rodata*)
. = ALIGN(4096);
}
.other : {
*(.eh_*)
*(.rel*)
. = ALIGN(4096);
}
.data : {
data = .; _data = .; __data = .;
*(.data*)
. = ALIGN(4096);
}
.bss : {
bss = .; _bss = .; __bss = .;
*(.bss*)
. = ALIGN(4096);
}
end = .; _end = .; __end = .;
}
+2
View File
@@ -0,0 +1,2 @@
include $(HOS_TOPLEVEL)/subdir.mak
+405
View File
@@ -0,0 +1,405 @@
#include <stddef.h>
#include "mm.h"
#include "stack.h"
#include "boot/k_early_panic.h"
#include "lang/string.h"
#include "lang/kio.h"
#include "sys/cpu.h"
#define MM_MAX_MMAP_ENTRIES 64
/* mmap management */
static mm_mem_range_t mm_mmap_entries[MM_MAX_MMAP_ENTRIES];
static int mm_mmap_num_entries = 0;
/* free/total page statistics */
static int mm_num_free_pages = 0;
static int mm_num_total_pages = 0;
gdtr_t mm_gdtr;
static u64_t * mm_gdt; /* NOT mapped into virtual address space */
static u32_t mm_heap_base; /* virtual address of start of heap */
static pagedirectory_t * early_page_directory_ptr;
/* physical addresses of page allocation pages to map in before the heap */
static u32_t page_alloc_page_numbers[1025]; /* supports 4GB physical memory */
static int last_page_alloc_page = -1; /* index of last valid page alloc page */
static int page_alloc_page_index = -1;
static mm_page_alloc_page_t * page_alloc_pages;
static int page_alloc_pages_index = -1;
/**************************************************************************
* Internal Functions *
*************************************************************************/
static void record_phys_page(u32_t base_address);
/**************************************************************************
* Compile-time tests *
*************************************************************************/
static void build_tests()
{
/* check that a mm_page_alloc_page_t fits exactly in a page */
BUILD_BUG_ON(sizeof(mm_page_alloc_page_t) != PAGE_SIZE);
}
/**************************************************************************
* This function is run in segmented memory before paging is in effect. *
* Record an mmap entry from the bootloader into our kernel space. *
*************************************************************************/
void mm_record_mmap_entry(mb_mmap_t * mmap)
{
if (mm_mmap_num_entries < MM_MAX_MMAP_ENTRIES)
{
if (mmap->type == MB_MMAP_TYPE_RAM)
{
mm_mmap_entries[mm_mmap_num_entries].base = mmap->base;
mm_mmap_entries[mm_mmap_num_entries].length = mmap->length;
mm_mmap_num_entries++;
}
}
else
{
k_early_panic("Too many mmap_entries!");
}
}
/**************************************************************************
* This function is run in segmented memory before paging is in effect. *
* It is run after the bootloader information has been read, so we can *
* overwrite that memory now. *
*************************************************************************/
void mm_bootstrap()
{
u32_t max_ram_address = KERNEL_PHYSICAL_ADDRESS + KERNEL_SIZE - 1;
if (mm_mmap_num_entries < 1)
{
k_early_panic("No mmap entries read from bootloader!");
}
mm_heap_base = (u32_t) KERNEL_END;
page_alloc_pages = (mm_page_alloc_page_t *) mm_heap_base;
for (int mmap_idx = 0; mmap_idx < mm_mmap_num_entries; mmap_idx++)
{
u32_t base_address = mm_mmap_entries[mmap_idx].base;
u32_t address_limit = base_address + mm_mmap_entries[mmap_idx].length;
if (base_address & PAGE_LOW_MASK)
{
/* start of this mmap range is not page-aligned */
base_address = (base_address & PAGE_HIGH_MASK) + PAGE_SIZE;
}
if (address_limit & PAGE_LOW_MASK)
{
/* end of this mmap range is not page-aligned */
address_limit &= PAGE_HIGH_MASK;
}
/* record the highest RAM address found */
if ((address_limit - 1) > max_ram_address)
{
max_ram_address = (address_limit - 1);
}
/*
* loop through every page in the mmap range and add
* pages into the free page linked list
*/
for (; base_address < address_limit; base_address += PAGE_SIZE)
{
/* check to make sure the page doesn't overlap the kernel */
if ( base_address + PAGE_SIZE <= KERNEL_PHYSICAL_ADDRESS
|| base_address >= KERNEL_PHYSICAL_ADDRESS + KERNEL_SIZE )
{
record_phys_page(base_address);
mm_num_free_pages++;
}
mm_num_total_pages++;
}
}
if (mm_num_free_pages < 10)
{
k_early_panic("Not enough free pages of RAM!");
}
/* ok, now mm_early_page_alloc() should be functional */
/* move the heap back to after the page allocation pages */
mm_heap_base = (u32_t) &page_alloc_pages[last_page_alloc_page + 1];
/* ok, now mm_early_vpage_alloc() should be functional */
/* allocate the page directory */
u32_t page_directory_phys = mm_early_page_alloc();
early_page_directory_ptr = (pagedirectory_t *)
(page_directory_phys + KERNEL_OFFSET);
/* Clear the page directory */
for (unsigned int i = 0; i < NUM_PAGETABLE_ENTRIES; i++)
{
(*early_page_directory_ptr)[i] = 0;
}
/* ok, now mm_early_map() should be functional */
/* map in the page directory itself so we can modify it once paging is on */
(*early_page_directory_ptr)[PAGE_DIR_SELF_REF_INDEX] =
(page_directory_phys) | (0x1 << 1) | (0x1);
/* map in the physical page allocator pages */
for (int i = 0; i <= last_page_alloc_page; i++)
{
mm_early_map((u32_t) &page_alloc_pages[i],
page_alloc_page_numbers[i], 0, 1);
}
/* map the kernel's virtual address space into RAM */
for (u32_t page_base = KERNEL_VIRTUAL_ADDRESS;
page_base < KERNEL_VIRTUAL_ADDRESS + KERNEL_SIZE;
page_base += PAGE_SIZE)
{
/* map page_base to page_base - KERNEL_OFFSET */
mm_early_map(page_base, page_base - KERNEL_OFFSET, 0, 1);
}
/* map console memory */
mm_early_map(CONSOLE_MEMORY, CONSOLE_MEMORY, 0, 1);
/* set up the global descriptor table */
u32_t gdt_base = mm_early_page_alloc();
mm_gdt = (u64_t *) ((u32_t) gdt_base + (u32_t) KERNEL_OFFSET);
mm_gdt[0] = 0x0ull;
mm_gdt[1] = MAKE_DESCRIPTOR(0, 0xFFFFF, 1, 0, 1, 1); /* kernel code */
mm_gdt[2] = MAKE_DESCRIPTOR(0, 0xFFFFF, 1, 0, 1, 0); /* kernel data */
mm_gdtr.limit = 3 * sizeof(mm_gdt[0]) - 1;
mm_gdtr.base = gdt_base;
__asm__ __volatile__ (
"lgdt (mm_gdtr);\n"
"jmp $0x08, $42f;\n"
"42:\n"
"mov $0x10, %%cx\n"
"mov %%cx, %%ss\n"
"mov %%cx, %%ds\n"
"mov %%cx, %%es\n"
"mov %%cx, %%fs\n"
"mov %%cx, %%gs\n"
: /* no outputs */
: /* no inputs */
: "ecx");
/* set the page directory base register */
write_cr3(page_directory_phys);
/* set up permanent stack before enabling paging */
stack_bootstrap();
/* turn on paging */
write_cr0(read_cr0() | (1 << 31));
}
/**************************************************************************
* This function is run in segmented memory before paging is in effect. *
* Record a physical page in the page allocation pages. *
*************************************************************************/
static void record_phys_page(u32_t base_address)
{
if (page_alloc_page_index < 0)
{
/* allocate a new page alloc page */
last_page_alloc_page++;
page_alloc_pages_index++;
page_alloc_page_numbers[last_page_alloc_page] = base_address;
page_alloc_page_index = 0;
}
else
{
mm_page_alloc_page_t * current_page_alloc_page =
(mm_page_alloc_page_t *)
(page_alloc_page_numbers[page_alloc_pages_index] + KERNEL_OFFSET);
page_alloc_page_index++;
(*current_page_alloc_page)[page_alloc_page_index] = base_address;
if (page_alloc_page_index == NUM_PAGETABLE_ENTRIES - 1)
{
page_alloc_page_index = -1;
}
}
}
/**************************************************************************
* Map virtual_address to physical_address. *
* Both addresses should be page-aligned. *
* This 'early' version can be used during segmented bootstrapping *
*************************************************************************/
int mm_early_map(u32_t virtual_address, u32_t physical_address,
u32_t user_mode, u32_t writable)
{
u32_t directory_index = (virtual_address >> 22) & 0x3FF;
u32_t table_index = (virtual_address >> 12) & 0x3FF;
if ((*early_page_directory_ptr)[directory_index] == 0)
{
/* allocate a new page table */
u32_t page_table_phys = mm_early_page_alloc();
if (page_table_phys == 0)
{
return 0;
}
pagedirectory_entry_t * page_table_virt = (pagedirectory_entry_t *)
(page_table_phys + KERNEL_OFFSET);
for (unsigned int i = 0; i < NUM_PAGETABLE_ENTRIES; i++)
{
page_table_virt[i] = 0;
}
(*early_page_directory_ptr)[directory_index] = page_table_phys
| (0x1 << 2) /* PTs can be user mode */
| (0x1 << 1) /* writable */
| (0x1); /* present */
}
u32_t page_table_phys =
(*early_page_directory_ptr)[directory_index] & PAGE_HIGH_MASK;
pagedirectory_entry_t * page_table =
(pagedirectory_entry_t *) (page_table_phys + KERNEL_OFFSET);
page_table[table_index] = (physical_address & PAGE_HIGH_MASK)
| ((user_mode & 0x1) << 2)
| ((writable & 0x1) << 1)
| 0x1; /* present */
return 1;
}
/**************************************************************************
* Map virtual_address to physical_address. *
* Both addresses should be page-aligned. *
*************************************************************************/
int mm_map(u32_t virtual_address, u32_t physical_address,
u32_t user_mode, u32_t writable)
{
u32_t directory_index = (virtual_address >> 22) & 0x3FF;
u32_t table_index = (virtual_address >> 12) & 0x3FF;
pagedirectory_entry_t * page_dir_entry = (pagedirectory_entry_t *)
(PAGE_DIR_SELF_REF2 | (directory_index << 2));
if (*page_dir_entry == 0)
{
/* allocate a new page table */
u32_t page_table_phys = mm_page_alloc();
if (page_table_phys == 0)
{
return 0;
}
*page_dir_entry = page_table_phys
| (0x1 << 2) /* PTs can be user mode */
| (0x1 << 1) /* writable */
| (0x1); /* present */
pagedirectory_entry_t * page_table = (pagedirectory_entry_t *)
(PAGE_DIR_SELF_REF | (directory_index << 12));
for (unsigned int i = 0; i < NUM_PAGETABLE_ENTRIES; i++)
{
page_table[i] = 0;
}
}
pagedirectory_entry_t * page_table_entry = (pagedirectory_entry_t *)
(PAGE_DIR_SELF_REF | (directory_index << 12) | (table_index << 2));
*page_table_entry = (physical_address & PAGE_HIGH_MASK)
| ((user_mode & 0x1) << 2)
| ((writable & 0x1) << 1)
| 0x1; /* present */
return 1;
}
/**************************************************************************
* Returns the physical base address of a page in RAM *
* or 0 if no pages were available *
* This 'early' version can be used during segmented bootstrapping *
*************************************************************************/
u32_t mm_early_page_alloc()
{
u32_t page_address = 0;
if (page_alloc_pages_index >= 0)
{
if (page_alloc_page_index >= 0)
{
mm_page_alloc_page_t * current_pap = (mm_page_alloc_page_t *)
(page_alloc_page_numbers[page_alloc_pages_index]
+ KERNEL_OFFSET);
page_address = (*current_pap)[page_alloc_page_index];
page_alloc_page_index--;
}
else
{
/* return the page allocation page itself */
page_address = page_alloc_page_numbers[page_alloc_pages_index];
page_alloc_pages_index--;
page_alloc_page_index = NUM_PAGETABLE_ENTRIES - 1;
}
mm_num_free_pages--;
}
return page_address;
}
/**************************************************************************
* Returns the physical base address of a page in RAM *
* or 0 if no pages were available *
*************************************************************************/
u32_t mm_page_alloc()
{
u32_t page_address = 0;
if (page_alloc_pages_index >= 0)
{
if (page_alloc_page_index >= 0)
{
page_address =
page_alloc_pages[page_alloc_pages_index][page_alloc_page_index];
page_alloc_page_index--;
}
else
{
/* return the page allocation page itself */
page_address = page_alloc_page_numbers[page_alloc_pages_index];
page_alloc_pages_index--;
page_alloc_page_index = NUM_PAGETABLE_ENTRIES - 1;
}
mm_num_free_pages--;
}
return page_address;
}
/**************************************************************************
* This function allocates a virtual page. It should only be called *
* during the bootstrap process, before the kernel begins its normal *
* operation. It adjusts the heap pointer to push it back beyond any *
* bootstrap pages allocated. *
*************************************************************************/
u32_t mm_early_vpage_alloc()
{
u32_t vaddress = mm_heap_base;
mm_heap_base += PAGE_SIZE;
return vaddress;
}
void mm_print_memory_map()
{
kprintf("Bootloader provided memory map:\n");
kprintf(" Base Address Length\n");
for (int i = 0; i < mm_mmap_num_entries; i++)
{
kprintf(" 0x%016X 0x%016X (%l bytes / %l KB / %l MB)\n",
mm_mmap_entries[i].base,
mm_mmap_entries[i].length,
mm_mmap_entries[i].length,
mm_mmap_entries[i].length >> 10,
mm_mmap_entries[i].length >> 20);
}
kprintf("Used pages: %d\n", mm_num_total_pages - mm_num_free_pages);
kprintf("Free pages: %d\n", mm_num_free_pages);
}
+65
View File
@@ -0,0 +1,65 @@
#ifndef MM_H
#define MM_H MM_H
#include "hos_types.h"
#include "hos_defines.h"
#include "multiboot.h"
#define KERNEL_CODE_SEGMENT 0x08
#define KERNEL_DATA_SEGMENT 0x10
typedef u32_t pagedirectory_entry_t;
#define NUM_PAGETABLE_ENTRIES (PAGE_SIZE / sizeof(pagedirectory_entry_t))
#define PAGE_DIR_SELF_REF (0x20000000u - (PAGE_SIZE * NUM_PAGETABLE_ENTRIES))
#define PAGE_DIR_SELF_REF_INDEX ((PAGE_DIR_SELF_REF >> 22) & 0x3FF)
#define PAGE_DIR_SELF_REF2 (PAGE_DIR_SELF_REF | (PAGE_DIR_SELF_REF_INDEX << 12))
typedef pagedirectory_entry_t pagedirectory_t[NUM_PAGETABLE_ENTRIES];
typedef struct
{
u64_t base;
u64_t length;
} mm_mem_range_t;
typedef u32_t mm_page_alloc_page_t[NUM_PAGETABLE_ENTRIES];
/* http://courses.ece.illinois.edu/ece391/references/descriptors.pdf */
/* granularity: 0: limit in bytes; 1: limit in pages */
/* dpl: 0: system mode; 3: user mode */
/* normal: 0: TSS/LDT/call gate; 1: code/data segment */
/* code_seg: 0: data segment; 1: code segment */
#define MAKE_DESCRIPTOR(base, limit, granularity, dpl, normal, code_seg) \
(u64_t) ( ( (((u64_t) base) & 0xFF000000ull) << 32 ) /* base 31:24 */ \
| ( (((u64_t) granularity) & 0x1ull) << 55 ) /* granularity */ \
| ( ( (u64_t) 0x1ull) << 54 ) /* 32-bit */ \
| ( (((u64_t) limit) & 0xF0000ull) << 32 ) /* limit 19:16 */ \
| ( ( (u64_t) 0x1ull) << 47 ) /* present */ \
| ( (((u64_t) dpl) & 0x3ull) << 45 ) /* dpl */ \
| ( (((u64_t) normal) & 0x1ull) << 44 ) /* normal */ \
| ( (((u64_t) code_seg) & 0x1ull) << 43 ) /* code seg */ \
| ( ( (u64_t) 0x2ull) << 40 ) /* ? */ \
| ( (((u64_t) base) & 0x00FFFFFFull) << 16) /* base 23:00 */ \
| ( (((u64_t) limit) & 0x0000FFFFull) ) ) /* limit 15:00 */
typedef u64_t descriptor_t;
void mm_record_mmap_entry(mb_mmap_t * mmap);
void mm_bootstrap();
int mm_early_map(u32_t virtual_address, u32_t physical_address,
u32_t user_mode, u32_t writable);
int mm_map(u32_t virtual_address, u32_t physical_address,
u32_t user_mode, u32_t writable);
u32_t mm_early_page_alloc();
u32_t mm_page_alloc();
u32_t mm_early_vpage_alloc();
void mm_print_memory_map();
#endif
+19
View File
@@ -0,0 +1,19 @@
#include "stack.h"
#include "mm.h"
#include "hos_defines.h"
void stack_bootstrap()
{
/*
* running from our temporary stack while segmentation is enabled,
* set up the "permanent" stack for use while paging
*/
u32_t stack_page_virt = KERNEL_STACK_TOP - PAGE_SIZE;
for (int i = 0; i < STACK_INITIAL_SIZE; i++)
{
u32_t stack_page_phys = mm_early_page_alloc();
mm_early_map(stack_page_virt, stack_page_phys, 0, 1);
stack_page_virt -= PAGE_SIZE;
}
}
+13
View File
@@ -0,0 +1,13 @@
#ifndef STACK_H
#define STACK_H
#include "mm/mm.h"
#define KERNEL_STACK_TOP PAGE_DIR_SELF_REF
#define STACK_INITIAL_SIZE 2 /* number of initial stack pages */
void stack_bootstrap();
#endif
+54
View File
@@ -0,0 +1,54 @@
ASMOBJS := $(patsubst %.asm,%.o,$(wildcard *.asm))
COBJS := $(patsubst %.c,%.o,$(wildcard *.c))
CXXOBJS := $(patsubst %.cc,%.o,$(wildcard *.cc))
CDEPS := $(COBJS:.o=.dep)
CXXDEPS := $(CXXOBJS:.o=.dep)
DEPS := $(CDEPS) $(CXXDEPS)
OUTPUT_FILE := $(SUBDIR)_all.o
ifdef SUBDIRS
SUBDIRS_clean := $(SUBDIRS:%=%.clean)
endif
all: $(OUTPUT_FILE)
$(OUTPUT_FILE): $(ASMOBJS) $(COBJS) $(CXXOBJS) $(SUBDIRS)
$(LD) -r -o $@ $(ASMOBJS) $(COBJS) $(CXXOBJS) $(foreach subdir,$(SUBDIRS),$(subdir)/$(subdir)_all.o)
%.o: %.asm
$(NASM) -f elf -o $@ -l $<.lst $<
%.o: %.c
$(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $<
%.o: %.cc
$(CXX) -c -o $@ $(CPPFLAGS) $(CXXFLAGS) $<
ifdef SUBDIRS
.PHONY: $(SUBDIRS)
$(SUBDIRS):
$(MAKE) -C $@ SUBDIR=$@
endif
# Make dependency files
%.dep: %.c
@set -e; rm -f $@; \
$(CC) -MM $(CPPFLAGS) $< | sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' > $@
%.dep: %.cc
@set -e; rm -f $@; \
$(CXX) -MM $(CPPFLAGS) $< | sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' > $@
clean: $(SUBDIRS_clean)
-rm -f *.o *.dep *.lst *~
ifdef SUBDIRS
%.clean:
$(MAKE) -C $* clean clean=1
endif
# Include dependency files
ifndef clean
-include $(DEPS)
endif
+2
View File
@@ -0,0 +1,2 @@
include $(HOS_TOPLEVEL)/subdir.mak
+40
View File
@@ -0,0 +1,40 @@
#ifndef CPU_H
#define CPU_H
#include "hos_types.h"
static u32_t read_cr0() __attribute__ ((unused));
static u32_t read_cr0()
{
u32_t val;
__asm__ __volatile__ ("movl %%cr0, %0" : "=r" (val));
return val;
}
static u32_t read_cr2() __attribute__ ((unused));
static u32_t read_cr2()
{
u32_t val;
__asm__ __volatile__ ("movl %%cr2, %0" : "=r" (val));
return val;
}
static u32_t read_cr3() __attribute__ ((unused));
static u32_t read_cr3()
{
u32_t val;
__asm__ __volatile__ ("movl %%cr3, %0" : "=r" (val));
return val;
}
#define write_cr0(val) \
__asm__ __volatile__ ("movl %0, %%cr0" : : "r" (val));
#define write_cr3(val) \
__asm__ __volatile__ ("movl %0, %%cr3" : : "r" (val));
#define write_esp(val) \
__asm__ __volatile__ ("movl %0, %%esp" : : "r" (val));
#endif
+29
View File
@@ -0,0 +1,29 @@
#include "pic.h"
#include "portio.h"
/*
* Re-maps the Programmable Interrupr Controllers
* so IRQ0->pic1 base address, IRG8->pic2 base address
*/
void pic_remap(u8_t base1, u8_t base2)
{
u8_t a1, a2;
a1 = inportb(PIC1_DATA); /* 0x21 */
a2 = inportb(PIC2_DATA); /* 0xA1 */
outportb(PIC1_COMMAND, ICW1_INIT+ICW1_ICW4); /* 0x20, 0x10+0x01 00010001b */
outportb(PIC2_COMMAND, ICW1_INIT+ICW1_ICW4); /* 0xA0, 0x10+0x01 00010001b */
outportb(PIC1_DATA, base1); /* 0x21, pic1 */
outportb(PIC2_DATA, base2); /* 0xA1, pic2 */
outportb(PIC1_DATA, 4); /* 0x21, 0x04 00000100b */
outportb(PIC2_DATA, 2); /* 0xA1, 0x02 00000010b */
outportb(PIC1_DATA, ICW4_8086); /* 0x21, 0x01 00000001b */
outportb(PIC2_DATA, ICW4_8086); /* 0xA1, 0x01 00000001b */
outportb(PIC1_DATA, a1); /* 0x21 */
outportb(PIC2_DATA, a2); /* 0xA1 */
}
+46
View File
@@ -0,0 +1,46 @@
#ifndef PIC_H
#define PIC_H
#include "hos_types.h"
#include "portio.h"
#define PIC1 0x20
#define PIC2 0xA0
#define PIC1_COMMAND PIC1
#define PIC1_DATA (PIC1+1)
#define PIC2_COMMAND PIC2
#define PIC2_DATA (PIC2+1)
#define PIC_EOI 0x20
#define ICW1_ICW4 0x01 /* ICW4 (not) needed */
#define ICW1_SINGLE 0x02 /* Single (cascade) mode */
#define ICW1_INTERVAL4 0x04 /* Call address interval 4 (8) */
#define ICW1_LEVEL 0x08 /* Level triggered (edge) mode */
#define ICW1_INIT 0x10 /* Initialization - required! */
#define ICW4_8086 0x01 /* 8086/88 (MCS-80/85) mode */
#define ICW4_AUTO 0x02 /* Auto (normal) EOI */
#define ICW4_BUF_SLAVE 0x08 /* Buffered mode/slave */
#define ICW4_BUF_MASTER 0x0C /* Buffered mode/master */
#define ICW4_SFNM 0x10 /* Special fully nested (not) */
void pic_remap(u8_t base1, u8_t base2);
/* Masks interrupts on first Programmable Interrupt Controller */
#define pic_mask1(mask) outportb(PIC1_DATA, mask) /* 0x21, maskfield *OCW1* */
/* Masks interrupts on second Programmable Interrupt Controller */
#define pic_mask2(mask) outportb(PIC2_DATA, mask) /* 0xA1, maskfield *OCW1* */
/* Signals an End Of Interrupt signal to the first PIC */
#define pic_eoi() outportb(0x20, 0x20)
/* Signals an End Of Interrupt signal to both the second and first PIC unit */
static inline void pic_eoi2()
{
outportb(0xA0, 0x20);
outportb(0x20, 0x20);
}
#endif
+12
View File
@@ -0,0 +1,12 @@
#include "timer.h"
#include "portio.h"
void timer_init(u32_t freq)
{
/* how many ticks the PIT must wait before issuing an interrupt */
u32_t wait = 1193180 / freq;
outportb(0x43, 0x34);
outportb(0x40, wait); /* LSB */
outportb(0x40, wait >> 8); /* MSB */
}
+9
View File
@@ -0,0 +1,9 @@
#ifndef TIMER_H
#define TIMER_H
#include "hos_types.h"
void timer_init(u32_t freq);
#endif
-89
View File
@@ -1,89 +0,0 @@
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
-46
View File
@@ -1,46 +0,0 @@
#!/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
-173
View File
@@ -1,173 +0,0 @@
#include <stdlib.h>
#include <stdint.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 void generate(const char * d_file_name)
{
FILE * fh = fopen(d_file_name, "wb");
fprintf(fh, "module hulk.kfont;\n");
fprintf(fh, "struct CharInfo {\n");
fprintf(fh, " uint width;\n");
fprintf(fh, " uint height;\n");
fprintf(fh, " int top;\n");
fprintf(fh, " int left;\n");
fprintf(fh, " const ubyte[] bitmap;\n");
fprintf(fh, "};\n");
fprintf(fh, "struct FontInfo {\n");
fprintf(fh, " uint line_height;\n");
fprintf(fh, " uint advance;\n");
fprintf(fh, " int baseline_offset;\n");
fprintf(fh, " const CharInfo[] chars;\n");
fprintf(fh, "};\n");
fprintf(fh, "__gshared const FontInfo kfont = {\n");
fprintf(fh, " %du,\n", line_height);
fprintf(fh, " %du,\n", max_advance);
fprintf(fh, " %d,\n", baseline_offset);
fprintf(fh, " [\n");
for (int i = 0; i < N_CHARS; i++)
{
fprintf(fh, " CharInfo(\n");
fprintf(fh, " %du,\n", char_infos[i].width);
fprintf(fh, " %du,\n", char_infos[i].height);
fprintf(fh, " %d,\n", char_infos[i].top);
fprintf(fh, " %d,\n", char_infos[i].left);
if (char_infos[i].width > 0)
{
fprintf(fh, " [\n");
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);
}
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;
generate(out_file);
return 0;
}
-181
View File
@@ -1,181 +0,0 @@
/**
* HELLO console support.
*/
module hello.console;
import uefi;
import hello.hello;
import core.stdc.stdarg;
struct console
{
/**
* Format a hexadecimal value to a string.
*
* @param s String buffer.
* @param v Value to format.
* @param ptr If true, always output all 16 digits, and separate the upper and
* lower halves with an underscore.
*/
private static size_t format_hex(CHAR16 * s, ulong v, bool ptr)
{
string hex_chars = "0123456789ABCDEF";
bool print = ptr;
size_t si = 0u;
for (size_t i = 0u; i < 16u; i++)
{
if (ptr && (i == 8u))
{
s[si++] = '_';
}
ulong n = (v >> (60u - 4u * i)) & 0xFu;
if (n != 0u)
{
print = true;
}
if (print || (i == 15u))
{
s[si++] = hex_chars[n];
}
}
return si;
}
/**
* Format a decimal value to a string.
*
* @param s String buffer.
* @param v Value to format.
*/
private static size_t format_dec(CHAR16 * s, ulong v)
{
string dec_chars = "0123456789";
bool print;
char[20] buf;
size_t buf_i;
while ((buf_i == 0u) || (v != 0u))
{
ulong n = v % 10u;
buf[buf_i++] = dec_chars[n];
v /= 10u;
}
for (size_t si = 0u; si < buf_i; si++)
{
s[si] = buf[buf_i - si - 1u];
}
return buf_i;
}
/**
* Write a string to the console.
*
* @param s Format string.
* @param args Variable arguments structure.
*/
public static void write(string s, va_list args)
{
__gshared static CHAR16[256] s16;
size_t i = 0u;
bool escape = false;
foreach (char c; s)
{
if (escape)
{
if (c == '%')
{
s16[i++] = '%';
}
else if (c == 'x')
{
ulong v;
va_arg(args, v);
i += format_hex(&s16[i], v, false);
}
else if (c == 'p')
{
ulong v;
va_arg(args, v);
i += format_hex(&s16[i], v, true);
}
else if (c == 'S')
{
const(CHAR16) * s2;
va_arg(args, s2);
for (size_t s2_i = 0u; s2[s2_i] != 0; s2_i++)
{
s16[i++] = s2[s2_i];
}
}
else if (c == 'u')
{
ulong v;
va_arg(args, v);
i += format_dec(&s16[i], v);
}
else
{
s16[i++] = c;
}
escape = false;
}
else if (c == '%')
{
escape = true;
}
else
{
s16[i++] = c;
}
}
s16[i++] = 0u;
st.ConOut.OutputString(st.ConOut, &s16[0]);
}
/**
* Write a string to the console.
*
* @param s Format string.
*/
public static extern (C) void write(string s, ...)
{
va_list args;
va_start(args, s);
write(s, args);
va_end(args);
}
/**
* Write a string to the console.
*
* @param s Format string.
*/
public static extern (C) void writeln(string s, ...)
{
va_list args;
va_start(args, s);
write(s, args);
write("\r\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()
{
writeln("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);
}
}
-562
View File
@@ -1,562 +0,0 @@
/**
* 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;
__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.writeln("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.writeln("HandleProtocol: error %x", status);
return false;
}
if (gop_interface == null)
{
console.writeln("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.writeln("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.writeln("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.writeln("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)
{
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();
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();
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;
found_fb_buffer1 = true;
}
}
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;
}
/* 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.writeln("Welcome to HELLO, HOS EFI Lightweight LOader, v0.1.0");
console.writeln("Firmware vendor: '%S', version: 0x%x", st.FirmwareVendor, st.FirmwareVendor);
if (!find_acpi_xsdt())
{
console.writeln("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.writeln("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;
}
-102
View File
@@ -1,102 +0,0 @@
/**
* ACPI (Advanced Configuration and Power Interface) functionality.
*/
module hulk.acpi;
import hulk.hurl;
import hulk.klog;
import hulk.memory;
struct acpi
{
enum uint APIC_SIGNATURE = 0x43495041u;
enum uint XSDT_SIGNATURE = 0x54445358u;
static struct XsdtHeader
{
uint signature;
uint length;
ubyte revision;
ubyte checksum;
char[6] oemid;
ulong oemtableid;
uint oem_revision;
uint creator_id;
uint creator_revision;
}
static struct Xsdt
{
XsdtHeader header;
uint _pad;
ulong[0] tables;
}
static struct MadtHeader
{
uint signature;
uint length;
ubyte revision;
ubyte checksum;
char[6] oemid;
ulong oemtableid;
uint oem_revision;
uint creator_id;
uint creator_revision;
uint local_apic_address;
uint flags;
}
static struct MadtEntry
{
ubyte type;
ubyte length;
}
public static __gshared ulong apic_address;
public static void initialize(ulong acpi_xsdt_phys)
{
/* Map the XSDT header. */
hurl.identity_map_range(acpi_xsdt_phys, Xsdt.sizeof, 0u);
const(Xsdt) * xsdt = cast(const(Xsdt) *)acpi_xsdt_phys;
if (xsdt.header.signature != XSDT_SIGNATURE)
{
klog.writef("XSDT signature invalid\n");
return;
}
/* Map the entire XSDT. */
hurl.identity_map_range(acpi_xsdt_phys, xsdt.header.length, 0u);
size_t n_entries = (xsdt.header.length - xsdt.header.sizeof) / xsdt.tables[0].sizeof;
for (size_t i = 0u; i < n_entries; i++)
{
ulong address = xsdt.tables[i];
hurl.identity_map_range(address, 4u, 0u);
uint signature = *cast(const(uint) *)address;
if (signature == APIC_SIGNATURE)
{
parse_apic_table(address);
}
}
}
private static parse_apic_table(ulong address)
{
const(MadtHeader) * madt_header = cast(const(MadtHeader) *)address;
hurl.identity_map_range(address, madt_header.length, 0u);
apic_address = madt_header.local_apic_address;
klog.writefln("Found 32-bit APIC address: 0x%x", apic_address);
const(void) * madt_end = cast(const(void) *)(address + madt_header.length);
const(MadtEntry) * madt_entry = cast(const(MadtEntry) *)(address + 0x2Cu);
while (madt_entry < madt_end)
{
madt_entry = cast(const(MadtEntry) *)(cast(size_t)madt_entry + madt_entry.length);
if (madt_entry.type == 5u)
{
/* Found a 64-bit Local APIC Address Override entry. */
memcpy(cast(void *)&apic_address, cast(const(void) *)madt_entry + 4u, 8u);
klog.writefln("Found 64-bit APIC address: 0x%x", apic_address);
}
}
}
}
-104
View File
@@ -1,104 +0,0 @@
/**
* APIC (Advanced Programmable Interrupt Controller) functionality.
*/
module hulk.apic;
import hulk.klog;
import hulk.hurl;
import hulk.acpi;
import hulk.idt;
struct apic
{
private enum uint PERIODIC_MODE = 0x2_0000u;
static struct ApicRegister
{
public uint value;
alias value this;
private ubyte[12] _padding;
}
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;
}
static struct IoApicRegisters
{
ApicRegister address;
ApicRegister data;
}
private static __gshared ApicRegisters * apic_registers;
private static __gshared IoApicRegisters * io_apic_registers;
public static void initialize()
{
apic_registers = cast(ApicRegisters *)acpi.apic_address;
io_apic_registers = cast(IoApicRegisters *)0xFEC0_0000u;
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);
klog.writefln("LAPIC ID: 0x%08x", apic_registers.lapic_id.value);
klog.writefln("LAPIC version: 0x%08x", apic_registers.lapic_version.value);
/* Enable local APIC to receive interrupts and set spurious interrupt
* vector to 0xFF. */
apic_registers.spurious_interrupt_vector.value = 0x1FFu;
// apic_registers.lvt_timer.value = idt.INT_LAPIC_TIMER | PERIODIC_MODE;
apic_registers.lvt_timer.value = idt.INT_LAPIC_TIMER;
apic_registers.lvt_lint[0].value = idt.INT_LAPIC_LINT0;
apic_registers.lvt_lint[1].value = idt.INT_LAPIC_LINT1;
// apic_registers.divide_configuration.value = 3u;
configure_io_apic_irq(8u, 0x48u);
}
private static void configure_io_apic_irq(size_t io_apic_irq, size_t interrupt_id)
{
ulong entry = interrupt_id;
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;
}
public static void eoi()
{
apic_registers.eoi.value = 0u;
}
public static void isr(ulong vector)
{
klog.writefln("APIC ISR 0x%x", vector);
eoi();
}
}
-77
View File
@@ -1,77 +0,0 @@
/**
* 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;
}
-102
View File
@@ -1,102 +0,0 @@
/**
* HULK Console functionality.
*/
module hulk.console;
import hulk.fb;
import hulk.kfont;
struct console
{
/** Console width in text columns. */
private static __gshared size_t m_width;
/** Console height in text rows. */
private static __gshared size_t m_height;
/** Current console cursor X position. */
private static __gshared size_t m_x;
/** Current console cursor Y position. */
private static __gshared size_t m_y;
/**
* Initialize the console.
*/
public static void initialize()
{
m_width = fb.width / kfont.advance;
m_height = fb.height / kfont.line_height;
}
/**
* Clear the console.
*/
public static void clear()
{
fb.clear();
m_x = 0u;
m_y = 0u;
}
/**
* Write a character to the console.
*
* @param ch Character to write.
*/
public static void write(char ch)
{
if (ch == '\n')
{
m_x = 0u;
m_y++;
}
else
{
render_char(m_x, m_y, ch);
m_x++;
if (m_x == m_width)
{
m_x = 0u;
m_y++;
}
}
if (m_y == m_height)
{
m_y--;
fb.copy_rows_up(fb_y(m_height - 1u),
(m_height - 1u) * kfont.line_height,
kfont.line_height);
fb.rect(0u, fb_y(m_height - 1u), fb_x(m_width), kfont.line_height, 0u);
}
}
/**
* 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)
{
const(CharInfo) * ci = &kfont.chars[ch];
fb.blit_alpha_bitmap(fb_x(x) + ci.left, fb_y(y) + ci.top - ci.height, ci.bitmap, ci.width, ci.height);
}
/**
* Get the framebuffer X coordinate corresponding to the console X position.
*/
private static size_t fb_x(size_t x)
{
return x * kfont.advance;
}
/**
* Get the framebuffer Y coordinate corresponding to the console Y position.
*/
private static size_t fb_y(size_t y)
{
return fb.height - ((y + 1u) * kfont.line_height);
}
}
-247
View File
@@ -1,247 +0,0 @@
/**
* 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 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);
}
ulong in32(ushort ioaddr)
{
return __asm!ulong("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, ulong 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);
}
-292
View File
@@ -1,292 +0,0 @@
/**
* HULK Framebuffer support.
*/
module hulk.fb;
import hulk.memory;
import hulk.kfont;
/**
* Represent a graphical frame buffer.
*
* 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 side of rectangle.
* @param y Y coordinate of bottom side of rectangle.
* @param width Width of rectangle.
* @param height Height of rectangle.
* @param color Color of rectangle.
*/
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 side 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 bottom 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;
}
}
/**
* Draw a character.
*
* @param x X coordinate of left side of character.
* @param y Y coordinate of bottom side of character.
* @param ch Character to draw.
* @param color Color of character.
*/
static void character(int x, int y, char ch, uint color)
{
const(CharInfo) * ci = &kfont.chars[ch];
blend_alpha_bitmap(x + ci.left, y + kfont.baseline_offset + ci.top - ci.height, ci.bitmap, ci.width, ci.height, color);
}
/**
* Blend an 8-bit alpha bitmap to the framebuffer.
*
* @param x X coordinate of left side of target location.
* @param y Y coordinate of bottom side of target location.
* @param alpha_bitmap 8-bit alpha-channel bitmap.
* @param width Bitmap width.
* @param height Bitmap height.
* @param color Color to blend with alpha value.
*/
static void blend_alpha_bitmap(size_t x, size_t y, const(ubyte) * alpha_bitmap,
size_t width, size_t height, uint color)
{
y += height - 1u;
size_t bitmap_index;
for (size_t iy = 0u; iy < height; iy++)
{
size_t row_buffer_index = buffer_index(x, y);
for (size_t ix = 0u; ix < width; ix++)
{
size_t buffer_index = row_buffer_index + ix;
ubyte alpha = alpha_bitmap[bitmap_index];
uint current_color = m_buffer1[buffer_index];
uint in_color_scaled = scale_color(color, alpha);
uint old_color_scaled = scale_color(current_color, 255u - alpha);
uint new_color = old_color_scaled + in_color_scaled;
m_buffer1[buffer_index] = new_color;
bitmap_index++;
}
memcpy32(&m_device_buffer[row_buffer_index], &m_buffer1[row_buffer_index], width);
y--;
}
}
/**
* Blend an 8-bit alpha bitmap to the framebuffer.
*
* @param x X coordinate of left side of target location.
* @param y Y coordinate of bottom side of target location.
* @param alpha_bitmap 8-bit alpha-channel bitmap.
* @param width Bitmap width.
* @param height Bitmap height.
* @param color Color to blend with alpha value.
*/
static void blend_alpha_bitmap(size_t x, size_t y, const(ubyte)[] alpha_bitmap,
size_t width, size_t height, uint color)
{
blend_alpha_bitmap(x, y, alpha_bitmap.ptr, width, height, color);
}
/**
* Blit an 8-bit alpha bitmap to the framebuffer.
* The foreground will be white (based on the alpha value), and the
* background black.
*
* @param x X coordinate of left side of target location.
* @param y Y coordinate of bottom side of target location.
* @param alpha_bitmap 8-bit alpha-channel bitmap.
* @param width Bitmap width.
* @param height Bitmap height.
*/
static void blit_alpha_bitmap(size_t x, size_t y, const(ubyte) * alpha_bitmap,
size_t width, size_t height)
{
y += height - 1u;
size_t bitmap_index;
for (size_t iy = 0u; iy < height; iy++)
{
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 side of target location.
* @param y Y coordinate of bottom side of target location.
* @param alpha_bitmap 8-bit alpha-channel bitmap.
* @param width Bitmap width.
* @param height Bitmap height.
*/
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 bottom side of region to copy up.
* @param height Height of region to copy up.
* @param offset Number of rows to copy region up by.
*/
static void copy_rows_up(size_t y, size_t height, size_t offset)
{
size_t dest_buffer_index = buffer_index(0u, y + height + offset - 1u);
size_t src_buffer_index = buffer_index(0u, y + height - 1u);
memcpy32(&m_buffer1[dest_buffer_index],
&m_buffer1[src_buffer_index],
(m_stride * height));
memcpy32(&m_device_buffer[dest_buffer_index],
&m_buffer1[dest_buffer_index],
(m_stride * height));
}
/**
* Scale a color value by an alpha amount.
*
* @param color Color value.
* @param alpha Alpha amount.
*
* @return Scaled color value.
*/
private static uint scale_color(uint color, ubyte alpha)
{
return ((((color & 0xFFu) * alpha) >> 8u) & 0xFFu) |
((((color & 0xFF00u) * alpha) >> 8u) & 0xFF00u) |
((((color & 0xFF0000u) * alpha) >> 8u) & 0xFF0000u);
}
/**
* Return the buffer index for the given X and Y coordinates.
*
* @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 (m_height - y - 1u) * m_stride + x;
}
}
-58
View File
@@ -1,58 +0,0 @@
/**
* 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
@@ -1,40 +0,0 @@
/**
* 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;
}
-69
View File
@@ -1,69 +0,0 @@
/**
* 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;
}
}
-86
View File
@@ -1,86 +0,0 @@
/**
* 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.idt;
import hulk.cpu;
import ldc.llvmasm;
import hulk.pic;
import hulk.acpi;
import hulk.apic;
import hulk.rtc;
import hulk.pit;
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 */
16u * 1024u, /* stack_size */
HULK_VIRTUAL_BASE_ADDRESS, /* virt_base */
HULK_VIRTUAL_STACK_TOP_ADDRESS, /* virt_stack_top */
HULK_VIRTUAL_FRAMEBUFFER_ADDRESS, /* virt_fb_buffer */
};
private void initialize_cpu()
{
/* 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()
{
cli();
initialize_cpu();
gdt.initialize();
idt.initialize();
fb.initialize(cast(uint *)HULK_VIRTUAL_FRAMEBUFFER_ADDRESS,
cast(uint *)hulk_header.bootinfo.fb_buffer1_phys,
hulk_header.bootinfo.fb.width,
hulk_header.bootinfo.fb.height,
hulk_header.bootinfo.fb.stride);
console.initialize();
console.clear();
klog.initialize();
klog.writefln("Welcome to HULK, the HOS UltraLight Kernel!");
hurl.initialize(&hulk_header);
pci.initialize();
pic.initialize();
acpi.initialize(hulk_header.bootinfo.acpi_xsdt_phys);
apic.initialize();
rtc.initialize();
pit.initialize();
sti();
for (;;)
{
hlt();
}
}
-61
View File
@@ -1,61 +0,0 @@
SECTIONS
{
. = 0xFFFF800000000000;
_hulk_mem_start = .;
_hulk_header_start = .;
.hulk_header :
{
*(.hulk_header)
}
. = ALIGN(4K);
_hulk_header_end = .;
_hulk_text_start = .;
.text :
{
*(.text)
}
. = ALIGN(4K);
_hulk_text_end = .;
_hulk_rodata_start = .;
.rodata :
{
*(.rodata)
}
. = ALIGN(4K);
_hulk_rodata_end = .;
_hulk_data_start = .;
.data :
{
*(.data)
}
. = ALIGN(4K);
_hulk_data_end = .;
_hulk_binary_size = . - _hulk_mem_start;
_hulk_bss_start = .;
.bss :
{
*(COMMON)
*(.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;
}
-296
View File
@@ -1,296 +0,0 @@
/**
* HURL, the HOS Unreal Region Locator.
*
* HURL provides virtual memory management for HULK.
*/
module hulk.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;
/** HULK virtual base address. */
enum ulong HULK_VIRTUAL_BASE_ADDRESS = 0xFFFF_8000_0000_0000u;
/** HULK virtual stack top address. */
enum ulong HULK_VIRTUAL_STACK_TOP_ADDRESS = 0xFFFF_A000_0000_0000u;
/** HULK virtual framebuffer address. */
enum ulong HULK_VIRTUAL_FRAMEBUFFER_ADDRESS = 0xFFFF_A000_0000_0000u;
struct hurl
{
/**
* 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_VIRTUAL_BASE_ADDRESS;
/* 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_VIRTUAL_STACK_TOP_ADDRESS - header.stack_size,
header.bootinfo.stack_phys,
header.stack_size,
PT_WRITABLE | PT_NO_EXECUTE);
/* Map device framebuffer. */
map_range(HULK_VIRTUAL_FRAMEBUFFER_ADDRESS,
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 = (header.bootinfo.fb.height * header.bootinfo.fb.stride * 4u + PAGE_SIZE - 1u) & ~(PAGE_SIZE - 1u);
ulong[2][2] reserved = [
[header.bootinfo.hulk_phys, LinkerAddresses.hulk_binary_size],
[cast(ulong)header.bootinfo.fb.buffer, fb_size],
];
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(T, U)(T virtual, U 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_range(size_t virtual, size_t 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 identity_map_range(size_t address, size_t length, ulong flags)
{
size_t end = address + length;
for (size_t page = address & ~0xFFFu; page < end; page += PAGE_SIZE)
{
map(page, page, 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;
}
}
-128
View File
@@ -1,128 +0,0 @@
/**
* IDT (Interrupt Descriptor Table) functionality.
*/
module hulk.idt;
import hulk.gdt;
import ldc.llvmasm;
import hulk.fb;
import hulk.console;
import hulk.klog;
import hulk.apic;
import hulk.rtc;
struct idt
{
/* The I/O APIC is configured to map IRQ 0 to interrupt 64 (0x40). */
public static enum ulong INT_RTC = 0x48u; /* IRQ 8 */
public static enum ulong INT_LAPIC_TIMER = 0x70u;
public static enum ulong INT_LAPIC_LINT0 = 0x71u;
public static enum ulong INT_LAPIC_LINT1 = 0x72u;
struct idtr_t
{
ushort limit;
align(2) ulong offset;
}
static assert(idtr_t.sizeof == 10u);
alias descriptor_t = ulong[2];
static __gshared align(0x10) descriptor_t[256] idt;
static assert(idt.sizeof == (256u * 16u));
static __gshared idtr_t idtr;
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 bool isr_has_error_code(size_t isr)
{
return (isr == 8) ||
((10 <= isr) && (isr <= 14)) ||
(isr == 17) ||
(isr == 21) ||
(isr == 29) ||
(isr == 30);
}
private static bool isr_is_trap(size_t isr)
{
return (isr < 32u) && (isr != 2u);
}
private static void set_isrs()
{
ulong isr_address;
static foreach(isr; 0 .. 256)
{
mixin("isr_address = __asm!ulong(`
movabs $$1f, %rax
jmp 2f
1:
pushq %rdi
pushq %rsi
pushq %rax
mov $$", isr, ", %rdi
" ~ (isr_has_error_code(isr) ? "mov 0x18(%rsp), %rsi" : "") ~ "
movabs $$isr, %rax
callq *%rax
popq %rax
popq %rsi
popq %rdi
" ~ (isr_has_error_code(isr) ? "add $$8, %rsp" : "") ~ "
iretq
2:`, `={rax}`);");
mixin("set_descriptor(", isr, ", 0u, " ~
(isr_is_trap(isr) ? "true" : "false") ~ ", isr_address);");
}
}
private static void set_descriptor(size_t index, ulong dpl, bool trap, ulong offset)
{
idt[index][0] =
0x0000_8E_00_0000_0000u |
((offset & 0xFFFF_0000u) << 32u) |
(dpl << 45u) |
((trap ? 1uL : 0uL) << 40u) |
(gdt.SELECTOR_KERNEL_CODE << 16u) |
(offset & 0xFFFFu);
idt[index][1] = offset >> 32u;
}
}
public extern(C) void isr(ulong vector, ulong arg)
{
switch (vector)
{
case idt.INT_RTC:
rtc.isr();
break;
case idt.INT_LAPIC_TIMER:
case idt.INT_LAPIC_LINT0:
case idt.INT_LAPIC_LINT1:
apic.isr(vector);
break;
default:
console.clear();
fb.clear(0xFF8000u);
klog.writefln("ISR %u, 0x%x", vector, arg);
__asm("cli", "");
for (;;)
{
__asm("hlt", "");
}
}
}
-73
View File
@@ -1,73 +0,0 @@
/**
* HULK Kernel Log buffer.
*/
module hulk.klog;
import core.stdc.stdarg;
import hulk.console;
static import hulk.writef;
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.writef(s, args, function void(ubyte ch) {
console.write(ch);
});
}
/**
* 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 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);
}
}
-139
View File
@@ -1,139 +0,0 @@
/**
* 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;
}
}
-62
View File
@@ -1,62 +0,0 @@
/**
* 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
@@ -1,70 +0,0 @@
/**
* 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);
}
}
-185
View File
@@ -1,185 +0,0 @@
/**
* 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);
-48
View File
@@ -1,48 +0,0 @@
module hulk.pci;
import hulk.cpu;
import hulk.klog;
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;
private static ulong read_config_register(ulong bus_id, ulong device_id, ulong register_id)
{
ulong addr = 0x8000_0000u | (bus_id << 16u) | (device_id << 11u) | (register_id << 2u);
out32(IO_ADDR_CONFIG_ADDRESS, addr);
return in32(IO_ADDR_CONFIG_DATA);
}
private static void scan(ulong bus_id, ulong device_id)
{
ulong reg0 = read_config_register(bus_id, device_id, 0u);
if (reg0 != 0xFFFFFFFFu)
{
ulong reg2 = read_config_register(bus_id, device_id, 2u);
klog.writefln("Found PCI device %04x:%04x (%02x:%02x:%02x) at %02u:%02u",
(reg0 & 0xFFFFu), (reg0 >> 16u),
(reg2 >> 24u) & 0xFFu,
(reg2 >> 16u) & 0xFFu,
(reg2 >> 8u) & 0xFFu,
bus_id, device_id);
}
}
public static void initialize()
{
klog.writefln("Scanning PCI devices...");
for (ulong bus_id = 0u; bus_id < 256u; bus_id++)
{
for (ulong device_id = 0u; device_id < 32u; device_id++)
{
scan(bus_id, device_id);
}
}
klog.writefln("PCI scan complete.");
}
}
-16
View File
@@ -1,16 +0,0 @@
/**
* 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);
}
}
-42
View File
@@ -1,42 +0,0 @@
/**
* PIT (Programmable Interval Timer) functionality.
*/
module hulk.pit;
import hulk.cpu;
import hulk.klog;
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 = 100u;
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()
{
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()
{
klog.writefln("PIT ISR");
}
}
-58
View File
@@ -1,58 +0,0 @@
/**
* RTC (Real-Time Clock) functionality.
*/
module hulk.rtc;
import hulk.cpu;
import hulk.klog;
import hulk.apic;
struct rtc
{
private enum ubyte PORT_SELECT = 0x70u;
private enum ubyte PORT_DATA = 0x71u;
private enum ubyte DISABLE_NMI = 0x80u;
private enum ubyte SR_A = 0xAu;
private enum ubyte SR_B = 0xBu;
private enum ubyte SR_C = 0xCu;
private enum ubyte SR_B_ENABLE_IRQ = 0x40u;
public static void initialize()
{
/* Enable IRQ 8 to receive RTC interrupts. */
out8(PORT_SELECT, DISABLE_NMI | SR_B);
ubyte sr_b = in8(PORT_DATA);
out8(PORT_SELECT, DISABLE_NMI | SR_B);
out8(PORT_DATA, sr_b | SR_B_ENABLE_IRQ);
out8(PORT_SELECT, DISABLE_NMI | SR_A);
klog.writefln("SR_A = 0x%x", in8(PORT_DATA));
/* Send EOI to enable more RTC interrupts and re-enable NMIs. */
eoi();
}
private static void eoi()
{
/* Read from status register C to clear the interrupt. */
out8(PORT_SELECT, SR_C);
in8(PORT_DATA);
}
public static void isr()
{
static __gshared ulong count;
static __gshared ulong seconds;
count++;
if ((count % 1024) == 0u)
{
seconds++;
klog.writefln("Seconds: %u", seconds);
}
eoi();
apic.eoi();
}
}
-151
View File
@@ -1,151 +0,0 @@
/**
* 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 s Format string.
* @param args Variable arguments structure.
* @param ch_out Character output function.
*
* @return Number of characters written.
*/
size_t writef(string s, va_list args, ch_out_fn ch_out)
{
size_t length_written;
bool escape = false;
char pad = ' ';
size_t width;
foreach (char c; s)
{
if (escape)
{
if (c == 'x')
{
ulong v;
va_arg(args, v);
length_written += write_hex(v, false, pad, width, ch_out);
escape = false;
}
else if (c == 'X')
{
ulong v;
va_arg(args, v);
length_written += write_hex(v, true, 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 value in hexadecimal to the given output function.
*
* @param v Value to format.
* @param upper Whether to use uppercase letters.
* @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, 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[16] buf;
size_t i;
do
{
ulong n = v & 0xFu;
buf[i] = upper ? hex_chars_upper[n] : hex_chars_lower[n];
v >>= 4u;
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;
}
/**
* 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 uefi-d deleted from e70959ce8a.
+100
View File
@@ -0,0 +1,100 @@
#!/bin/bash -x
BINUTILS_VERSION=${BINUTILS_VERSION:-"2.20"}
GCC_VERSION=${GCC_VERSION:-"4.4.2"}
TARGET=${TARGET:-"i586-elf"}
PREFIX=${PREFIX:-"$HOME/local/$TARGET"}
GNUFTP=ftp://ftp.gnu.org/gnu
export PATH=$PREFIX/bin:$PATH
mkdir -p build-binutils build-gcc
if [ ! -f "binutils-$BINUTILS_VERSION.tar.bz2" ]; then
wget "$GNUFTP/binutils/binutils-$BINUTILS_VERSION.tar.bz2"
if [ $? != 0 ]; then
echo "Error downloading binutils"
exit 1
fi
fi
if [ ! -f "gcc-$GCC_VERSION.tar.bz2" ]; then
wget "$GNUFTP/gcc/gcc-$GCC_VERSION/gcc-$GCC_VERSION.tar.bz2"
if [ $? != 0 ]; then
echo "Error downloading gcc"
exit 1
fi
fi
if [ ! -d "binutils-$BINUTILS_VERSION" ]; then
tar xvjf "binutils-$BINUTILS_VERSION.tar.bz2"
if [ $? != 0 ]; then
echo "Error extracting binutils"
exit 1
fi
fi
if [ ! -d "gcc-$GCC_VERSION" ]; then
tar xvjf "gcc-$GCC_VERSION.tar.bz2"
if [ $? != 0 ]; then
echo "Error extracting gcc"
exit 1
fi
fi
# build binutils
dum=`which $TARGET-ar`
if [ $? != 0 ]; then
pushd build-binutils
../binutils-$BINUTILS_VERSION/configure --target=$TARGET --prefix=$PREFIX --disable-nls
if [ $? != 0 ]; then
echo "Error configuring binutils"
exit 1
fi
make all
if [ $? != 0 ]; then
echo "Error building binutils"
exit 1
fi
make install
if [ $? != 0 ]; then
echo "Error installing binutils"
exit 1
fi
popd
fi
# build gcc
dum=`which $TARGET-gcc`
if [ $? != 0 ]; then
pushd build-gcc
../gcc-$GCC_VERSION/configure --target=$TARGET --prefix=$PREFIX --disable-nls --enable-languages=c,c++ --without-headers
if [ $? != 0 ]; then
echo "Error configuring gcc"
exit 1
fi
make all-gcc
if [ $? != 0 ]; then
echo "Error building gcc"
exit 1
fi
make install-gcc
if [ $? != 0 ]; then
echo "Error installing gcc"
exit 1
fi
make all-target-libgcc
if [ $? != 0 ]; then
echo "Error building libgcc"
exit 1
fi
make install-target-libgcc
if [ $? != 0 ]; then
echo "Error installing libgcc"
exit 1
fi
popd
fi
exit 0
-76
View File
@@ -1,76 +0,0 @@
project_name "x86_64-elf-gcc"
binutils_version = "2.35"
binutils_checksum = "1b11659fb49e20e18db460d44485f09442c8c56d5df165de9461eb09c8302f85"
gcc_version = "10.2.0"
gcc_checksum = "b8dd4368bb9c7f0b98188317ee0254dd8cc99d1e3a18d0ff146c855fe16c1d8c"
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)
# Download archives.
download "https://ftp.gnu.org/gnu/binutils/binutils-#{binutils_version}.tar.xz",
"#{build_dir}/binutils-#{binutils_version}.tar.xz",
sha256sum: binutils_checksum
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.
sh "tar", "xJf", "binutils-#{binutils_version}.tar.xz",
chdir: build_dir
sh "tar", "xJf", "gcc-#{gcc_version}.tar.xz",
chdir: build_dir
# Build 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.
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.
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