├── .gitignore ├── Disk.vmdk ├── MBR2GPT.vbox ├── MBR2GPT.vmx ├── MBR2GPT.vmxf ├── README.md ├── bbp ├── README.md ├── bbp.ld ├── bbp.vcxproj ├── boot │ ├── README.md │ ├── bios.asm │ ├── boot.asm │ ├── boot.ld │ ├── common16.h │ ├── common32.h │ ├── main16.c │ ├── main16.h │ ├── main32.c │ ├── main32.h │ └── makefile ├── buildimg.bat ├── config.h ├── kernel │ ├── README.md │ ├── acpi.c │ ├── acpi.h │ ├── ahci.c │ ├── ahci.h │ ├── apic.c │ ├── apic.h │ ├── common.h │ ├── cpuid.h │ ├── debug_print.c │ ├── debug_print.h │ ├── interrupts.asm │ ├── interrupts.c │ ├── interrupts.h │ ├── io.h │ ├── kernel.ld │ ├── kmain.c │ ├── kmain.h │ ├── lib.c │ ├── lib.h │ ├── makefile │ ├── msr.h │ ├── paging.c │ ├── paging.h │ ├── pci.c │ └── pci.h └── makefile ├── bochsrc.bxrc ├── bochsrc_debug.bxrc ├── mbr ├── README.md ├── main.asm ├── main.inc ├── makefile └── mbr.vcxproj ├── mbr2gpt.sln ├── run_bochs.bat ├── run_bochs_debug.bat └── run_qemu.bat /.gitignore: -------------------------------------------------------------------------------- 1 | *.user 2 | *.filter 3 | *.o 4 | /*.suo 5 | /*.sdf 6 | /bochsdbg.txt 7 | /bochsout.txt 8 | /Release 9 | /ipch 10 | /bbp/Release 11 | /mbr/Release 12 | /doc 13 | /Logs 14 | /*.vbox-prev 15 | /*.vmsd 16 | /*.nvram 17 | /vmware* 18 | 19 | /bbp/kernel/acpica 20 | -------------------------------------------------------------------------------- /Disk.vmdk: -------------------------------------------------------------------------------- 1 | # Disk DescriptorFile 2 | version=1 3 | CID=bc86b9fe 4 | parentCID=ffffffff 5 | createType="monolithicFlat" 6 | 7 | # Extent description 8 | RW 10080 FLAT "Release/disk.img" 0 9 | 10 | # The disk Data Base 11 | #DDB 12 | 13 | ddb.virtualHWVersion = "4" 14 | ddb.adapterType="ide" 15 | ddb.uuid.image="6530d803-6ee0-4ecd-a3fb-c218a8f6e4aa" 16 | ddb.uuid.parent="00000000-0000-0000-0000-000000000000" 17 | ddb.uuid.modification="00000000-0000-0000-0000-000000000000" 18 | ddb.uuid.parentmodification="00000000-0000-0000-0000-000000000000" 19 | ddb.geometry.cylinders="10" 20 | ddb.geometry.heads="16" 21 | ddb.geometry.sectors="63" 22 | ddb.geometry.biosCylinders="10" 23 | ddb.geometry.biosHeads="16" 24 | ddb.geometry.biosSectors="63" 25 | -------------------------------------------------------------------------------- /MBR2GPT.vbox: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | -------------------------------------------------------------------------------- /MBR2GPT.vmx: -------------------------------------------------------------------------------- 1 | .encoding = "UTF-8" 2 | config.version = "8" 3 | virtualHW.version = "8" 4 | vcpu.hotadd = "FALSE" 5 | sched.swap.vmxSwapEnabled = "FALSE" 6 | memsize = "256" 7 | mem.hotadd = "FALSE" 8 | nvram = "Memory.nvram" 9 | floppy0.startConnected = "FALSE" 10 | floppy0.fileName = "" 11 | floppy0.autodetect = "TRUE" 12 | ethernet0.present = "TRUE" 13 | ethernet0.connectionType = "nat" 14 | ethernet0.virtualDev = "e1000" 15 | ethernet0.wakeOnPcktRcv = "FALSE" 16 | ethernet0.addressType = "generated" 17 | usb.present = "TRUE" 18 | ehci.present = "TRUE" 19 | sound.present = "TRUE" 20 | sound.startConnected = "TRUE" 21 | sound.fileName = "-1" 22 | sound.autodetect = "TRUE" 23 | pciBridge0.present = "TRUE" 24 | pciBridge4.present = "TRUE" 25 | pciBridge4.virtualDev = "pcieRootPort" 26 | pciBridge4.functions = "8" 27 | pciBridge5.present = "TRUE" 28 | pciBridge5.virtualDev = "pcieRootPort" 29 | pciBridge5.functions = "8" 30 | pciBridge6.present = "TRUE" 31 | pciBridge6.virtualDev = "pcieRootPort" 32 | pciBridge6.functions = "8" 33 | pciBridge7.present = "TRUE" 34 | pciBridge7.virtualDev = "pcieRootPort" 35 | pciBridge7.functions = "8" 36 | vmci0.present = "TRUE" 37 | hpet0.present = "TRUE" 38 | usb.vbluetooth.startConnected = "TRUE" 39 | displayName = "MBR2GPT" 40 | guestOS = "other-64" 41 | virtualHW.productCompatibility = "hosted" 42 | gui.exitOnCLIHLT = "FALSE" 43 | powerType.powerOff = "hard" 44 | powerType.powerOn = "hard" 45 | powerType.suspend = "hard" 46 | powerType.reset = "hard" 47 | extendedConfigFile = "MBR2GPT.vmxf" 48 | ethernet0.generatedAddress = "00:0c:29:d2:7f:24" 49 | vmci0.id = "-1934875086" 50 | uuid.location = "56 4d d9 14 44 2e 2d ab-20 2a 0e 53 2d d2 7f 24" 51 | uuid.bios = "56 4d d9 14 44 2e 2d ab-20 2a 0e 53 2d d2 7f 24" 52 | #bios.bootdelay = 10000 53 | cleanShutdown = "TRUE" 54 | replay.supported = "FALSE" 55 | replay.filename = "" 56 | pciBridge0.pciSlotNumber = "17" 57 | pciBridge4.pciSlotNumber = "21" 58 | pciBridge5.pciSlotNumber = "22" 59 | pciBridge6.pciSlotNumber = "23" 60 | pciBridge7.pciSlotNumber = "24" 61 | scsi0.pciSlotNumber = "16" 62 | usb.pciSlotNumber = "32" 63 | ethernet0.pciSlotNumber = "33" 64 | sound.pciSlotNumber = "34" 65 | ehci.pciSlotNumber = "35" 66 | vmci0.pciSlotNumber = "36" 67 | usb:1.present = "TRUE" 68 | ethernet0.generatedAddressOffset = "0" 69 | vmotion.checkpointFBSize = "5242880" 70 | usb:1.speed = "2" 71 | usb:1.deviceType = "hub" 72 | usb:1.port = "1" 73 | usb:1.parent = "-1" 74 | svga.autodetect = "FALSE" 75 | svga.maxWidth = "1280" 76 | svga.maxHeight = "1024" 77 | svga.vramSize = "5242880" 78 | tools.syncTime = "FALSE" 79 | unity.wasCapable = "FALSE" 80 | tools.remindInstall = "FALSE" 81 | softPowerOff = "FALSE" 82 | numvcpus = "2" 83 | ide0:0.present = "TRUE" 84 | ide0:0.fileName = "Disk.vmdk" 85 | monitor.virtual_mmu = "software" 86 | monitor.virtual_exec = "hardware" 87 | ide0:0.redo = "" 88 | scsi0.present = "TRUE" 89 | scsi0.virtualDev = "lsilogic" 90 | tools.upgrade.policy = "manual" 91 | mks.keyboardFilter = "allow" 92 | ide0:1.present = "FALSE" 93 | scsi0:0.present = "FALSE" 94 | ide1:0.present = "FALSE" 95 | scsi0:1.present = "FALSE" 96 | serial0.present = "FALSE" 97 | usb:0.present = "TRUE" 98 | usb:0.deviceType = "hid" 99 | usb:0.port = "0" 100 | usb:0.parent = "-1" 101 | -------------------------------------------------------------------------------- /MBR2GPT.vmxf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 52 ea 1c 7e 7b ec 13 53-f8 b0 85 63 fc 28 d6 a4 5 | 6 | 7 | 8 | MBR2GPT.vmx02 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | mbr2gpt 2 | ======= 3 | 4 | MBR bootcode to read GPT headers and load bootloader from BIOS Boot Partition 5 | 6 | mbr 7 | --- 8 | 9 | Master Boot Record code 10 | 11 | bbp 12 | --- 13 | 14 | Test BIOS Boot Partition code (my playground to write an OS) 15 | 16 | Virtual Machines 17 | ---------------- 18 | 19 | * MBR2GPT.vbox - VirtualBox test machine 20 | * MBR2GPT.vmx - VMWare Player test machine 21 | * run_bochs.bat - launch Bochs test machine 22 | * run_bochs_debug.bat - launch Bochs test machine with GUI debugger 23 | * run_qemu.bat - launch QEMU test machine 24 | 25 | Other files 26 | ----------- 27 | 28 | * bochsrc.bxrc - Bochs configuration file 29 | * bochsrc_debug.bxrc - Bochs configuration file (with GUI debugger) 30 | * Disk.vmdk - VMDK disk image header for VirtualBox and VMWare Player test machines 31 | 32 | Build Requirements 33 | ------------------ 34 | 35 | You'll need: 36 | * MinGW Cross-compiler that's capable of building ELF files. See how to build one here: http://gusc.lv/2012/12/myos-mingw-cross-compiler/ 37 | * Netwide Assembler from: http://www.nasm.us/ 38 | * DiskUtils from: https://github.com/gusc/diskutils 39 | * Microsoft Visual Studio Express 2010 40 | -------------------------------------------------------------------------------- /bbp/README.md: -------------------------------------------------------------------------------- 1 | BIOS Boot Partition 2 | =================== 3 | 4 | This is the BBP bootcode that get's loaded by MBR. 5 | 6 | File list 7 | --------- 8 | 9 | Main entry files: 10 | * boot/boot.asm - main BBP entry code (real mode code) 11 | * boot/ - Real Mode -> Protected Mode -> Long Mode bootstrap code 12 | * kernel/ - Kernel code 13 | 14 | Build files: 15 | * bbp.ld - BBP linker script 16 | * bbp.vcxproj - Visual Studio 2010 project file 17 | * buildimg.bat - Bach script to merge MBR and BBP code into Bochs disk image file using DiskUtils 18 | * config.h - global configuration file (compile-time configuration) 19 | * makefile - Make build script 20 | 21 | 22 | Requirements 23 | ------------ 24 | 25 | * MinGW Cross-compiler that's capable of building ELF64 files. See how to build one here: http://gusc.lv/2012/12/myos-mingw-cross-compiler/ 26 | * Netwide Assembler from: http://www.nasm.us/ 27 | * DiskUtils from: https://github.com/gusc/diskutils 28 | * Microsoft Visual Studio Express 2010 29 | -------------------------------------------------------------------------------- /bbp/bbp.ld: -------------------------------------------------------------------------------- 1 | /*OUTPUT_FORMAT(elf64-x86-64)*/ 2 | OUTPUT_FORMAT(binary) 3 | ENTRY(start16) 4 | SECTIONS { 5 | .text 0x7C00 : AT( 0x7C00 ) { 6 | boot.o(.text); 7 | *(.text); 8 | } 9 | .rodata : { 10 | *(.rodata); 11 | } 12 | .data : { 13 | *(.data); 14 | } 15 | .bss : { 16 | *(.bss); 17 | } 18 | /DISCARD/ : { 19 | *(.eh_frame); 20 | } 21 | . = ALIGN(4096); 22 | } -------------------------------------------------------------------------------- /bbp/bbp.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Release 6 | Win32 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | {3D779CE6-A610-49F7-AC07-992AEEB4115D} 76 | kernel 77 | bbp 78 | 79 | 80 | 81 | Makefile 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | C:\MinGW\bin;C:\MinGW\msys\1.0\bin;C:\Program Files\Netwide Assembler;C:\cross-gcc\i786-elf\bin;C:\cross-gcc\x86_64-elf\bin 90 | make -C "$(ProjectDir)" 91 | buildimg.bat 92 | $(NMakeBuildCommandLine) 93 | del *.o "boot\*.o" "kernel\*.o" "..\Release\bbp.img" "..\Release\disk.img" 94 | 95 | 96 | 97 | 98 | 99 | bbp.img 100 | 101 | 102 | -------------------------------------------------------------------------------- /bbp/boot/README.md: -------------------------------------------------------------------------------- 1 | Boot 2 | ==== 3 | 4 | This is the main bootstrap code 5 | 6 | File list 7 | --------- 8 | 9 | Main entry files: 10 | * boot.asm - This file is compiled at the top of BBP binary image and receives control from MBR 11 | 12 | Helper files: 13 | * bios.asm - BIOS wrapper routines used by main16.c 14 | * common16.h - Real Mode data types (also directs GCC to emmit 16bit assembly) 15 | * common32.h - Protected Mode data types 16 | * main16.* - Real Mode initialization code 17 | * main32.* - Protected Mode initialization code 18 | 19 | Build files: 20 | * boot.ld - Bootstrap linker script 21 | * makefile - Make build script 22 | -------------------------------------------------------------------------------- /bbp/boot/bios.asm: -------------------------------------------------------------------------------- 1 | ; 2 | ; BIOS utility subroutines 3 | ; ======================== 4 | ; 5 | ; This file contains wrappers for BIOS funciton calls to be used in C. 6 | ; All the functions are written with cdecl calling convention 7 | ; 8 | ; License (BSD-3) 9 | ; =============== 10 | ; 11 | ; Copyright (c) 2013, Gusts 'gusC' Kaksis 12 | ; All rights reserved. 13 | ; 14 | ; Redistribution and use in source and binary forms, with or without 15 | ; modification, are permitted provided that the following conditions are met: 16 | ; * Redistributions of source code must retain the above copyright 17 | ; notice, this list of conditions and the following disclaimer. 18 | ; * Redistributions in binary form must reproduce the above copyright 19 | ; notice, this list of conditions and the following disclaimer in the 20 | ; documentation and/or other materials provided with the distribution. 21 | ; * Neither the name of the nor the 22 | ; names of its contributors may be used to endorse or promote products 23 | ; derived from this software without specific prior written permission. 24 | ; 25 | ; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 26 | ; ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 27 | ; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 28 | ; DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY 29 | ; DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 30 | ; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 31 | ; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 32 | ; ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 33 | ; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 34 | ; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35 | ; 36 | 37 | [section .text] 38 | [global set_video_mode] ; Export void set_video_mode(uint16 mode) to C 39 | [global set_svga_mode] ; Export void set_svga_mode(uint16 mode) to C 40 | [global enable_a20] ; Export void enable_a20() to C 41 | [global check_a20] ; Export uint16 check_a20() to C 42 | [global read_e820] ; Export void read_e820(e820map_t *mem_map) to C 43 | 44 | [bits 16] ; Real mode 45 | 46 | set_video_mode: ; Set video mode 47 | push bp ; save base pointer 48 | mov bp, sp ; set stack pointer as our base pointer 49 | add bp, 4 ; increment base pointer (as the first 2 values 50 | ; on the stack are the old base pointer and 51 | ; old instruction pointer) 52 | add bp, 2 ; if using .code16gcc add 2 more bytes, as GCC pushes 32bit values on the stack 53 | mov ax, word [bp] ; get video mode parameter 54 | mov ah, 0x00 ; command: change video mode 55 | int 0x10 ; call video interrupt 56 | pop bp ; restore the old base pointer 57 | ret ; return to callee 58 | 59 | set_svga_mode: ; Set SuperVGA video mode 60 | push bp ; save base pointer 61 | mov bp, sp ; set stack pointer as our base pointer 62 | add bp, 4 ; increment base pointer (as the first 2 values 63 | ; on the stack are the old base pointer and 64 | ; old instruction pointer) 65 | add bp, 2 ; if using .code16gcc add 2 more bytes, as GCC pushes 32bit values on the stack 66 | mov bx, word [bp] ; get video mode parameter 67 | mov ax, 4F02h ; command: set SuperVGA video mode 68 | int 0x10 ; call video interrupt 69 | pop bp ; restore the old base pointer 70 | ret ; return to callee 71 | 72 | enable_a20: ; Enable A20 Gate to access high memory in protected mode (Fast A20) 73 | in al, 0x92 ; read from io port 0x92 74 | mov cl, al 75 | and cl, 2 ; test if bit 2 is not set 76 | jnz .ret ; if it's set, then we're skipping 77 | or al, 2 ; set 2nd bit to 1 78 | out 0x92, al ; write back to port 0x92 79 | .ret: 80 | ret ; return to callee 81 | 82 | read_e820: ; Read E820 Memory map 83 | push bp ; save base pointer 84 | mov bp, sp ; set stack pointer as our base pointer 85 | add bp, 4 ; increment base pointer (as the first 2 values 86 | ; on the stack are the old base pointer and 87 | ; old instruction pointer + 2 more bytes, as GCC pushes 32bit values on the stack) 88 | add bp, 2 ; if using .code16gcc add 2 more bytes, as GCC pushes 32bit values on the stack 89 | 90 | mov di, word [bp] ; set DI to location where we'll read E820 map (a pointer argument from C) 91 | add di, 4 ; first word is reserved for array size 92 | ; second word is the size of the size of the first entry 93 | 94 | xor eax, eax ; initially we have no entries in the table 95 | push ax ; store current count on the stack 96 | xor ebx, ebx ; clear ebx 97 | 98 | .read_more: 99 | mov eax, 0x0000E820 ; command: E820 map 100 | mov ecx, 0x18 ; set ECX to value of 24 - the max size of entry (only ACPI 3.0 has 24 byte entries) 101 | mov edx, 0x534D4150 ; set EDX to magic number "SMAP" 102 | 103 | int 0x15 ; call memory interrupt 104 | jc .end ; if carry flag set, then we failed 105 | cmp eax, 0x534D4150 ; should be the magic number "SMAP", is it? 106 | jne .end ; if magic number is not set, then we failed 107 | 108 | cmp ebx, 0x0 ; test EBX for 0 109 | je .end ; if EBX is 0, this was the last entry 110 | 111 | pop ax ; pop array size from the stack 112 | inc ax ; increment it by 1 113 | push ax ; push it back on the stack 114 | 115 | mov [di - 2], cx ; save entry size 116 | add di, 0x1A ; increment DI by 26 117 | 118 | jmp .read_more ; read some more 119 | 120 | .end: 121 | pop ax ; get entry count 122 | mov di, [bp] ; move back to the beginning of the array 123 | mov [di], ax ; no entries on E820 map 124 | pop bp ; restore the old base pointer 125 | ret ; return to callee 126 | -------------------------------------------------------------------------------- /bbp/boot/boot.asm: -------------------------------------------------------------------------------- 1 | ; 2 | ; BBP programm entry 3 | ; ================== 4 | ; 5 | ; This file contains entry point and glue code between real mode and long mode 6 | ; 7 | ; Program flow: 8 | ; 1. setup registers 9 | ; 2. execute C main16() function that sets up everything to enter protected mode 10 | ; 3. enter Protected Mode 11 | ; 4. execute C main32() function that sets up everything to enter long mode 12 | ; 3. enter Long Mode 13 | ; 4. execute C kmain() function that starts up the kernel 14 | ; 15 | ; License (BSD-3) 16 | ; =============== 17 | ; 18 | ; Copyright (c) 2013, Gusts 'gusC' Kaksis 19 | ; All rights reserved. 20 | ; 21 | ; Redistribution and use in source and binary forms, with or without 22 | ; modification, are permitted provided that the following conditions are met: 23 | ; * Redistributions of source code must retain the above copyright 24 | ; notice, this list of conditions and the following disclaimer. 25 | ; * Redistributions in binary form must reproduce the above copyright 26 | ; notice, this list of conditions and the following disclaimer in the 27 | ; documentation and/or other materials provided with the distribution. 28 | ; * Neither the name of the nor the 29 | ; names of its contributors may be used to endorse or promote products 30 | ; derived from this software without specific prior written permission. 31 | ; 32 | ; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 33 | ; ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 34 | ; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 35 | ; DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY 36 | ; DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 37 | ; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 38 | ; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 39 | ; ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 40 | ; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 41 | ; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 42 | ; 43 | 44 | ; Definitions: 45 | %define ORG_LOC 0x7C00 ; Initial position in memory (where MBR loads us) 46 | 47 | [section .text] 48 | [global start16] ; Export start16 to linker 49 | [extern main16] ; Import main16() from C 50 | [extern main32] ; Import main32() from C 51 | [extern kmain] ; Import kmain() from C 52 | 53 | ; Remember in NASM it's: 54 | ; instruction destination, source 55 | 56 | [bits 16] ; Real mode 57 | 58 | start16: ; Boot entry point 59 | ; Setup registers 60 | xor eax, eax ; clear EAX 61 | xor ebx, ebx ; clear EBX 62 | xor ecx, ecx ; clear ECX 63 | xor edx, edx ; clear EDX 64 | xor esi, esi ; clear ESI 65 | xor edi, edi ; clear EDI 66 | xor ebp, ebp ; clear EBP 67 | mov ds, ax ; zero out data segment register (DS) 68 | mov es, ax ; zero out extra segment register (ES) 69 | mov ss, ax ; zero out stack segment register (SS) 70 | mov fs, ax ; zero out general purpose data segment register (FS) 71 | mov gs, ax ; zero out general purpose data segment register (FS) 72 | mov sp, ORG_LOC ; set stack pointer to the begining of MBR location in memory 73 | 74 | ; Call Real Mode initialization 75 | cli ; disable all maskable interrupts 76 | call main16 ; call C function main16() (see: boot/main16.c) 77 | 78 | ; Enter Protected mode 79 | lgdt [gdt32_ptr] ; load 32bit GDT pointer 80 | 81 | mov eax, cr0 ; read from CR0 82 | or eax, 0x00000001 ; set Protected Mode bit 83 | mov cr0, eax ; write to CR0 84 | 85 | jmp 0x08:start32 ; do the magic jump to finalize Protected Mode setup 86 | 87 | [bits 32] ; Protected mode 88 | 89 | start32: ; Protected mode entry point 90 | ; Setup segment registers 91 | mov eax, 0x10 ; selector 0x10 - data descriptor 92 | xor ebx, ebx ; clear EBX 93 | xor ecx, ecx ; clear ECX 94 | xor edx, edx ; clear EDX 95 | xor esi, esi ; clear ESI 96 | xor edi, edi ; clear EDI 97 | xor ebp, ebp ; clear EBP 98 | mov esp, ORG_LOC ; clear the stack 99 | mov ss, ax ; set stack segment 100 | mov ds, ax ; set data segment 101 | mov es, ax ; set extra segment 102 | mov fs, ax ; set general purpose data Segment 103 | mov gs, ax ; set general purpose data Segment 104 | 105 | ; Call Protected Mode Initialization 106 | call main32 ; call C function main32() (see: boot/main32.c) 107 | 108 | ; Disable all IRQs 109 | mov al, 0xFF ; set out 0xFF to 0xA1 and 0x21 to disable all IRQs 110 | out 0xA1, al 111 | out 0x21, al 112 | 113 | ; Setup long mode. 114 | mov eax, cr0 ; read from CR0 115 | and eax, 0x7FFFFFFF ; clear paging bit 116 | mov cr0, eax ; write to CR0 117 | 118 | mov eax, cr4 ; read from CR4 119 | or eax, 0x000000A0 ; set the PAE and PGE bit 120 | mov cr4, eax ; write to CR4 121 | 122 | mov eax, [pml4_ptr32] ; point eax to PML4 pointer location 123 | or eax, 0x0000000B ; enable write-through 124 | mov cr3, eax ; save PML4 pointer into CR3 125 | 126 | mov ecx, 0xC0000080 ; read from the EFER MSR 127 | rdmsr ; read MSR 128 | or eax, 0x00000101 ; set the LME and SYSCALL/SYSRET bits 129 | wrmsr ; write MSR 130 | 131 | lgdt [gdt64_ptr] ; load 64bit GDT pointer 132 | 133 | mov eax, cr0 ; read from CR0 134 | or eax, 0x80000000 ; set paging bit 135 | mov cr0, eax ; write to CR0 136 | jmp 0x08:start64 ; do the magic jump to Long Mode 137 | 138 | align 16 139 | [bits 64] ; Long mode 140 | 141 | start64: ; Long Mode entry point 142 | ; Register cleanup 143 | xor rax, rax ; aka r0 144 | xor rbx, rbx ; aka r1 145 | xor rcx, rcx ; aka r2 146 | xor rdx, rdx ; aka r3 147 | xor rsi, rsi ; aka r4 148 | xor rdi, rdi ; aka r5 149 | xor rbp, rbp ; aka r6 150 | mov rsp, ORG_LOC ; aka r7 and clear the stack 151 | xor r8, r8 152 | xor r9, r9 153 | xor r10, r10 154 | xor r11, r11 155 | xor r12, r12 156 | xor r13, r13 157 | xor r14, r14 158 | xor r15, r15 159 | mov ds, ax ; clear the legacy segment registers 160 | mov es, ax 161 | mov ss, ax 162 | mov fs, ax 163 | mov gs, ax 164 | 165 | call kmain ; call C function kmain() (see: kernel/kmain.c) 166 | cli ; disable interrupts 167 | jmp $ ; hang 168 | 169 | [section .data] 170 | 171 | [global pml4_ptr32] ; Make PML4 pointer accessible from C 172 | 173 | ; PML4 pointer (for 32bit CR3) 174 | pml4_ptr32: 175 | dd 0 ; Dummy entry - we'll populate it in main32 and later in kmain 176 | pml4_ptr32_end: 177 | 178 | [section .rodata] 179 | 180 | ; Global Descriptor Table (GDT) used to do the Protected Mode jump (this is read-only as we don't need to update it) 181 | gdt32: 182 | ; Null Descriptor (selector: 0x00) 183 | .null_desc: 184 | dw 0x0000 185 | dw 0x0000 186 | db 0x00 187 | db 0x00 188 | db 0x00 189 | db 0x00 190 | 191 | ; Code Descriptor (selector: 0x08) 192 | .code_desc: 193 | dw 0xffff ; 0:15 - Limit 194 | dw 0x0000 ; 16:31 - Base (low word) 195 | db 0x00 ; 32:39 - Base (high word low byte) 196 | db 10011010b ; 40:47 - Access byte 197 | db 11001111b ; 48:55 - Limit (high nibble) + Flags (4 bits) 198 | db 0x00 ; 56:64 - Base (high word high byte) 199 | 200 | ; Data Descriptor (selector: 0x10) 201 | .data_desc: 202 | dw 0xffff ; 0:15 - Limit 203 | dw 0x0000 ; 16:31 - Base (low word) 204 | db 0x00 ; 32:39 - Base (high word low byte) 205 | db 10010010b ; 40:47 - Access byte 206 | db 11001111b ; 48:55 - Limit (high nibble) + Flags (4 bits) 207 | db 0x00 ; 56:64 - Base (high word high byte) 208 | gdt32_end: 209 | 210 | ; GDT pointer (this get's passed to LGDT) 211 | gdt32_ptr: 212 | dw (gdt32_end - gdt32 - 1) ; Limit (size) 213 | dd (gdt32 + 0x000000000000) ; Base (location) 214 | gdt32_ptr_end: 215 | 216 | ; 64bit GDT 217 | align 16 218 | gdt64: 219 | ; Null Descriptor (selector: 0x00) 220 | .null_desc: 221 | dw 0x0000 222 | dw 0x0000 223 | db 0x00 224 | db 0x00 225 | db 0x00 226 | db 0x00 227 | 228 | ; Code Descriptor (selector: 0x08) 229 | .code_desc: 230 | dw 0x0000 ; 0:15 - Limit 231 | dw 0x0000 ; 16:31 - Base (low word) 232 | db 0x00 ; 32:39 - Base (high word low byte) 233 | ; P|DPL|DPL|1|1|C|R|A 234 | db 10011100b ; 40:47 - Access byte 235 | ; G|D|L|AVL|0|0|0|0 236 | db 00100000b ; 48:55 - Limit (high nibble) + Flags (4 bits) 237 | db 0x00 ; 56:64 - Base (high word high byte) 238 | 239 | ; Data Descriptor (selector: 0x10) 240 | .data_desc: 241 | dw 0x0000 ; 0:15 - Limit 242 | dw 0x0000 ; 16:31 - Base (low word) 243 | db 0x00 ; 32:39 - Base (high word low byte) 244 | db 10010000b ; 40:47 - Access byte 245 | db 00100000b ; 48:55 - Limit (high nibble) + Flags (4 bits) 246 | db 0x00 ; 56:64 - Base (high word high byte) 247 | gdt64_end: 248 | 249 | align 16 250 | gdt64_ptr: 251 | dw (gdt64_end - gdt64 - 1) ; Limit (size) 252 | dq (gdt64 + 0x0000000000000000) ; Base (location) 253 | gdt64_ptr_end: 254 | -------------------------------------------------------------------------------- /bbp/boot/boot.ld: -------------------------------------------------------------------------------- 1 | OUTPUT_FORMAT(elf64-x86-64) 2 | SECTIONS { 3 | .text : { 4 | boot.s.o(.text); 5 | bios.s.o(.text); 6 | main16.c64.o(.text); 7 | *(.text); 8 | } 9 | .rodata : { 10 | *(.rodata); 11 | } 12 | .data : { 13 | *(.data); 14 | } 15 | .bss : { 16 | *(.bss); 17 | } 18 | . = ALIGN(4096); 19 | } -------------------------------------------------------------------------------- /bbp/boot/common16.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Common data types (real mode) 4 | ============================= 5 | 6 | This file contains type definitions and helper structures. 7 | 8 | The idea of this file is to keep a precise control over data type sizes, so 9 | instead of int and long, we should have int32 or int64. 10 | 11 | Maybe in the future we'll introduce memory pointer type intptr or simply ptr, 12 | that will reference the largest integer type for memory access of the machine. 13 | That is, a 64bit int for x86_64 architecture and 32bit int for x86. 14 | 15 | License (BSD-3) 16 | =============== 17 | 18 | Copyright (c) 2013, Gusts 'gusC' Kaksis 19 | All rights reserved. 20 | 21 | Redistribution and use in source and binary forms, with or without 22 | modification, are permitted provided that the following conditions are met: 23 | * Redistributions of source code must retain the above copyright 24 | notice, this list of conditions and the following disclaimer. 25 | * Redistributions in binary form must reproduce the above copyright 26 | notice, this list of conditions and the following disclaimer in the 27 | documentation and/or other materials provided with the distribution. 28 | * Neither the name of the nor the 29 | names of its contributors may be used to endorse or promote products 30 | derived from this software without specific prior written permission. 31 | 32 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 33 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 34 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 35 | DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY 36 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 37 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 38 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 39 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 40 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 41 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 42 | 43 | */ 44 | 45 | #ifndef __common16_h 46 | #define __common16_h 47 | 48 | // Make this C output 16-bit 49 | asm(".code16gcc\n"); 50 | //asm(".code16\n"); 51 | 52 | #define __INLINE __attribute__((always_inline)) 53 | #define __NORETURN __attribute__((noreturn)) 54 | #define __PACKED __attribute__((packed)) 55 | #define __ALIGN(x) __attribute__((aligned(x))) 56 | 57 | #define BREAK() asm volatile ("xchg %bx, %bx") 58 | #define HANG() asm volatile ("int $0x18") // go to BASIC :) 59 | #define STOP() while(true){} 60 | 61 | // If we use .code16 then all ret and leave functions behave as in 16bit mode, 62 | // but the function entries are still behaving as in 32bit mode (GCC bug?) 63 | // So this is the fix - we move base pointer 2 bytes further thus leave cleans out 64 | // the stack frame correctly 65 | #define RET16() asm volatile ("add $2, %bp") 66 | // If we use .code16gcc then all ret and leave functions behave as in 32bit mode, 67 | // so right after leave (which is 0x66 prefixed) we do a magic switch to 68 | // 16-bit mode so that ret does not do a far jump. 69 | #define RET32() asm volatile ("leave\n\ 70 | .code16\n\ 71 | ret\n\ 72 | .code16gcc\n"); 73 | 74 | // Default types 75 | typedef unsigned char uchar; 76 | 77 | typedef unsigned char uint8; 78 | typedef unsigned short uint16; 79 | typedef unsigned int uint32; 80 | typedef unsigned long long uint64; 81 | 82 | typedef char int8; 83 | typedef short int16; 84 | typedef int int32; 85 | typedef long long int64; 86 | 87 | typedef float float32; 88 | typedef double float64; 89 | 90 | typedef void *handle_t; 91 | #define null 0 92 | #define true 1 93 | #define false 0 94 | 95 | #endif /* __common16_h */ 96 | -------------------------------------------------------------------------------- /bbp/boot/common32.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Common data types (protected mode) 4 | ================================== 5 | 6 | This file contains type definitions and helper structures. 7 | 8 | The idea of this file is to keep a precise control over data type sizes, so 9 | instead of int and long, we should have int32 or int64. 10 | 11 | Maybe in the future we'll introduce memory pointer type intptr or simply ptr, 12 | that will reference the largest integer type for memory access of the machine. 13 | That is, a 64bit int for x86_64 architecture and 32bit int for x86. 14 | 15 | License (BSD-3) 16 | =============== 17 | 18 | Copyright (c) 2013, Gusts 'gusC' Kaksis 19 | All rights reserved. 20 | 21 | Redistribution and use in source and binary forms, with or without 22 | modification, are permitted provided that the following conditions are met: 23 | * Redistributions of source code must retain the above copyright 24 | notice, this list of conditions and the following disclaimer. 25 | * Redistributions in binary form must reproduce the above copyright 26 | notice, this list of conditions and the following disclaimer in the 27 | documentation and/or other materials provided with the distribution. 28 | * Neither the name of the nor the 29 | names of its contributors may be used to endorse or promote products 30 | derived from this software without specific prior written permission. 31 | 32 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 33 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 34 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 35 | DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY 36 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 37 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 38 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 39 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 40 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 41 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 42 | 43 | */ 44 | 45 | #ifndef __common32_h 46 | #define __common32_h 47 | 48 | #define __INLINE __attribute__((always_inline)) 49 | #define __NORETURN __attribute__((noreturn)) 50 | #define __PACKED __attribute__((packed)) 51 | #define __ALIGN(x) __attribute__((aligned(x))) 52 | 53 | #define BREAK() asm volatile ("xchg %bx, %bx") 54 | #define HANG() while(true){} 55 | 56 | // Default types 57 | typedef unsigned char uchar; 58 | 59 | typedef unsigned char uint8; 60 | typedef unsigned short uint16; 61 | typedef unsigned int uint32; 62 | typedef unsigned long long uint64; 63 | 64 | typedef char int8; 65 | typedef short int16; 66 | typedef int int32; 67 | typedef long long int64; 68 | 69 | typedef float float32; 70 | typedef double float64; 71 | 72 | typedef void *handle_t; 73 | #define null 0 74 | #define true 1 75 | #define false 0 76 | 77 | #endif /* __common32_h */ 78 | -------------------------------------------------------------------------------- /bbp/boot/main16.c: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Real Mode initialization 4 | ============================= 5 | 6 | This file contains initialization code real mode (preparation to switch to 7 | protected mode). 8 | 9 | It does: 10 | * video mode switch 11 | * memory mapping 12 | 13 | License (BSD-3) 14 | =============== 15 | 16 | Copyright (c) 2013, Gusts 'gusC' Kaksis 17 | All rights reserved. 18 | 19 | Redistribution and use in source and binary forms, with or without 20 | modification, are permitted provided that the following conditions are met: 21 | * Redistributions of source code must retain the above copyright 22 | notice, this list of conditions and the following disclaimer. 23 | * Redistributions in binary form must reproduce the above copyright 24 | notice, this list of conditions and the following disclaimer in the 25 | documentation and/or other materials provided with the distribution. 26 | * Neither the name of the nor the 27 | names of its contributors may be used to endorse or promote products 28 | derived from this software without specific prior written permission. 29 | 30 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 31 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 32 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 33 | DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY 34 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 35 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 36 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 37 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 38 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 39 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 40 | 41 | */ 42 | 43 | #include "main16.h" 44 | #include "../config.h" 45 | 46 | /** 47 | * Set video mode 48 | * @see bios.asm 49 | * @param mode - BIOS video mode 50 | */ 51 | extern void set_video_mode(uint16 mode); 52 | /** 53 | * Set video mode SuperVGA 54 | * @see bios.asm 55 | * @param mode - SuperVGA video mode 56 | */ 57 | extern void set_svga_mode(uint16 mode); 58 | /** 59 | * Enable A20 gate 60 | * @see bios.asm 61 | */ 62 | extern void enable_a20(); 63 | /** 64 | * Check if A20 gate is open already 65 | * @see bios.asm 66 | */ 67 | extern uint16 check_a20(); 68 | /** 69 | * Read E820 memory map 70 | * @see bios.asm 71 | * @param mem_map - e820 memory map structure pointer 72 | * @return status code (1 - ok, 0 - failed) 73 | */ 74 | extern uint32 read_e820(e820map_t *mem_map); 75 | 76 | /** 77 | * Initialize Real Mode 78 | */ 79 | void main16(){ 80 | // This a static location (see config.h) 81 | e820map_t *mem_map = (e820map_t *)E820_LOC; 82 | 83 | // Setup video mode 84 | #if DEBUG == 1 85 | #if VIDEOMODE == 1 86 | set_video_mode(0x03); // Teletype 87 | #elif VIDEOMODE == 2 88 | set_svga_mode(0x011B); // 1280x1024 (24 bit) 89 | #endif 90 | #endif 91 | 92 | // Enable A20 gate 93 | enable_a20(); 94 | // Read E820 map 95 | read_e820(mem_map); 96 | 97 | // Exit like we want it! 98 | // It's uggly, but as we can not control the entry of this function 99 | // at least we can control the exit. 100 | RET32(); 101 | } 102 | -------------------------------------------------------------------------------- /bbp/boot/main16.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Real Mode initialization 4 | ============================= 5 | 6 | This file contains initialization code real mode (preparation to switch to 7 | protected mode). 8 | 9 | It does: 10 | * video mode switch 11 | * memory mapping 12 | 13 | License (BSD-3) 14 | =============== 15 | 16 | Copyright (c) 2013, Gusts 'gusC' Kaksis 17 | All rights reserved. 18 | 19 | Redistribution and use in source and binary forms, with or without 20 | modification, are permitted provided that the following conditions are met: 21 | * Redistributions of source code must retain the above copyright 22 | notice, this list of conditions and the following disclaimer. 23 | * Redistributions in binary form must reproduce the above copyright 24 | notice, this list of conditions and the following disclaimer in the 25 | documentation and/or other materials provided with the distribution. 26 | * Neither the name of the nor the 27 | names of its contributors may be used to endorse or promote products 28 | derived from this software without specific prior written permission. 29 | 30 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 31 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 32 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 33 | DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY 34 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 35 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 36 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 37 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 38 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 39 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 40 | 41 | */ 42 | 43 | #ifndef __main16_h 44 | #define __main16_h 45 | 46 | #include "common16.h" 47 | 48 | /** 49 | * E820 memory map entry structure 50 | */ 51 | struct e820entry_struct { 52 | uint16 entry_size; // if 24, then it has attributes 53 | uint64 base; 54 | uint64 length; 55 | uint32 type; 56 | uint32 attributes; // ACPI 3.0 only 57 | } __PACKED; 58 | typedef struct e820entry_struct e820entry_t; 59 | /** 60 | * E820 memory map structure 61 | */ 62 | struct e820map_struct { 63 | uint16 size; 64 | e820entry_t entries[]; 65 | } __PACKED; 66 | typedef struct e820map_struct e820map_t; 67 | 68 | #endif /* __main16_h */ 69 | -------------------------------------------------------------------------------- /bbp/boot/main32.c: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Protected Mode initialization 4 | ============================= 5 | 6 | This file contains initialization code protected mode (preparation to switch to 7 | long mode). 8 | 9 | It does: 10 | * page setup and initialization 11 | 12 | License (BSD-3) 13 | =============== 14 | 15 | Copyright (c) 2013, Gusts 'gusC' Kaksis 16 | All rights reserved. 17 | 18 | Redistribution and use in source and binary forms, with or without 19 | modification, are permitted provided that the following conditions are met: 20 | * Redistributions of source code must retain the above copyright 21 | notice, this list of conditions and the following disclaimer. 22 | * Redistributions in binary form must reproduce the above copyright 23 | notice, this list of conditions and the following disclaimer in the 24 | documentation and/or other materials provided with the distribution. 25 | * Neither the name of the nor the 26 | names of its contributors may be used to endorse or promote products 27 | derived from this software without specific prior written permission. 28 | 29 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 30 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 31 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 32 | DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY 33 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 34 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 35 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 36 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 37 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 38 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 39 | 40 | */ 41 | 42 | #include "main32.h" 43 | #include "../config.h" 44 | 45 | /** 46 | * PML4 pointer (to be passed over to CR3) 47 | * @see boot.asm 48 | */ 49 | extern uint32 pml4_ptr32; 50 | 51 | /** 52 | * Clear memory region 53 | * @param dest - destination address (pointer to destination buffer) 54 | * @param len - length to clear 55 | */ 56 | static void mem_clear(uint8 *dest, uint32 len){ 57 | while(len--){ 58 | *dest++ = 0; 59 | } 60 | } 61 | /** 62 | * Setup PML4 pages to enter Long Mode 63 | * @param ammount - ammount of memory to map 64 | */ 65 | static void setup_pages(uint64 ammount){ 66 | uint64 p; 67 | uint64 t; 68 | uint64 d; 69 | uint64 dr; 70 | uint64 ptr; 71 | 72 | // Single page (PML1 entry) holds 4KB of RAM 73 | uint64 page_count = ammount / PAGE_SIZE; 74 | if (ammount % PAGE_SIZE > 0){ 75 | page_count ++; 76 | } 77 | // Single table (PML2 entry) holds 2MB of RAM 78 | uint64 table_count = page_count / 512; 79 | if (page_count % 512 > 0){ 80 | table_count ++; 81 | } 82 | // Single directory (PML3 entry, directory table pointer) holds 1GB of RAM 83 | uint64 directory_count = table_count / 512; 84 | if (table_count % 512 > 0){ 85 | directory_count ++; 86 | } 87 | // Single drawer (PML4 entry) holds 512GB of RAM 88 | uint64 drawer_count = directory_count / 512; 89 | if (directory_count % 512 > 0){ 90 | drawer_count ++; 91 | } 92 | 93 | // Position the page table structures in memory 94 | 95 | // Located at 0x00100000 (1MB mark, see config.h) 96 | // a.k.a. PML4T (512GB per entry = 256TB total, this is a page cabinet) 97 | // Holds 512 entries, only 1st is active - enough to map 512GB 98 | pm_t *pml4 = (pm_t*)PT_LOC; 99 | // Located at PML4 + (8 * 512) 100 | // a.k.a. PDPT (page directory pointer table, 1GB per entry, let's call this a page drawer) 101 | // Holds 512 entries, each entry maps up to 1GB, table = 512GB 102 | pm_t *pml3 = (pm_t*)(((uint32)pml4) + (sizeof(pm_t) * 512)); 103 | // Located at PML3 + (8 * 512 * drawer_count) 104 | // a.k.a. PD (page directory, 2MB per entry) 105 | // Holds 512 entries * directory_count, each entry maps up to 2MB, table = 1GB 106 | pm_t *pml2 = (pm_t*)(((uint32)pml3) + (sizeof(pm_t) * 512 * (uint32)drawer_count)); 107 | // Located at PML2 + (8 * 512 * directory_count) 108 | // a.k.a. PT (page table, 4KB per entry) 109 | // Holds 512 entries * table_count, each entry maps 4KB, table = 2MB 110 | pm_t *pml1 = (pm_t*)(((uint32)pml2) + (sizeof(pm_t) * 512 * (uint32)directory_count)); 111 | 112 | // Clear memory region where the page tables will reside 113 | mem_clear((uint8 *)pml4, sizeof(pm_t) * 512); 114 | mem_clear((uint8 *)pml3, sizeof(pm_t) * 512 * drawer_count); 115 | mem_clear((uint8 *)pml2, sizeof(pm_t) * 512 * directory_count); 116 | mem_clear((uint8 *)pml1, sizeof(pm_t) * 512 * table_count); 117 | 118 | // Set up pages, tables, directories and drawers in the cabinet :) 119 | for (p = 0; p < page_count; p ++){ 120 | ptr = (uint64)(p * PAGE_SIZE); 121 | pml1[p].raw = ptr & PAGE_MASK; 122 | pml1[p].s.present = 1; 123 | pml1[p].s.writable = 1; 124 | pml1[p].s.write_through = 1; 125 | //pml1[p].s.cache_disable = 1; 126 | //pml1[p].s.global = 1; 127 | } 128 | for (t = 0; t < table_count; t ++){ 129 | ptr = (uint64)(((uint32)pml1) + (sizeof(pm_t) * 512 * t)); 130 | pml2[t].raw = ptr & PAGE_MASK; 131 | pml2[t].s.present = 1; 132 | pml2[t].s.writable = 1; 133 | pml2[t].s.write_through = 1; 134 | //pml2[t].s.cache_disable = 1; 135 | } 136 | for (d = 0; d < directory_count; d ++){ 137 | ptr = (uint64)(((uint32)pml2) + (sizeof(pm_t) * 512 * d)); 138 | pml3[d].raw = ptr & PAGE_MASK; 139 | pml3[d].s.present = 1; 140 | pml3[d].s.writable = 1; 141 | pml3[d].s.write_through = 1; 142 | //pml3[d].s.cache_disable = 1; 143 | } 144 | for (dr = 0; dr < drawer_count; dr ++){ 145 | ptr = (uint64)(((uint32)pml3) + (sizeof(pm_t) * 512 * dr)); 146 | pml4[dr].raw = ptr & PAGE_MASK; 147 | pml4[dr].s.present = 1; 148 | pml4[dr].s.writable = 1; 149 | pml4[dr].s.write_through = 1; 150 | //pml4[dr].s.cache_disable = 1; 151 | } 152 | 153 | // Set PML4 pointer address 154 | pml4_ptr32 = (uint32)pml4; // Point to our cabinet :) 155 | } 156 | 157 | /** 158 | * Initialize Protected Mode 159 | */ 160 | void main32(){ 161 | // Page map some memory (identity map) 162 | setup_pages(INIT_MEM); 163 | } 164 | -------------------------------------------------------------------------------- /bbp/boot/main32.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Protected Mode initialization 4 | ============================= 5 | 6 | This file contains initialization code protected mode (preparation to switch to 7 | long mode). 8 | 9 | It does: 10 | * page setup and initialization 11 | 12 | License (BSD-3) 13 | =============== 14 | 15 | Copyright (c) 2013, Gusts 'gusC' Kaksis 16 | All rights reserved. 17 | 18 | Redistribution and use in source and binary forms, with or without 19 | modification, are permitted provided that the following conditions are met: 20 | * Redistributions of source code must retain the above copyright 21 | notice, this list of conditions and the following disclaimer. 22 | * Redistributions in binary form must reproduce the above copyright 23 | notice, this list of conditions and the following disclaimer in the 24 | documentation and/or other materials provided with the distribution. 25 | * Neither the name of the nor the 26 | names of its contributors may be used to endorse or promote products 27 | derived from this software without specific prior written permission. 28 | 29 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 30 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 31 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 32 | DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY 33 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 34 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 35 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 36 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 37 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 38 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 39 | 40 | */ 41 | 42 | #ifndef __main32_h 43 | #define __main32_h 44 | 45 | #include "common32.h" 46 | 47 | /** 48 | * 64-bit page table/directory/level3/level4 entry structure 49 | */ 50 | 51 | typedef union { 52 | struct { 53 | uint64 present : 1; // Is the page present in memory? 54 | uint64 writable : 1; // Is the page writable? 55 | uint64 user : 1; // Is the page for userspace? 56 | uint64 write_through : 1; // Do we want write-trough? (when cached, this also writes to memory) 57 | uint64 cache_disable : 1; // Disable cache on this page? 58 | uint64 accessed : 1; // Has the page been accessed by software? 59 | uint64 dirty : 1; // Has the page been written to since last refresh? 60 | uint64 pat : 1; // Is the page a PAT? (dunno what it is) 61 | uint64 global : 1; // Is the page global? (dunno what it is) 62 | uint64 data : 3; // Available for kernel use (do what you want?) 63 | uint64 frame : 52; // Frame address (shifted right 12 bits) 64 | } s; 65 | uint64 raw; // Raw value 66 | } pm_t; 67 | 68 | #define PAGE_MASK 0xFFFFFFFFF000; 69 | 70 | #endif /* __main32_h */ 71 | -------------------------------------------------------------------------------- /bbp/boot/makefile: -------------------------------------------------------------------------------- 1 | AS = nasm -felf64 -O0 2 | CC = x86_64-pc-elf-gcc -m32 -march=i686 -nostartfiles -nostdlib -nodefaultlibs -fno-builtin -Wno-attributes 3 | LD = x86_64-pc-elf-ld -i 4 | OC = x86_64-pc-elf-objcopy -I elf32-i386 -O elf64-x86-64 5 | OBJECTS = boot.s.o bios.s.o main16.c64.o main32.c64.o 6 | 7 | all: boot.o 8 | 9 | boot.o: $(OBJECTS) 10 | $(LD) -T boot.ld $(OBJECTS) -o ../boot.o 11 | 12 | %.s.o: %.asm 13 | $(AS) -o $@ $< 14 | 15 | %.c.o: %.c 16 | $(CC) -c $< -o $@ 17 | 18 | %.c64.o: %.c.o 19 | $(OC) $< $@ 20 | 21 | clean: 22 | rm -f *.o -------------------------------------------------------------------------------- /bbp/buildimg.bat: -------------------------------------------------------------------------------- 1 | ::@ECHO OFF 2 | 3 | ::REM 10 tracs, 16 heads, 63 sectors-per-track = 10080 sectors 4 | SET maxbytes=5160960 5 | SET mbr=..\Release\mbr.img 6 | SET bbp=..\Release\bbp.img 7 | SET output=..\Release\disk.img 8 | 9 | ..\..\diskutils\Release\buildimg.exe -m %mbr% -b %bbp% -s %maxbytes% %output% 10 | 11 | ECHO Cleanup 12 | ::DEL %mbr% 13 | ::DEL %bbp% 14 | 15 | ::PAUSE -------------------------------------------------------------------------------- /bbp/config.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Global configuration 4 | ==================== 5 | 6 | This file contains global configuration used at compile-time. 7 | 8 | License (BSD-3) 9 | =============== 10 | 11 | Copyright (c) 2013, Gusts 'gusC' Kaksis 12 | All rights reserved. 13 | 14 | Redistribution and use in source and binary forms, with or without 15 | modification, are permitted provided that the following conditions are met: 16 | * Redistributions of source code must retain the above copyright 17 | notice, this list of conditions and the following disclaimer. 18 | * Redistributions in binary form must reproduce the above copyright 19 | notice, this list of conditions and the following disclaimer in the 20 | documentation and/or other materials provided with the distribution. 21 | * Neither the name of the nor the 22 | names of its contributors may be used to endorse or promote products 23 | derived from this software without specific prior written permission. 24 | 25 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 26 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 27 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 28 | DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY 29 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 30 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 31 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 32 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 33 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 34 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35 | 36 | */ 37 | 38 | 39 | #ifndef __config_h 40 | #define __config_h 41 | 42 | // 43 | // Global settings 44 | // 45 | 46 | // Video mode 47 | // 0 - none, leave it as is 48 | // 1 - teletype 49 | // 2 - VGA 50 | #define VIDEOMODE 1 51 | // Enable debug output 52 | #define DEBUG 1 53 | // Initial memory size to map to enter Long Mode 54 | // we don't need more than this, but it should be more than 1MB 55 | // as the PMLx structures will be located at the 1MB mark 56 | #define INIT_MEM 0x200000 // 2MB 57 | // Default page size 58 | #define PAGE_SIZE 0x1000 59 | 60 | // 61 | // Hard-coded memory locations 62 | // 63 | 64 | // E820 memory map location 65 | #define E820_LOC 0x0800 66 | // Memory location where to store PMLx page tables 67 | #define PT_LOC 0x00100000 68 | 69 | #if VIDEOMODE == 1 70 | // Teletype video memory location 71 | // This can be used only in 32+ bit modes 72 | #define VIDEOMEM_LOC 0xB8000 73 | #elif VIDEOMODE == 2 74 | // VGA video memory location 75 | // This can be used only in 32+ bit modes 76 | #define VIDEOMEM_LOC 0xA0000 77 | #else 78 | // Null address 79 | #define VIDEOMEM_LOC 0x0 80 | #endif 81 | 82 | #endif 83 | -------------------------------------------------------------------------------- /bbp/kernel/README.md: -------------------------------------------------------------------------------- 1 | Kernel 2 | ====== 3 | 4 | This is the Long Mode BBP kernel code 5 | 6 | File list 7 | --------- 8 | 9 | Main entry files: 10 | * kmain.c - C entry point that get's called by ../boot/boot.asm 11 | 12 | Helper files: 13 | * acpi.* - ACPI table lokup implementation 14 | * ahci.* - AHCI driver 15 | * apic.* - APIC/xAPIC/x2APIC initialization 16 | * common.h - data type definitions 17 | * cpuid.h - inline assembly definition for CPUID instruction 18 | * interrupts.c - interrupt inititialization 19 | * interrupts.asm - interrupt service routines 20 | * interrupts.h - intterupt service routine import in C 21 | * io.h - legacy IO instruction inline definitions 22 | * lib.* - tiny C helper library 23 | * msr.h - Model Specific Register (MSR) instructions inline definitions 24 | * paging.* - Paging functions 25 | * pci.* - PCI operation functions 26 | * debug_print.* - Debug output to text-mode video 27 | 28 | Build files: 29 | * kernel.ld - Kernel linker script 30 | * makefile - Make build script 31 | -------------------------------------------------------------------------------- /bbp/kernel/acpi.c: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | ACPI functions 4 | ============== 5 | 6 | License (BSD-3) 7 | =============== 8 | 9 | Copyright (c) 2012, Gusts 'gusC' Kaksis 10 | All rights reserved. 11 | 12 | Redistribution and use in source and binary forms, with or without 13 | modification, are permitted provided that the following conditions are met: 14 | * Redistributions of source code must retain the above copyright 15 | notice, this list of conditions and the following disclaimer. 16 | * Redistributions in binary form must reproduce the above copyright 17 | notice, this list of conditions and the following disclaimer in the 18 | documentation and/or other materials provided with the distribution. 19 | * Neither the name of the nor the 20 | names of its contributors may be used to endorse or promote products 21 | derived from this software without specific prior written permission. 22 | 23 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 24 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 25 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 26 | DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY 27 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 28 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 29 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 30 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 31 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 32 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 | 34 | */ 35 | 36 | #include "../config.h" 37 | #include "acpi.h" 38 | #include "lib.h" 39 | #include "paging.h" 40 | #include "io.h" 41 | #if DEBUG == 1 42 | #include "debug_print.h" 43 | #endif 44 | 45 | RSDP_t *_rsdp = null; 46 | 47 | /** 48 | * Calculate ACPI checksum 49 | * @param [in] block - memory address of a first byte of ACPI structure 50 | * @param len - structure size in memory 51 | * @return checksum value 52 | */ 53 | static uint8 acpi_checksum(uint8 *block, uint64 len){ 54 | uint32 sum = 0; 55 | while (len--){ 56 | sum += *(block++); 57 | } 58 | return (uint8)(sum); 59 | } 60 | /** 61 | * Find root system descriptor pointer (RSDP) 62 | * @retun true if found 63 | */ 64 | static bool acpi_find(){ 65 | const char sign[9] = "RSD PTR "; 66 | if (_rsdp == null){ 67 | _rsdp = (RSDP_t *)0x80000; // We start at the beginning of EBDA 68 | do { 69 | if (mem_compare((uint8 *)_rsdp->signature, (uint8 *)sign, 8)){ 70 | if (_rsdp->revision == 0){ 71 | if (acpi_checksum((uint8 *)_rsdp, sizeof(uint8) * 20) == 0){ // Revision 1.0 checksum 72 | // Map RSDT address 73 | page_map_mmio((uint64)_rsdp->RSDT_address); 74 | return true; 75 | } 76 | } else { 77 | if (acpi_checksum((uint8 *)_rsdp, sizeof(RSDP_t)) == 0){ // Revision 2.0+ checksum 78 | // Map XSDT address 79 | page_map_mmio(_rsdp->XSDT_address); 80 | return true; 81 | } 82 | } 83 | } 84 | _rsdp = (RSDP_t *)((uint64)_rsdp + 0x10); 85 | } while ((uint64)_rsdp < 0x100000); // Up until 1MB mark 86 | _rsdp = null; 87 | } 88 | return false; 89 | } 90 | /** 91 | * Map pages to ACPI tables 92 | */ 93 | static void acpi_map(){ 94 | if (_rsdp != null){ 95 | SDTHeader_t *th; 96 | uint64 i; 97 | uint64 j; 98 | uint64 count; 99 | uint64 ptr; 100 | if (_rsdp->revision == 0){ 101 | // ACPI version 1.0 102 | RSDT_t *rsdt = (RSDT_t *)((uint64)_rsdp->RSDT_address); 103 | // Get count of other table pointers 104 | count = (rsdt->h.length - sizeof(SDTHeader_t)) / 4; 105 | for (i = 0; i < count; i ++){ 106 | // Get an address of table pointer array 107 | ptr = (uint64)&rsdt->ptr; 108 | // Move on to entry i (32bits = 4 bytes) in table pointer array 109 | ptr += (i * 4); 110 | // Map the page 111 | page_map_mmio(ptr); 112 | // Get the pointer of table in table pointer array 113 | th = (SDTHeader_t *)((uint64)(*((uint32 *)ptr))); 114 | // If the length is greater than a page, map additional pages 115 | if (th->length > PAGE_SIZE){ 116 | for (j = (ptr & PAGE_MASK) + PAGE_SIZE; j < ((ptr + th->length) & PAGE_MASK); j += PAGE_SIZE){ 117 | page_map_mmio(j); 118 | } 119 | } 120 | } 121 | } else { 122 | // ACPI version 2.0+ 123 | XSDT_t *xsdt = (XSDT_t *)_rsdp->XSDT_address; 124 | // Get count of other table pointers 125 | count = (xsdt->h.length - sizeof(SDTHeader_t)) / 8; 126 | for (i = 0; i < count; i ++){ 127 | // Get an address of table pointer array 128 | ptr = (uint64)&xsdt->ptr; 129 | // Move on to entry i (64bits = 8 bytes) in table pointer array 130 | ptr += (i * 8); 131 | // Map the page 132 | page_map_mmio(ptr); 133 | // Get the pointer of table in table pointer array 134 | th = (SDTHeader_t *)(*((uint64 *)ptr)); 135 | // If the length is greater than a page, map additional pages 136 | if (th->length > PAGE_SIZE){ 137 | for (j = (ptr & PAGE_MASK) + PAGE_SIZE; j < ((ptr + th->length) & PAGE_MASK); j += PAGE_SIZE){ 138 | page_map_mmio(j); 139 | } 140 | } 141 | } 142 | } 143 | } 144 | } 145 | 146 | bool acpi_init(){ 147 | if (acpi_find()){ 148 | // Map pages to ACPI tables, so we don't get page faults 149 | acpi_map(); 150 | 151 | char facp[4] = {'F', 'A', 'C', 'P'}; 152 | FADT_t *fadt = (FADT_t *)acpi_table(facp); 153 | if (fadt != null){ 154 | // Enable ACPI 155 | if ((fadt->pm1a_control_block & 0x1) == 0){ // Only if SCI_EN is not set 156 | if (fadt->smi_command_port > 0){ // and SMI_CMD is set 157 | if (fadt->acpi_enable > 0){ // and ACPI_ENABLE is set 158 | outb((uint16)fadt->smi_command_port, fadt->acpi_enable); 159 | } 160 | } 161 | } 162 | 163 | //FACS_t *facs = (FACS_t *)((uint64)fadt->firmware_ctrl); 164 | 165 | //DSDT_t *dsdt = (DSDT_t *)((uint64)fadt->dsdt); 166 | // TODO: parse DSDT 167 | 168 | //char ssdt_sig[4] = {'S', 'S', 'D', 'T'}; 169 | //SSDT_t *ssdt = (SSDT_t *)acpi_table(ssdt_sig); 170 | //if (ssdt != null){ 171 | // TODO: parse SSDT 172 | //} 173 | 174 | return true; 175 | } 176 | } 177 | return false; 178 | } 179 | 180 | RSDP_t *acpi_rsdp(){ 181 | return _rsdp; 182 | } 183 | 184 | SDTHeader_t *acpi_table(const char signature[4]){ 185 | if (_rsdp != null){ 186 | SDTHeader_t *th; 187 | uint32 i; 188 | uint32 count; 189 | uint64 ptr; 190 | if (_rsdp->revision == 0){ 191 | // ACPI version 1.0 192 | RSDT_t *rsdt = (RSDT_t *)((uint64)_rsdp->RSDT_address); 193 | // Get count of other table pointers 194 | count = (rsdt->h.length - sizeof(SDTHeader_t)) / 4; 195 | for (i = 0; i < count; i ++){ 196 | // Get an address of table pointer array 197 | ptr = (uint64)&rsdt->ptr; 198 | // Move on to entry i (32bits = 4 bytes) in table pointer array 199 | ptr += (i * 4); 200 | // Get the pointer of table in table pointer array 201 | th = (SDTHeader_t *)((uint64)(*((uint32 *)ptr))); 202 | if (mem_compare((uint8 *)th->signature, (uint8 *)signature, 4)){ 203 | if (acpi_checksum((uint8 *)th, th->length) == 0){ 204 | return th; 205 | } 206 | } 207 | } 208 | } else { 209 | // ACPI version 2.0+ 210 | XSDT_t *xsdt = (XSDT_t *)_rsdp->XSDT_address; 211 | // Get count of other table pointers 212 | count = (xsdt->h.length - sizeof(SDTHeader_t)) / 8; 213 | for (i = 0; i < count; i ++){ 214 | // Get an address of table pointer array 215 | ptr = (uint64)&xsdt->ptr; 216 | // Move on to entry i (64bits = 8 bytes) in table pointer array 217 | ptr += (i * 8); 218 | // Get the pointer of table in table pointer array 219 | th = (SDTHeader_t *)(*((uint64 *)ptr)); 220 | if (mem_compare((uint8 *)th->signature, (uint8 *)signature, 4)){ 221 | if (acpi_checksum((uint8 *)th, th->length) == 0){ 222 | return th; 223 | } 224 | } 225 | } 226 | } 227 | } 228 | return null; 229 | } 230 | 231 | #if DEBUG == 1 232 | void acpi_list(){ 233 | if (_rsdp != null){ 234 | SDTHeader_t *th; 235 | uint32 i; 236 | uint32 count; 237 | char sign[5] = ""; 238 | 239 | debug_print(DC_WB, "RSDP @%x", (uint64)_rsdp); 240 | 241 | if (_rsdp->revision == 0){ 242 | // ACPI version 1.0 243 | debug_print(DC_WB, "ACPI v1.0"); 244 | debug_print(DC_WB, "XSDT @%x", (uint64)_rsdp->RSDT_address); 245 | 246 | RSDT_t *rsdt = (RSDT_t *)((uint64)_rsdp->RSDT_address); 247 | uint64 ptr; 248 | // Get count of other table pointers 249 | count = (rsdt->h.length - sizeof(SDTHeader_t)) / 4; 250 | for (i = 0; i < count; i ++){ 251 | // Get an address of table pointer array 252 | ptr = (uint64)&rsdt->ptr; 253 | // Move on to entry i (32bits = 4 bytes) in table pointer array 254 | ptr += (i * 4); 255 | // Get the pointer of table in table pointer array 256 | th = (SDTHeader_t *)((uint64)(*((uint32 *)ptr))); 257 | mem_fill((uint8 *)sign, 5, 0); 258 | mem_copy((uint8 *)sign, 4, (uint8 *)th->signature); 259 | debug_print(DC_WB, "%s @%x", sign, (uint64)th); 260 | } 261 | } else { 262 | // ACPI version 2.0+ 263 | debug_print(DC_WB, "ACPI v%d", (uint32)_rsdp->revision); 264 | debug_print(DC_WB, "XSDT @%x", _rsdp->XSDT_address); 265 | 266 | XSDT_t *xsdt = (XSDT_t *)_rsdp->XSDT_address; 267 | uint64 ptr; 268 | // Get count of other table pointers 269 | count = (xsdt->h.length - sizeof(SDTHeader_t)) / 8; 270 | for (i = 0; i < count; i ++){ 271 | // Get an address of table pointer array 272 | ptr = (uint64)&xsdt->ptr; 273 | // Move on to entry i (64bits = 8 bytes) in table pointer array 274 | ptr += (i * 8); 275 | // Get the pointer of table in table pointer array 276 | th = (SDTHeader_t *)(*((uint64 *)ptr)); 277 | mem_fill((uint8 *)sign, 5, 0); 278 | mem_copy((uint8 *)sign, 4, (uint8 *)th->signature); 279 | debug_print(DC_WB, "%s @%x", sign, (uint64)th); 280 | } 281 | } 282 | } 283 | } 284 | #endif -------------------------------------------------------------------------------- /bbp/kernel/acpi.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | ACPI functions 4 | ============== 5 | 6 | License (BSD-3) 7 | =============== 8 | 9 | Copyright (c) 2012, Gusts 'gusC' Kaksis 10 | All rights reserved. 11 | 12 | Redistribution and use in source and binary forms, with or without 13 | modification, are permitted provided that the following conditions are met: 14 | * Redistributions of source code must retain the above copyright 15 | notice, this list of conditions and the following disclaimer. 16 | * Redistributions in binary form must reproduce the above copyright 17 | notice, this list of conditions and the following disclaimer in the 18 | documentation and/or other materials provided with the distribution. 19 | * Neither the name of the nor the 20 | names of its contributors may be used to endorse or promote products 21 | derived from this software without specific prior written permission. 22 | 23 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 24 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 25 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 26 | DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY 27 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 28 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 29 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 30 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 31 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 32 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 | 34 | */ 35 | 36 | #ifndef __acpi_h 37 | #define __acpi_h 38 | 39 | #include "common.h" 40 | #include "../config.h" 41 | 42 | /** 43 | * Root System Descriptor Pointer 44 | * See ACPI specs 45 | */ 46 | struct RSDP_struct { 47 | // Version 1.0 48 | char signature[8]; 49 | uint8 checksum; 50 | char oem_id[6]; 51 | uint8 revision; 52 | uint32 RSDT_address; 53 | // Version 2.0 54 | uint32 length; 55 | uint64 XSDT_address; 56 | uint8 extended_checksum; 57 | uint8 reserved[3]; 58 | } __PACKED; 59 | typedef struct RSDP_struct RSDP_t; 60 | /** 61 | * Standard System Descriptor Table header structure 62 | * This is common to all ACPI tables 63 | */ 64 | struct SDTHeader_struct { 65 | char signature[4]; 66 | uint32 length; 67 | uint8 revision; 68 | uint8 checksum; 69 | char oem_id[6]; 70 | char oem_table_id[8]; 71 | uint32 oem_revision; 72 | uint32 creator_id; 73 | uint32 creator_revision; 74 | } __PACKED; 75 | typedef struct SDTHeader_struct SDTHeader_t; 76 | /** 77 | * Root System Descriptor table 78 | */ 79 | struct RSDT_struct { 80 | SDTHeader_t h; // Standard ACPI header 81 | uint32 ptr; // This actually is an array, we're using only first entry 82 | } __PACKED; 83 | typedef struct RSDT_struct RSDT_t; 84 | /** 85 | * eXtended System Descriptor Table 86 | */ 87 | struct XSDT_struct { 88 | SDTHeader_t h; // Standard ACPI header 89 | uint64 ptr; // This actually is an array, we're using only first entry 90 | } __PACKED; 91 | typedef struct XSDT_struct XSDT_t; 92 | /** 93 | * Secondary System Descriptor table 94 | */ 95 | struct SSDT_struct { 96 | SDTHeader_t h; // Standard ACPI header 97 | uint8 ptr; // AML bytecode 98 | } __PACKED; 99 | typedef struct SSDT_struct SSDT_t; 100 | /** 101 | * Differentiated System Descriptor table 102 | */ 103 | struct DSDT_struct { 104 | SDTHeader_t h; // Standard ACPI header 105 | uint8 ptr; // AML bytecode 106 | } __PACKED; 107 | typedef struct DSDT_struct DSDT_t; 108 | /** 109 | * Firmware ACPI Control Structure 110 | */ 111 | struct FACS_struct { 112 | char signature[4]; 113 | uint32 length; 114 | uint32 hw_signature; 115 | uint32 fw_vector; 116 | uint32 global_lock; 117 | uint32 flags; 118 | 119 | uint64 x_fw_vector; 120 | uint8 version; 121 | uint8 reserved[3]; 122 | uint32 ospm_flags; 123 | uint8 reserved2[24]; 124 | } __PACKED; 125 | typedef struct FACS_struct FACS_t; 126 | /** 127 | * Generic Address structure 128 | */ 129 | struct GAS_struct { 130 | uint8 address_space; 131 | uint8 bit_width; 132 | uint8 bit_offset; 133 | uint8 access_size; 134 | uint64 address; 135 | } __PACKED; 136 | typedef struct GAS_struct GAS_t; 137 | /** 138 | * Fixed ACPI Description Table structure 139 | */ 140 | struct FADT_struct { 141 | SDTHeader_t h; // Standard ACPI header 142 | uint32 firmware_ctrl; // Pointer to FACS table 143 | uint32 dsdt; // Pointer to DSDT table 144 | 145 | // field used in ACPI 1.0; no longer in use, for compatibility only 146 | uint8 reserved; 147 | 148 | uint8 pref_pmp; 149 | uint16 sci_interrupt; 150 | uint32 smi_command_port; 151 | uint8 acpi_enable; 152 | uint8 acpi_disable; 153 | uint8 s4_bios_req; 154 | uint8 pstate_control; 155 | uint32 pm1a_event_block; 156 | uint32 pm1b_event_block; 157 | uint32 pm1a_control_block; 158 | uint32 pm1b_control_block; 159 | uint32 pm2_control_block; 160 | uint32 pm_timer_block; 161 | uint32 gpe0_block; 162 | uint32 gpe1_block; 163 | uint8 pm1_event_length; 164 | uint8 pm1_control_length; 165 | uint8 pm2_control_length; 166 | uint8 pm_timer_length; 167 | uint8 gpe0_length; 168 | uint8 gpe1_length; 169 | uint8 gpe1_base; 170 | uint8 cstate_control; 171 | uint16 worst_c2_latency; 172 | uint16 worst_c3_latency; 173 | uint16 flush_size; 174 | uint16 flush_stride; 175 | uint8 duty_offset; 176 | uint8 duty_width; 177 | uint8 day_alarm; 178 | uint8 month_alarm; 179 | uint8 century; 180 | 181 | // reserved in ACPI 1.0; used since ACPI 2.0+ 182 | uint16 boot_arch_flags; 183 | 184 | uint8 reserved2; 185 | uint32 flags; 186 | 187 | // 12 byte structure; see below for details 188 | GAS_t reset_reg; 189 | 190 | uint8 reset_value; 191 | uint8 reserved3[3]; 192 | 193 | // 64bit pointers - Available on ACPI 2.0+ 194 | uint64 x_firmware_control; 195 | uint64 x_dsdt; 196 | 197 | GAS_t x_pm1a_event_block; 198 | GAS_t x_pm1b_event_block; 199 | GAS_t x_pm1a_control_block; 200 | GAS_t x_pm1b_control_block; 201 | GAS_t x_pm2_control_block; 202 | GAS_t x_pm_timer_block; 203 | GAS_t x_gpe0_block; 204 | GAS_t x_gpe1_block; 205 | } __PACKED; 206 | typedef struct FADT_struct FADT_t; 207 | /** 208 | * Multiple APIC Description Table structure 209 | */ 210 | struct MADT_struct { 211 | SDTHeader_t h; 212 | uint32 lapic_addr; // Physical address of local APIC 213 | uint32 flags; // Flags 214 | uint32 ptr; // Local, IO and other APIC structures (we use it as an offset) 215 | } __PACKED; 216 | typedef struct MADT_struct MADT_t; 217 | /** 218 | * ACPI APIC structure header 219 | */ 220 | struct APICHeader_struct { 221 | uint8 type; 222 | uint8 length; 223 | } __PACKED; 224 | typedef struct APICHeader_struct APICHeader_t; 225 | /** 226 | * Local APIC structure 227 | */ 228 | struct LocalAPIC_struct { 229 | APICHeader_t h; 230 | uint8 processor_id; 231 | uint8 apic_id; 232 | uint32 flags; 233 | } __PACKED; 234 | typedef struct LocalAPIC_struct LocalAPIC_t; 235 | /** 236 | * I/O APIC strcuture 237 | */ 238 | struct IOAPIC_struct { 239 | APICHeader_t h; 240 | uint8 apic_id; 241 | uint8 reserved; 242 | uint32 apic_addr; 243 | uint32 gsi_base; 244 | } __PACKED; 245 | typedef struct IOAPIC_struct IOAPIC_t; 246 | /** 247 | * Non Maskable Interrupt (NMI) structure 248 | */ 249 | struct NMI_struct { 250 | APICHeader_t h; 251 | uint16 flags; 252 | uint32 gsi; 253 | } __PACKED; 254 | typedef struct NMI_struct NMI_t; 255 | /** 256 | * Local APIC structure 257 | */ 258 | struct LocalNMI_struct { 259 | APICHeader_t h; 260 | uint8 processor_id; 261 | uint16 flags; 262 | uint8 lint; 263 | } __PACKED; 264 | typedef struct LocalNMI_struct LocalNMI_t; 265 | 266 | /** 267 | * Initialize ACPI 268 | * @return true on success, false on failure (if ACPI is not supported) 269 | */ 270 | bool acpi_init(); 271 | /** 272 | * Get the RSDP pointer 273 | * @return RSDP pointer or null if ACPI is not initialized or failed to initialize 274 | */ 275 | RSDP_t *acpi_rsdp(); 276 | /** 277 | * Locate ACPI table - you must run acpi_init() first 278 | * @param [in] signature - table signature (table name) 279 | * @return pointer to table header (from here on you can locate all the other data) 280 | */ 281 | SDTHeader_t *acpi_table(const char signature[4]); 282 | 283 | #if DEBUG == 1 284 | /** 285 | * List available ACPI tables on screen 286 | */ 287 | void acpi_list(); 288 | #endif 289 | 290 | #endif 291 | -------------------------------------------------------------------------------- /bbp/kernel/ahci.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gusc/mbr2gpt/45302b4709e892bb3e0ba951235af5d2ab25bc98/bbp/kernel/ahci.c -------------------------------------------------------------------------------- /bbp/kernel/ahci.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | AHCI driver 4 | =========== 5 | 6 | 7 | License (BSD-3) 8 | =============== 9 | 10 | Copyright (c) 2012, Gusts 'gusC' Kaksis 11 | All rights reserved. 12 | 13 | Redistribution and use in source and binary forms, with or without 14 | modification, are permitted provided that the following conditions are met: 15 | * Redistributions of source code must retain the above copyright 16 | notice, this list of conditions and the following disclaimer. 17 | * Redistributions in binary form must reproduce the above copyright 18 | notice, this list of conditions and the following disclaimer in the 19 | documentation and/or other materials provided with the distribution. 20 | * Neither the name of the nor the 21 | names of its contributors may be used to endorse or promote products 22 | derived from this software without specific prior written permission. 23 | 24 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 25 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 26 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 27 | DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY 28 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 29 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 30 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 31 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 32 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 33 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 | 35 | */ 36 | 37 | #ifndef __ahci_h 38 | #define __ahci_h 39 | 40 | #include "common.h" 41 | #include "../config.h" 42 | 43 | /** 44 | * Initialize AHCI driver 45 | * @return false if no AHCI controller has been found 46 | */ 47 | bool ahci_init(); 48 | /** 49 | * Get the number of AHCI devices connected 50 | * @return number of devices available 51 | */ 52 | uint64 ahci_num_dev(); 53 | /** 54 | * Read data from AHCI drive 55 | * @param idx - device index in the device list 56 | * @param buff - byte buffer to write into 57 | * @param len - number of bytes to read 58 | * @todo implement 59 | * @return false if read failed 60 | */ 61 | bool ahci_read(uint64 idx, uint8 *buff, uint64 len); 62 | /** 63 | * Write data to AHCI drive 64 | * @param idx - device index in the device list 65 | * @param buff - byte buffer to read from 66 | * @param len - number of bytes to write 67 | * @todo implement 68 | * @return false if write failed 69 | */ 70 | bool ahci_write(uint64 idx, uint8 *buff, uint64 len); 71 | 72 | #endif 73 | -------------------------------------------------------------------------------- /bbp/kernel/apic.c: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | APIC, xAPIC, x2APIC functions 4 | ============================= 5 | 6 | License (BSD-3) 7 | =============== 8 | 9 | Copyright (c) 2012, Gusts 'gusC' Kaksis 10 | All rights reserved. 11 | 12 | Redistribution and use in source and binary forms, with or without 13 | modification, are permitted provided that the following conditions are met: 14 | * Redistributions of source code must retain the above copyright 15 | notice, this list of conditions and the following disclaimer. 16 | * Redistributions in binary form must reproduce the above copyright 17 | notice, this list of conditions and the following disclaimer in the 18 | documentation and/or other materials provided with the distribution. 19 | * Neither the name of the nor the 20 | names of its contributors may be used to endorse or promote products 21 | derived from this software without specific prior written permission. 22 | 23 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 24 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 25 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 26 | DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY 27 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 28 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 29 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 30 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 31 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 32 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 | 34 | */ 35 | 36 | #include "../config.h" 37 | #include "apic.h" 38 | #include "msr.h" 39 | #include "acpi.h" 40 | #include "paging.h" 41 | #if DEBUG == 1 42 | #include "debug_print.h" 43 | #endif 44 | 45 | static LocalAPIC_t *_lapic[256]; 46 | static uint64 _lapic_count = 0; 47 | static uint64 _lapic_addr; 48 | 49 | static IOAPIC_t *_ioapic[256]; 50 | static uint64 _ioapic_count = 0; 51 | 52 | static void lapic_init(){ 53 | apic_base_t apic = apic_get_base(); 54 | // Address is 4KB aligned 55 | _lapic_addr = (apic.raw & PAGE_MASK); 56 | #if DEBUG == 1 57 | debug_print(DC_WB, "Local APIC @%x", _lapic_addr); 58 | if (apic.s.bsp){ 59 | debug_print(DC_WB, "Boot CPU"); 60 | } 61 | #endif 62 | // Map pages to Local APIC and disable cache 63 | pm_t pe; 64 | uint64 i; 65 | page_map_mmio(_lapic_addr); 66 | for (i = 0; i < 4; i ++){ 67 | pe = page_get_pml_entry(_lapic_addr, i); 68 | pe.s.cache_disable = 1; 69 | page_set_pml_entry(_lapic_addr, i, pe); 70 | } 71 | 72 | // Initialize Local APIC 73 | uint32 val = apic_read_reg(APIC_LAPIC_VERSION); 74 | #if DEBUG == 1 75 | debug_print(DC_WBL, "Version: %d", val); 76 | #endif 77 | 78 | // Initialize Other Local APICs if this is a bootstrap processor 79 | if (apic.s.bsp){ 80 | for (i = 0; i < _lapic_count; i ++){ 81 | #if DEBUG == 1 82 | debug_print(DC_WBL, "CPU_ID:APIC_ID = %d:%d", _lapic[i]->processor_id, _lapic[i]->apic_id); 83 | #endif 84 | //TODO: signal other CPUs to start 85 | } 86 | } 87 | } 88 | 89 | static void ioapic_init(){ 90 | // Address is 4KB aligned 91 | uint64 i; 92 | for (i = 0; i < _ioapic_count; i ++){ 93 | uint64 ioapic_addr = (_ioapic[i]->apic_addr & PAGE_MASK); 94 | #if DEBUG == 1 95 | debug_print(DC_WB, "IO APIC @%x", ioapic_addr); 96 | debug_print(DC_WB, "IOAPIC ID:%d", _ioapic[i]->apic_id); 97 | #endif 98 | // Map pages to Local APIC and disable cache 99 | pm_t pe; 100 | uint64 l; 101 | page_map_mmio(ioapic_addr); 102 | for (l = 0; l < 4; l ++){ 103 | pe = page_get_pml_entry(ioapic_addr, i); 104 | pe.s.cache_disable = 1; 105 | page_set_pml_entry(ioapic_addr, i, pe); 106 | } 107 | 108 | // TODO: setup IRQs 109 | } 110 | } 111 | 112 | bool apic_init(){ 113 | char apic[4] = {'A', 'P', 'I', 'C'}; 114 | MADT_t *madt = (MADT_t *)acpi_table(apic); 115 | if (madt != null){ 116 | // Gather Local and IO APIC(s) 117 | _lapic_addr = (uint64)madt->lapic_addr; 118 | 119 | // Enumerate APICs 120 | uint64 length = (madt->h.length - sizeof(MADT_t) + 4); 121 | APICHeader_t *ah = (APICHeader_t *)(&madt->ptr); 122 | while (length > 0){ 123 | #if DEBUG == 1 124 | //debug_print(DC_WGR, "APIC type: %d", ah->type); 125 | #endif 126 | switch (ah->type){ 127 | case APIC_TYPE_LAPIC: 128 | // Test if it's enabled - if not - don't touch it 129 | if ((((LocalAPIC_t *)ah)->flags & 1) != 0){ 130 | _lapic[_lapic_count] = (LocalAPIC_t *)ah; 131 | _lapic_count ++; 132 | } 133 | break; 134 | case APIC_TYPE_IOAPIC: 135 | _ioapic[_ioapic_count] = (IOAPIC_t *)ah; 136 | _ioapic_count ++; 137 | break; 138 | } 139 | length -= ah->length; 140 | ah = (APICHeader_t *)(((uint64)ah) + ah->length); 141 | } 142 | #if DEBUG == 1 143 | debug_print(DC_WB, "CPU count:%d", _lapic_count); 144 | #endif 145 | 146 | // Initialize Local APIC 147 | lapic_init(); 148 | // Initialize IO APIC 149 | ioapic_init(); 150 | } 151 | } 152 | 153 | apic_base_t apic_get_base(){ 154 | apic_base_t addr; 155 | msr_read(MSR_IA32_APIC_BASE, &addr.raw); 156 | return addr; 157 | } 158 | void apic_set_base(apic_base_t addr){ 159 | msr_write(MSR_IA32_APIC_BASE, addr.raw); 160 | } 161 | 162 | uint32 apic_read_reg(uint64 reg){ 163 | uint32 volatile *apic = (uint32 volatile *)(_lapic_addr + reg); 164 | return *apic; 165 | } 166 | void apic_write_reg(uint64 reg, uint32 value){ 167 | uint32 volatile *apic = (uint32 volatile *)(_lapic_addr + reg); 168 | (*apic) = value; 169 | } 170 | 171 | uint32 apic_read_ioapic(uint64 addr, uint32 reg){ 172 | uint32 volatile *ioapic = (uint32 volatile *)(addr); 173 | ioapic[0] = (reg & 0xFFFF); 174 | return ioapic[4]; 175 | } 176 | void apic_write_ioapic(uint64 addr, uint32 reg, uint32 data){ 177 | uint32 volatile *ioapic = (uint32 volatile *)(addr); 178 | ioapic[0] = (reg & 0xFFFF); 179 | ioapic[4] = data; 180 | } 181 | -------------------------------------------------------------------------------- /bbp/kernel/apic.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | APIC, xAPIC, x2APIC functions 4 | ============================= 5 | 6 | License (BSD-3) 7 | =============== 8 | 9 | Copyright (c) 2012, Gusts 'gusC' Kaksis 10 | All rights reserved. 11 | 12 | Redistribution and use in source and binary forms, with or without 13 | modification, are permitted provided that the following conditions are met: 14 | * Redistributions of source code must retain the above copyright 15 | notice, this list of conditions and the following disclaimer. 16 | * Redistributions in binary form must reproduce the above copyright 17 | notice, this list of conditions and the following disclaimer in the 18 | documentation and/or other materials provided with the distribution. 19 | * Neither the name of the nor the 20 | names of its contributors may be used to endorse or promote products 21 | derived from this software without specific prior written permission. 22 | 23 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 24 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 25 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 26 | DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY 27 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 28 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 29 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 30 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 31 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 32 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 | 34 | */ 35 | 36 | #ifndef __apic_h 37 | #define __apic_h 38 | 39 | #include "common.h" 40 | 41 | // 42 | // APIC register selector definitions 43 | // 44 | 45 | #define APIC_LAPIC_ID 0x20 // Local APIC ID Register (Read/Write) 46 | #define APIC_LAPIC_VERSION 0x30 // Local APIC Version Register (Read Only) 47 | #define APIC_TPR 0x80 // Task Priority Register (Read/Write) 48 | #define APIC_APR 0x90 // Arbitration Priority Register (Read Only) 49 | #define APIC_PPR 0xA0 // Processor Priority Register (Read Only) 50 | #define APIC_EOIR 0xB0 // EOI Register (Write Only) 51 | #define APIC_RRR 0xC0 // Remote Read Register (Read Only) 52 | #define APIC_LDR 0xD0 // Logical Destination Register (Read/Write) 53 | #define APIC_DFR 0xE0 // Destination Format Register (Read/Write) 54 | #define APIC_SIVR 0xF0 // Spurious Interrupt Vector Register (Read/Write) 55 | #define APIC_ISR1 0x0100 // In-Service Register bits 31:0 (Read Only) 56 | #define APIC_ISR2 0x0110 // In-Service Register bits 63:32 (Read Only) 57 | #define APIC_ISR3 0x0120 // In-Service Register bits 95:64 (Read Only) 58 | #define APIC_ISR4 0x0130 // In-Service Register bits 127:96 (Read Only) 59 | #define APIC_ISR5 0x0140 // In-Service Register bits 159:128 (Read Only) 60 | #define APIC_ISR6 0x0150 // In-Service Register bits 191:160 (Read Only) 61 | #define APIC_ISR7 0x0160 // In-Service Register bits 223:192 (Read Only) 62 | #define APIC_ISR8 0x0170 // In-Service Register bits 255:224 (Read Only) 63 | #define APIC_TMR1 0x0180 // Trigger Mode Register bits 31:0 (Read Only) 64 | #define APIC_TMR2 0x0190 // Trigger Mode Register bits 63:32 (Read Only) 65 | #define APIC_TMR3 0x01A0 // Trigger Mode Register bits 95:64 (Read Only) 66 | #define APIC_TMR4 0x01B0 // Trigger Mode Register bits 127:96 (Read Only) 67 | #define APIC_TMR5 0x01C0 // Trigger Mode Register bits 159:128 (Read Only) 68 | #define APIC_TMR6 0x01D0 // Trigger Mode Register bits 191:160 (Read Only) 69 | #define APIC_TMR7 0x01E0 // Trigger Mode Register bits 223:192 (Read Only) 70 | #define APIC_TMR8 0x01F0 // Trigger Mode Register bits 255:224 (Read Only) 71 | #define APIC_IRR1 0x0200 // Interrupt Request Register bits 31:0 (Read Only) 72 | #define APIC_IRR2 0x0210 // Interrupt Request Register bits 63:32 (Read Only) 73 | #define APIC_IRR3 0x0220 // Interrupt Request Register bits 95:64 (Read Only) 74 | #define APIC_IRR4 0x0230 // Interrupt Request Register bits 127:96 (Read Only) 75 | #define APIC_IRR5 0x0240 // Interrupt Request Register bits 159:128 (Read Only) 76 | #define APIC_IRR6 0x0250 // Interrupt Request Register bits 191:160 (Read Only) 77 | #define APIC_IRR7 0x0260 // Interrupt Request Register bits 223:192 (Read Only) 78 | #define APIC_IRR8 0x0270 // Interrupt Request Register bits 255:224 (Read Only) 79 | #define APIC_ESR 0x0280 // Error Status Register (Read Only) 80 | #define APIC_LVT_CMCI 0x02F0 // LVT CMCI Register (Read/Write) 81 | #define APIC_ICR1 0x0300 // Interrupt Command Register bits 0-31 (Read/Write) 82 | #define APIC_ICR2 0x0310 // Interrupt Command Register bits 32-63 (Read/Write) 83 | #define APIC_LVT_TIMER 0x0320 // LVT Timer Register (Read/Write) 84 | #define APIC_LVT_THERMAL 0x0330 // LVT Thermal Sensor Register (Read/Write) 85 | #define APIC_LVT_PMC 0x0340 // LVT Performance Monitoring Counters Register (Read/Write) 86 | #define APIC_LVT_LINT0 0x0350 // LVT LINT0 Register (Read/Write) 87 | #define APIC_LVT_LINT1 0x0360 // LVT LINT1 Register (Read/Write) 88 | #define APIC_LVT_EREG 0x0370 // LVT Error Register (Read/Write) 89 | #define APIC_INIT_COUNT 0x0380 // Initial Count Register (for Timer) (Read/Write) 90 | #define APIC_CURR_COUNT 0x0390 // Current Count Register (for Timer) (Read Only) 91 | #define APIC_DIV_CONF 0x03E0 // Divide Configuration Register (for Timer) (Read/Write) 92 | 93 | // 94 | // APIC entry types from ACPI MADT table 95 | // 96 | 97 | #define APIC_TYPE_LAPIC 0 // Local APIC 98 | #define APIC_TYPE_IOAPIC 1 // IO APIC 99 | #define APIC_TYPE_ISO 2 // Interrupt Service Override 100 | #define APIC_TYPE_NMI 3 // Non-Maskable Interrupt Source 101 | #define APIC_TYPE_LAPIC_NMI 4 // Local APIC NMI 102 | #define APIC_TYPE_LAPIC_AO 5 // Local APIC Adress Override 103 | #define APIC_TYPE_IOSAPIC 6 // IO SAPIC 104 | #define APIC_TYPE_LSAPIC 7 // Local SAPIC 105 | #define APIC_TYPE_PIS 8 // Platform Interrupt Sources 106 | #define APIC_TYPE_Lx2APIC 9 // Local x2APIC 107 | #define APIC_TYPE_Lx2APIC_NMI 10 // Local x2APIC NMI 108 | 109 | /** 110 | * APIC base MSR structure 111 | */ 112 | typedef union { 113 | struct { 114 | uint64 reserved1 : 8; // Reserved 115 | uint64 bsp : 1; // Bootstrap processor 116 | uint64 reserved2 : 2; // Reserved 117 | uint64 enable : 1; // Global APIC enable/disable bit 118 | uint64 base_addr : 24; // APIC base address (4 KByte aligned) 119 | uint64 reserved : 28; // Reserved 120 | } s; 121 | uint64 raw; 122 | } apic_base_t; 123 | 124 | /** 125 | * Initialize APIC(s) 126 | * @return true on success, false on failure 127 | */ 128 | bool apic_init(); 129 | /** 130 | * Get APIC base address 131 | * @return physical address of APIC memory maped registers 132 | */ 133 | apic_base_t apic_get_base(); 134 | /** 135 | * Set APIC base address 136 | * @param addr - physical address of APIC memory maped registers 137 | */ 138 | void apic_set_base(apic_base_t addr); 139 | 140 | /** 141 | * Read Local APIC register 142 | * @param reg - APIC register selector 143 | * @return data stored in register 144 | */ 145 | uint32 apic_read_reg(uint64 reg); 146 | /** 147 | * Write Local APIC register 148 | * @param reg - APIC register selector 149 | * @param data - data to be stored in register 150 | */ 151 | void apic_write_reg(uint64 reg, uint32 value); 152 | 153 | /** 154 | * Read IOAPIC value 155 | * @param addr - APIC base address 156 | * @param reg - IOAPIC register selector 157 | * @return data stored in register 158 | */ 159 | uint32 apic_read_ioapic(uint64 addr, uint32 reg); 160 | /** 161 | * Write IOAPIC value 162 | * @param addr - APIC base address 163 | * @param reg - IOAPIC register selector 164 | * @param data - data to be stored in register 165 | */ 166 | void apic_write_ioapic(uint64 addr, uint32 reg, uint32 data); 167 | 168 | #endif /* __apic_h */ 169 | -------------------------------------------------------------------------------- /bbp/kernel/common.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Common data types (long mode) 4 | ============================= 5 | 6 | This file contains type definitions and helper structures. 7 | 8 | The idea of this file is to keep a precise control over data type sizes, so 9 | instead of int and long, we should have int32 or int64. 10 | 11 | Maybe in the future we'll introduce memory pointer type intptr or simply ptr, 12 | that will reference the largest integer type for memory access of the machine. 13 | That is, a 64bit int for x86_64 architecture and 32bit int for x86. 14 | 15 | License (BSD-3) 16 | =============== 17 | 18 | Copyright (c) 2012, Gusts 'gusC' Kaksis 19 | All rights reserved. 20 | 21 | Redistribution and use in source and binary forms, with or without 22 | modification, are permitted provided that the following conditions are met: 23 | * Redistributions of source code must retain the above copyright 24 | notice, this list of conditions and the following disclaimer. 25 | * Redistributions in binary form must reproduce the above copyright 26 | notice, this list of conditions and the following disclaimer in the 27 | documentation and/or other materials provided with the distribution. 28 | * Neither the name of the nor the 29 | names of its contributors may be used to endorse or promote products 30 | derived from this software without specific prior written permission. 31 | 32 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 33 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 34 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 35 | DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY 36 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 37 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 38 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 39 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 40 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 41 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 42 | 43 | */ 44 | 45 | #ifndef __common_h 46 | #define __common_h 47 | 48 | #define __NOINLINE __attribute__((noinline)) 49 | #define __INLINE __attribute__((always_inline)) 50 | #define __REGPARM __attribute__((regparm(3))) 51 | #define __NORETURN __attribute__((noreturn)) 52 | #define __PACKED __attribute__((packed)) 53 | #define __ALIGN(x) __attribute__((aligned(x))) 54 | 55 | #define BREAK() asm volatile ("xchg %bx, %bx") 56 | #define HANG() while(true){} 57 | 58 | // Default types 59 | typedef unsigned char uchar; 60 | 61 | typedef unsigned char uint8; 62 | typedef unsigned short uint16; 63 | typedef unsigned int uint32; 64 | typedef unsigned long long uint64; 65 | 66 | typedef char int8; 67 | typedef short int16; 68 | typedef int int32; 69 | typedef long long int64; 70 | 71 | #define null 0 72 | #define true 1 73 | #define false 0 74 | #define bool uint64 75 | 76 | // Variadic funciton arguments 77 | #define va_list __builtin_va_list 78 | #define va_start(v, f) __builtin_va_start(v, f) 79 | #define va_end(v) __builtin_va_end(v) 80 | #define va_arg(v, a) __builtin_va_arg(v, a) 81 | 82 | typedef struct { 83 | uint32 low; 84 | uint32 high; 85 | } split_uint64_t; 86 | 87 | #endif /* __common_h */ 88 | -------------------------------------------------------------------------------- /bbp/kernel/cpuid.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Helper function for CPUID operations 4 | ==================================== 5 | 6 | ASM wrappers 7 | 8 | License (BSD-3) 9 | =============== 10 | 11 | Copyright (c) 2012, Gusts 'gusC' Kaksis 12 | All rights reserved. 13 | 14 | Redistribution and use in source and binary forms, with or without 15 | modification, are permitted provided that the following conditions are met: 16 | * Redistributions of source code must retain the above copyright 17 | notice, this list of conditions and the following disclaimer. 18 | * Redistributions in binary form must reproduce the above copyright 19 | notice, this list of conditions and the following disclaimer in the 20 | documentation and/or other materials provided with the distribution. 21 | * Neither the name of the nor the 22 | names of its contributors may be used to endorse or promote products 23 | derived from this software without specific prior written permission. 24 | 25 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 26 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 27 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 28 | DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY 29 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 30 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 31 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 32 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 33 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 34 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35 | 36 | */ 37 | #ifndef __cpuid_h 38 | #define __cpuid_h 39 | 40 | #include "common.h" 41 | 42 | /** 43 | * Read CPUID 44 | * @param type - initial EAX value (information type to get from CPUID) 45 | * @param [out] eax - EAX value returned by CPUID 46 | * @param [out] ebx - EBX value returned by CPUID 47 | * @param [out] ecx - ECX value returned by CPUID 48 | * @param [out] edx - EDX value returned by CPUID 49 | * @return void 50 | */ 51 | static void cpuid(uint32 type, uint32 *eax, uint32 *ebx, uint32 *ecx, uint32 *edx){ 52 | asm volatile("cpuid" : "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx) : "a"(type)); 53 | } 54 | 55 | #endif 56 | -------------------------------------------------------------------------------- /bbp/kernel/debug_print.c: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Helper functions for operations with teletype (text mode) screen 4 | ================================================================ 5 | 6 | Teletype video functions: 7 | * clear screen 8 | * print a formated string on the screen 9 | 10 | License (BSD-3) 11 | =============== 12 | 13 | Copyright (c) 2012, Gusts 'gusC' Kaksis 14 | All rights reserved. 15 | 16 | Redistribution and use in source and binary forms, with or without 17 | modification, are permitted provided that the following conditions are met: 18 | * Redistributions of source code must retain the above copyright 19 | notice, this list of conditions and the following disclaimer. 20 | * Redistributions in binary form must reproduce the above copyright 21 | notice, this list of conditions and the following disclaimer in the 22 | documentation and/or other materials provided with the distribution. 23 | * Neither the name of the nor the 24 | names of its contributors may be used to endorse or promote products 25 | derived from this software without specific prior written permission. 26 | 27 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 28 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 29 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 30 | DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY 31 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 32 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 33 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 34 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 35 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 36 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 37 | 38 | */ 39 | 40 | #include "../config.h" 41 | #include "debug_print.h" 42 | #include "lib.h" 43 | 44 | // Video screen size 45 | static uint64 _columns = 80; 46 | static uint64 _rows = 25; 47 | // Global cursor 48 | static uint64 _x = 0; 49 | static uint64 _y = 0; 50 | static uint8 _base_color = 0x00; 51 | 52 | static void __debug_print_f(uint8 x, uint8 y, uint8 color, const char *format, va_list args); 53 | 54 | void debug_clear(uint8 color){ 55 | char *vidmem = (char *)VIDEOMEM_LOC; 56 | _base_color = color; 57 | _y = 0; 58 | _x = 0; 59 | uint16 fill = (_base_color << 8) + ' '; 60 | // Fast clear line 61 | asm volatile ("rep\n\tstosw" : : "a"(fill), "c"(_columns * _rows), "D"(vidmem)); 62 | } 63 | 64 | void debug_scroll(){ 65 | char *vidmem = (char *)VIDEOMEM_LOC; 66 | uint16 row_len = _columns * 2; 67 | uint16 last_row_char = (_rows - 1) * _columns; 68 | uint16 fill = (_base_color << 8) + ' '; 69 | // Fast scroll 70 | asm volatile ("rep\n\tmovsw" : : "c"(last_row_char), "S"(vidmem + row_len), "D"(vidmem)); 71 | // Fast clear line 72 | asm volatile ("rep\n\tstosw" : : "a"(fill), "c"(_columns), "D"(vidmem + (last_row_char * 2))); 73 | } 74 | 75 | void debug_print_at(uint8 x, uint8 y, uint8 color, const char *format, ...){ 76 | va_list args; 77 | va_start(args, format); 78 | __debug_print_f(x, y, color, format, args); 79 | va_end(args); 80 | } 81 | 82 | void debug_print(uint8 color, const char *format, ...){ 83 | if (_y >= _rows){ 84 | debug_scroll(); 85 | _y = _rows - 1; 86 | } 87 | va_list args; 88 | va_start(args, format); 89 | __debug_print_f(_x, _y, color, format, args); 90 | va_end(args); 91 | _y ++; 92 | } 93 | 94 | static void __debug_print_f(uint8 x, uint8 y, uint8 color, const char *format, va_list args){ 95 | char *vidmem = (char *)VIDEOMEM_LOC; 96 | static char str[2001]; 97 | mem_fill((uint8 *)str, 2001, 0); 98 | uint16 i; 99 | // Keep everything in bounds 100 | if (__write_f(str, 2000, format, args)){ 101 | char *s = (char *)str; 102 | while (*s != 0){ 103 | if (*s == 0x0A || x >= _columns){ // New line (a.k.a \n) or forced wrap 104 | x = 0; 105 | y ++; 106 | if (y >= _rows){ 107 | debug_scroll(); 108 | y = _rows - 1; 109 | } 110 | } 111 | if (*s >= 0x20 && *s <= 0x7E){ // Only valid ASCII chars 112 | i = (y * _columns * 2) + (x * 2); 113 | vidmem[i] = *s; 114 | vidmem[i + 1] = color; 115 | x ++; 116 | } 117 | s++; 118 | } 119 | } 120 | } -------------------------------------------------------------------------------- /bbp/kernel/debug_print.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Helper functions for operations with teletype (text mode) screen 4 | ================================================================ 5 | 6 | Teletype video functions: 7 | * clear screen 8 | * print a formated string on the screen 9 | 10 | License (BSD-3) 11 | =============== 12 | 13 | Copyright (c) 2012, Gusts 'gusC' Kaksis 14 | All rights reserved. 15 | 16 | Redistribution and use in source and binary forms, with or without 17 | modification, are permitted provided that the following conditions are met: 18 | * Redistributions of source code must retain the above copyright 19 | notice, this list of conditions and the following disclaimer. 20 | * Redistributions in binary form must reproduce the above copyright 21 | notice, this list of conditions and the following disclaimer in the 22 | documentation and/or other materials provided with the distribution. 23 | * Neither the name of the nor the 24 | names of its contributors may be used to endorse or promote products 25 | derived from this software without specific prior written permission. 26 | 27 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 28 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 29 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 30 | DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY 31 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 32 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 33 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 34 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 35 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 36 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 37 | 38 | */ 39 | 40 | #ifndef __video_h 41 | #define __video_h 42 | 43 | #include "common.h" 44 | 45 | // Some fancy color definitions :) 46 | #define DC_WB 0xF0 47 | #define DC_BW 0x0F 48 | #define DC_WLG 0xF7 49 | #define DC_WDG 0xF8 50 | #define DC_WBL 0xF1 51 | #define DC_WGR 0xF2 52 | #define DC_WRD 0xF4 53 | 54 | /** 55 | * Clear the teletype (text mode) screen 56 | * @param color - color byte 57 | * @return void 58 | */ 59 | void debug_clear(uint8 color); 60 | /** 61 | * Scroll whole video buffer upwards 62 | * @return void 63 | */ 64 | void debug_scroll(); 65 | /** 66 | * Print a formated string on the teletype (text mode) screen 67 | * @param x coordinate (a.k.a. column 0-79) 68 | * @param y coordinate (a.k.a. line 0-24) 69 | * @param color - color byte 70 | * @param [in] format - standard C printf format string 71 | * @param [in] ... - additional arguments 72 | * @return void 73 | */ 74 | void debug_print_at(uint8 x, uint8 y, uint8 color, const char *format, ...); 75 | /** 76 | * Print a formated string on the teletype (text mode) screen 77 | * @param color - color byte 78 | * @param [in] format - standard C printf format string 79 | * @param [in] ... - additional arguments 80 | * @return void 81 | */ 82 | void debug_print(uint8 color, const char *format, ...); 83 | 84 | #endif /* __video_h */ 85 | -------------------------------------------------------------------------------- /bbp/kernel/interrupts.asm: -------------------------------------------------------------------------------- 1 | ; 2 | ; Helper functions for operations interrupts 3 | ; ================== 4 | ; 5 | ; This contains imports from ASM stub subroutines that catch all the neccessary 6 | ; exception interrupts and calls a C function interrupt_handler(). 7 | ; It also contains LIDT wrapper function. 8 | ; 9 | ; License (BSD-3) 10 | ; =============== 11 | ; 12 | ; Copyright (c) 2013, Gusts 'gusC' Kaksis 13 | ; All rights reserved. 14 | ; 15 | ; Redistribution and use in source and binary forms, with or without 16 | ; modification, are permitted provided that the following conditions are met: 17 | ; * Redistributions of source code must retain the above copyright 18 | ; notice, this list of conditions and the following disclaimer. 19 | ; * Redistributions in binary form must reproduce the above copyright 20 | ; notice, this list of conditions and the following disclaimer in the 21 | ; documentation and/or other materials provided with the distribution. 22 | ; * Neither the name of the nor the 23 | ; names of its contributors may be used to endorse or promote products 24 | ; derived from this software without specific prior written permission. 25 | ; 26 | ; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 27 | ; ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 28 | ; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 29 | ; DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY 30 | ; DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 31 | ; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 32 | ; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 33 | ; ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34 | ; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 35 | ; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 | ; 37 | 38 | [section .text] 39 | [bits 64] 40 | [extern isr_handler] ; Import int_handler from C 41 | [extern irq_handler] ; Import irq_handler from C 42 | [global idt_set] ; Export void idt_set(idt_ptr_t *idt) to C 43 | 44 | ; Macro to create an intterupt service routine for interrupts that do not pass error codes 45 | %macro INT_NO_ERR 1 46 | [global isr%1] 47 | isr%1: 48 | cli ; disable interrupts 49 | push qword 0 ; set error code to 0 50 | push qword %1 ; set interrupt number 51 | call isr_handler ; call void isr_handler(int_stack_t args) 52 | sti ; enable interrupts 53 | add rsp, 16 ; cleanup stack 54 | iretq ; return from interrupt handler 55 | %endmacro 56 | 57 | ; Macro to create an interrupt service routine for interrupts that DO pass an error code 58 | %macro INT_HAS_ERR 1 59 | [global isr%1] 60 | isr%1: 61 | cli ; disable interrupts 62 | push qword %1 ; set interrupt number 63 | call isr_handler ; call void isr_handler(int_stack_t args) 64 | sti ; enable interrupts 65 | add rsp, 16 ; cleanup stack 66 | iretq ; return from interrupt handler 67 | %endmacro 68 | 69 | ; Macro to create an IRQ interrupt service routine 70 | ; First parameter is the IRQ number 71 | ; Second parameter is the interrupt number it is remapped to 72 | %macro IRQ 2 73 | [global irq%1] 74 | irq%1: 75 | cli ; disable interrupts 76 | push qword %1 ; set IRQ number in the place of error code (see registers_t in interrupts.h) 77 | push qword %2 ; set interrupt number 78 | call irq_handler ; calls void irq_handler(int_stack_t args) 79 | sti ; enable interrupts 80 | add rsp, 16 ; cleanup stack 81 | iretq ; return from interrupt handler 82 | %endmacro 83 | 84 | idt_set: ; prototype: void idt_set(uint32 idt_ptr) 85 | cli ; disable interrupts 86 | lidt [rdi] ; load the IDT (x86_64 calling convention - 1st argument goes into RDI) 87 | sti ; enable interrupts 88 | ret ; return to C 89 | 90 | ; Setup all the neccessary service routines with macros 91 | INT_NO_ERR 0 92 | INT_NO_ERR 1 93 | INT_NO_ERR 2 94 | INT_NO_ERR 3 95 | INT_NO_ERR 4 96 | INT_NO_ERR 5 97 | INT_NO_ERR 6 98 | INT_NO_ERR 7 99 | INT_NO_ERR 8 ; By all specs int 8 is double fault WITH error message, but not in Bochs, WHY? 100 | INT_NO_ERR 9 101 | INT_HAS_ERR 10 102 | INT_HAS_ERR 11 103 | INT_HAS_ERR 12 104 | INT_HAS_ERR 13 105 | INT_HAS_ERR 14 106 | INT_NO_ERR 15 107 | INT_NO_ERR 16 108 | INT_NO_ERR 17 109 | INT_NO_ERR 18 110 | INT_NO_ERR 19 111 | INT_NO_ERR 20 112 | INT_NO_ERR 21 113 | INT_NO_ERR 22 114 | INT_NO_ERR 23 115 | INT_NO_ERR 24 116 | INT_NO_ERR 25 117 | INT_NO_ERR 26 118 | INT_NO_ERR 27 119 | INT_NO_ERR 28 120 | INT_NO_ERR 29 121 | INT_NO_ERR 30 122 | INT_NO_ERR 31 123 | IRQ 0, 32 124 | IRQ 1, 33 125 | IRQ 2, 34 126 | IRQ 3, 35 127 | IRQ 4, 36 128 | IRQ 5, 37 129 | IRQ 6, 38 130 | IRQ 7, 39 131 | IRQ 8, 40 132 | IRQ 9, 41 133 | IRQ 10, 42 134 | IRQ 11, 43 135 | IRQ 12, 44 136 | IRQ 13, 45 137 | IRQ 14, 46 138 | IRQ 15, 47 139 | -------------------------------------------------------------------------------- /bbp/kernel/interrupts.c: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Helper functions for operations interrupts 4 | ========================================== 5 | 6 | This contains imports from ASM stub subroutines that catch all the neccessary 7 | exception interrupts and calls a C function interrupt_handler(). 8 | It also contains LIDT wrapper function and C functions to handle interrupts. 9 | 10 | License (BSD-3) 11 | =============== 12 | 13 | Copyright (c) 2012, Gusts 'gusC' Kaksis 14 | All rights reserved. 15 | 16 | Redistribution and use in source and binary forms, with or without 17 | modification, are permitted provided that the following conditions are met: 18 | * Redistributions of source code must retain the above copyright 19 | notice, this list of conditions and the following disclaimer. 20 | * Redistributions in binary form must reproduce the above copyright 21 | notice, this list of conditions and the following disclaimer in the 22 | documentation and/or other materials provided with the distribution. 23 | * Neither the name of the nor the 24 | names of its contributors may be used to endorse or promote products 25 | derived from this software without specific prior written permission. 26 | 27 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 28 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 29 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 30 | DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY 31 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 32 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 33 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 34 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 35 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 36 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 37 | 38 | */ 39 | 40 | #include "../config.h" 41 | #include "interrupts.h" 42 | #include "lib.h" 43 | #include "io.h" 44 | #include "paging.h" 45 | #if DEBUG == 1 46 | #include "debug_print.h" 47 | #endif 48 | 49 | /** 50 | * Exception names 51 | */ 52 | static char *ints[] = { 53 | "Division by zero", 54 | "Debug exception", 55 | "NMI interrupt", 56 | "Breakpoint", 57 | "INTO overflow", 58 | "BOUND exception", 59 | "Invalid opcode", 60 | "No FPU", 61 | "Double Fault!", 62 | "FPU segment overrun", 63 | "Bad TSS", 64 | "Segment not present", 65 | "Stack fault", 66 | "GPF", 67 | "Page fault", 68 | "", 69 | "FPU Exception", 70 | "Alignament check exception", 71 | "Machine check exception" 72 | }; 73 | /** 74 | * Interrupt Descriptor Table 75 | */ 76 | idt_entry_t idt[256]; 77 | /** 78 | * Interrupt Descriptor Table pointer 79 | */ 80 | idt_ptr_t idt_ptr; 81 | 82 | static void idt_set_entry(uint8 num, uint64 addr, uint16 flags){ 83 | idt[num].offset_lo = (uint16)(addr & 0xFFFF); 84 | idt[num].offset_hi = (uint16)((addr >> 16) & 0xFFFF); 85 | idt[num].offset_64 = (uint32)((addr >> 32) & 0xFFFFFFFFF); 86 | idt[num].segment = 0x08; // Allways a code selector 87 | idt[num].flags.raw = flags; 88 | idt[num].reserved = 0; // Zero out 89 | } 90 | 91 | void interrupt_init(){ 92 | mem_fill((uint8 *)&idt, sizeof(idt_entry_t) * 256, 0); 93 | 94 | // Remap the IRQ table. 95 | outb(0x20, 0x11); // Initialize master PIC 96 | outb(0xA0, 0x11); // Initialize slave PIC 97 | outb(0x21, 0x20); // Master PIC vector offset (IRQ0 target interrupt number) 98 | outb(0xA1, 0x28); // Slave PIC vector offset (IRQ8 landing interrupt number) 99 | outb(0x21, 0x04); // Tell Master PIC that Slave PIC is at IRQ2 100 | outb(0xA1, 0x02); // Tell Slave PIC that it's cascaded to IRQ2 101 | outb(0x21, 0x01); // Enable 8085 mode (whatever that means) 102 | outb(0xA1, 0x01); // Enable 8085 mode (whatever that means) 103 | outb(0x21, 0x0); // Clear masks 104 | outb(0xA1, 0x0); // Clear masks 105 | 106 | idt_set_entry( 0, (uint64)isr0 , 0x8E00); // Division by zero exception 107 | idt_set_entry( 1, (uint64)isr1 , 0x8E00); // Debug exception 108 | idt_set_entry( 2, (uint64)isr2 , 0x8E00); // Non maskable (external) interrupt 109 | idt_set_entry( 3, (uint64)isr3 , 0x8E00); // Breakpoint exception 110 | idt_set_entry( 4, (uint64)isr4 , 0x8E00); // INTO instruction overflow exception 111 | idt_set_entry( 5, (uint64)isr5 , 0x8E00); // Out of bounds exception (BOUND instruction) 112 | idt_set_entry( 6, (uint64)isr6 , 0x8E00); // Invalid opcode exception 113 | idt_set_entry( 7, (uint64)isr7 , 0x8E00); // No coprocessor exception 114 | idt_set_entry( 8, (uint64)isr8 , 0x8E00); // Double fault (pushes an error code) 115 | idt_set_entry( 9, (uint64)isr9 , 0x8E00); // Coprocessor segment overrun 116 | idt_set_entry(10, (uint64)isr10, 0x8E00); // Bad TSS (pushes an error code) 117 | idt_set_entry(11, (uint64)isr11, 0x8E00); // Segment not present (pushes an error code) 118 | idt_set_entry(12, (uint64)isr12, 0x8E00); // Stack fault (pushes an error code) 119 | idt_set_entry(13, (uint64)isr13, 0x8E00); // General protection fault (pushes an error code) 120 | idt_set_entry(14, (uint64)isr14, 0x8E00); // Page fault (pushes an error code) 121 | idt_set_entry(15, (uint64)isr15, 0x8E00); // Reserved 122 | idt_set_entry(16, (uint64)isr16, 0x8E00); // FPU exception 123 | idt_set_entry(17, (uint64)isr17, 0x8E00); // Alignment check exception 124 | idt_set_entry(18, (uint64)isr18, 0x8E00); // Machine check exception 125 | idt_set_entry(19, (uint64)isr19, 0x8E00); // Reserved 126 | idt_set_entry(20, (uint64)isr20, 0x8E00); // Reserved 127 | idt_set_entry(21, (uint64)isr21, 0x8E00); // Reserved 128 | idt_set_entry(22, (uint64)isr22, 0x8E00); // Reserved 129 | idt_set_entry(23, (uint64)isr23, 0x8E00); // Reserved 130 | idt_set_entry(24, (uint64)isr24, 0x8E00); // Reserved 131 | idt_set_entry(25, (uint64)isr25, 0x8E00); // Reserved 132 | idt_set_entry(26, (uint64)isr26, 0x8E00); // Reserved 133 | idt_set_entry(27, (uint64)isr27, 0x8E00); // Reserved 134 | idt_set_entry(28, (uint64)isr28, 0x8E00); // Reserved 135 | idt_set_entry(29, (uint64)isr29, 0x8E00); // Reserved 136 | idt_set_entry(30, (uint64)isr30, 0x8E00); // Reserved 137 | idt_set_entry(31, (uint64)isr31, 0x8E00); // Reserved 138 | 139 | idt_set_entry(32, (uint64)irq0 , 0x8E00); // IRQ0 - Programmable Interrupt Timer Interrupt 140 | idt_set_entry(33, (uint64)irq1 , 0x8E00); // IRQ1 - Keyboard Interrupt 141 | idt_set_entry(34, (uint64)irq2 , 0x8E00); // IRQ2 - Cascade (used internally by the two PICs. never raised) 142 | idt_set_entry(35, (uint64)irq3 , 0x8E00); // IRQ3 - COM2 (if enabled) 143 | idt_set_entry(36, (uint64)irq4 , 0x8E00); // IRQ4 - COM1 (if enabled) 144 | idt_set_entry(37, (uint64)irq5 , 0x8E00); // IRQ5 - LPT2 (if enabled) 145 | idt_set_entry(38, (uint64)irq6 , 0x8E00); // IRQ6 - Floppy Disk 146 | idt_set_entry(39, (uint64)irq7 , 0x8E00); // IRQ7 - LPT1 / Unreliable "spurious" interrupt (usually) 147 | idt_set_entry(40, (uint64)irq8 , 0x8E00); // IRQ8 - CMOS real-time clock (if enabled) 148 | idt_set_entry(41, (uint64)irq9 , 0x8E00); // IRQ9 - Free for peripherals / legacy SCSI / NIC 149 | idt_set_entry(42, (uint64)irq10, 0x8E00); // IRQ10 - Free for peripherals / SCSI / NIC 150 | idt_set_entry(43, (uint64)irq11, 0x8E00); // IRQ11 - Free for peripherals / SCSI / NIC 151 | idt_set_entry(44, (uint64)irq12, 0x8E00); // IRQ12 - PS2 Mouse 152 | idt_set_entry(45, (uint64)irq13, 0x8E00); // IRQ13 - FPU / Coprocessor / Inter-processor 153 | idt_set_entry(46, (uint64)irq14, 0x8E00); // IRQ14 - Primary ATA Hard Disk 154 | idt_set_entry(47, (uint64)irq15, 0x8E00); // IRQ15 - Secondary ATA Hard Disk 155 | 156 | idt_ptr.limit = (sizeof(idt_entry_t) * 256) - 1; 157 | idt_ptr.base = (uint64)&idt; 158 | idt_set(&idt_ptr); 159 | } 160 | 161 | void isr_handler(int_stack_t stack){ 162 | #if DEBUG == 1 163 | if (stack.int_no < 19){ 164 | debug_print(DC_WB, ints[stack.int_no]); 165 | } else { 166 | debug_print(DC_WB, "Interrupt: %x", stack.int_no); 167 | } 168 | #endif 169 | // Process some exceptions here 170 | uint64 cr2 = 0; 171 | switch (stack.int_no){ 172 | case 0: // Division by zero 173 | //stack.rip++; // it's ok to divide by zero - move to next instruction :P 174 | break; 175 | case 13: // General protection fault 176 | #if DEBUG == 1 177 | debug_print(DC_WRD, "Error: %x", stack.err_code); 178 | #endif 179 | HANG(); 180 | break; 181 | case 14: // Page fault 182 | asm volatile ("mov %%cr2, %0" : "=a"(cr2) :); 183 | // Map this page if it's not mapped yet, otherwise hang 184 | if (!page_resolve(cr2)){ 185 | page_map(cr2); 186 | } else { 187 | #if DEBUG == 1 188 | debug_print(DC_WRD, "Error: %x", stack.err_code); 189 | debug_print(DC_WRD, "Addr: @%x", cr2); 190 | #endif 191 | HANG(); 192 | } 193 | // Do something! 194 | break; 195 | } 196 | } 197 | 198 | void irq_handler(int_stack_t stack){ 199 | #if DEBUG == 1 200 | debug_print(DC_WB, "IRQ %d", stack.err_code); 201 | #endif 202 | } -------------------------------------------------------------------------------- /bbp/kernel/interrupts.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Helper functions for operations interrupts 4 | ========================================== 5 | 6 | This contains imports from ASM stub subroutines that catch all the neccessary 7 | exception interrupts and calls a C function interrupt_handler(). 8 | It also contains LIDT wrapper function. 9 | 10 | License (BSD-3) 11 | =============== 12 | 13 | Copyright (c) 2012, Gusts 'gusC' Kaksis 14 | All rights reserved. 15 | 16 | Redistribution and use in source and binary forms, with or without 17 | modification, are permitted provided that the following conditions are met: 18 | * Redistributions of source code must retain the above copyright 19 | notice, this list of conditions and the following disclaimer. 20 | * Redistributions in binary form must reproduce the above copyright 21 | notice, this list of conditions and the following disclaimer in the 22 | documentation and/or other materials provided with the distribution. 23 | * Neither the name of the nor the 24 | names of its contributors may be used to endorse or promote products 25 | derived from this software without specific prior written permission. 26 | 27 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 28 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 29 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 30 | DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY 31 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 32 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 33 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 34 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 35 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 36 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 37 | 38 | */ 39 | 40 | #ifndef __interrupts_h 41 | #define __interrupts_h 42 | 43 | #include "common.h" 44 | 45 | // Remaped IRQ numbers to interrupt numbers 46 | #define IRQ0 32 47 | #define IRQ1 33 48 | #define IRQ2 34 49 | #define IRQ3 35 50 | #define IRQ4 36 51 | #define IRQ5 37 52 | #define IRQ6 38 53 | #define IRQ7 39 54 | #define IRQ8 40 55 | #define IRQ9 41 56 | #define IRQ10 42 57 | #define IRQ11 43 58 | #define IRQ12 44 59 | #define IRQ13 45 60 | #define IRQ14 46 61 | #define IRQ15 47 62 | 63 | /** 64 | * Register stack passed from assembly 65 | */ 66 | typedef struct { 67 | uint64 int_no; // Interrupt number 68 | uint64 err_code; // Error code (or IRQ number for IRQs) 69 | uint64 rip; // Return instruction pointer 70 | uint64 cs; // Code segment 71 | uint64 rflags; // RFLAGS 72 | uint64 rsp; // Previous stack pointer 73 | uint64 ss; // Stack segment 74 | } int_stack_t; 75 | /** 76 | * Interrupt Descriptor Table (IDT) entry structure 77 | */ 78 | struct idt_entry_struct { 79 | uint16 offset_lo; // The lower 16 bits of 32bit address to jump to when this interrupt fires 80 | uint16 segment; // Kernel segment selector 81 | union { 82 | uint16 raw; // Raw value 83 | struct { // IDT flag structure 84 | uint16 ist :3; // Interrupt stack table 85 | uint16 res1 :5; // This must be zero 86 | uint16 type :4; // Interrupt gate, trap gate, task gate, etc. 87 | uint16 res2 :1; // This must be zero 88 | uint16 dpl :2; // Descriptor privilege level 89 | uint16 present :1; // Present flag 90 | } s; 91 | } flags; 92 | uint16 offset_hi; // The upper 16 bits of 32bit address to jump to 93 | uint32 offset_64; // The upper 32 bits of 64bit address 94 | uint32 reserved; // Reserved for 96bit systems :) 95 | } __PACKED; 96 | /** 97 | * Interrupt Descriptor Table (IDT) entry 98 | */ 99 | typedef struct idt_entry_struct idt_entry_t; 100 | /** 101 | * Interrupt Descriptor Table (IDT) pointer structure 102 | */ 103 | struct idt_ptr_struct { 104 | uint16 limit; 105 | uint64 base; // The address of the first element in our idt_entry_t array. 106 | } __PACKED; 107 | /** 108 | * Interrupt Descriptor Table (IDT) pointer 109 | */ 110 | typedef struct idt_ptr_struct idt_ptr_t; 111 | /** 112 | * Initialize interrupt handlers 113 | */ 114 | void interrupt_init(); 115 | /** 116 | * Set IDT pointer 117 | * @see interrupts.asm 118 | * @param idt_ptr - an address of IDT pointer structure in memory 119 | * @return void 120 | */ 121 | extern void idt_set(idt_ptr_t *idt_ptr); 122 | /** 123 | * Interrupt Service Routine (ISR) handler 124 | * This will be defined in kernel code 125 | * @param regs - registers pushed on the stack by assembly 126 | * @return void 127 | */ 128 | void isr_handler(int_stack_t regs); 129 | /** 130 | * Interrupt Request (IRQ) handler 131 | * This will be defined in kernel code 132 | * @param regs - registers pushed on the stack by assembly 133 | * @return void 134 | */ 135 | void irq_handler(int_stack_t regs); 136 | 137 | // Defined in interrupts.asm (with macros!) 138 | extern void isr0(); 139 | extern void isr1(); 140 | extern void isr2(); 141 | extern void isr3(); 142 | extern void isr4(); 143 | extern void isr5(); 144 | extern void isr6(); 145 | extern void isr7(); 146 | extern void isr8(); 147 | extern void isr9(); 148 | extern void isr10(); 149 | extern void isr11(); 150 | extern void isr12(); 151 | extern void isr13(); 152 | extern void isr14(); 153 | extern void isr15(); 154 | extern void isr16(); 155 | extern void isr17(); 156 | extern void isr18(); 157 | extern void isr19(); 158 | extern void isr20(); 159 | extern void isr21(); 160 | extern void isr22(); 161 | extern void isr23(); 162 | extern void isr24(); 163 | extern void isr25(); 164 | extern void isr26(); 165 | extern void isr27(); 166 | extern void isr28(); 167 | extern void isr29(); 168 | extern void isr30(); 169 | extern void isr31(); 170 | // Defined in interrupts.asm (with macros!) 171 | extern void irq0(); 172 | extern void irq1(); 173 | extern void irq2(); 174 | extern void irq3(); 175 | extern void irq4(); 176 | extern void irq5(); 177 | extern void irq6(); 178 | extern void irq7(); 179 | extern void irq8(); 180 | extern void irq9(); 181 | extern void irq10(); 182 | extern void irq11(); 183 | extern void irq12(); 184 | extern void irq13(); 185 | extern void irq14(); 186 | extern void irq15(); 187 | 188 | 189 | #endif -------------------------------------------------------------------------------- /bbp/kernel/io.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Helper functions for legacy IO operations 4 | ========================================= 5 | 6 | ASM wrappers 7 | 8 | License (BSD-3) 9 | =============== 10 | 11 | Copyright (c) 2012, Gusts 'gusC' Kaksis 12 | All rights reserved. 13 | 14 | Redistribution and use in source and binary forms, with or without 15 | modification, are permitted provided that the following conditions are met: 16 | * Redistributions of source code must retain the above copyright 17 | notice, this list of conditions and the following disclaimer. 18 | * Redistributions in binary form must reproduce the above copyright 19 | notice, this list of conditions and the following disclaimer in the 20 | documentation and/or other materials provided with the distribution. 21 | * Neither the name of the nor the 22 | names of its contributors may be used to endorse or promote products 23 | derived from this software without specific prior written permission. 24 | 25 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 26 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 27 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 28 | DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY 29 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 30 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 31 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 32 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 33 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 34 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35 | 36 | */ 37 | 38 | #ifndef __io_h 39 | #define __io_h 40 | 41 | #include "common.h" 42 | 43 | /** 44 | * Write a byte out to the specified port. 45 | * @param port - IO port number 46 | * @param value - byte value 47 | * @return void 48 | */ 49 | static void outb(uint16 port, uint8 value){ 50 | asm volatile ("outb %1, %0" : : "d"(port), "a"(value)); 51 | } 52 | /** 53 | * Write a word out to the specified port. 54 | * @param port - IO port number 55 | * @param value - word value 56 | * @return void 57 | */ 58 | static void outw(uint16 port, uint16 value){ 59 | asm volatile ("outw %1, %0" : : "d"(port), "a"(value)); 60 | } 61 | /** 62 | * Write a dword out to the specified port. 63 | * @param port - IO port number 64 | * @param value - dword value 65 | * @return void 66 | */ 67 | static void outd(uint16 port, uint32 value){ 68 | asm volatile ("outl %1, %0" : : "d"(port), "a"(value)); 69 | } 70 | /** 71 | * Read a byte from specified port. 72 | * @param port - IO port number 73 | * @return byte value 74 | */ 75 | static uint8 inb(uint16 port){ 76 | uint8 ret; 77 | asm volatile("inb %1, %0" : "=a"(ret) : "d"(port)); 78 | return ret; 79 | } 80 | /** 81 | * Read a word from specified port. 82 | * @param port - IO port number 83 | * @return word value 84 | */ 85 | static uint16 inw(uint16 port){ 86 | uint16 ret; 87 | asm volatile("inw %1, %0" : "=a"(ret) : "d"(port)); 88 | return ret; 89 | } 90 | /** 91 | * Read a dword from specified port. 92 | * @param port - IO port number 93 | * @return dword value 94 | */ 95 | static uint32 ind(uint16 port){ 96 | uint32 ret; 97 | asm volatile("inl %1, %0" : "=a"(ret) : "d"(port)); 98 | return ret; 99 | } 100 | 101 | #endif 102 | -------------------------------------------------------------------------------- /bbp/kernel/kernel.ld: -------------------------------------------------------------------------------- 1 | OUTPUT_FORMAT(elf64-x86-64) 2 | SECTIONS { 3 | .text : { 4 | *(.text); 5 | } 6 | .rodata : { 7 | *(.rodata); 8 | } 9 | .data : { 10 | *(.data); 11 | } 12 | .bss : { 13 | *(.bss); 14 | } 15 | . = ALIGN(4096); 16 | } -------------------------------------------------------------------------------- /bbp/kernel/kmain.c: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Kernel entry point 4 | ================== 5 | 6 | This is where the fun part begins 7 | 8 | License (BSD-3) 9 | =============== 10 | 11 | Copyright (c) 2012, Gusts 'gusC' Kaksis 12 | All rights reserved. 13 | 14 | Redistribution and use in source and binary forms, with or without 15 | modification, are permitted provided that the following conditions are met: 16 | * Redistributions of source code must retain the above copyright 17 | notice, this list of conditions and the following disclaimer. 18 | * Redistributions in binary form must reproduce the above copyright 19 | notice, this list of conditions and the following disclaimer in the 20 | documentation and/or other materials provided with the distribution. 21 | * Neither the name of the nor the 22 | names of its contributors may be used to endorse or promote products 23 | derived from this software without specific prior written permission. 24 | 25 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 26 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 27 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 28 | DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY 29 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 30 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 31 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 32 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 33 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 34 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35 | 36 | */ 37 | 38 | #include "../config.h" 39 | #include "kmain.h" 40 | #include "lib.h" 41 | #include "io.h" 42 | #include "interrupts.h" 43 | #include "paging.h" 44 | #include "acpi.h" 45 | #include "apic.h" 46 | #include "pci.h" 47 | #include "ahci.h" 48 | #if DEBUG == 1 49 | #include "debug_print.h" 50 | #endif 51 | 52 | /** 53 | * Kernel entry point 54 | */ 55 | void kmain(){ 56 | 57 | #if DEBUG == 1 58 | // Clear the screen 59 | debug_clear(DC_WB); 60 | // Show something on the screen 61 | debug_print(DC_WB, "Long mode"); 62 | #endif 63 | 64 | // Initialize paging (well, actually re-initialize) 65 | page_init(); 66 | // Initialize interrupts 67 | interrupt_init(); 68 | 69 | #if DEBUG == 1 70 | // Show memory ammount 71 | debug_print(DC_WB, "RAM Total: %dMB", page_total_mem() / 1024 / 1024); 72 | debug_print(DC_WB, "RAM Avail: %dMB", page_available_mem() / 1024 / 1024); 73 | #endif 74 | 75 | // Initialize ACPI 76 | if (acpi_init()){ 77 | #if DEBUG == 1 78 | //acpi_list(); 79 | #endif 80 | // Initialize APIC 81 | apic_init(); 82 | // Initialize PCI 83 | pci_init(); 84 | #if DEBUG == 1 85 | //pci_list(); 86 | debug_clear(DC_WB); 87 | #endif 88 | // Initialize AHCI 89 | if (ahci_init()){ 90 | 91 | } 92 | } 93 | 94 | // Test interrupt exceptions 95 | // division by zero: 96 | //uint32 a = 1; 97 | //uint32 b = 0; 98 | //uint32 c = a / b; 99 | // page fault: 100 | //char *xyz = (char *)0xFFFFFFFF; 101 | //*xyz = 'A'; 102 | 103 | // Infinite loop 104 | while(true){} 105 | } 106 | -------------------------------------------------------------------------------- /bbp/kernel/kmain.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Kernel entry point 4 | ================== 5 | 6 | This is where the fun part begins 7 | 8 | License (BSD-3) 9 | =============== 10 | 11 | Copyright (c) 2012, Gusts 'gusC' Kaksis 12 | All rights reserved. 13 | 14 | Redistribution and use in source and binary forms, with or without 15 | modification, are permitted provided that the following conditions are met: 16 | * Redistributions of source code must retain the above copyright 17 | notice, this list of conditions and the following disclaimer. 18 | * Redistributions in binary form must reproduce the above copyright 19 | notice, this list of conditions and the following disclaimer in the 20 | documentation and/or other materials provided with the distribution. 21 | * Neither the name of the nor the 22 | names of its contributors may be used to endorse or promote products 23 | derived from this software without specific prior written permission. 24 | 25 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 26 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 27 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 28 | DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY 29 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 30 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 31 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 32 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 33 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 34 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35 | 36 | */ 37 | 38 | #ifndef __kmain_h 39 | #define __kmain_h 40 | 41 | #include "common.h" 42 | 43 | #endif /* __kmain_h */ 44 | -------------------------------------------------------------------------------- /bbp/kernel/lib.c: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Tiny helper function library 4 | ============================ 5 | 6 | TOC: 7 | * Memory manipulation functions 8 | * Character string functions 9 | 10 | License (BSD-3) 11 | =============== 12 | 13 | Copyright (c) 2012, Gusts 'gusC' Kaksis 14 | All rights reserved. 15 | 16 | Redistribution and use in source and binary forms, with or without 17 | modification, are permitted provided that the following conditions are met: 18 | * Redistributions of source code must retain the above copyright 19 | notice, this list of conditions and the following disclaimer. 20 | * Redistributions in binary form must reproduce the above copyright 21 | notice, this list of conditions and the following disclaimer in the 22 | documentation and/or other materials provided with the distribution. 23 | * Neither the name of the nor the 24 | names of its contributors may be used to endorse or promote products 25 | derived from this software without specific prior written permission. 26 | 27 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 28 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 29 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 30 | DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY 31 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 32 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 33 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 34 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 35 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 36 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 37 | 38 | */ 39 | 40 | #include "lib.h" 41 | #include "common.h" 42 | 43 | // 44 | // Memory manipulation functions 45 | // 46 | 47 | void mem_copy(uint8 *dest, uint64 len, const uint8 *src){ 48 | // Fast copy 49 | asm volatile ("rep\n\tmovsb" : : "c"(len), "S"(src), "D"(dest)); 50 | } 51 | void mem_fill(uint8 *dest, uint64 len, uint8 val){ 52 | // Fast fill 53 | asm volatile ("rep\n\tstosb" : : "c"(len), "a"(val), "D"(dest)); 54 | } 55 | bool mem_compare(const uint8 *buff1, const uint8 *buff2, uint64 len){ 56 | while (len--){ 57 | if (*(buff1++) != *(buff2++)){ 58 | return false; 59 | } 60 | } 61 | return true; 62 | } 63 | 64 | // 65 | // String functions 66 | // 67 | 68 | #define MAX_INT_STR 32 69 | 70 | uint64 str_copy(char *dest, uint64 len, const char *src){ 71 | char *sp = (char *)src; 72 | char *dp = (char *)dest; 73 | uint64 s = 0; 74 | while (*sp != 0 && len != 0){ 75 | // Copy till the end of source or destination has been reached 76 | *(dp++) = *(sp++); 77 | len --; 78 | s ++; 79 | } 80 | return s; 81 | } 82 | uint64 str_length(const char *str){ 83 | uint64 len = 0; 84 | while (*(str++) != 0){ 85 | // Increment till the end of string 86 | len ++; 87 | } 88 | return len; 89 | } 90 | int64 str_char_idx(const char *haystack, const char needle, uint64 offset){ 91 | int64 idx = 0; 92 | // Move offset 93 | while (offset--){ 94 | if (*(haystack++) == 0){ 95 | // End of the string 96 | return -1; 97 | } 98 | } 99 | while (*haystack != 0){ 100 | if (*haystack == needle){ 101 | // Found an occurence 102 | return idx; 103 | } 104 | idx++; 105 | haystack++; 106 | } 107 | return -1; 108 | } 109 | uint64 int_to_str(char *dest, uint64 len, int64 val, int64 base){ 110 | static char tmp[MAX_INT_STR + 1]; 111 | mem_fill((uint8 *)tmp, MAX_INT_STR + 1, 0); 112 | char *b = (char *)tmp + MAX_INT_STR; 113 | char c = 0; 114 | if (val >= 0){ 115 | // Process positive value 116 | do { 117 | c = (char)(val % base); 118 | if (c > 9){ 119 | *--b = 'A' + (c - 10); 120 | } else { 121 | *--b = '0' + c; 122 | } 123 | val /= base; 124 | } while (val != 0); 125 | } else if (val < 0){ 126 | // Process negative value 127 | do { 128 | c = (char)(val % base); 129 | if (c < -9){ 130 | *--b = 'A' - (c + 10); 131 | } else { 132 | *--b = '0' - c; 133 | } 134 | val /= base; 135 | } while (val != 0); 136 | // Add minus sign only for decimals 137 | if (base == 10){ 138 | *--b = '-'; 139 | } 140 | } 141 | // Copy the result and return number of digits processed 142 | return str_copy(dest, len, b); 143 | } 144 | int64 str_to_int(const char *str, int64 base){ 145 | char *b = (char *)str; 146 | int64 val = 0; 147 | uint8 negative = 0; 148 | // Trim leading spaces 149 | while (*b == 0x20 || *b == 0x09){ // space || tab 150 | b++; 151 | } 152 | // Check if a negative number 153 | if (*b == '-'){ 154 | negative = 1; 155 | } 156 | // Calculate integer value 157 | while (*b >= 0x30 && *b <= 0x39){ // >= 0 && <= 9 (as in ascii 0, 1, ..., 9) 158 | val *= 10; // multiply upwwards 159 | val += (*b) - 0x30; // add current digit 160 | b ++; 161 | } 162 | // Set minus sign if necessary 163 | if (negative){ 164 | return 0 - val; 165 | } 166 | return val; 167 | } 168 | uint64 str_write_f(char *dest, uint64 len, const char *format, ...){ 169 | va_list args; 170 | va_start(args, format); 171 | uint64 ret = __write_f(dest, len, format, args); 172 | va_end(args); 173 | return ret; 174 | } 175 | uint64 str_read_f(const char *src, const char *format, ...){ 176 | va_list args; 177 | va_start(args, format); 178 | uint64 ret = __read_f(src, format, args); 179 | va_end(args); 180 | return ret; 181 | } 182 | 183 | 184 | // 185 | // Private functions 186 | // 187 | 188 | uint64 __write_f(char *dest, uint64 len, const char *format, va_list args){ 189 | char *f = (char *)format; 190 | char *d = (char *)dest; 191 | uint64 ret = 0; 192 | 193 | // Temporary value variables 194 | uint64 val_len; 195 | int64 val_int64; 196 | uint64 val_uint64; 197 | char val_char; 198 | char *val_str; 199 | 200 | while (*f && ret < len){ 201 | if (*f == '%'){ // possible specifier 202 | switch (*(f + 1)){ 203 | case 'd': // integer 204 | val_int64 = va_arg(args, int64); 205 | val_len = int_to_str(d, MAX_INT_STR, val_int64, 10); 206 | d += val_len; 207 | ret += val_len; 208 | f ++; 209 | break; 210 | case 'u': // unsigned integer 211 | val_uint64 = va_arg(args, uint64); 212 | val_len = int_to_str(d, MAX_INT_STR, val_uint64, 10); 213 | d += val_len; 214 | ret += val_len; 215 | f ++; 216 | break; 217 | case 'x': // unsigned integer in hex 218 | val_uint64 = va_arg(args, uint64); 219 | val_len = int_to_str(d, MAX_INT_STR, val_uint64, 16); 220 | d += val_len; 221 | ret += val_len; 222 | f ++; 223 | break; 224 | case 'b': // unsigned integer in binary 225 | val_uint64 = va_arg(args, uint64); 226 | val_len = int_to_str(d, MAX_INT_STR, val_uint64, 2); 227 | d += val_len; 228 | ret += val_len; 229 | f ++; 230 | break; 231 | case 'c': // char 232 | val_char = (char)va_arg(args, int64); // chars are promoted to int in va_list 233 | *(d++) = val_char; 234 | ret ++; 235 | f ++; 236 | break; 237 | case 's': // string 238 | val_str = (char *)va_arg(args, uint64); 239 | while (*val_str){ 240 | *(d ++) = *(val_str ++); 241 | ret ++; 242 | } 243 | f ++; 244 | break; 245 | default: // not a specifier 246 | *(d ++) = *f; 247 | ret ++; 248 | break; 249 | } 250 | f ++; 251 | } else { // copy string 252 | *(d ++) = *(f ++); 253 | ret ++; 254 | } 255 | } 256 | return ret; 257 | } 258 | uint64 __read_f(const char *src, const char *format, va_list args){ 259 | 260 | return 0; 261 | } -------------------------------------------------------------------------------- /bbp/kernel/lib.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Tiny helper function library 4 | ============================ 5 | 6 | TOC: 7 | * Memory manipulation functions 8 | * Character string functions 9 | 10 | Function argument order explanation. Basically it should sound like this: 11 | "Fill this bucket for that many items of that other bucket", thus it's like 12 | the Intel ASM syntax of "instruction destination, source" whith an extra size 13 | specifier, so to prevent buffer overflows etc. 14 | 15 | License (BSD-3) 16 | =============== 17 | 18 | Copyright (c) 2012, Gusts 'gusC' Kaksis 19 | All rights reserved. 20 | 21 | Redistribution and use in source and binary forms, with or without 22 | modification, are permitted provided that the following conditions are met: 23 | * Redistributions of source code must retain the above copyright 24 | notice, this list of conditions and the following disclaimer. 25 | * Redistributions in binary form must reproduce the above copyright 26 | notice, this list of conditions and the following disclaimer in the 27 | documentation and/or other materials provided with the distribution. 28 | * Neither the name of the nor the 29 | names of its contributors may be used to endorse or promote products 30 | derived from this software without specific prior written permission. 31 | 32 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 33 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 34 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 35 | DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY 36 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 37 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 38 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 39 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 40 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 41 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 42 | 43 | */ 44 | 45 | #ifndef __lib_h 46 | #define __lib_h 47 | 48 | #include "common.h" 49 | 50 | #define INT_BASE_BIN 2 51 | #define INT_BASE_OCT 8 52 | #define INT_BASE_DEC 10 53 | #define INT_BASE_HEX 16 54 | 55 | // 56 | // Memory manipulation functions 57 | // 58 | 59 | /** 60 | * Copy data from one memory location to another 61 | * @param [out] dest - destination memory 62 | * @param [in] src - source memory 63 | * @param len - number of bytes to copy 64 | * @return void 65 | */ 66 | void mem_copy(uint8 *dest, uint64 len, const uint8 *src); 67 | /** 68 | * Fill a memory buffer with a single byte value 69 | * @param [out] dest - destination memory 70 | * @param [in] val - value to set 71 | * @param len - number of bytes to set 72 | * @return void 73 | */ 74 | void mem_fill(uint8 *dest, uint64 len, uint8 val); 75 | /** 76 | * Compare two memory regions 77 | * @param [in] buff1 78 | * @param [in] buff2 79 | * @param len - comparison length 80 | * @return true if they are equal, false if not 81 | */ 82 | bool mem_compare(const uint8 *buff1, const uint8 *buff2, uint64 len); 83 | 84 | // 85 | // String functions 86 | // 87 | 88 | /** 89 | * Copy a string from one buffer to another 90 | * @param [out] dest - destination buffer 91 | * @param len - destination buffer length 92 | * @param [in] src - source buffer 93 | * @return number of characters copied 94 | */ 95 | uint64 str_copy(char *dest, uint64 len, const char *src); 96 | /** 97 | * Calculate the length of a string 98 | * @param [in] str - string 99 | * @return string length 100 | */ 101 | uint64 str_length(const char *str); 102 | /** 103 | * Search for a character in a string 104 | * @param [in] haystack - source buffer 105 | * @param needle - character to find 106 | * @param offset - number of characters to offset from the beginning of haystack 107 | * @return character index (-1 if not found) 108 | */ 109 | int64 str_char_idx(const char *haystack, const char needle, uint64 offset); 110 | /** 111 | * Convert integer to string 112 | * @param [out] dest - destination buffer 113 | * @param len - destination buffer length 114 | * @param in - input integer 115 | * @param base - the base of the integer represented by the string (8, 10 or 16) 116 | * @return number of characters in a string representation 117 | */ 118 | uint64 int_to_str(char *dest, uint64 len, int64 val, int64 base); 119 | /** 120 | * Convert a string to integer 121 | * @param [in] str - integer string 122 | * @param base - the base of the integer represented by the string (8, 10 or 16) 123 | * @return output integer 124 | */ 125 | int64 str_to_int(const char *str, int64 base); 126 | /** 127 | * Build a formated string from a format and additional parameters 128 | * @param [out] dest - destination string pointer 129 | * @param len - maximum length allowed to fill 130 | * @param [in] format - standard C printf format string 131 | * @param [in] ... - additional arguments 132 | * @return number of characters written 133 | */ 134 | uint64 str_write_f(char *dest, uint64 len, const char *format, ...); 135 | /** 136 | * Parse a formated string using a format and store results in additional parameters 137 | * @param [in] src - source string pointer 138 | * @param [in] format - standard C printf format string 139 | * @param [out] ... - additional argument pointers 140 | * @return number of arguments parsed 141 | */ 142 | uint64 str_read_f(const char *src, const char *format, ...); 143 | 144 | // 145 | // Private functions 146 | // 147 | 148 | uint64 __write_f(char *dest, uint64 len, const char *format, va_list args); 149 | uint64 __read_f(const char *src, const char *format, va_list args); 150 | 151 | 152 | #endif /* __lib_h */ -------------------------------------------------------------------------------- /bbp/kernel/makefile: -------------------------------------------------------------------------------- 1 | AS = nasm -felf64 2 | CC = x86_64-pc-elf-gcc -nostdlib -fno-builtin -nostartfiles -nodefaultlibs 3 | LD = x86_64-pc-elf-ld -i 4 | OBJECTS = lib.c.o interrupts.s.o interrupts.c.o apic.c.o acpi.c.o debug_print.c.o paging.c.o pci.c.o ahci.c.o kmain.c.o 5 | 6 | all: kernel.o 7 | 8 | kernel.o: $(OBJECTS) 9 | $(LD) -T kernel.ld $(OBJECTS) -o ../kernel.o 10 | 11 | %.s.o: %.asm 12 | $(AS) -o $@ $< 13 | 14 | %.c.o: %.c 15 | $(CC) -c $< -o $@ 16 | 17 | clean: 18 | rm -f *.o -------------------------------------------------------------------------------- /bbp/kernel/msr.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Helper functions for Model Specific Register (MSR) operations 4 | ============================================================= 5 | 6 | This file also contains some notable MSR values defined as macros 7 | 8 | License (BSD-3) 9 | =============== 10 | 11 | Copyright (c) 2012, Gusts 'gusC' Kaksis 12 | All rights reserved. 13 | 14 | Redistribution and use in source and binary forms, with or without 15 | modification, are permitted provided that the following conditions are met: 16 | * Redistributions of source code must retain the above copyright 17 | notice, this list of conditions and the following disclaimer. 18 | * Redistributions in binary form must reproduce the above copyright 19 | notice, this list of conditions and the following disclaimer in the 20 | documentation and/or other materials provided with the distribution. 21 | * Neither the name of the nor the 22 | names of its contributors may be used to endorse or promote products 23 | derived from this software without specific prior written permission. 24 | 25 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 26 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 27 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 28 | DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY 29 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 30 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 31 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 32 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 33 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 34 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35 | 36 | */ 37 | 38 | #ifndef __msr_h 39 | #define __msr_h 40 | 41 | #include "common.h" 42 | 43 | // 44 | // MSR macros (Core2+) 45 | // 46 | 47 | #define MSR_IA32_P5_MC_ADDR 0x0 48 | #define MSR_IA32_P5_MC_TYPE 0x1 49 | #define MSR_IA32_APIC_BASE 0x1B 50 | #define MSR_IA32_FEATURE_CONTROL 0x3A 51 | #define MSR_BBL_CR_CTL3 0x11E 52 | #define MSR_IA32_SYSENTER_CS 0x174 53 | #define MSR_IA32_SYSENTER_ESP 0x175 54 | #define MSR_IA32_SYSENTER_EIP 0x176 55 | #define MSR_IA32_MISC_ENABLE 0x1A0 56 | #define MSR_IA32_X2APIC_APICID 0x802 57 | #define MSR_IA32_X2APIC_VERSION 0x803 58 | #define MSR_IA32_X2APIC_TPR 0x808 59 | #define MSR_IA32_X2APIC_PPR 0x80A 60 | #define MSR_IA32_X2APIC_EOI 0x80B 61 | #define MSR_IA32_X2APIC_LDR 0x80D 62 | #define MSR_IA32_X2APIC_SIVR 0x80F 63 | #define MSR_IA32_X2APIC_ISR0 0x810 64 | #define MSR_IA32_X2APIC_ISR1 0x811 65 | #define MSR_IA32_X2APIC_ISR2 0x812 66 | #define MSR_IA32_X2APIC_ISR3 0x813 67 | #define MSR_IA32_X2APIC_ISR4 0x814 68 | #define MSR_IA32_X2APIC_ISR5 0x815 69 | #define MSR_IA32_X2APIC_ISR6 0x816 70 | #define MSR_IA32_X2APIC_ISR7 0x817 71 | #define MSR_IA32_X2APIC_TMR0 0x818 72 | #define MSR_IA32_X2APIC_TMR1 0x819 73 | #define MSR_IA32_X2APIC_TMR2 0x81A 74 | #define MSR_IA32_X2APIC_TMR3 0x81B 75 | #define MSR_IA32_X2APIC_TMR4 0x81C 76 | #define MSR_IA32_X2APIC_TMR5 0x81D 77 | #define MSR_IA32_X2APIC_TMR6 0x81E 78 | #define MSR_IA32_X2APIC_TMR7 0x81F 79 | #define MSR_IA32_X2APIC_IRR0 0x820 80 | #define MSR_IA32_X2APIC_IRR1 0x821 81 | #define MSR_IA32_X2APIC_IRR2 0x822 82 | #define MSR_IA32_X2APIC_IRR3 0x823 83 | #define MSR_IA32_X2APIC_IRR4 0x824 84 | #define MSR_IA32_X2APIC_IRR5 0x825 85 | #define MSR_IA32_X2APIC_IRR6 0x826 86 | #define MSR_IA32_X2APIC_IRR7 0x827 87 | #define MSR_IA32_X2APIC_ESR 0x828 88 | #define MSR_IA32_X2APIC_LVT_CMCI 0x82F 89 | #define MSR_IA32_X2APIC_ICR 0x830 90 | #define MSR_IA32_X2APIC_LVT_TIMER 0x832 91 | #define MSR_IA32_X2APIC_LVT_THERMAL 0x833 92 | #define MSR_IA32_X2APIC_LVT_PMI 0x834 93 | #define MSR_IA32_X2APIC_LVT_LINT0 0x835 94 | #define MSR_IA32_X2APIC_LVT_LINT1 0x836 95 | #define MSR_IA32_X2APIC_LVT_ERROR 0x837 96 | #define MSR_IA32_X2APIC_INIT_COUNT 0x838 97 | #define MSR_IA32_X2APIC_CUR_COUNT 0x839 98 | #define MSR_IA32_X2APIC_DIV_CONF 0x83E 99 | #define MSR_IA32_X2APIC_SELF_IPI 0x83F 100 | #define MSR_IA32_EFER 0xC0000080 101 | #define MSR_IA32_STAR 0xC0000081 102 | #define MSR_IA32_FMASK 0xC0000084 103 | #define MSR_IA32_FS_BASE 0xC0000100 104 | #define MSR_IA32_GS_BASE 0xC0000101 105 | #define MSR_IA32_KERNEL_GS_BASE 0xC0000102 106 | 107 | /** 108 | * Read MSR value 109 | * @param msr - Model Specific Register 110 | * @param [out] val - pointer to memory location where to write MSR value 111 | * @return void 112 | */ 113 | static void msr_read(uint32 msr, uint64 *val){ 114 | split_uint64_t *v = (split_uint64_t *)val; 115 | asm volatile("rdmsr" : "=a"(v->low), "=d"(v->high) : "c"(msr)); 116 | } 117 | /** 118 | * Write MSR value 119 | * @param msr - Model Specific Register 120 | * @param [in] val - value to write into MSR 121 | * @return void 122 | */ 123 | static void msr_write(uint32 msr, uint64 val){ 124 | split_uint64_t *v = (split_uint64_t *)&val; 125 | asm volatile("wrmsr" : : "a"(v->low), "d"(v->high), "c"(msr)); 126 | } 127 | 128 | #endif 129 | -------------------------------------------------------------------------------- /bbp/kernel/paging.c: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Memory paging functions 4 | ======================= 5 | 6 | License (BSD-3) 7 | =============== 8 | 9 | Copyright (c) 2012, Gusts 'gusC' Kaksis 10 | All rights reserved. 11 | 12 | Redistribution and use in source and binary forms, with or without 13 | modification, are permitted provided that the following conditions are met: 14 | * Redistributions of source code must retain the above copyright 15 | notice, this list of conditions and the following disclaimer. 16 | * Redistributions in binary form must reproduce the above copyright 17 | notice, this list of conditions and the following disclaimer in the 18 | documentation and/or other materials provided with the distribution. 19 | * Neither the name of the nor the 20 | names of its contributors may be used to endorse or promote products 21 | derived from this software without specific prior written permission. 22 | 23 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 24 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 25 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 26 | DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY 27 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 28 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 29 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 30 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 31 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 32 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 | 34 | */ 35 | 36 | #include "../config.h" 37 | #include "paging.h" 38 | #include "lib.h" 39 | #if DEBUG == 1 40 | #include "debug_print.h" 41 | #endif 42 | 43 | /** 44 | * Memory type codes for E820 45 | */ 46 | enum eMemType { 47 | kMemOk = 1, // Normal memory - usable 48 | kMemReserved, // Reserved memory - unusable 49 | kMemACPIReclaim, // ACPI reclaimable memory - might be usable after ACPI is taken care of 50 | kMemACPI, // ACPI NVS memory - unusable 51 | kMemBad // Bad memory - unsuable 52 | }; 53 | /** 54 | * E820 memory map entry structure 55 | */ 56 | struct e820entry_struct { 57 | uint16 entry_size; // if 24, then it has attributes 58 | uint64 base; 59 | uint64 length; 60 | uint32 type; 61 | uint32 attributes; // ACPI 3.0 only 62 | } __PACKED; 63 | typedef struct e820entry_struct e820entry_t; 64 | /** 65 | * E820 memory map structure 66 | */ 67 | struct e820map_struct { 68 | uint16 size; 69 | e820entry_t entries[]; 70 | } __PACKED; 71 | typedef struct e820map_struct e820map_t; 72 | 73 | /** 74 | * Page table structures 75 | */ 76 | static pm_t *_pml4 = (pm_t *)PT_LOC; 77 | static uint64 _page_offset = PT_LOC; 78 | 79 | static uint64 _total_mem = 0; 80 | static uint64 _available_mem = 0; 81 | 82 | static uint64 *_page_frames; 83 | static uint64 _page_count = 0; 84 | 85 | // Get bitset index 86 | #define BIT_INDEX(b) (b / 64) 87 | // Get bit offset in bitset 88 | #define BIT_OFFSET(b) (b % 64) 89 | 90 | /** 91 | * Mark frame allocated 92 | * @param paddr - physical address to mark 93 | */ 94 | static void page_set_frame(uint64 paddr){ 95 | uint64 page = paddr / 4069; 96 | uint64 idx = BIT_INDEX(page); 97 | uint64 offset = BIT_OFFSET(page); 98 | _page_frames[idx] |= (0x1 << offset); 99 | } 100 | /** 101 | * Mark frame free 102 | * @param paddr - physical address to mark 103 | */ 104 | static void page_clear_frame(uint64 paddr){ 105 | uint64 page = paddr / 4069; 106 | uint64 idx = BIT_INDEX(page); 107 | uint64 offset = BIT_OFFSET(page); 108 | _page_frames[idx] &= ~(0x1 << offset); 109 | } 110 | /** 111 | * Check if frame is allocated or free 112 | * @param paddr - physical address to check 113 | * @return true if set false if not 114 | */ 115 | static bool page_check_frame(uint64 paddr){ 116 | uint64 page = paddr / 4069; 117 | uint64 idx = BIT_INDEX(page); 118 | uint64 offset = BIT_OFFSET(page); 119 | return (_page_frames[idx] & (0x1 << offset)); 120 | } 121 | 122 | /** 123 | * Sort memory map in ascending order 124 | */ 125 | static void sort_e820(e820map_t *mem_map){ 126 | uint64 i = 0; 127 | // Do the bubble sort to make them in ascending order 128 | e820entry_t e; 129 | uint64 swapped = 1; 130 | uint64 count = mem_map->size; 131 | while (count > 0 && swapped ){ 132 | i = 0; 133 | swapped = 0; 134 | while (i < count - 1){ 135 | if (mem_map->entries[i].base > mem_map->entries[i + 1].base){ 136 | e = mem_map->entries[i]; 137 | mem_map->entries[i] = mem_map->entries[i + 1]; 138 | mem_map->entries[i + 1] = e; 139 | swapped = 1; 140 | } 141 | i ++; 142 | } 143 | count --; 144 | } 145 | // Get total RAM 146 | for (i = 0; i < mem_map->size; i ++){ 147 | #if DEBUG == 1 148 | //debug_print(DC_WB, "%x -> %x (%d)", mem_map->entries[i].base, mem_map->entries[i].base + mem_map->entries[i].length, mem_map->entries[i].type); 149 | #endif 150 | if (mem_map->entries[i].type != kMemReserved){ 151 | if (mem_map->entries[i].base + mem_map->entries[i].length > _total_mem){ 152 | _total_mem = mem_map->entries[i].base + mem_map->entries[i].length; 153 | } 154 | if (mem_map->entries[i].type == kMemOk){ 155 | _available_mem += mem_map->entries[i].length; 156 | } 157 | } 158 | } 159 | } 160 | 161 | void page_init(){ 162 | // Read E820 memory map and mark used regions 163 | e820map_t *mem_map = (e820map_t *)E820_LOC; 164 | // Sort memory map 165 | sort_e820(mem_map); 166 | 167 | // Single page (PML1 entry) holds 4KB of RAM 168 | uint64 page_count = INIT_MEM / PAGE_SIZE; 169 | if (INIT_MEM % PAGE_SIZE > 0){ 170 | page_count ++; 171 | } 172 | // Single table (PML2 entry) holds 2MB of RAM 173 | uint64 table_count = page_count / 512; 174 | if (page_count % 512 > 0){ 175 | table_count ++; 176 | } 177 | // Single directory (PML3 entry, directory table pointer) holds 1GB of RAM 178 | uint64 directory_count = table_count / 512; 179 | if (table_count % 512 > 0){ 180 | directory_count ++; 181 | } 182 | // Single drawer (PML4 entry) holds 512GB of RAM 183 | uint64 drawer_count = directory_count / 512; 184 | if (directory_count % 512 > 0){ 185 | drawer_count ++; 186 | } 187 | 188 | // Determine the end of PMLx structures to add new ones 189 | _page_offset += (sizeof(pm_t) * 512) * (1 + drawer_count + directory_count + table_count); 190 | // Calculate total frame count 191 | _page_count = _total_mem / PAGE_SIZE; 192 | // Allocate frame bitset at the next page boundary 193 | _page_frames = (uint64 *)_page_offset; 194 | // Clear bitset 195 | mem_fill((uint8 *)_page_count, _page_count / 8, 0); 196 | // Move offset further 197 | _page_offset += (_page_count / 8); 198 | // Align the offset 199 | if ((_page_offset & PAGE_MASK) != _page_offset){ 200 | _page_offset &= PAGE_MASK; 201 | _page_offset += PAGE_SIZE; 202 | } 203 | 204 | #if DEBUG == 1 205 | debug_print(DC_WB, "Frames: %d", _page_count); 206 | #endif 207 | 208 | // Determine unsuable memory regions 209 | uint64 i; 210 | uint64 paddr_from; 211 | uint64 paddr_to; 212 | for (i = 0; i < mem_map->size; i ++){ 213 | if (mem_map->entries[i].type != kMemOk){ 214 | // Mark all unusable regions used 215 | paddr_from = (mem_map->entries[i].base & PAGE_MASK); 216 | paddr_to = ((mem_map->entries[i].base + mem_map->entries[i].length) & PAGE_MASK); 217 | while (paddr_from < paddr_to){ 218 | page_set_frame(paddr_from); 219 | paddr_from += PAGE_SIZE; 220 | } 221 | } 222 | } 223 | } 224 | uint64 page_total_mem(){ 225 | return _total_mem; 226 | } 227 | uint64 page_available_mem(){ 228 | return _available_mem; 229 | } 230 | uint64 page_normalize_vaddr(uint64 vaddr){ 231 | vaddr_t va; 232 | va.raw = vaddr; 233 | if ((va.s.drawer_idx & 0x100) != 0){ 234 | va.s.canonical = 0xFFFF; 235 | } else { 236 | va.s.canonical = 0x0000; 237 | } 238 | return va.raw; 239 | } 240 | uint64 page_map(uint64 paddr){ 241 | // Do the identity map 242 | vaddr_t va; 243 | pm_t *pml3; 244 | pm_t *pml2; 245 | pm_t *pml1; 246 | va.raw = page_normalize_vaddr(paddr); 247 | if (!_pml4[va.s.drawer_idx].s.present){ 248 | page_set_frame(_page_offset); 249 | pml3 = (pm_t *)_page_offset; 250 | mem_fill((uint8 *)pml3, sizeof(pm_t) * 512, 0); 251 | _pml4[va.s.drawer_idx].raw = (uint64)pml3; 252 | _pml4[va.s.drawer_idx].s.present = 1; 253 | _pml4[va.s.drawer_idx].s.writable = 1; 254 | //_pml4[va.s.drawer_idx].s.write_through = 1; 255 | //_pml4[va.s.drawer_idx].s.cache_disable = 1; 256 | _page_offset += (sizeof(pm_t) * 512); 257 | } 258 | pml3 = (pm_t *)(_pml4[va.s.drawer_idx].raw & PAGE_MASK); 259 | if (!pml3[va.s.directory_idx].s.present){ 260 | page_set_frame(_page_offset); 261 | pml2 = (pm_t *)_page_offset; 262 | mem_fill((uint8 *)pml2, sizeof(pm_t) * 512, 0); 263 | pml3[va.s.directory_idx].raw = (uint64)pml2; 264 | pml3[va.s.directory_idx].s.present = 1; 265 | pml3[va.s.directory_idx].s.writable = 1; 266 | //pml3[va.s.directory_idx].s.write_through = 1; 267 | //pml3[va.s.directory_idx].s.cache_disable = 1; 268 | _page_offset += (sizeof(pm_t) * 512); 269 | } 270 | pml2 = (pm_t *)(pml3[va.s.directory_idx].raw & PAGE_MASK); 271 | if (!pml2[va.s.table_idx].s.present){ 272 | page_set_frame(_page_offset); 273 | pml1 = (pm_t *)_page_offset; 274 | mem_fill((uint8 *)pml1, sizeof(pm_t) * 512, 0); 275 | pml2[va.s.table_idx].raw = (uint64)pml1; 276 | pml2[va.s.table_idx].s.present = 1; 277 | pml2[va.s.table_idx].s.writable = 1; 278 | //pml2[va.s.table_idx].s.write_through = 1; 279 | //pml2[va.s.table_idx].s.cache_disable = 1; 280 | _page_offset += (sizeof(pm_t) * 512); 281 | } 282 | pml1 = (pm_t *)(pml2[va.s.table_idx].raw & PAGE_MASK); 283 | if (!pml1[va.s.page_idx].s.present){ 284 | pml1[va.s.page_idx].raw = (paddr & PAGE_MASK); 285 | pml1[va.s.page_idx].s.present = 1; 286 | pml1[va.s.page_idx].s.writable = 1; 287 | //pml1[va.s.page_idx].s.write_through = 1; 288 | //pml1[va.s.page_idx].s.cache_disable = 1; 289 | } 290 | return va.raw; 291 | } 292 | uint64 page_map_mmio(uint64 paddr){ 293 | // Do the identity map 294 | vaddr_t va; 295 | pm_t *pml3; 296 | pm_t *pml2; 297 | pm_t *pml1; 298 | va.raw = page_normalize_vaddr(paddr); 299 | if (!_pml4[va.s.drawer_idx].s.present){ 300 | page_set_frame(_page_offset); 301 | pml3 = (pm_t *)_page_offset; 302 | mem_fill((uint8 *)pml3, sizeof(pm_t) * 512, 0); 303 | _pml4[va.s.drawer_idx].raw = (uint64)pml3; 304 | _pml4[va.s.drawer_idx].s.present = 1; 305 | _pml4[va.s.drawer_idx].s.writable = 1; 306 | _pml4[va.s.drawer_idx].s.write_through = 1; 307 | _pml4[va.s.drawer_idx].s.cache_disable = 1; 308 | _page_offset += (sizeof(pm_t) * 512); 309 | } 310 | pml3 = (pm_t *)(_pml4[va.s.drawer_idx].raw & PAGE_MASK); 311 | if (!pml3[va.s.directory_idx].s.present){ 312 | page_set_frame(_page_offset); 313 | pml2 = (pm_t *)_page_offset; 314 | mem_fill((uint8 *)pml2, sizeof(pm_t) * 512, 0); 315 | pml3[va.s.directory_idx].raw = (uint64)pml2; 316 | pml3[va.s.directory_idx].s.present = 1; 317 | pml3[va.s.directory_idx].s.writable = 1; 318 | pml3[va.s.directory_idx].s.write_through = 1; 319 | pml3[va.s.directory_idx].s.cache_disable = 1; 320 | _page_offset += (sizeof(pm_t) * 512); 321 | } 322 | pml2 = (pm_t *)(pml3[va.s.directory_idx].raw & PAGE_MASK); 323 | if (!pml2[va.s.table_idx].s.present){ 324 | page_set_frame(_page_offset); 325 | pml1 = (pm_t *)_page_offset; 326 | mem_fill((uint8 *)pml1, sizeof(pm_t) * 512, 0); 327 | pml2[va.s.table_idx].raw = (uint64)pml1; 328 | pml2[va.s.table_idx].s.present = 1; 329 | pml2[va.s.table_idx].s.writable = 1; 330 | pml2[va.s.table_idx].s.write_through = 1; 331 | pml2[va.s.table_idx].s.cache_disable = 1; 332 | _page_offset += (sizeof(pm_t) * 512); 333 | } 334 | pml1 = (pm_t *)(pml2[va.s.table_idx].raw & PAGE_MASK); 335 | if (!pml1[va.s.page_idx].s.present){ 336 | pml1[va.s.page_idx].raw = (paddr & PAGE_MASK); 337 | pml1[va.s.page_idx].s.present = 1; 338 | pml1[va.s.page_idx].s.writable = 1; 339 | pml1[va.s.page_idx].s.write_through = 1; 340 | pml1[va.s.page_idx].s.cache_disable = 1; 341 | } 342 | return va.raw; 343 | } 344 | uint64 page_resolve(uint64 vaddr){ 345 | vaddr_t va; 346 | uint64 paddr = 0; 347 | pm_t *table; 348 | va.raw = vaddr; 349 | if (_pml4[va.s.drawer_idx].s.present){ 350 | table = (pm_t *)(_pml4[va.s.drawer_idx].raw & PAGE_MASK); 351 | if (table[va.s.directory_idx].s.present){ 352 | table = (pm_t *)(table[va.s.directory_idx].raw & PAGE_MASK); 353 | if (table[va.s.table_idx].s.present){ 354 | table = (pm_t *)(table[va.s.table_idx].raw & PAGE_MASK); 355 | if (table[va.s.page_idx].s.present){ 356 | paddr = va.s.offset; // set offset 357 | paddr |= (table[va.s.page_idx].raw & PAGE_MASK); // merge page aligned address 358 | } 359 | } 360 | } 361 | } 362 | return paddr; 363 | } 364 | 365 | pm_t page_get_pml_entry(uint64 vaddr, uint8 level){ 366 | vaddr_t va; 367 | va.raw = vaddr; 368 | pm_t *table = _pml4; 369 | if (level >= 3){ 370 | return table[va.s.drawer_idx]; 371 | } 372 | table = (pm_t *)(table[va.s.drawer_idx].raw & PAGE_MASK); 373 | if (level == 2){ 374 | return table[va.s.directory_idx]; 375 | } 376 | table = (pm_t *)(table[va.s.directory_idx].raw & PAGE_MASK); 377 | if (level == 1){ 378 | return table[va.s.table_idx]; 379 | } 380 | table = (pm_t *)(table[va.s.table_idx].raw & PAGE_MASK); 381 | return table[va.s.page_idx]; 382 | } 383 | 384 | void page_set_pml_entry(uint64 vaddr, uint8 level, pm_t pe){ 385 | vaddr_t va; 386 | va.raw = page_normalize_vaddr(vaddr); 387 | pm_t *table = _pml4; 388 | if (level >= 3){ 389 | table[va.s.drawer_idx].raw = pe.raw; 390 | } 391 | table = (pm_t *)(table[va.s.drawer_idx].raw & PAGE_MASK); 392 | if (level == 2){ 393 | table[va.s.directory_idx].raw = pe.raw; 394 | } 395 | table = (pm_t *)(table[va.s.directory_idx].raw & PAGE_MASK); 396 | if (level == 1){ 397 | table[va.s.table_idx].raw = pe.raw; 398 | } 399 | table = (pm_t *)(table[va.s.table_idx].raw & PAGE_MASK); 400 | table[va.s.page_idx].raw = pe.raw; 401 | } 402 | -------------------------------------------------------------------------------- /bbp/kernel/paging.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Memory paging functions 4 | ======================= 5 | 6 | License (BSD-3) 7 | =============== 8 | 9 | Copyright (c) 2012, Gusts 'gusC' Kaksis 10 | All rights reserved. 11 | 12 | Redistribution and use in source and binary forms, with or without 13 | modification, are permitted provided that the following conditions are met: 14 | * Redistributions of source code must retain the above copyright 15 | notice, this list of conditions and the following disclaimer. 16 | * Redistributions in binary form must reproduce the above copyright 17 | notice, this list of conditions and the following disclaimer in the 18 | documentation and/or other materials provided with the distribution. 19 | * Neither the name of the nor the 20 | names of its contributors may be used to endorse or promote products 21 | derived from this software without specific prior written permission. 22 | 23 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 24 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 25 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 26 | DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY 27 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 28 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 29 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 30 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 31 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 32 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 | 34 | */ 35 | 36 | #ifndef __paging_h 37 | #define __paging_h 38 | 39 | #include "common.h" 40 | 41 | typedef union { 42 | struct { 43 | uint64 present : 1; // Is the page present in memory? 44 | uint64 writable : 1; // Is the page writable? 45 | uint64 user : 1; // Is the page for userspace? 46 | uint64 write_through : 1; // Do we want write-trough? (when cached, this also writes to memory) 47 | uint64 cache_disable : 1; // Disable cache on this page? 48 | uint64 accessed : 1; // Has the page been accessed by software? 49 | uint64 dirty : 1; // Has the page been written to since last refresh? 50 | uint64 pat : 1; // Is the page a PAT? (dunno what it is) 51 | uint64 global : 1; // Is the page global? (dunno what it is) 52 | uint64 data : 3; // Available for kernel use (do what you want?) 53 | uint64 frame : 52; // Frame address (shifted right 12 bits) 54 | } s; 55 | uint64 raw; // Raw value 56 | } pm_t; 57 | 58 | typedef union { 59 | struct { 60 | uint64 offset : 12; // Offset from the begining of page 61 | uint64 page_idx : 9; // Page index (in pml1) 62 | uint64 table_idx : 9; // Table index (in pml2) 63 | uint64 directory_idx : 9; // Directory index (in pml3) 64 | uint64 drawer_idx : 9; // Drawer index (in pml4) 65 | uint64 canonical : 16; // Should be FFF... if drawer_idx 9th bit is 1 (see: canonical address) 66 | } s; 67 | uint64 raw; 68 | } vaddr_t; 69 | 70 | #define PAGE_MASK 0xFFFFFFFFFFFFF000 71 | #define PAGE_IMASK 0x0000000000000FFF // Inverse mask 72 | 73 | /** 74 | * Initialize paging 75 | */ 76 | void page_init(); 77 | /** 78 | * Get total installed RAM 79 | * @return RAM size in bytes 80 | */ 81 | uint64 page_total_mem(); 82 | /** 83 | * Get total available RAM 84 | * @return RAM size in bytes 85 | */ 86 | uint64 page_available_mem(); 87 | /** 88 | * Normalize virtual address to canonical form 89 | * Usefull when converting from 32bit addresses to 64bit 90 | * @param vaddr - virtual address to normalize 91 | * @return normalized virtual address 92 | */ 93 | uint64 page_normalize_vaddr(uint64 vaddr); 94 | /** 95 | * Identity map a physical address 96 | * @param paddr - physical address to map 97 | * @return virtual address 98 | */ 99 | uint64 page_map(uint64 paddr); 100 | /** 101 | * Identity map a physical address for memory maped IO (no cache!) 102 | * @param paddr - physical address to map 103 | * @return virtual address 104 | */ 105 | uint64 page_map_mmio(uint64 paddr); 106 | /** 107 | * Resolve physical address from virtual addres 108 | * @param vaddr - virtual address to resolve 109 | * @return physical address 110 | */ 111 | uint64 page_resolve(uint64 vaddr); 112 | 113 | /** 114 | * Get the PMLx entry from virtual address 115 | * @param vaddr - virtual address 116 | * @param level - zero based level (0-3 for PML4 paging) 117 | * @return PMLx entry 118 | */ 119 | pm_t page_get_pml_entry(uint64 vaddr, uint8 level); 120 | /** 121 | * Set the PML4 entry for virtual address 122 | * @param vaddr - virtual address 123 | * @param level - zero based level (0-3 for PML4 paging) 124 | * @param pe - PML4 entry 125 | */ 126 | void page_set_pml_entry(uint64 vaddr, uint8 level, pm_t pe); 127 | 128 | #endif /* __paging_h */ -------------------------------------------------------------------------------- /bbp/kernel/pci.c: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Helper functions for PCI operations 4 | =================================== 5 | 6 | 7 | License (BSD-3) 8 | =============== 9 | 10 | Copyright (c) 2012, Gusts 'gusC' Kaksis 11 | All rights reserved. 12 | 13 | Redistribution and use in source and binary forms, with or without 14 | modification, are permitted provided that the following conditions are met: 15 | * Redistributions of source code must retain the above copyright 16 | notice, this list of conditions and the following disclaimer. 17 | * Redistributions in binary form must reproduce the above copyright 18 | notice, this list of conditions and the following disclaimer in the 19 | documentation and/or other materials provided with the distribution. 20 | * Neither the name of the nor the 21 | names of its contributors may be used to endorse or promote products 22 | derived from this software without specific prior written permission. 23 | 24 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 25 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 26 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 27 | DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY 28 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 29 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 30 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 31 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 32 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 33 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 | 35 | */ 36 | 37 | #include "../config.h" 38 | #include "lib.h" 39 | #include "io.h" 40 | #include "pci.h" 41 | #if DEBUG == 1 42 | #include "debug_print.h" 43 | #endif 44 | 45 | /** 46 | * Local PCI cache strucure 47 | * used to ease device lookup on run-time 48 | */ 49 | typedef struct { 50 | pci_addr_t address; 51 | uint16 vendor_id; 52 | uint16 device_id; 53 | uint8 class_id; 54 | uint8 subclass_id; 55 | uint8 prog_if; 56 | uint8 type; 57 | } pci_cache_t; 58 | 59 | /* 60 | static uint32 pci_get_addr(uint16 bus, uint8 device, uint8 function, uint8 reg){ 61 | uint32 addr = 0x80000000; 62 | addr |= ((uint32)bus) << 16; 63 | addr |= (((uint32)device) & 0x1F) << 11; 64 | addr |= (((uint32)function) & 0x7) << 8; 65 | addr |= (uint32)(reg & 0xfc); 66 | return addr; 67 | } 68 | */ 69 | 70 | // Local PCI device cache 71 | static pci_cache_t _cache[256]; 72 | static uint8 _cache_len = 0; 73 | 74 | /** 75 | * Enumerate a single PCI bus 76 | * @param bus - bus number 77 | */ 78 | static void pci_enum_bus(uint16 bus); 79 | /** 80 | * Enumerate a single PCI device on a bus 81 | * @param bus - bus number 82 | * @param device - device number 83 | */ 84 | static void pci_enum_device(uint16 bus, uint8 device); 85 | /** 86 | * Enumeration PCI device functions 87 | * @param bus - bus number 88 | * @param device - device number 89 | */ 90 | static void pci_enum_function(uint16 bus, uint8 device, uint8 function); 91 | /** 92 | * Get secondary bus number from PCI-to-PCI bridge 93 | */ 94 | static uint16 pci_get_secondary_bus(uint16 bus, uint8 device, uint8 function){ 95 | uint32 secondary_bus = 0; 96 | pci_addr_t addr; 97 | if (bus < 256 && device < 32 && function < 8){ 98 | addr.raw = 0; 99 | addr.s.enabled = 1; 100 | addr.s.bus = bus; 101 | addr.s.device = device; 102 | addr.s.function = function; 103 | addr.s.reg = 6; 104 | secondary_bus = pci_read(addr); 105 | return (uint16)((secondary_bus >> 8) & 0xFF); 106 | } 107 | return bus; 108 | } 109 | 110 | void pci_init(){ 111 | uint16 bus = 0; 112 | pci_header_t header; 113 | pci_addr_t addr; 114 | addr.raw = 0x80000000; 115 | // Recursive scan - thanks OSDev Wiki 116 | pci_get_header(&header, addr); 117 | if ((header.type & 0x80) != 0){ 118 | // Multiple PCI host controllers 119 | for (bus = 0; bus < 8; bus ++){ 120 | addr.s.bus = bus; 121 | pci_get_header(&header, addr); 122 | if (header.vendor_id != 0xFFFF){ 123 | // Valid PCI host controller 124 | pci_enum_bus(bus); 125 | } 126 | } 127 | } else { 128 | // Single PCI host controller 129 | pci_enum_bus(0); 130 | } 131 | } 132 | 133 | uint8 pci_num_device(uint8 class_id, uint8 subclass_id){ 134 | uint16 i = 0; 135 | uint8 x = 0; 136 | for (i = 0; i < _cache_len; i ++){ 137 | if (_cache[i].class_id == class_id && _cache[i].subclass_id == subclass_id){ 138 | x ++; 139 | } 140 | } 141 | return x; 142 | } 143 | 144 | pci_addr_t pci_get_device(uint8 class_id, uint8 subclass_id, uint8 idx){ 145 | uint16 i = 0; 146 | uint8 x = 0; 147 | pci_addr_t addr_none; 148 | addr_none.raw = 0; 149 | for (i = 0; i < _cache_len; i ++){ 150 | if (_cache[i].class_id == class_id && _cache[i].subclass_id == subclass_id){ 151 | if (x == idx){ 152 | return _cache[i].address; 153 | } 154 | x ++; 155 | } 156 | } 157 | return addr_none; 158 | } 159 | 160 | void pci_get_header(pci_header_t *header,pci_addr_t addr){ 161 | uint32 *rows = (uint32 *)header; 162 | uint8 row; 163 | for (row = 0; row < 4; row ++){ 164 | addr.s.reg = row; 165 | rows[row] = pci_read(addr); 166 | } 167 | } 168 | 169 | void pci_get_config(pci_device_t *device, pci_addr_t addr){ 170 | uint32 *rows = (uint32 *)device; 171 | uint8 row; 172 | for (row = 0; row < 16; row ++){ 173 | addr.s.reg = row; 174 | rows[row] = pci_read(addr); 175 | } 176 | } 177 | 178 | uint32 pci_read(pci_addr_t addr){ 179 | uint32 data; 180 | outd(PCI_CONFIG_ADDRESS, addr.raw); 181 | data = ind(PCI_CONFIG_DATA); 182 | return data; 183 | } 184 | 185 | void pci_write(pci_addr_t addr, uint32 data){ 186 | outd(PCI_CONFIG_ADDRESS, addr.raw); 187 | outd(PCI_CONFIG_DATA, data); 188 | } 189 | 190 | /*uint32 pci_read(uint32 addr){ 191 | uint32 data; 192 | asm volatile ("outl %%eax, %%dx" : : "d"(PCI_CONFIG_ADDRESS), "a"(addr)); 193 | asm volatile("inl %%dx, %%eax" : "=a"(data) : "d"(PCI_CONFIG_DATA)); 194 | return data; 195 | } 196 | 197 | void pci_write(uint32 addr, uint32 data){ 198 | asm volatile ("outl %%eax, %%dx" : : "d"(PCI_CONFIG_ADDRESS), "a"(addr)); 199 | asm volatile ("outl %%eax, %%dx" : : "d"(PCI_CONFIG_DATA), "a"(data)); 200 | }*/ 201 | 202 | static void pci_enum_bus(uint16 bus){ 203 | uint8 device = 0; 204 | for (; device < 32; device ++){ 205 | pci_enum_device(bus, device); 206 | } 207 | } 208 | 209 | static void pci_enum_device(uint16 bus, uint8 device){ 210 | uint8 function = 0; 211 | pci_header_t header; 212 | pci_addr_t addr; 213 | addr.raw = 0x80000000; 214 | addr.s.bus = bus; 215 | addr.s.device = device; 216 | addr.s.function = 0; 217 | pci_get_header(&header, addr); 218 | if (header.vendor_id != 0xFFFF){ 219 | if ((header.type & 0x80) != 0){ 220 | // Multifunctional device 221 | for (function = 1; function < 8; function ++){ 222 | pci_enum_function(bus, device, function); 223 | } 224 | } else { 225 | // Single function device 226 | pci_enum_function(bus, device, 0); 227 | } 228 | } 229 | } 230 | 231 | static void pci_enum_function(uint16 bus, uint8 device, uint8 function){ 232 | uint16 secondary_bus = 0; 233 | pci_header_t header; 234 | pci_addr_t addr; 235 | addr.raw = 0x80000000; 236 | addr.s.bus = bus; 237 | addr.s.device = device; 238 | addr.s.function = function; 239 | pci_get_header(&header, addr); 240 | if (header.vendor_id != 0xFFFF){ 241 | _cache[_cache_len].address.raw = addr.raw; 242 | _cache[_cache_len].class_id = header.class_id; 243 | _cache[_cache_len].subclass_id = header.subclass_id; 244 | _cache[_cache_len].prog_if = header.prog_if; 245 | _cache[_cache_len].type = header.type; 246 | _cache[_cache_len].vendor_id = header.vendor_id; 247 | _cache[_cache_len].device_id = header.device_id; 248 | _cache_len ++; 249 | if (header.class_id == 0x06 && header.subclass_id == 0x04){ 250 | secondary_bus = pci_get_secondary_bus(bus, device, function); 251 | if (secondary_bus != bus){ 252 | pci_enum_bus(secondary_bus); 253 | } 254 | } 255 | } 256 | } 257 | 258 | #if DEBUG == 1 259 | void pci_list(){ 260 | uint16 i = 0; 261 | for (; i < _cache_len; i ++){ 262 | debug_print(DC_BW, "pci:%u:%u:%u, class:0x%x:0x%x, vendor:0x%x:0x%x", (uint64)_cache[i].address.s.bus, (uint64)_cache[i].address.s.device, (uint64)_cache[i].address.s.function, (uint64)_cache[i].class_id, (uint64)_cache[i].subclass_id, (uint64)_cache[i].vendor_id, (uint64)_cache[i].device_id); 263 | } 264 | } 265 | #endif -------------------------------------------------------------------------------- /bbp/kernel/pci.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Helper functions for PCI operations 4 | =================================== 5 | 6 | 7 | License (BSD-3) 8 | =============== 9 | 10 | Copyright (c) 2012, Gusts 'gusC' Kaksis 11 | All rights reserved. 12 | 13 | Redistribution and use in source and binary forms, with or without 14 | modification, are permitted provided that the following conditions are met: 15 | * Redistributions of source code must retain the above copyright 16 | notice, this list of conditions and the following disclaimer. 17 | * Redistributions in binary form must reproduce the above copyright 18 | notice, this list of conditions and the following disclaimer in the 19 | documentation and/or other materials provided with the distribution. 20 | * Neither the name of the nor the 21 | names of its contributors may be used to endorse or promote products 22 | derived from this software without specific prior written permission. 23 | 24 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 25 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 26 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 27 | DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY 28 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 29 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 30 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 31 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 32 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 33 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 | 35 | */ 36 | 37 | #ifndef __pci_h 38 | #define __pci_h 39 | 40 | #include "common.h" 41 | #include "../config.h" 42 | 43 | #define PCI_CONFIG_ADDRESS 0x0CF8 44 | #define PCI_CONFIG_DATA 0x0CFC 45 | 46 | #define PCI_REG_DEVID_VNDID 0x0 47 | #define PCI_REG_STATUS_CMD 0x4 48 | #define PCI_REG_CLS_PRG_REV 0x8 49 | #define PCI_REG_BIST_TYPE 0xC 50 | 51 | /** 52 | * PCI address structure 53 | */ 54 | typedef union { 55 | struct { 56 | uint32 empty : 2; // Always 0 57 | uint32 reg : 6; // Register number 58 | uint32 function : 3; // Function number 59 | uint32 device : 5; // Device number 60 | uint32 bus : 8; // Bus number 61 | uint32 reserved : 7; // Reserved 62 | uint32 enabled : 1; // Enabled bit 63 | } s; 64 | uint32 raw; 65 | } pci_addr_t; 66 | /** 67 | * PCI configuration space header structure 68 | */ 69 | typedef volatile struct { 70 | uint16 vendor_id; 71 | uint16 device_id; 72 | uint16 command; 73 | uint16 status; 74 | uint8 revision_id; 75 | uint8 prog_if; 76 | uint8 subclass_id; 77 | uint8 class_id; 78 | uint8 cache_line_size; 79 | uint8 latency_timer; 80 | uint8 type; 81 | uint8 bist; 82 | } pci_header_t; 83 | /** 84 | * Standard PCI device configuration space structure 85 | */ 86 | typedef volatile struct { 87 | pci_header_t header; 88 | uint32 bar[6]; 89 | uint32 cis_ptr; 90 | uint16 sub_vendor_id; 91 | uint16 subsystem_id; 92 | uint32 exp_rom; 93 | uint8 compat; 94 | uint8 reserved[7]; 95 | uint8 int_line; 96 | uint8 int_pin; 97 | uint8 min_grant; 98 | uint8 max_latency; 99 | } pci_device_t; 100 | 101 | /** 102 | * Enumerate PCI bus 103 | */ 104 | void pci_init(); 105 | /** 106 | * Get the number of devices represented by a class and subclass 107 | * @param class_id - class code 108 | * @param subclass_id - sub-class 109 | * @return number of devices found 110 | */ 111 | uint8 pci_num_device(uint8 class_id, uint8 subclass_id); 112 | /** 113 | * Locate PCI device by class and subclass 114 | * @param class_id - class code 115 | * @param subclass_id - sub-class 116 | * @param idx - device index (@see pci_num_device) 117 | * @return PCI address (check if it's not 0!) 118 | */ 119 | pci_addr_t pci_get_device(uint8 class_id, uint8 subclass_id, uint8 idx); 120 | /** 121 | * Read PCI device header 122 | * @param header - a pointer to header structure that needs to be filled 123 | * @param addr - PCI address 124 | */ 125 | void pci_get_header(pci_header_t *header, pci_addr_t addr); 126 | /** 127 | * Read PCI device configuration structure 128 | * @param device - a pointer to configuration structure that needs to be filled 129 | * @param addr - PCI address 130 | */ 131 | void pci_get_config(pci_device_t *device, pci_addr_t addr); 132 | /** 133 | * Read from PCI bus/device 134 | * @param addr - PCI address 135 | * @return register value 136 | */ 137 | uint32 pci_read(pci_addr_t addr); 138 | /** 139 | * Write to PCI bus/device 140 | * @param addr - PCI address 141 | * @param data - data to write 142 | */ 143 | void pci_write(pci_addr_t addr, uint32 data); 144 | 145 | 146 | #if DEBUG == 1 147 | /** 148 | * List available PCI devices on screen 149 | */ 150 | void pci_list(); 151 | #endif 152 | 153 | 154 | #endif /* __pci_h */ -------------------------------------------------------------------------------- /bbp/makefile: -------------------------------------------------------------------------------- 1 | AS = nasm -felf64 -O0 2 | LD = x86_64-pc-elf-ld -melf_x86_64 3 | OBJECTS = boot.o kernel.o 4 | 5 | all: $(OBJECTS) 6 | $(LD) -T bbp.ld $(OBJECTS) -o ../Release/bbp.img 7 | 8 | boot.o: 9 | make -C boot/ 10 | 11 | kernel.o: 12 | make -C kernel/ 13 | 14 | %.s.o: %.asm 15 | $(AS) -o $@ $< 16 | 17 | clean: 18 | rm -f *.o boot/*.o kernel/*.o ../Release/bbp.img ../Release/disk.img -------------------------------------------------------------------------------- /bochsrc.bxrc: -------------------------------------------------------------------------------- 1 | # 2 | # MBR2GPT test environment 3 | # 4 | 5 | # CPU 6 | cpu: count=1:2:1, ips=9000000, quantum=16, model=core2_penryn_t9600, reset_on_triple_fault=1, cpuid_limit_winnt=0, ignore_bad_msrs=1, mwait_is_nop=0 7 | 8 | # RAM 9 | memory: host=256, guest=256 10 | 11 | # ROM images 12 | romimage: file="C:\Bochs-2.6\BIOS-bochs-latest" 13 | vgaromimage: file="C:\Bochs-2.6\VGABIOS-lgpl-latest" 14 | 15 | # Boot 16 | boot: disk 17 | floppy_bootsig_check: disabled=0 18 | 19 | # Storage 20 | ata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14 21 | ata0-master: type=disk, mode=flat, translation=auto, path="Release\disk.img", cylinders=10, heads=16, spt=63, biosdetect=auto, model="Generic 1234" 22 | ata1: enabled=1, ioaddr1=0x170, ioaddr2=0x370, irq=15 23 | ata2: enabled=0 24 | ata3: enabled=0 25 | 26 | # IO 27 | pci: enabled=1, chipset=i440fx 28 | parport1: enabled=1, file="" 29 | parport2: enabled=0 30 | com1: enabled=1, mode=null, dev="" 31 | com2: enabled=0 32 | com3: enabled=0 33 | com4: enabled=0 34 | 35 | # Video 36 | display_library: win32 37 | vga: extension=vbe, update_freq=5 38 | private_colormap: enabled=0 39 | 40 | # Bochs 41 | plugin_ctrl: unmapped=1, biosdev=1, speaker=1, extfpuirq=1, parallel=1, serial=1, gameport=1 42 | config_interface: win32config 43 | print_timestamps: enabled=0 44 | port_e9_hack: enabled=0 45 | clock: sync=none, time0=local, rtc_sync=0 46 | 47 | # HID 48 | keyboard: type=mf, serial_delay=250, paste_delay=100000, keymap= 49 | user_shortcut: keys=none 50 | mouse: enabled=0, type=ps2, toggle=ctrl+mbutton 51 | 52 | # Logging 53 | log: bochsout.txt 54 | logprefix: %t%e%d 55 | panic: action=ask 56 | error: action=report 57 | info: action=report 58 | debug: action=ignore 59 | -------------------------------------------------------------------------------- /bochsrc_debug.bxrc: -------------------------------------------------------------------------------- 1 | # 2 | # MBR2GPT debug environment 3 | # 4 | 5 | # CPU 6 | cpu: count=1:2:1, ips=9000000, quantum=16, model=core2_penryn_t9600, reset_on_triple_fault=1, cpuid_limit_winnt=0, ignore_bad_msrs=1, mwait_is_nop=0 7 | 8 | # RAM 9 | memory: host=256, guest=256 10 | 11 | # ROM images 12 | romimage: file="C:\Bochs-2.6\BIOS-bochs-latest" 13 | vgaromimage: file="C:\Bochs-2.6\VGABIOS-lgpl-latest" 14 | 15 | # Boot 16 | boot: disk 17 | floppy_bootsig_check: disabled=0 18 | 19 | # Storage 20 | ata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14 21 | ata0-master: type=disk, mode=flat, translation=auto, path="Release\disk.img", cylinders=10, heads=16, spt=63, biosdetect=auto, model="Generic 1234" 22 | ata1: enabled=1, ioaddr1=0x170, ioaddr2=0x370, irq=15 23 | ata2: enabled=0 24 | ata3: enabled=0 25 | 26 | # IO 27 | pci: enabled=1, chipset=i440fx 28 | parport1: enabled=1, file="" 29 | parport2: enabled=0 30 | com1: enabled=1, mode=null, dev="" 31 | com2: enabled=0 32 | com3: enabled=0 33 | com4: enabled=0 34 | 35 | # Video 36 | display_library: win32, options="gui_debug" 37 | vga: extension=vbe, update_freq=5 38 | private_colormap: enabled=0 39 | 40 | # Bochs 41 | magic_break: enabled=1 42 | plugin_ctrl: unmapped=1, biosdev=1, speaker=1, extfpuirq=1, parallel=1, serial=1, gameport=1 43 | config_interface: win32config 44 | print_timestamps: enabled=0 45 | port_e9_hack: enabled=0 46 | clock: sync=none, time0=local, rtc_sync=0 47 | 48 | # HID 49 | keyboard: type=mf, serial_delay=250, paste_delay=100000, keymap= 50 | user_shortcut: keys=none 51 | mouse: enabled=0, type=ps2, toggle=ctrl+mbutton 52 | 53 | # Logging 54 | log: bochsout.txt 55 | logprefix: %t%e%d 56 | panic: action=ask 57 | error: action=report 58 | info: action=report 59 | debug: action=ignore 60 | -------------------------------------------------------------------------------- /mbr/README.md: -------------------------------------------------------------------------------- 1 | Master Boot Record 2 | ================== 3 | 4 | This is the MBR bootcode that read GPT headers and partition array and loads first 512KiB of BIOS Boot Partition bootcode 5 | 6 | File list 7 | --------- 8 | 9 | * main.asm - main MBR code 10 | * main.inc - data structure definitions and memory location definitions 11 | * mbr.vcxproj - Visual Studio 2010 project file 12 | 13 | Requirements 14 | ------------ 15 | 16 | * Netwide Assembler from: http://www.nasm.us/ 17 | * Microsoft Visual Studio Express 2010 18 | -------------------------------------------------------------------------------- /mbr/main.asm: -------------------------------------------------------------------------------- 1 | ; Program flow: 2 | ; 1. we are loaded at 0x7C00 3 | ; 2. init and store drive ID 4 | ; 3. do a check on MBR parition table for GPT protective record 5 | ; 4. do a check for LBA capabilities (extended read/write) 6 | ; 5. read GPT header 7 | ; 6. do a check on GPT signature 8 | ; 7. do a check on GPT partition count (should be more than or equal to 1) 9 | ; 8. read first 4 entries from GPT partition array 10 | ; 9. do a check on each partition entry for GUID of BBP 11 | ; 10. store BBP partition's start LBA 12 | ; 10. calculate and store BBP partition's lenght 13 | ; 11. relocate rest of the MBR (just the part that loads data from BBP) to 0x0700 14 | ; 12. read BBP from the disk and store in memory starting at 0x7C00 15 | ; 13. jump to BBP (0x7C00) 16 | ; 17 | ; memory map at the start: 18 | ; 0x0600 - 0x7BFF - free 19 | ; 0x7C00 - 0x7DFF - MBR loaded by BIOS 20 | ; 0x7E00 - 0x0007FFFF - free 21 | ; 22 | ; memory map before the jump to BBP: 23 | ; 0x0600 - Disk address packet (DAP) location (2x qword) 24 | ; 0x0660 - Local data (disk ID, bbp size, etc.) location (2x dword) 25 | ; 0x0700 - MBR bootstrap after relocation (curently it looks like just 16 bytes) 26 | ; 0x0800 - Read buffer location (512 bytes usually) 27 | ; 0x7C00 - Stack pointer 28 | ; 0x7C00 - ??? - Bootloader code loaded by MBR bootstrap (we need atleas 512KiB or 1024 sectors) 29 | 30 | %include "main.inc" ; Include data structures and memory location constants 31 | 32 | ; Remember in NASM it's: 33 | ; instruction destination, source 34 | 35 | [org ORG_LOC] ; set origin at 0x7C00 36 | [bits 16] ; tell NASM that we are working in 16bit environment 37 | jmp 0x0000:start 38 | 39 | start: ; Start MBR procedures 40 | xor eax, eax ; clear eax (is this some kind of asm developers way of seting value to 0? why can't we use 41 | ; mov ax, word 0x0000 instead? is this faster or cleaner?) 42 | mov ss, ax ; set stack segment to zero (is it, i'm dumb in assembly?) 43 | mov sp, ORG_LOC ; set stack pointer to the begining of MBR location in memory 44 | mov es, ax ; zero-out extra segment 45 | mov ds, ax ; zero-out data segment 46 | .setup_data: 47 | mov [DATA(drive_id)], dl ; store drive ID into memory 48 | .setup_dap: 49 | mov [DAP(size)], byte 0x10 ; set packet size 50 | mov [DAP(reserved)], byte 0x00 ; set reserved byte 51 | mov [DAP(lba_count)], word 0x0001 ; set number of blocks to transfer 52 | mov [DAP(dest_buff)], dword BUFF_LOC ; set read buffer position in memory 53 | mov [DAP(lba_start_l)], dword 0x0 ; clear start LBA low dword 54 | mov [DAP(lba_start_h)], dword 0x0 ; clear start LBA high dword 55 | 56 | test_mem: ; Get available lower memory ammount 57 | int 0x12 ; call memory interrupt 58 | jc $ ; hang if interrupt call failed 59 | test ax, ax ; check if memory is more than 0 (weird instruction - got to wrap my head around this) 60 | jz $ ; hang if ax is 0 (right?) 61 | sub ax, 0x001F ; 0x7C00 / 1024 = 0x001F 62 | ; we need to know if we have a region between 0x7C00 and 0xA0000 which is at least 512KiB 63 | cmp ax, 0x0200 ; test weather it's enough 64 | jl $ ; hang if not enough memory 65 | 66 | test_mbr_part: ; Test weather we are a protective MBR, we certanly don't want to be a hybrid MBR 67 | cmp [MBR(type)], byte 0xEE ; check weather we have GPT partitioning (0xEE - GPT protective partition) 68 | jne $ ; hang if not a protective partition 69 | 70 | test_ext: ; Check if drive supports extended read 71 | mov ah, 0x41 ; command - check for extensions 72 | mov bx, 0x55AA ; some magic test value 73 | mov dl, [DATA(drive_id)] ; set drive ID 74 | int 0x13 ; call disk interrupt 75 | jc $ ; hang if extensions are not supported 76 | cmp bx, 0xAA55 ; extra test for return value from extension test 77 | jne $ ; hang if the return value is not the one we expected 78 | 79 | reset_disk: ; Reset current disk 80 | mov ah, 0x00 ; command - reset disk 81 | mov dl, [DATA(drive_id)] ; set drive ID 82 | int 0x13 ; call disk interrupt 83 | jc $ ; hang if reset failed 84 | 85 | read_gpt: ; Read GPT header 86 | mov [DAP(lba_count)], word 0x0001 ; set number of blocks to transfer 87 | mov [DAP(lba_start_l)], dword 0x00000001 ; set start block address (low dword, 2nd block) 88 | mov ah, 0x42 ; command - extended read 89 | mov dl, [DATA(drive_id)] ; set drive ID 90 | mov si, DAP_LOC ; set DAP location 91 | int 0x13 ; call disk interrupt 92 | jc $ ; hang if disk read failed 93 | 94 | test_gpt: ; Parse GPT signature (should be "EFI PART" - look up ASCII yourself) 95 | cmp dword [GPT(signature)], 0x20494645 ; should be "EFI " (or " IFE" in little-endian order) 96 | jne $ ; hang - not even close 97 | cmp dword [GPT(signature) + 4], 0x54524150 ; should be "PART" (or "TRAP", pun intended?) 98 | jne $ ; hang - not quite there 99 | 100 | read_part_arr: ; Read Partition array 101 | mov [DAP(lba_start_l)], dword 0x00000002 ; set start block address (low dword, 3d block) 102 | mov ah, 0x42 ; command - extended read 103 | mov dl, [DATA(drive_id)] ; set drive ID 104 | mov si, DAP_LOC ; set DAP location 105 | int 0x13 ; call disk interrupt 106 | jc $ ; hang if disk read failed 107 | mov word cx, 0x0004 ; we only read first 4 partitions 108 | 109 | test_part: ; Read GPT partition entries to find if it's BBP (BIOS Boot Partition) 110 | ; we only accept first partition to be BIOS bootable 111 | mov ax, word 0x0004 ; set AX to 4 (we need it to calculate partition number) 112 | sub ax, cx ; subtract current step from AX (thus partition number is 4-4=0, 4-3=1, etc) 113 | mov dx, word 0x0080 ; set DX to 128 bytes (partition entry size) 114 | mul dx ; multiply our result in AX to get the offset 115 | mov bx, ax ; store offset in BX (I think it's base offset register, is it?) 116 | ; and we test it, and it's uggly (GUID and little-endianness I mean) 117 | cmp dword [PART(part_guid) + bx], 0x21686148 118 | jne test_next ; stop, you're no BBP 119 | cmp dword [PART(part_guid) + bx + 4], 0x6E6F6449 120 | jne test_next ; nice try 121 | cmp dword [PART(part_guid) + bx + 8], 0x65654E74 122 | jne test_next ; yeah, almost got me 123 | cmp dword [PART(part_guid) + bx + 12], 0x49464564 124 | jne test_next ; sooo close 125 | jmp prepare_copy ; found it! 126 | 127 | test_next: 128 | dec cx ; one step back means one step forward in partition entry array 129 | cmp cx, word 0x0000 ; check if we're not at the end of our 4 entry array 130 | jg test_part ; try our luck on the next one 131 | jmp $ ; hang - no BBPs found 132 | 133 | prepare_copy: ; Prepare our BBP copy 134 | mov [DAP(dest_buff)], dword BOOT_LOC ; set read buffer position in memory 135 | mov [DAP(lba_count)], word 0x0040 ; copy 64 sectors at a time 136 | .test_start_lba: 137 | cmp dword [PART(lba_start_h) + bx], 0x0 ; test if the start LBA is on the near side of disk 138 | jne $ ; hang if BBP is out of bounds 139 | .test_end_lba: 140 | cmp dword [PART(lba_end_h) + bx], 0x0 ; test if the end LBA is on the near side of disk 141 | jne $ ; hang if BBP is out of bounds 142 | .cont_prep: 143 | mov eax, dword [PART(lba_end_l) + bx] ; store low dword of end LBA 144 | sub eax, dword [PART(lba_start_l) + bx] ; subtract low dword of start LBA 145 | mov [DATA(bbp_size)], eax ; store sector count in memory 146 | mov eax, dword [PART(lba_start_l) + bx] ; get the low dword of start LBA 147 | mov [DAP(lba_start_l)], eax ; store it into DAP package 148 | mov eax, dword [PART(lba_start_h) + bx] ; get the high dword of start LBA 149 | mov [DAP(lba_start_h)], eax ; store it into DAP package 150 | 151 | mbr_relocate: ; Reallocate us in memory, so that we have more contiguous area where to put 152 | ; our bootloader 153 | mov si, bootstrap_start ; set source index (we only need the part from read_boot, rest is already a history) 154 | mov di, RELOC_LOC ; set destination index (where to put our MBR) 155 | mov cx, (bootstrap_end - bootstrap_start) ; how many blocks to copy (only from read_boot till padding) 156 | 157 | cld ; clear direction flag for copy 158 | rep ; repeat the copy cx times 159 | movsb ; move single byte 160 | jmp RELOC_LOC ; jump to relocated location 161 | 162 | bootstrap_start: ; Read bootable partition 163 | xor eax, eax ; clear eax 164 | xor ebx, ebx ; clear ebx 165 | xor ecx, ecx ; clear ecx 166 | mov eax, dword [DATA(bbp_size)] ; copy boot partition sector count 167 | cmp eax, 0x0400 ; test if not bigger than 1024 sectors (512 KiB) 168 | jle .prep_copy_loop ; continiue if less or equal 169 | mov eax, 0x0400 ; limit to 1024 sectors only 170 | .prep_copy_loop: 171 | mov bx, 0x0040 ; 64 sectors per iteration (32 KiB) 172 | div bx ; calculate iteration count 173 | mov cx, ax ; set iteration count 174 | .copy_block: 175 | mov ah, 0x42 ; command - extended read 176 | mov dl, [DATA(drive_id)] ; set drive ID 177 | mov si, DAP_LOC ; set DAP location 178 | int 0x13 ; call disk interrupt 179 | jc $ ; halt on error 180 | dec cx ; decrement cx for the next iteration 181 | cmp cx, 0x0 ; test if not the final iteration 182 | je .end ; last iteration - pass control over to BBP code 183 | mov eax, [DAP(dest_buff)] ; get current buffer position 184 | add eax, 0x8000000 ; move forward by 32 KiB (just increment the f*ing segments - ugly) 185 | mov [DAP(dest_buff)], eax ; set current buffer position 186 | jmp .copy_block ; next pass 187 | .end: 188 | jmp 0x0000:BOOT_LOC ; pass control over to BBP code 189 | bootstrap_end: 190 | 191 | padding: ; Zerofill up to 440 bytes 192 | times 0x01B8 - ($ - $$) db 0 193 | 194 | ; This is needed so we don't overwrite partition table with our assembly code 195 | part_table: 196 | times 0x0200 - 2 - ($ - $$) db 0 197 | 198 | magic: ; Add "magic number" 199 | dw 0xAA55 ; Magic number - boot sector signature 200 | -------------------------------------------------------------------------------- /mbr/main.inc: -------------------------------------------------------------------------------- 1 | ; Code location constants 2 | %define ORG_LOC 0x7C00 ; Initial MBR position in memory (where BIOS loads it) 3 | %define RELOC_LOC 0x0800 ; Relocation position (where we will copy neccessary MBR code to chainload bootloader) 4 | %define BUFF_LOC 0x0800 ; Location of read buffer in memory 5 | %define BOOT_LOC 0x7C00 ; Location of BBP bootcode 6 | 7 | ; Local data structure 8 | struc tDATA 9 | .drive_id resb 1 ; drive ID 10 | ._pad resb 3 ; dummy padding 11 | .bbp_size resd 1 ; BBP sector count 12 | endstruc 13 | %define DATA_LOC 0x0660 ; Location of our global data structure in memory 14 | %define DATA(x) DATA_LOC + tDATA. %+ x ; Helper macro to clean up the code a bit 15 | 16 | ; MBR Partition entry structure 17 | struc tMBRPart 18 | .status resb 1 ; Partition status (0x80 if bootable, 0x00 otherwise) 19 | .chs_start resb 3 ; Start of partition as a CHS value (we're not going to use this) 20 | .type resb 1 ; Partition type (we're looking for 0xEE) 21 | .chs_end resb 3 ; End of partition as a CHS value 22 | .lba_start resd 1 ; Start of partition as a LBA value 23 | .lba_length resd 1 ; Size of partition - number of sectors 24 | endstruc 25 | %define MBR_LOC 0x7DBE ; Partition table start 26 | %define MBR(x) MBR_LOC + tMBRPart. %+ x ; Helper macro to clean up the code a bit 27 | 28 | ; DAP structure for extended read 29 | struc tDAP 30 | .size resb 1 ; Packet size 31 | .reserved resb 1 ; Reserved - should be 0 32 | .lba_count resw 1 ; Number of sectors to transfer 33 | .dest_buff resd 1 ; Desination buffer where to transfer data 34 | .lba_start_l resd 1 ; Low dword of start LBA 35 | .lba_start_h resd 1 ; High dword of start LBA 36 | endstruc 37 | %define DAP_LOC 0x0600 ; Location in memory 38 | %define DAP(x) DAP_LOC + tDAP. %+ x ; Helper macro to clean up the code a bit 39 | 40 | ; GPT Header 41 | struc tGPTHead 42 | .signature resd 2 ; EFI PART signature 43 | .version resd 1 ; Version number 44 | .header_size resd 1 ; Size of a header (should be 92) 45 | .header_crc32 resd 1 ; CRC32 of first 3 entries 46 | .reserved resd 1 ; Should be 0 47 | .lba_curr resd 2 ; Current address of GPT header 48 | .lba_backup resd 2 ; Address of backup GPT header 49 | .lba_first resd 2 ; First usable LBA 50 | .lba_last resd 2 ; Last usable LBA 51 | .disk_guid resd 4 ; Disk GUID 52 | .part_arr_lba resd 2 ; LBA adress of partition array 53 | .part_count resd 1 ; Number of entries in partition array 54 | .part_size resd 1 ; Size of partition entry 55 | .part_arr_crc32 resd 1 ; CRC32 of partition array 56 | ; There should be a definition of 420 reserved bytes, bet we don't need them 57 | endstruc 58 | %define GPT(x) BUFF_LOC + tGPTHead. %+ x ; Helper macro to clean up the code a bit 59 | 60 | ; GPT Partition 61 | struc tGPTPart 62 | .part_guid resd 4 ; Partition type GUID 63 | .unique_guid resd 4 ; Unique GUID of partition 64 | .lba_start_l resd 1 ; Start LBA low dword 65 | .lba_start_h resd 1 ; Start LBA high dword 66 | .lba_end_l resd 1 ; End LBA low dword 67 | .lba_end_h resd 1 ; End LBA high dword 68 | .attributes resd 2 ; Partition attributes 69 | .name resw 36 ; UTF-16 partition name 70 | endstruc 71 | %define PART(x) BUFF_LOC + tGPTPart. %+ x ; Helper macro to clean up the code a bit 72 | -------------------------------------------------------------------------------- /mbr/makefile: -------------------------------------------------------------------------------- 1 | AS = nasm -fbin 2 | 3 | all: mbr.img 4 | 5 | mbr.img: main.asm 6 | $(AS) -o ../Release/mbr.img main.asm 7 | 8 | clean: 9 | rm -f ../Release/mbr.img -------------------------------------------------------------------------------- /mbr/mbr.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Release 6 | Win32 7 | 8 | 9 | 10 | {FC061F2D-BC1C-4918-8FCD-CD6F0CBDBE36} 11 | mbr 12 | mbr 13 | 14 | 15 | 16 | Makefile 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | C:\MinGW\bin;C:\MinGW\msys\1.0\bin;C:\Program Files\Netwide Assembler 25 | make -C "$(ProjectDir)" 26 | $(NMakeBuildCommandLine) 27 | del "..\Release\mbr.img" 28 | 29 | 30 | 31 | 32 | 33 | mbr.img 34 | 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /mbr2gpt.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 11.00 3 | # Visual C++ Express 2010 4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bbp", "bbp\bbp.vcxproj", "{3D779CE6-A610-49F7-AC07-992AEEB4115D}" 5 | ProjectSection(ProjectDependencies) = postProject 6 | {FC061F2D-BC1C-4918-8FCD-CD6F0CBDBE36} = {FC061F2D-BC1C-4918-8FCD-CD6F0CBDBE36} 7 | EndProjectSection 8 | EndProject 9 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mbr", "mbr\mbr.vcxproj", "{FC061F2D-BC1C-4918-8FCD-CD6F0CBDBE36}" 10 | EndProject 11 | Global 12 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 13 | Release|Win32 = Release|Win32 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {3D779CE6-A610-49F7-AC07-992AEEB4115D}.Release|Win32.ActiveCfg = Release|Win32 17 | {3D779CE6-A610-49F7-AC07-992AEEB4115D}.Release|Win32.Build.0 = Release|Win32 18 | {FC061F2D-BC1C-4918-8FCD-CD6F0CBDBE36}.Release|Win32.ActiveCfg = Release|Win32 19 | {FC061F2D-BC1C-4918-8FCD-CD6F0CBDBE36}.Release|Win32.Build.0 = Release|Win32 20 | EndGlobalSection 21 | GlobalSection(SolutionProperties) = preSolution 22 | HideSolutionNode = FALSE 23 | EndGlobalSection 24 | EndGlobal 25 | -------------------------------------------------------------------------------- /run_bochs.bat: -------------------------------------------------------------------------------- 1 | ECHO Starting bochs... 2 | bochs-i7ivy-smp.exe -q -f "%CD%\bochsrc.bxrc" 3 | -------------------------------------------------------------------------------- /run_bochs_debug.bat: -------------------------------------------------------------------------------- 1 | ECHO Starting bochs... 2 | bochsdbg-i7ivy-smp.exe -q -f "%CD%\bochsrc_debug.bxrc" 3 | -------------------------------------------------------------------------------- /run_qemu.bat: -------------------------------------------------------------------------------- 1 | ECHO Starting QEmu... 2 | 3 | SET SDL_VIDEODRIVER=windib 4 | SET QEMU_AUDIO_DRV=sdl 5 | SET SDL_AUDIODRIVER=waveout 6 | SET QEMU_AUDIO_LOG_TO_MONITOR=0 7 | 8 | START qemu-system-x86_64w.exe -smp 2 -m 256M -L C:\Qemu\Bios -drive file=Release/disk.img,media=disk,if=none,id=mydisk -device ich9-ahci,id=ahci -device ide-drive,drive=mydisk,bus=ahci.0 -vga std -name MBR2GPT -rtc base=localtime,clock=host -no-reboot --------------------------------------------------------------------------------