├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── all-in-one.asm ├── boot.conf ├── bootloader.png ├── bootstrap.asm └── stage2 ├── crunch.h ├── defs.h ├── elf.c ├── elf.h ├── ext2.c ├── ext2.h ├── lib.c ├── main.c └── vga.c /.gitignore: -------------------------------------------------------------------------------- 1 | *.bin 2 | bootloader 3 | boot 4 | *.img 5 | ext2util 6 | kernel 7 | boot.img 8 | boot.img.bak 9 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Michael Lazear 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | COBJS = stage2/main.o \ 3 | stage2/ext2.o \ 4 | stage2/lib.o \ 5 | stage2/vga.o \ 6 | stage2/elf.o 7 | 8 | CC = /home/lazear/opt/cross/bin/i686-elf-gcc 9 | LD = /home/lazear/opt/cross/bin/i686-elf-ld 10 | AS = nasm 11 | 12 | CCFLAGS = -w -fno-pic -fno-builtin -nostdlib -ffreestanding -std=gnu99 -m32 -c 13 | EXT2UTIL= ../ext2util/ext2util 14 | 15 | DISK = boot.img 16 | 17 | 18 | all: compile clean 19 | run: kernel compile clean emu 20 | nok: compile clean emu 21 | 22 | 23 | %.o : %.c 24 | $(CC) $(CCFLAGS) $< -o $@ 25 | 26 | stage2: $(COBJS) 27 | 28 | 29 | kernel: 30 | make -C ../crunchy 31 | 32 | compile: stage2 33 | $(AS) -f bin bootstrap.asm -o stage1.bin 34 | 35 | $(LD) -N -e stage2_main -Ttext 0x00050000 -o stage2.bin $(COBJS) --oformat binary 36 | 37 | cp boot.img.bak boot.img 38 | dd if=stage1.bin of=$(DISK) conv=notrunc 39 | 40 | #cp ../crunchy/bin/kernel.bin ./kernel 41 | 42 | $(EXT2UTIL) -x $(DISK) -wf stage2.bin -i 5 43 | $(EXT2UTIL) -x $(DISK) -wf kernel 44 | $(EXT2UTIL) -x $(DISK) -wf boot.conf 45 | 46 | new: 47 | dd if=/dev/zero of=boot.img bs=1k count=16k 48 | sudo mke2fs boot.img 49 | 50 | emu: 51 | qemu-system-i386 -hdb boot.img -curses 52 | 53 | clean: 54 | 55 | rm stage2/*.o 56 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ext2-boot 2 | 3 | ### x86 bootloader for ext2 filesystems and elf32 kernels 4 | ext2-boot aims to be a configurable bootloader utilizing the reserved bootloader block from the ext2 specification to load and run 32 bit ELF executables. 5 | Stage2 is essentially a minimal kernel, with only print-to-screen, ext2 file reading, and ELF execution capabilities. 6 | 7 | ext2-boot currently supports BIOS memory mapping, and passes along the information. 8 | Goals of this project are to provide easy-to-read, minimal yet functional code that can be used on native ext2 partitions, and be easier to set up than GRUB for people running Windows. 9 | 10 | ![alt tag](https://raw.githubusercontent.com/lazear/ext2-boot/master/bootloader.png) 11 | 12 | #### To-Do: 13 | * Add in configuration file 14 | * Finish video mode selection code 15 | * Add support for multiboot 16 | 17 | #### Requirements: 18 | * [ext2util](https://github.com/lazear/ext2util), or some other way to write the second stage loader to inode #5 19 | * elf32 executable 20 | 21 | #### Build 22 | Simply run 23 | ```sh 24 | $ make 25 | ``` 26 | And all necessary files will be compiled and moved onto the ext2 image. 27 | 28 | If you need a fresh ext2 disk image: 29 | ```sh 30 | $ dd if=/dev/zero of=disk.img bs=1k count=16k 31 | $ mke2fs disk.img 32 | ``` 33 | ext2util can be used to write files (such as a kernel) to the ext2 image. 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /all-in-one.asm: -------------------------------------------------------------------------------- 1 | [BITS 16] ; We need 16-bit intructions for Real mode 2 | [Org 0x7C00] 3 | global entry 4 | entry: 5 | 6 | mov bx, superblock 7 | mov [db_add], bx 8 | call read_disk 9 | 10 | jmp stage_oneandhalf 11 | 12 | 13 | read_disk: 14 | mov si, PACKET ; address of "disk address packet" 15 | mov ah, 0x42 ; AL is unused 16 | mov dl, 0x80 ; drive number 0 (OR the drive # with 0x80) 17 | int 0x13 18 | jc error 19 | ret 20 | 21 | print: 22 | lodsb 23 | or al, al ; test for NULL termination 24 | jz .printdone 25 | mov ah, 0eh 26 | int 10h 27 | jmp print 28 | .printdone: 29 | ret 30 | 31 | 32 | error: 33 | mov si, ext2_error 34 | call print 35 | ret 36 | 37 | 38 | ; LBA DATA PACKET 39 | PACKET: 40 | db 0x10 ; packet size (16 bytes) 41 | db 0 ; always 0 42 | blkcnt: dw 4 ; number of sectors to transfer 43 | db_add: dw 0 ; memory buffer destination address (0:7c00) 44 | dw 0 ; in memory page zero 45 | d_lba: dd 2 ; put the lba to read in this spot 46 | dd 0 ; more storage bytes only for big lba's ( > 4 bytes ) 47 | 48 | 49 | ext2_success db 13, "EXT2 Magic Header Good!", 10, 0 50 | ext2_error db 13, "ERROR", 10, 0 51 | in5_success db 13, "Stage2 loaded!", 10, 0 52 | stageonepointfive db 13, "Stage1.5 loaded!", 10, 0 53 | protmode db 13, "Entering PM!", 10, 0 54 | 55 | ;times 510-($-$$) db 0 ; Fill up the file with zeros 56 | dw 0AA55h ; Last 2 bytes = Boot sector identifyer 57 | 58 | ; LBA SECTOR 1. This is not loaded by BIOS. Stage1 loads Stage1.5 59 | 60 | stage_oneandhalf: 61 | 62 | mov si, stageonepointfive 63 | call print 64 | 65 | xor bx, bx 66 | 67 | mov ax, [superblock +56] ; EXT2_MAGUC 68 | cmp ax, 0xEF53 69 | jne error ; Not a valid EXT2 disk 70 | 71 | mov si, ext2_success 72 | call print 73 | 74 | ; We need to read the inode table entry for inode 5 75 | 76 | mov ax, [superblock + 1024 + 8] ; Block_Group_Descriptor->inode_table 77 | mov cx, 2 78 | mul cx ; ax = cx * ax 79 | 80 | mov [d_lba], ax ; which sector do we read? 81 | 82 | mov ax, 2 ; read 1024 bytes 83 | mov [blkcnt], ax 84 | 85 | mov bx, 0x1000 ; copy data to 0x1000 86 | mov [db_add], bx 87 | 88 | call read_disk 89 | 90 | xor bx, bx 91 | mov bx, 0x1200 ; Inode 5 is 0x200 into the first block (index 4 * 128 bytes per inode) 92 | mov cx, [bx + 28] ; # of sectors for inode 93 | lea di, [bx + 40] ; address of first block pointer 94 | 95 | mov bx, 0x5000 96 | mov [db_add+2], bx 97 | mov bx, 0 ; where inode5 will be loaded. 0xF0000 98 | mov [db_add], bx 99 | call read_loop 100 | 101 | mov si, in5_success 102 | call print 103 | 104 | 105 | jmp enter_pm 106 | 107 | ; We enter the loop with: 108 | ; bx = inode pointer 109 | ; cx = # of sectors to read (2 per block) 110 | ; di = address of first block pointer 111 | ; No support for indirect pointers. So keep 112 | ; stage2 113 | read_loop: 114 | xor ax, ax ; clear ax 115 | mov dx, ax ; clear dx 116 | mov ax, [di] ; set ax = block pointer 117 | mov dx, 2 ; multiply by 2 for sectors 118 | mul dx ; ax = dx * ax 119 | 120 | mov [d_lba], ax 121 | mov [db_add], bx 122 | 123 | call read_disk 124 | 125 | add bx, 0x400 ; increase by 1 kb 126 | add di, 0x4 ; move to next block pointer 127 | sub cx, 0x2 ; reading two blocks 128 | jnz read_loop 129 | ret 130 | 131 | nop 132 | hlt 133 | 134 | enter_pm: 135 | cli 136 | mov si, protmode 137 | call print 138 | 139 | 140 | ;xor ax, ax 141 | in al, 0x92 ; enable a20 142 | or al, 2 143 | out 0x92, al 144 | 145 | xor ax, ax ; Clear AX register 146 | mov ds, ax ; Set DS-register to 0 147 | mov es, ax 148 | mov fs, ax 149 | mov gs, ax 150 | 151 | lgdt [gdt_desc] ; Load the Global Descriptor Table 152 | 153 | ; ENTER PROTECTED MODE 154 | 155 | mov eax, cr0 ; Copy the contents of CR0 into EAX 156 | or eax, 1 ; Set bit 0 (0xFE = Real Mode) 157 | mov cr0, eax ; Copy the contents of EAX into CR0 158 | 159 | ;jmp $ 160 | ;sti 161 | jmp 08h:pm ; Jump to code segment, offset kernel_segments 162 | 163 | 164 | [BITS 32] ; We now need 32-bit instructions 165 | pm: 166 | mov ax, 10h ; Save data segment identifyer 167 | mov ds, ax ; Setup data segment 168 | mov es, ax 169 | mov fs, ax 170 | mov gs, ax 171 | mov ss, ax ; Setup stack segment 172 | mov esp, 0x00900000 ; Move the stack pointer to 090000h 173 | 174 | ;jmp 08h:0x1000 ; Jump to section 08h (code), offset 01000h 175 | jmp 0x00050000 176 | 177 | ; GLOBAL DESCRIPTOR TABLE 178 | 179 | align 16 180 | gdt: ; Address for the GDT 181 | 182 | gdt_null: ; Null Segment 183 | dd 0 184 | dd 0 185 | 186 | 187 | KERNEL_CODE equ $-gdt ; 0x08 188 | gdt_kernel_code: 189 | dw 0FFFFh ; Limit 0xFFFF 190 | dw 0 ; Base 0:15 191 | db 0 ; Base 16:23 192 | db 09Ah ; Present, Ring 0, Code, Non-conforming, Readable 193 | db 0CFh ; Page-granular 194 | db 0 ; Base 24:31 195 | 196 | KERNEL_DATA equ $-gdt ; 0x10 197 | gdt_kernel_data: 198 | dw 0FFFFh ; Limit 0xFFFF 199 | dw 0 ; Base 0:15 200 | db 0 ; Base 16:23 201 | db 092h ; Present, Ring 0, Data, Expand-up, Writable 202 | db 0CFh ; Page-granular 203 | db 0 ; Base 24:32 204 | 205 | gdt_end: ; Used to calculate the size of the GDT 206 | 207 | gdt_desc: ; The GDT descriptor 208 | dw gdt_end - gdt - 1 ; Limit (size) 209 | dd gdt ; Address of the GDT 210 | 211 | 212 | ;times 1020-($-$$) db 0 213 | dd 0xDEADBEEF 214 | times 510-($-$$) db 0 ; Fill up the file with zeros 215 | dw 0AA55h ; Last 2 bytes = Boot sector identifyer 216 | ; We can use the end of the file for a convenient label 217 | ; Superblock starts at LBA 2, which is the end of this 218 | ; sector 219 | superblock: 220 | -------------------------------------------------------------------------------- /boot.conf: -------------------------------------------------------------------------------- 1 | load kernel 2 | give memory 3 | video 1024 768 4 | -------------------------------------------------------------------------------- /bootloader.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lazear/ext2-boot/d6698890ac9b832c8ad2f5d4548f327c7747396d/bootloader.png -------------------------------------------------------------------------------- /bootstrap.asm: -------------------------------------------------------------------------------- 1 | ; BOOTSTRAP.S 2 | ;============================================================================== 3 | ;MIT License 4 | ;Copyright (c) 2007-2016 Michael Lazear 5 | ; 6 | ;Permission is hereby granted, free of charge, to any person obtaining a copy 7 | ;of this software and associated documentation files (the "Software"), to deal 8 | ;in the Software without restriction, including without limitation the rights 9 | ;to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | ;copies of the Software, and to permit persons to whom the Software is 11 | ;furnished to do so, subject to the following conditions: 12 | ; 13 | ;The above copyright notice and this permission notice shall be included in all 14 | ;copies or substantial portions of the Software. 15 | ; 16 | ;THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | ;IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | ;FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | ;AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | ;LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | ;OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | ;SOFTWARE. 23 | ;============================================================================== 24 | ; MEMORY MAP 25 | ; 0x0400 : 0x0500 - memory map info 26 | ; 0x2000 : 0x2??? - VESA controller info 27 | ; 0x3000 : 28 | ; 0x5000 : 0x7200 Stage2 bootloader 29 | ; 0x7C00 : 0x8000 Stage1/1.5 bootloader 30 | ; 31 | 32 | 33 | 34 | 35 | 36 | [BITS 16] 37 | [ORG 0x7C00] 38 | 39 | GLOBAL entry 40 | 41 | ; Stage1 is responsible for loading Stage1.5, and mapping video modes 42 | 43 | 44 | entry: 45 | 46 | and dl, 0x80 47 | jz error 48 | 49 | mov [drive], dl ; BIOS stores drive # in dl 50 | 51 | mov bx, stage_oneandhalf ; Load into address of Stage1.5 52 | mov [dest], bx 53 | call read_disk 54 | 55 | jmp stage_oneandhalf 56 | 57 | 58 | read_disk: 59 | mov esi, PACKET ; address of "disk address packet" 60 | mov ah, 0x42 ; extended read 61 | mov dl, [drive] ; drive number 0 (OR the drive # with 0x80) 62 | int 0x13 63 | jc error 64 | ret 65 | 66 | print: 67 | lodsb 68 | or al, al ; test for NULL termination 69 | jz .printdone 70 | mov ah, 0eh 71 | int 10h 72 | jmp print 73 | .printdone: 74 | ret 75 | 76 | 77 | error: 78 | mov esi, ext2_error 79 | call print 80 | jmp $ 81 | 82 | 83 | 84 | ; 0x56455341 = VESA 85 | video_map: 86 | xor eax, eax 87 | mov es, ax 88 | mov bx, 0x2000 89 | mov di, bx 90 | mov ax, 0x4F00 91 | int 0x10 92 | 93 | cmp ax, 0x004F 94 | jne .error 95 | 96 | ;mov [vid_info+4], bx ; Store pointer to video controller array 97 | mov si, [bx + 0xE] ; Offset to mode pointer 98 | mov ax, [bx + 0x10] ; Segment to mode pointer 99 | mov es, ax 100 | 101 | mov di, 0x3000 102 | 103 | .loop: 104 | mov bx, [es:si] ; Load BX with video mode 105 | cmp bx, 0xFFFF 106 | je .done ; End of list 107 | 108 | add si, 2 109 | mov [.mode], bx 110 | 111 | mov ax, 0x4F01 ; Get mode info pitch+16, width+18, height+20 112 | mov cx, [.mode] 113 | 114 | int 0x10 115 | cmp ax, 0x004F 116 | jne .error 117 | xor ax, ax 118 | 119 | mov ax, [es:di + 42] 120 | mov [.framebuffer], ax 121 | 122 | mov ax, [es:di + 16] ; pitch 123 | mov bx, [es:di + 18] ; width 124 | mov cx, [es:di + 20] ; height 125 | mov dx, [es:di + 25] ; bpp 126 | mov [.bpp], dx 127 | 128 | add di, 0x100 129 | 130 | cmp ax, [.pitch] 131 | jne .loop 132 | 133 | cmp bx, [.width] 134 | jne .loop 135 | 136 | cmp cx, [.height] 137 | jne .loop 138 | 139 | lea ax, [es:di - 0x100] 140 | mov [vid_info.array], ax ; Pointer to mode array 141 | 142 | .setmode: 143 | xor ax, ax 144 | mov ax, 0x4F02 ; Function AX=4F02h; 145 | mov bx, [.mode] 146 | mov [vid_info], bx 147 | or bx, 0x4000 ; enable LFB 148 | 149 | ; int 0x10 150 | ; cmp ax, 0x004F 151 | ; jne .error 152 | 153 | .done: 154 | ret 155 | 156 | .error: 157 | mov si, video_error 158 | call print 159 | jmp $ 160 | 161 | 162 | .mode dw 0 163 | .width dw 1024 164 | .height dw 768 165 | .pitch dw 3072 166 | .bpp dw 0 167 | .framebuffer dd 0 168 | 169 | ;============================================================================== 170 | ; LBA DATA PACKET 171 | PACKET: 172 | db 0x10 ; packet size (16 bytes) 173 | db 0 ; always 0 174 | count: dw 4 ; number of sectors to transfer 175 | dest: dw 0 ; destination offset (0:7c00) 176 | dw 0 ; destination segment 177 | lba: dd 1 ; put the lba # to read in this spot 178 | dd 0 ; more storage bytes only for big lba's ( > 4 bytes ) 179 | ;============================================================================== 180 | 181 | 182 | ext2_success db 13, "EXT2 Magic Header Good!", 10, 0 183 | ext2_error db 13, "EXT2 superblock not found", 10, 0 184 | stageonepointfive db 13, "Stage1.5 loaded!", 10, 0 185 | video_error db 13, "VESA ERROR", 10, 0 186 | drive db 0 187 | 188 | vid_info: 189 | .mode dd 0 190 | .array dd 0 191 | 192 | 193 | times 510-($-$$) db 0 ; Fill up the file with zeros 194 | dw 0AA55h ; Last 2 bytes = Boot sector identifyer 195 | 196 | 197 | ;============================================================================== 198 | ; END LBA SECTOR 0. 199 | ; 200 | ; We are now out of the zone loaded by the BIOS 201 | ; However, Stage1 contains some useful functions that we can continue 202 | ; to use, since Stage1.5 is directly loaded at the end of stage1 (0x7E00) 203 | ; 204 | ; Stage1.5 mainly focuses on parsing ext2 data to find the blocks used for 205 | ; inode #5, which is reserved by ext2 specific for bootloaders - and we have 206 | ; placed the Stage2 loaded there. Memory mapping function is also placed here 207 | ; 208 | ; BEGIN LBA SECTOR 1 209 | ;============================================================================== 210 | 211 | 212 | stage_oneandhalf: 213 | 214 | mov esi, stageonepointfive 215 | call print 216 | 217 | xor bx, bx 218 | 219 | mov ax, [superblock +56] ; EXT2_MAGUC 220 | cmp ax, 0xEF53 221 | jne error ; Not a valid EXT2 disk 222 | 223 | mov si, ext2_success 224 | call print 225 | 226 | ; We need to read the inode table entry for inode 5 227 | 228 | mov ax, [superblock + 1024 + 8] ; Block_Group_Descriptor->inode_table 229 | mov cx, 2 230 | mul cx ; ax = cx * ax 231 | 232 | mov [lba], ax ; which sector do we read? 233 | 234 | mov ax, 2 ; read 1024 bytes 235 | mov [count], ax 236 | 237 | mov bx, 0x1000 ; copy data to 0x1000 238 | mov [dest], bx 239 | 240 | call read_disk 241 | 242 | xor bx, bx 243 | mov bx, 0x1200 ; Inode 5 is 0x200 into the first block (index 4 * 128 bytes per inode) 244 | mov cx, [bx + 28] ; # of sectors for inode 245 | lea di, [bx + 40] ; address of first block pointer 246 | 247 | mov bx, 0x5000 248 | mov [dest+2], bx 249 | mov bx, 0 ; where inode5 will be loaded. 0xF0000 250 | mov [dest], bx 251 | call read_stagetwo 252 | 253 | call video_map 254 | ; Prepare to call the memory mapping function 255 | xor eax, eax ; Clear EAX 256 | mov es, eax ; Clear ES 257 | mov edi, 0x400 ; DI = 0x400. ES:DI => 0x00000400 258 | push edi ; Push start of memory map 259 | 260 | call memory_map 261 | push edi ; Push end of memory map 262 | jmp enter_pm ; Enter protected mode 263 | 264 | 265 | ; Bios function INT 15h, AX=E820h 266 | ; EBX must contain 0 on first call, and remain unchanged 267 | ; on subsequent calls until it is zero again 268 | ; Code adapted from OSDEV wiki 269 | ; Memory map is 24 byte struct placed at [ES:DI] 270 | memory_map: 271 | xor ebx, ebx ; ebx must be 0 to start 272 | mov edx, 0x0534D4150 ; Place "SMAP" into edx 273 | mov eax, 0xe820 274 | mov [es:di + 20], dword 1 ; force a valid ACPI 3.X entry 275 | mov ecx, 24 ; ask for 24 bytes 276 | int 0x15 277 | jc short .fail ; carry set on first call means "unsupported function" 278 | 279 | mov edx, 0x0534D4150 ; 280 | cmp eax, edx ; on success, eax must have been set to "SMAP" 281 | jne short .fail 282 | 283 | test ebx, ebx ; ebx = 0 implies list is only 1 entry long (worthless) 284 | je short .fail 285 | 286 | jmp short .loop 287 | 288 | .e820lp: 289 | mov eax, 0xe820 ; eax, ecx get trashed on every int 0x15 call 290 | mov [es:di + 20], dword 1 ; force a valid ACPI 3.X entry 291 | mov ecx, 24 ; ask for 24 bytes again 292 | int 0x15 293 | jc short .done ; carry set means "end of list already reached" 294 | mov edx, 0x0534D4150 ; repair potentially trashed register 295 | .loop: 296 | jcxz .skip ; skip any 0 length entries 297 | cmp cl, 20 ; got a 24 byte ACPI 3.X response? 298 | jbe short .notext 299 | test byte [es:di + 20], 1 ; if so: is the "ignore this data" bit clear? 300 | je short .skip 301 | .notext: 302 | mov ecx, [es:di + 8] ; get lower uint32_t of memory region length 303 | or ecx, [es:di + 12] ; "or" it with upper uint32_t to test for zero 304 | jz .skip ; if length uint64_t is 0, skip entry 305 | add di, 24 306 | 307 | .skip: 308 | test ebx, ebx ; if ebx resets to 0, list is complete 309 | jne short .e820lp 310 | .done: 311 | clc ; there is "jc" on end of list to this point, so the carry must be cleared 312 | ret 313 | .fail: 314 | stc ; "function unsupported" error exit 315 | ret 316 | 317 | ; We enter the loop with: 318 | ; bx = inode pointer 319 | ; cx = # of sectors to read (2 per block) 320 | ; di = address of first block pointer 321 | ; No support for indirect pointers. So keep 322 | ; stage2 323 | read_stagetwo: 324 | xor ax, ax ; clear ax 325 | mov dx, ax ; clear dx 326 | mov ax, [di] ; set ax = block pointer 327 | mov dx, 2 ; multiply by 2 for sectors 328 | mul dx ; ax = dx * ax 329 | 330 | mov [lba], ax 331 | mov [dest], bx 332 | 333 | call read_disk 334 | 335 | add bx, 0x400 ; increase by 1 kb 336 | add di, 0x4 ; move to next block pointer 337 | sub cx, 0x2 ; reading two blocks 338 | jnz read_stagetwo 339 | ret 340 | 341 | nop 342 | hlt 343 | 344 | 345 | enter_pm: 346 | cli ; Turn off interrupts 347 | ;xor ax, ax 348 | in al, 0x92 ; enable a20 349 | or al, 2 350 | out 0x92, al 351 | 352 | xor ax, ax ; Clear AX register 353 | mov ds, ax ; Set DS-register to 0 354 | mov es, ax 355 | mov fs, ax 356 | mov gs, ax 357 | 358 | lgdt [gdt_desc] ; Load the Global Descriptor Table 359 | 360 | ;============================================================================== 361 | ; ENTER PROTECTED MODE 362 | 363 | mov eax, cr0 364 | or eax, 1 ; Set bit 0 365 | mov cr0, eax 366 | 367 | jmp 08h:pm ; Jump to code segment, offset kernel_segments 368 | 369 | 370 | [BITS 32] 371 | pm: 372 | pop ecx ; End of memory map 373 | mov [mem_info+4], ecx 374 | pop ecx 375 | mov [mem_info], ecx 376 | 377 | xor eax, eax 378 | 379 | mov ax, 10h ; Save data segment identifyer 380 | mov ds, ax ; Setup data segment 381 | mov es, ax 382 | mov ss, ax ; Setup stack segment 383 | mov fs, ax 384 | mov gs, ax 385 | 386 | mov esp, 0x00900000 ; Move temp stack pointer to 090000h 387 | 388 | mov eax, vid_info 389 | push eax 390 | mov eax, mem_info 391 | push eax 392 | mov edx, 0x00050000 393 | lea eax, [edx] 394 | call eax ; stage2_main(mem_info, vid_info) 395 | 396 | ;============================================================================== 397 | ; GLOBAL DESCRIPTOR TABLE 398 | 399 | align 16 400 | mem_info: 401 | dd 0 402 | dd 0 403 | 404 | 405 | 406 | align 32 407 | gdt: ; Address for the GDT 408 | 409 | gdt_null: 410 | dd 0 411 | dd 0 412 | 413 | ;KERNEL_CODE equ $-gdt ; 0x08 414 | gdt_kernel_code: 415 | dw 0FFFFh ; Limit 0xFFFF 416 | dw 0 ; Base 0:15 417 | db 0 ; Base 16:23 418 | db 09Ah ; Present, Ring 0, Code, Non-conforming, Readable 419 | db 0CFh ; Page-granular 420 | db 0 ; Base 24:31 421 | 422 | ;KERNEL_DATA equ $-gdt 423 | gdt_kernel_data: 424 | dw 0FFFFh ; Limit 0xFFFF 425 | dw 0 ; Base 0:15 426 | db 0 ; Base 16:23 427 | db 092h ; Present, Ring 0, Code, Non-conforming, Readable 428 | db 0CFh ; Page-granular 429 | db 0 ; Base 24:31 430 | 431 | gdt_end: ; Used to calculate the size of the GDT 432 | 433 | gdt_desc: ; The GDT descriptor 434 | dw gdt_end - gdt - 1 ; Limit (size) 435 | dd gdt ; Address of the GDT 436 | ;============================================================================== 437 | 438 | times 1024-($-$$) db 0 439 | 440 | ; We can use the end of the file for a convenient label 441 | ; Superblock starts at LBA 2, which is the end of this 442 | ; sector 443 | superblock: 444 | -------------------------------------------------------------------------------- /stage2/crunch.h: -------------------------------------------------------------------------------- 1 | /* 2 | crunch.h 3 | =============================================================================== 4 | MIT License 5 | Copyright (c) 2007-2016 Michael Lazear 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in all 15 | copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | SOFTWARE. 24 | =============================================================================== 25 | */ 26 | 27 | /* 28 | Defines common types for data structures passed from the bootloader to the kernel 29 | */ 30 | 31 | typedef struct _boot_mmap 32 | { 33 | uint64_t base; 34 | uint64_t len; 35 | uint64_t type; 36 | } mmap; 37 | 38 | 39 | typedef struct _gfx_context { 40 | uint16_t pitch; 41 | uint16_t width; 42 | uint16_t height; 43 | uint8_t bpp; 44 | uint32_t framebuffer; 45 | } gfx_context; -------------------------------------------------------------------------------- /stage2/defs.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef __defs__ 3 | #define __defs__ 4 | #include 5 | 6 | 7 | #define NULL ((void*) 0) 8 | #define malloc(n) ((void*)((HEAP += n) - n)) 9 | #define free(x) 10 | #define size_t uint32_t 11 | #define assert(e) ((e) ? (void) 0 : vga_pretty(#e, VGA_RED)) 12 | 13 | 14 | extern void lsroot(); 15 | 16 | extern char* itoa(uint32_t num, int base); 17 | extern void putx(char* msg, uint32_t i); 18 | extern size_t strlen( char* s ); 19 | extern char* strncat( char* destination, const char* source, size_t n ); 20 | extern char* strcat(char *destination, const char* source); 21 | extern char* strncpy(char *dest, const char *src, uint16_t n); 22 | extern char* strcpy(char *dest, const char *src) ; 23 | extern int strncmp(char* s1, char* s2, size_t n); 24 | extern int strcmp(char *s1, char* s2); 25 | extern char* strchr(const char* s, int c); 26 | extern char* strdup(const char* s) ; 27 | extern char* strrev(char* s); 28 | extern void* memcpy(void *s1, const void *s2, uint32_t n); 29 | extern void* memset(void *s, int c, size_t n) ; 30 | extern void* memsetw(void *s, int c, size_t n); 31 | extern void* memmove(void *s1, const void* s2, size_t n); 32 | extern void* memchr(const void* s, int c, size_t n); 33 | extern void* memrchr(const void* s, int c, size_t n) ; 34 | extern int memcmp(const uint8_t* s1, const uint8_t* s2, size_t n); 35 | extern char* strtok(char* s, const char* delim); 36 | extern inline uint8_t inb(uint16_t port); 37 | extern inline void outb(uint16_t port, uint16_t data); 38 | extern inline void insl(int port, void *addr, int cnt); 39 | 40 | extern uint32_t HEAP; 41 | extern uint32_t HEAP_START; 42 | 43 | #define VGA_BLACK 0x00 44 | #define VGA_BLUE 0x01 45 | #define VGA_GREEN 0x02 46 | #define VGA_CYAN 0x03 47 | #define VGA_RED 0x04 48 | #define VGA_MAGENTA 0x05 49 | #define VGA_BROWN 0x06 50 | #define VGA_LIGHTGREY 0x07 51 | #define VGA_DARKGREY 0x08 52 | #define VGA_LIGHTBLUE 0x09 53 | #define VGA_LIGHTGREEN 0x0A 54 | #define VGA_LIGHTCYAN 0x0B 55 | #define VGA_LIGHTRED 0x0C 56 | #define VGA_LIGHTMAGENTA 0x0D 57 | #define VGA_LIGHTBROWN 0x0E 58 | #define VGA_WHITE 0x0F 59 | 60 | #define VGA_COLOR(f, b) ((b << 4) | (f & 0xF)) 61 | #define RGB(r,g,b) (((r&0xFF)<<16) | ((g&0xFF)<<8) | (b & 0xFF)) 62 | 63 | #define isascii(c) (c >= 0 && c <= 127) 64 | #define isdigit(c) (c >= '0' && c <= '9') 65 | #define islower(c) (c >= 'a' && c <= 'z') 66 | #define isupper(c) (c >= 'A' && c <= 'Z') 67 | #define tolower(c) (isdigit(c) ? c : (islower(c) ? c : ((c - 'A') + 'a'))) 68 | #define toupper(c) (isdigit(c) ? c : (isupper(c) ? c : ((c - 'a') + 'A'))) 69 | 70 | 71 | typedef struct vbe { 72 | uint16_t attributes; // deprecated, only bit 7 should be of interest to you, and it indicates the mode supports a linear frame buffer. 73 | uint8_t window_a; // deprecated 74 | uint8_t window_b; // deprecated 75 | uint16_t granularity; // deprecated; used while calculating bank numbers 76 | uint16_t window_size; 77 | uint16_t segment_a; 78 | uint16_t segment_b; 79 | uint32_t win_func_ptr; // deprecated; used to switch banks from protected mode without returning to real mode 80 | uint16_t pitch; // number of bytes per horizontal line 81 | uint16_t width; // width in pixels 82 | uint16_t height; // height in pixels 83 | uint8_t w_char; // unused... 84 | uint8_t y_char; // ... 85 | uint8_t planes; 86 | uint8_t bpp; // bits per pixel in this mode 87 | uint8_t banks; // deprecated; total number of banks in this mode 88 | uint8_t memory_model; 89 | uint8_t bank_size; // deprecated; size of a bank, almost always 64 KB but may be 16 KB... 90 | uint8_t image_pages; 91 | uint8_t reserved0; 92 | 93 | uint8_t red_mask; 94 | uint8_t red_position; 95 | uint8_t green_mask; 96 | uint8_t green_position; 97 | uint8_t blue_mask; 98 | uint8_t blue_position; 99 | uint8_t reserved_mask; 100 | uint8_t reserved_position; 101 | uint8_t direct_color_attributes; 102 | 103 | uint32_t framebuffer; // physical address of the linear frame buffer; write here to draw to the screen 104 | uint32_t off_screen_mem_off; 105 | uint16_t off_screen_mem_size; // size of memory in the framebuffer but not being displayed on the screen 106 | } vbe; 107 | 108 | typedef struct _vid_info { 109 | uint32_t mode; 110 | vbe* info; 111 | } vid_info; 112 | 113 | 114 | #endif -------------------------------------------------------------------------------- /stage2/elf.c: -------------------------------------------------------------------------------- 1 | /* 2 | elf.c 3 | =============================================================================== 4 | MIT License 5 | Copyright (c) 2007-2016 Michael Lazear 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in all 15 | copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | SOFTWARE. 24 | =============================================================================== 25 | */ 26 | 27 | #include "defs.h" 28 | #include "ext2.h" 29 | #include "elf.h" 30 | #include "crunch.h" 31 | 32 | void elf_objdump(void* data) { 33 | elf32_ehdr *ehdr = (elf32_ehdr*) data; 34 | 35 | /* Make sure the file ain't fucked */ 36 | assert(ehdr->e_ident[0] == ELF_MAGIC); 37 | assert(ehdr->e_machine == EM_386); 38 | assert(ehdr->e_type == ET_EXEC); 39 | 40 | printx("ELF ident ",ehdr->e_ident[0]); 41 | printx("Entry ",ehdr->e_entry); 42 | 43 | /* Parse the program headers */ 44 | elf32_phdr* phdr = (uint32_t) data + ehdr->e_phoff; 45 | elf32_phdr* last_phdr = (uint32_t) phdr + (ehdr->e_phentsize * ehdr->e_phnum); 46 | vga_pretty("Offset \tVirt Addr\tPhys Addr\tFile Sz\tMem sz \tAlign \n", VGA_LIGHTMAGENTA); 47 | while(phdr < last_phdr) { 48 | vga_puts(" "); 49 | vga_puts(itoa(phdr->p_offset, 16)); 50 | vga_puts("\t"); 51 | vga_puts(itoa(phdr->p_vaddr, 16)); 52 | vga_putc('\t'); 53 | vga_puts(itoa(phdr->p_paddr, 16)); 54 | vga_putc('\t'); 55 | vga_puts(itoa(phdr->p_filesz, 10)); 56 | vga_putc('\t'); 57 | vga_puts(itoa(phdr->p_memsz, 16)); 58 | vga_putc('\t'); 59 | // vga_puts(itoa(phdr->p_align, 16)); 60 | vga_putc('\n'); 61 | // printf("LOAD:\toff 0x%x\tvaddr\t0x%x\tpaddr\t0x%x\n\t\tfilesz\t%d\tmemsz\t%d\talign\t%d\t\n", 62 | // phdr->p_offset, phdr->p_vaddr, phdr->p_paddr, phdr->p_filesz, phdr->p_memsz, phdr->p_align); 63 | phdr++; 64 | } 65 | 66 | /* Parse the section headers */ 67 | elf32_shdr* shdr = (uint32_t) data + ehdr->e_shoff; 68 | elf32_shdr* sh_str = (uint32_t) shdr + (ehdr->e_shentsize * ehdr->e_shstrndx); 69 | elf32_shdr* last_shdr = (uint32_t) shdr + (ehdr->e_shentsize * ehdr->e_shnum); 70 | 71 | char* string_table = (uint32_t) data + sh_str->sh_offset; 72 | 73 | shdr++; // Skip null entry 74 | int q = 0; 75 | 76 | vga_pretty("Sections:\nIdx Name\tSize\t\tAddress \tOffset\tAlign\n", VGA_LIGHTMAGENTA); 77 | while (shdr < last_shdr) { 78 | vga_puts(itoa(++q, 10)); 79 | vga_puts(" "); 80 | vga_puts(string_table + shdr->sh_name); 81 | if (strlen(string_table + shdr->sh_name) < 6) 82 | vga_puts("\t"); 83 | vga_putc('\t'); 84 | vga_puts(itoa(shdr->sh_size, 16)); 85 | vga_putc('\t'); 86 | vga_puts(itoa(shdr->sh_addr, 16)); 87 | vga_putc('\t'); 88 | vga_puts(itoa(shdr->sh_offset, 10)); 89 | vga_putc('\t'); 90 | vga_puts(itoa(shdr->sh_addralign, 16)); 91 | vga_putc('\n'); 92 | 93 | shdr++; 94 | } 95 | } 96 | 97 | 98 | void elf_load(mmap* one, gfx_context* two) { 99 | inode* ki = ext2_inode(1,12); 100 | uint32_t* data = ext2_read_file(ki); 101 | //uint32_t* data = ext2_file_seek(ext2_inode(1,12), 1024, 0); 102 | 103 | elf32_ehdr * ehdr = (elf32_ehdr*) data; 104 | 105 | assert(ehdr->e_ident[0] == ELF_MAGIC); 106 | 107 | elf_objdump(data); 108 | printx("data at: ", data); 109 | printx("heap at: ", malloc(0)); 110 | free(data); 111 | 112 | elf32_phdr* phdr = (uint32_t) data + ehdr->e_phoff; 113 | elf32_phdr* last_phdr = (uint32_t) phdr + (ehdr->e_phentsize * ehdr->e_phnum); 114 | 115 | uint32_t off = (phdr->p_vaddr - phdr->p_paddr); 116 | 117 | while(phdr < last_phdr) { 118 | printx("header: ", phdr->p_paddr); 119 | memcpy(phdr->p_paddr, (uint32_t)data + phdr->p_offset, phdr->p_filesz); 120 | phdr++; 121 | } 122 | 123 | 124 | 125 | void (*entry)(mmap*, gfx_context*); 126 | entry = (void(*)(void))(ehdr->e_entry - off); 127 | 128 | // CLEAR OUT THE ENTIRE HEAP 129 | 130 | uint32_t END_OF_HEAP = malloc(0); 131 | memset(HEAP_START, 0, (END_OF_HEAP - HEAP_START)); 132 | 133 | 134 | printx("entry: ", entry); 135 | asm volatile("cli"); 136 | entry(one, two); 137 | 138 | } 139 | -------------------------------------------------------------------------------- /stage2/elf.h: -------------------------------------------------------------------------------- 1 | /* 2 | elf.h 3 | =============================================================================== 4 | MIT License 5 | Copyright (c) 2007-2016 Michael Lazear 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in all 15 | copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | SOFTWARE. 24 | =============================================================================== 25 | */ 26 | 27 | #include 28 | 29 | #define ELF_MAGIC 0x464C457FU // "\x7FELF" in little endian 30 | 31 | /* e_type definitions */ 32 | #define ET_NONE 0 33 | #define ET_REL 1 // Relocatable file 34 | #define ET_EXEC 2 // Executable 35 | #define ET_DYN 3 // Shared object file 36 | #define ET_CORE 4 // Core file 37 | 38 | #define EM_386 3 // Intel x86 39 | 40 | typedef struct { 41 | uint32_t e_ident[4]; /* Magic number and other info */ 42 | uint16_t e_type; /* Object file type */ 43 | uint16_t e_machine; /* Architecture */ 44 | uint32_t e_version; /* Object file version */ 45 | uint32_t e_entry; /* Entry point virtual address */ 46 | uint32_t e_phoff; /* Program header table file offset */ 47 | uint32_t e_shoff; /* Section header table file offset */ 48 | uint32_t e_flags; /* Processor-specific flags */ 49 | uint16_t e_ehsize; /* ELF header size in bytes */ 50 | uint16_t e_phentsize; /* Program header table entry size */ 51 | uint16_t e_phnum; /* Program header table entry count */ 52 | uint16_t e_shentsize; /* Section header table entry size */ 53 | uint16_t e_shnum; /* Section header table entry count */ 54 | uint16_t e_shstrndx; /* Section header string table index */ 55 | } elf32_ehdr; 56 | 57 | #define SHT_NULL 0 /* inactive */ 58 | #define SHT_PROGBITS 1 /* Program defined */ 59 | #define SHT_SYMTAB 2 /* Symbol table */ 60 | #define SHT_STRTAB 3 /* String table */ 61 | #define SHT_RELA 4 /* Relocation entries Elf32_Rela */ 62 | #define SHT_HASH 5 63 | #define SHT_DYNAMIC 6 64 | #define SHT_NOTE 7 65 | #define SHT_NOBITS 8 /* .bss */ 66 | #define SHT_REL 9 /* Relocation entries Elf32_Rel */ 67 | #define SHT_SHLIB 10 68 | #define SHT_DYNSYM 11 69 | 70 | #define SHF_WRITE 1 /* Writable data */ 71 | #define SHF_ALLOC 2 /* Allocated memory */ 72 | #define SHF_EXEC 4 /* Executable instr */ 73 | 74 | typedef struct { 75 | uint32_t sh_name; /* Index into section header str table */ 76 | uint32_t sh_type; /* Section header type */ 77 | uint32_t sh_flags; 78 | uint32_t sh_addr; /* Address the section should appear at */ 79 | uint32_t sh_offset; /* Offset from first byte in file */ 80 | uint32_t sh_size; 81 | uint32_t sh_link; 82 | uint32_t sh_info; 83 | uint32_t sh_addralign; /* Address alignment constraints */ 84 | uint32_t sh_entsize; 85 | } elf32_shdr; 86 | 87 | typedef struct { 88 | uint32_t p_type; 89 | uint32_t p_offset; /* offset from beginning of file */ 90 | uint32_t p_vaddr; 91 | uint32_t p_paddr; 92 | uint32_t p_filesz; /* bytes of segment in file */ 93 | uint32_t p_memsz; /* bytes of segment in memory */ 94 | uint32_t p_flags; 95 | uint32_t p_align; 96 | } elf32_phdr; 97 | 98 | 99 | // table index 0 is reserved 100 | typedef struct { 101 | uint16_t st_name; 102 | uint32_t st_value; 103 | uint16_t st_size; 104 | uint8_t st_info; 105 | uint8_t st_other; 106 | uint16_t st_shndx; 107 | } elf32_sym; 108 | 109 | #define STB_LOCAL 0 110 | #define STB_GLOBAL 1 111 | #define STT_NOTYPE 0 112 | #define STT_OBJECT 1 113 | #define STT_FUNC 2 114 | #define STT_SECTION 3 115 | #define STT_FILE 4 116 | 117 | -------------------------------------------------------------------------------- /stage2/ext2.c: -------------------------------------------------------------------------------- 1 | /* 2 | ext2_bootloader.c 3 | =============================================================================== 4 | MIT License 5 | Copyright (c) 2007-2016 Michael Lazear 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in all 15 | copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | SOFTWARE. 24 | =============================================================================== 25 | 26 | This is intended to be used as a Stage2 bootloader. As such, only Read 27 | functionality. 28 | 29 | This loader will be located at inode 5 so that Stage1 bootloader can easily 30 | find it. 31 | */ 32 | 33 | #include "ext2.h" 34 | #include "defs.h" 35 | 36 | 37 | // void stage2_main() { 38 | // //clear the screen 39 | // vga_clear(); 40 | // vga_puts("Stage2 loaded...\n"); 41 | // lsroot(); 42 | 43 | // for(;;); 44 | // } 45 | 46 | 47 | 48 | /* 49 | Wait for IDE device to become ready 50 | check = 0, do not check for errors 51 | check != 0, return -1 if error bit set 52 | */ 53 | int ide_wait(int check) { 54 | char r; 55 | 56 | // Wait while drive is busy. Once just ready is set, exit the loop 57 | while (((r = (char)inb(IDE_IO | IDE_CMD)) & (IDE_BSY | IDE_RDY)) != IDE_RDY); 58 | 59 | // Check for errors 60 | if (check && (r & (IDE_DF | IDE_ERR)) != 0) 61 | return 0xF; 62 | return 0; 63 | } 64 | 65 | static void* ide_read(void* b, uint32_t block) { 66 | 67 | int sector_per_block = BLOCK_SIZE / SECTOR_SIZE; // 2 68 | int sector = block * sector_per_block; 69 | 70 | ide_wait(0); 71 | outb(IDE_IO | IDE_SECN, sector_per_block); // # of sectors 72 | outb(IDE_IO | IDE_LOW, LBA_LOW(sector)); 73 | outb(IDE_IO | IDE_MID, LBA_MID(sector)); 74 | outb(IDE_IO | IDE_HIGH, LBA_HIGH(sector)); 75 | // Slave/Master << 4 and last 4 bits 76 | outb(IDE_IO | IDE_HEAD, 0xE0 | (1 << 4) | LBA_LAST(sector)); 77 | outb(IDE_IO | IDE_CMD, IDE_CMD_READ); 78 | ide_wait(0); 79 | // Read only 80 | insl(IDE_IO, b, BLOCK_SIZE/4); 81 | 82 | return b; 83 | } 84 | 85 | 86 | /* Buffer_read and write are used as glue functions for code compatibility 87 | with hard disk ext2 driver, which has buffer caching functions. Those will 88 | not be included here. */ 89 | void* buffer_read(int block) { 90 | return ide_read(malloc(BLOCK_SIZE), block); 91 | } 92 | 93 | /* Read superblock from device dev, and check the magic flag. 94 | Return NULL if not a valid EXT2 partition */ 95 | superblock* ext2_superblock() { 96 | superblock* sb = buffer_read(EXT2_SUPER); 97 | if (sb->magic != EXT2_MAGIC) 98 | return NULL; 99 | return sb; 100 | } 101 | 102 | block_group_descriptor* ext2_blockdesc() { 103 | return buffer_read(EXT2_SUPER + 1); 104 | } 105 | 106 | inode* ext2_inode(int dev, int i) { 107 | superblock* s = ext2_superblock(); 108 | block_group_descriptor* bgd = ext2_blockdesc(); 109 | 110 | int block_group = (i - 1) / s->inodes_per_group; // block group # 111 | int index = (i - 1) % s->inodes_per_group; // index into block group 112 | int block = (index * INODE_SIZE) / BLOCK_SIZE; 113 | bgd += block_group; 114 | 115 | // Not using the inode table was the issue... 116 | uint32_t* data = buffer_read(bgd->inode_table+block); 117 | inode* in = (inode*)((uint32_t) data + (index % (BLOCK_SIZE/INODE_SIZE))*INODE_SIZE); 118 | return in; 119 | } 120 | 121 | uint32_t ext2_read_indirect(uint32_t indirect, size_t block_num) { 122 | char* data = buffer_read(indirect); 123 | return *(uint32_t*) ((uint32_t) data + block_num*4); 124 | } 125 | 126 | void* ext2_read_file(inode* in) { 127 | assert(in); 128 | if(!in) 129 | return NULL; 130 | 131 | int num_blocks = in->blocks / (BLOCK_SIZE/SECTOR_SIZE); 132 | 133 | assert(num_blocks != 0); 134 | if (!num_blocks) 135 | return NULL; 136 | 137 | 138 | size_t sz = BLOCK_SIZE*num_blocks; 139 | void* buf = malloc(sz); 140 | assert(buf != NULL); 141 | 142 | int indirect = 0; 143 | 144 | /* Singly-indirect block pointer */ 145 | if (num_blocks > 12) { 146 | indirect = in->block[12]; 147 | } 148 | 149 | int blocknum = 0; 150 | char* data; 151 | for (int i = 0; i < num_blocks; i++) { 152 | if (i < 12) { 153 | blocknum = in->block[i]; 154 | char* data = buffer_read(blocknum); 155 | memcpy((uint32_t) buf + (i * BLOCK_SIZE), data, BLOCK_SIZE); 156 | } 157 | if (i > 12) { 158 | blocknum = ext2_read_indirect(indirect, i-13); 159 | char* data = buffer_read(blocknum); 160 | memcpy((uint32_t) buf + ((i-1) * BLOCK_SIZE), data, BLOCK_SIZE); 161 | } 162 | 163 | } 164 | return buf; 165 | } 166 | 167 | 168 | void* ext2_file_seek(inode* in, size_t n, size_t offset) { 169 | int nblocks = ((n-1 + BLOCK_SIZE & ~(BLOCK_SIZE-1)) / BLOCK_SIZE); 170 | int off_block = (offset / BLOCK_SIZE); // which block 171 | int off = offset % BLOCK_SIZE; // offset in block 172 | 173 | void* buf = malloc(nblocks*BLOCK_SIZE); // round up to whole block size 174 | 175 | assert(nblocks <= in->blocks/2); 176 | assert(off_block <= in->blocks/2); 177 | for (int i = 0; i < nblocks; i++) { 178 | buffer* b = buffer_read(in->block[off_block+i]); 179 | memcpy(buf + (i*BLOCK_SIZE), b->data + off, BLOCK_SIZE); 180 | //printf("Read @ block %d (%d)\n",in->block[off_block+i], off_block); 181 | off = 0; // Eliminate offset after first block 182 | } 183 | return buf; 184 | 185 | } 186 | 187 | /* Finds an inode by name in dir_inode */ 188 | int ext2_find_child(const char* name, int dir_inode) { 189 | if (!dir_inode) 190 | return -1; 191 | inode* i = ext2_inode(1, dir_inode); // Root directory 192 | 193 | char* buf = malloc(BLOCK_SIZE*i->blocks/2); 194 | memset(buf, 0, BLOCK_SIZE*i->blocks/2); 195 | 196 | for (int q = 0; q < i->blocks / 2; q++) { 197 | char* data = buffer_read(i->block[q]); 198 | memcpy((uint32_t)buf+(q * BLOCK_SIZE), data, BLOCK_SIZE); 199 | } 200 | 201 | dirent* d = (dirent*) buf; 202 | 203 | int sum = 0; 204 | int calc = 0; 205 | do { 206 | // Calculate the 4byte aligned size of each entry 207 | calc = (sizeof(dirent) + d->name_len + 4) & ~0x3; 208 | sum += d->rec_len; 209 | //printf("%2d %10s\t%2d %3d\n", (int)d->inode, d->name, d->name_len, d->rec_len); 210 | if (strncmp(d->name, name, d->name_len)== 0) { 211 | 212 | free(buf); 213 | return d->inode; 214 | } 215 | d = (dirent*)((uint32_t) d + d->rec_len); 216 | 217 | } while(sum < (1024 * i->blocks/2)); 218 | free(buf); 219 | return -1; 220 | } 221 | 222 | 223 | void lsroot() { 224 | // vga_puts("lsroot"); 225 | inode* i = ext2_inode(1, 2); // Root directory 226 | 227 | char* buf = malloc(BLOCK_SIZE*i->blocks/2); 228 | // printx("Inode@: ", i); 229 | 230 | for (int q = 0; q < i->blocks / 2; q++) { 231 | // printx("Block: ", i->block[q]); 232 | char* data = buffer_read(i->block[q]); 233 | memcpy((uint32_t)buf+(q * BLOCK_SIZE), data, BLOCK_SIZE); 234 | } 235 | 236 | dirent* d = (dirent*) buf; 237 | 238 | int sum = 0; 239 | int calc = 0; 240 | vga_puts("Root directory:\n"); 241 | do { 242 | 243 | // Calculate the 4byte aligned size of each entry 244 | calc = (sizeof(dirent) + d->name_len + 4) & ~0x3; 245 | sum += d->rec_len; 246 | vga_puts("/"); 247 | vga_puts(d->name); 248 | vga_putc('\n'); 249 | if (d->rec_len != calc && sum == 1024) { 250 | /* if the calculated value doesn't match the given value, 251 | then we've reached the final entry on the block */ 252 | //sum -= d->rec_len; 253 | d->rec_len = calc; // Resize this entry to it's real size 254 | // d = (dirent*)((uint32_t) d + d->rec_len); 255 | } 256 | 257 | d = (dirent*)((uint32_t) d + d->rec_len); 258 | 259 | 260 | } while(sum < 1024); 261 | return NULL; 262 | } 263 | 264 | -------------------------------------------------------------------------------- /stage2/ext2.h: -------------------------------------------------------------------------------- 1 | /* 2 | ext2.h 3 | ================================================================================ 4 | MIT License 5 | Copyright (c) 2007-2016 Michael Lazear 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in all 15 | copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | SOFTWARE. 24 | ================================================================================ 25 | */ 26 | 27 | 28 | /* 29 | 30 | Block groups are found at the address (group number - 1) * blocks_per_group. 31 | Each block group has a backup superblock as it's first block 32 | */ 33 | 34 | #include 35 | 36 | #ifndef __baremetal_ext2__ 37 | #define __baremetal_ext2__ 38 | 39 | #define BLOCK_SIZE 1024 40 | #define SECTOR_SIZE 512 41 | #define EXT2_BOOT 0 // Block 0 is bootblock 42 | #define EXT2_SUPER 1 // Block 1 is superblock 43 | #define EXT2_MAGIC 0x0000EF53 44 | 45 | 46 | 47 | typedef struct superblock_s { 48 | uint32_t inodes_count; // Total # of inodes 49 | uint32_t blocks_count; // Total # of blocks 50 | uint32_t r_blocks_count; // # of reserved blocks for superuser 51 | uint32_t free_blocks_count; 52 | uint32_t free_inodes_count; 53 | uint32_t first_data_block; 54 | uint32_t log_block_size; // 1024 << Log2 block size = block size 55 | uint32_t log_frag_size; 56 | uint32_t blocks_per_group; 57 | uint32_t frags_per_group; 58 | uint32_t inodes_per_group; 59 | uint32_t mtime; // Last mount time, in POSIX time 60 | uint32_t wtime; // Last write time, in POSIX time 61 | uint16_t mnt_count; // # of mounts since last check 62 | uint16_t max_mnt_count; // # of mounts before fsck must be done 63 | uint16_t magic; // 0xEF53 64 | uint16_t state; 65 | uint16_t errors; 66 | uint16_t minor_rev_level; 67 | uint32_t lastcheck; 68 | uint32_t checkinterval; 69 | uint32_t creator_os; 70 | uint32_t rev_level; 71 | uint16_t def_resuid; 72 | uint16_t def_resgid; 73 | } __attribute__((packed)) superblock; 74 | 75 | /* 76 | Inode bitmap size = (inodes_per_group / 8) / BLOCK_SIZE 77 | block_group = (block_number - 1)/ (blocks_per_group) + 1 78 | */ 79 | typedef struct block_group_descriptor_s { 80 | uint32_t block_bitmap; 81 | uint32_t inode_bitmap; 82 | uint32_t inode_table; 83 | uint16_t free_blocks_count; 84 | uint16_t free_inodes_count; 85 | uint16_t used_dirs_count; 86 | uint16_t pad[7]; 87 | } block_group_descriptor; 88 | 89 | 90 | /* 91 | maximum value of inode.block[index] is inode.blocks / (2 << log_block_size) 92 | 93 | Locating an inode: 94 | block group = (inode - 1) / s_inodes_per_group 95 | 96 | inside block: 97 | local inode index = (inode - 1) % s_inodes_per_group 98 | 99 | containing block = (index * INODE_SIZE) / BLOCK_SIZE 100 | */ 101 | typedef struct inode_s { 102 | uint16_t mode; // Format of the file, and access rights 103 | uint16_t uid; // User id associated with file 104 | uint32_t size; // Size of file in bytes 105 | uint32_t atime; // Last access time, POSIX 106 | uint32_t ctime; // Creation time 107 | uint32_t mtime; // Last modified time 108 | uint32_t dtime; // Deletion time 109 | uint16_t gid; // POSIX group access 110 | uint16_t links_count; // How many links 111 | uint32_t blocks; // # of 512-bytes blocks reserved to contain the data 112 | uint32_t flags; // EXT2 behavior 113 | uint32_t osdl; // OS dependent value 114 | uint32_t block[15]; // Block pointers. Last 3 are indirect 115 | uint32_t generation; // File version 116 | uint32_t file_acl; // Block # containing extended attributes 117 | uint32_t dir_acl; 118 | uint32_t faddr; // Location of file fragment 119 | uint32_t osd2[3]; 120 | } inode; 121 | 122 | #define INODE_SIZE (sizeof(inode)) 123 | 124 | 125 | /* 126 | Directories must be 4byte aligned, and cannot extend between multiple 127 | blocks on the disk */ 128 | typedef struct dirent_s { 129 | uint32_t inode; // Inode 130 | uint16_t rec_len; // Total size of entry, including all fields 131 | uint8_t name_len; // Name length, least significant 8 bits 132 | uint8_t file_type; // Type indicator 133 | uint8_t name[]; 134 | } __attribute__((packed)) dirent; 135 | 136 | /* IMPORTANT: Inode addresses start at 1 */ 137 | 138 | typedef struct ide_buffer { 139 | uint32_t block; // block number 140 | uint8_t data[BLOCK_SIZE]; // 1 disk sector of data 141 | } buffer; 142 | 143 | 144 | 145 | #define B_BUSY 0x1 // buffer is locked by a process 146 | #define B_VALID 0x2 // buffer has been read from disk 147 | #define B_DIRTY 0x4 // buffer has been written to 148 | 149 | 150 | /* Define IDE status bits */ 151 | #define IDE_BSY (1<<7) // Drive is preparing to send/receive data 152 | #define IDE_RDY (1<<6) // Clear when drive is spun down, or after error 153 | #define IDE_DF (1<<5) // Drive Fault error 154 | #define IDE_ERR (1<<0) // Error has occured 155 | 156 | #define IDE_IO 0x1F0 // Main IO port 157 | #define IDE_DATA 0x0 // R/W PIO data bytes 158 | #define IDE_FEAT 0x1 // ATAPI devices 159 | #define IDE_SECN 0x2 // # of sectors to R/W 160 | #define IDE_LOW 0x3 // CHS/LBA28/LBA48 specific 161 | #define IDE_MID 0x4 162 | #define IDE_HIGH 0x5 163 | #define IDE_HEAD 0x6 // Select drive/heaad 164 | #define IDE_CMD 0x7 // Command/status port 165 | #define IDE_ALT 0x3F6 // alternate status 166 | #define LBA_LOW(c) ((uint8_t) (c & 0xFF)) 167 | #define LBA_MID(c) ((uint8_t) (c >> 8) & 0xFF) 168 | #define LBA_HIGH(c) ((uint8_t) (c >> 16) & 0xFF) 169 | #define LBA_LAST(c) ((uint8_t) (c >> 24) & 0xF) 170 | 171 | #define IDE_CMD_READ (BLOCK_SIZE/SECTOR_SIZE == 1) ? 0x20 : 0xC4 172 | #define IDE_CMD_WRITE (BLOCK_SIZE/SECTOR_SIZE == 1) ? 0x30 : 0xC5 173 | #define IDE_CMD_READ_MUL 0xC4 174 | #define IDE_CMD_WRITE_MUL 0xC5 175 | 176 | extern block_group_descriptor* ext2_blockdesc(); 177 | extern superblock* ext2_superblock(); 178 | extern void* ext2_read_file(inode* in); 179 | 180 | extern void vga_puts(char* s); 181 | 182 | #endif -------------------------------------------------------------------------------- /stage2/lib.c: -------------------------------------------------------------------------------- 1 | /* 2 | string.c 3 | =============================================================================== 4 | MIT License 5 | Copyright (c) 2007-2016 Michael Lazear 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in all 15 | copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | SOFTWARE. 24 | =============================================================================== 25 | 26 | Implementation of string library for baremetal project 27 | */ 28 | 29 | #include "defs.h" 30 | #include 31 | 32 | // Returns length of a null-terminated string 33 | size_t strlen( char* s ) { 34 | char* p = s; 35 | uint32_t i = 0; 36 | while (*p++ != 0 ) i++; 37 | return i; 38 | } 39 | 40 | 41 | // Appends a copy of the source string to the destination string 42 | char* strncat( char* destination, const char* source, size_t n ) { 43 | size_t length = strlen(destination); 44 | int i; 45 | for (i = 0; i < n && source[i] != '\0'; i++) 46 | destination[length+i] = source[i]; 47 | destination[length+i] = '\0'; 48 | return destination; 49 | } 50 | 51 | // wrapper for strncat 52 | char* strcat(char *destination, const char* source) { 53 | return strncat(destination, source, strlen(source)); 54 | } 55 | 56 | 57 | // Copy first n characters of src to destination 58 | char* strncpy(char *dest, const char *src, uint16_t n) { 59 | uint16_t i; 60 | 61 | for (i = 0; i < n && src[i] != '\0'; i++) 62 | dest[i] = src[i]; 63 | for ( ; i < n; i++) 64 | dest[i] = '\0'; 65 | 66 | return dest; 67 | } 68 | 69 | // Copy all of str to dest 70 | char* strcpy(char *dest, const char *src) { 71 | return strncpy(dest, src, strlen(src)); 72 | } 73 | 74 | 75 | int strncmp(char* s1, char* s2, size_t n) { 76 | for (size_t i = 0; i < n && *s1 == *s2; s1++, s2++, i++) 77 | if (*s1 == '\0') 78 | return 0; 79 | return ( *(unsigned char*)s1 - *(unsigned char*)s2 ); 80 | } 81 | 82 | int strcmp(char *s1, char* s2) { 83 | return strncmp(s1, s2, strlen(s1)); 84 | } 85 | 86 | 87 | char* strchr(const char* s, int c) { 88 | while (*s != '\0') 89 | if (*s++ == c) return (char*) s; 90 | return NULL; 91 | } 92 | 93 | char* strdup(const char* s) { 94 | return strcpy((char*) malloc(strlen(s)), s); 95 | } 96 | 97 | /* 98 | In place string reverse 99 | */ 100 | char* strrev(char* s) { 101 | int length = strlen(s) - 1; 102 | for (int i = 0; i <= length/2; i++) { 103 | char temp = s[i]; 104 | s[i] = s[length-i]; 105 | s[length-i] = temp; 106 | } 107 | return s; 108 | } 109 | 110 | 111 | void* memcpy(void *s1, const void *s2, uint32_t n) { 112 | uint8_t* src = (uint8_t*) s2; 113 | uint8_t* dest = (uint8_t*) s1; 114 | 115 | for (int i = 0; i < n; i++) 116 | dest[i] = src[i]; 117 | return s1; 118 | } 119 | 120 | void* memset(void *s, int c, size_t n) { 121 | uint8_t* dest = (uint8_t*) s; 122 | for (size_t i = 0; i < n; i++) 123 | dest[i] = c; 124 | return s; 125 | } 126 | 127 | void* memsetw(void *s, int c, size_t n) { 128 | uint16_t* dest = (uint16_t*) s; 129 | for (size_t i = 0; i < n; i++) *dest++ = c; 130 | } 131 | 132 | void* memmove(void *s1, const void* s2, size_t n) { 133 | char* dest = (char*) s1; 134 | char* src = (char*) s2; 135 | char* temp = (char*) malloc(n); 136 | 137 | for (int i = 0; i < n; i++) 138 | temp[i] = src[i]; 139 | for (int i = 0; i < n; i++) 140 | dest[i] = temp[i]; 141 | 142 | free(temp); 143 | return s1; 144 | } 145 | 146 | void* memchr(const void* s, int c, size_t n) { 147 | uint8_t* b = s; 148 | while (n--) 149 | if (*b++ == c) 150 | return b; 151 | return NULL; 152 | } 153 | 154 | void* memrchr(const void* s, int c, size_t n) { 155 | return strrev(memchr(strrev(s), c, n)); 156 | } 157 | 158 | int memcmp(const uint8_t* s1, const uint8_t* s2, size_t n) { 159 | 160 | while (*s1 == *s2 && n--) { 161 | s1++; 162 | s2++; 163 | } 164 | return ( *(uint8_t*)s1 - *(uint8_t*)s2 ); 165 | } 166 | 167 | 168 | char* strtok(char* s, const char* delim) { 169 | char* b = NULL; 170 | static char* ptr, d = NULL; 171 | 172 | 173 | if (s) 174 | ptr = s; 175 | 176 | if (!ptr && !s) 177 | return NULL; 178 | for (int i = 0; i < strlen(delim); i++) { 179 | b = ptr; 180 | ptr = strchr(ptr, delim[i]); 181 | if (!ptr) 182 | return b; 183 | *--ptr = '\0'; 184 | ptr++; 185 | return b; 186 | } 187 | return NULL; 188 | } 189 | 190 | inline uint8_t inb(uint16_t port) { 191 | // "=a" (result) means: put AL register in variable result when finished 192 | // "d" (_port) means: load EDX with _port 193 | unsigned char result; 194 | asm volatile("inb %1, %0" : "=a" (result) : "dN" (port)); 195 | return result; 196 | } 197 | 198 | inline void outb(uint16_t port, uint16_t data) { 199 | asm volatile ("outb %1, %0" : : "dN" (port), "a" (data)); 200 | } 201 | 202 | inline void insl(int port, void *addr, int cnt) 203 | { 204 | asm volatile("cld; rep insl" : 205 | "=D" (addr), "=c" (cnt) : 206 | "d" (port), "0" (addr), "1" (cnt) : 207 | "memory", "cc"); 208 | } 209 | 210 | char* itoa(uint32_t num, int base) { 211 | int i = 0; 212 | //num = abs(num); 213 | int len = 8; 214 | 215 | char* buffer = malloc(32); 216 | if (base == 2) 217 | len = 32; 218 | 219 | if (num == 0 && base == 2) { 220 | while(i < len) 221 | buffer[i++] = '0'; 222 | buffer[i] = '\0'; 223 | return buffer; 224 | } 225 | /* if (num == 0 && base == 0) { 226 | buffer[0] = '0'; 227 | buffer[1] = '\0'; 228 | return buffer; 229 | }*/ 230 | 231 | // go in reverse order 232 | while (num != 0 && len--) { 233 | int remainder = num % base; 234 | // case for hexadecimal 235 | buffer[i++] = (remainder > 9)? (remainder - 10) + 'A' : remainder + '0'; 236 | num = num / base; 237 | } 238 | 239 | while(len-- && base != 10) 240 | buffer[i++] = '0'; 241 | 242 | buffer[i] = '\0'; 243 | 244 | return strrev(buffer); 245 | } 246 | -------------------------------------------------------------------------------- /stage2/main.c: -------------------------------------------------------------------------------- 1 | #include "defs.h" 2 | #include "crunch.h" 3 | 4 | uint32_t HEAP = 0x00200000; 5 | uint32_t HEAP_START; 6 | 7 | static void putpixel(unsigned char* screen, int x,int y, int color); 8 | void parse_config(char* config); 9 | 10 | void stage2_main(uint32_t* mem_info, vid_info* v) { 11 | //clear the screen 12 | HEAP_START = HEAP; 13 | vga_clear(); 14 | vga_pretty("Stage2 loaded...\n", VGA_LIGHTGREEN); 15 | lsroot(); 16 | 17 | mmap* m = (mmap*) *mem_info; 18 | mmap* max = (mmap*) *++mem_info; 19 | printx("Video Mode:", v->mode); 20 | vga_puts("framebuffer@ 0x"); 21 | 22 | vga_puts(itoa(v->info->framebuffer, 16)); 23 | vga_putc('\n'); 24 | /* Don't use the heap, because it's going to be wiped */ 25 | gfx_context *c = (gfx_context*) 0x000F0000; 26 | c->pitch = v->info->pitch; 27 | c->width = v->info->width; 28 | c->height = v->info->height; 29 | c->bpp = v->info->bpp; 30 | c->framebuffer = v->info->framebuffer; 31 | memcpy(0x000F1000, m, (uint32_t) max - (uint32_t) m); 32 | 33 | vga_pretty("Memory map:\n", VGA_LIGHTGREEN); 34 | while (m < max) { 35 | 36 | vga_puts(itoa(m->base, 16)); 37 | vga_putc('-'); 38 | vga_puts(itoa(m->len + m->base, 16)); 39 | vga_putc('\t'); 40 | //vga_puts(itoa(m->type, 10)); 41 | switch((char)m->type) { 42 | case 1: { 43 | vga_puts("Usable Ram\t"); 44 | 45 | break; 46 | } case 2: { 47 | vga_puts("Reserved\t"); 48 | break; 49 | } default: 50 | vga_putc('\n'); 51 | } 52 | vga_puts(itoa(m->len/0x400, 10)); 53 | vga_puts(" KB\n"); 54 | m++; 55 | } 56 | 57 | int boot_conf_inode = ext2_find_child("boot.conf", 2); 58 | 59 | char* config = ext2_read_file(ext2_inode(1, boot_conf_inode)); 60 | parse_config(config); 61 | 62 | 63 | /* We should never reach this point */ 64 | for(;;); 65 | } 66 | 67 | void parse_config(char* config) { 68 | vga_puts(config); 69 | 70 | 71 | } 72 | 73 | static void putpixel(unsigned char* screen, int x,int y, int color) { 74 | unsigned where = x*3 + y*768*4; 75 | screen[where] = color & 255; // BLUE 76 | screen[where + 1] = (color >> 8) & 255; // GREEN 77 | screen[where + 2] = (color >> 16) & 255; // RED 78 | } 79 | -------------------------------------------------------------------------------- /stage2/vga.c: -------------------------------------------------------------------------------- 1 | /* 2 | vga.c 3 | =============================================================================== 4 | MIT License 5 | Copyright (c) 2007-2016 Michael Lazear 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in all 15 | copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | SOFTWARE. 24 | =============================================================================== 25 | Implementation of text-mode vga driver for baremetal 26 | */ 27 | 28 | #include "defs.h" 29 | 30 | char* VGA_MEMORY = 0x000B8000; 31 | 32 | int CURRENT_X = 0; 33 | int CURRENT_Y = 0; 34 | int CURRENT_ATTRIB = VGA_COLOR(VGA_WHITE, VGA_BLACK); 35 | 36 | int vga_current_x() { return CURRENT_X; } 37 | int vga_current_y() { return CURRENT_Y; } 38 | 39 | /* Move the screen's cursor to the specified pos and line 40 | * x is the char position, y is the line */ 41 | void vga_move_cursor( uint16_t x, uint16_t y ) { 42 | unsigned temp; 43 | temp = (y * 80) + x; 44 | 45 | outb(0x3D4, 14); 46 | outb(0x3D5, temp >> 8); 47 | outb(0x3D4, 15); 48 | outb(0x3D5, temp); 49 | } 50 | 51 | void vga_update_cursor() { 52 | vga_move_cursor(CURRENT_X/2, CURRENT_Y); 53 | } 54 | 55 | void vga_setcolor(int color) { 56 | CURRENT_ATTRIB = color; 57 | } 58 | 59 | void vga_clear() { 60 | char* vga_address = VGA_MEMORY; 61 | 62 | const long size = 80 * 25; 63 | for (long i = 0; i < size; i++ ) { 64 | *vga_address++ = 0; // character value 65 | *vga_address++ = CURRENT_ATTRIB; // color value 66 | } 67 | CURRENT_Y = 0; 68 | CURRENT_X = 0; 69 | } 70 | 71 | /* Scroll the screen up one line */ 72 | void vga_scroll() 73 | { 74 | if( CURRENT_Y >= 25) 75 | { 76 | uint8_t* vga_addr = VGA_MEMORY; 77 | uint8_t temp = CURRENT_Y - 24; 78 | memcpy(vga_addr, vga_addr + temp * 160, (25 - temp) * 160 * 2); 79 | //memset(vga_addr + 24 * 160, 0, 160); 80 | CURRENT_Y = 24; 81 | } 82 | vga_update_cursor(); 83 | } 84 | 85 | void vga_overwrite_color(int color, int start_x, int start_y, int end_x, int end_y) { 86 | char *vga_address = VGA_MEMORY; 87 | int sizeend = 2*end_x + (160* start_y); 88 | //const uint32_t size = 80*25; 89 | 90 | for (int i = (start_x+1 + (160*start_y)); i < sizeend; i += 2) { 91 | 92 | vga_address[i] = color; 93 | } 94 | } 95 | 96 | // kernel level putc, designate x and y position 97 | void vga_kputc(char c, int x, int y) { 98 | char *vga_address = VGA_MEMORY + (x + y * 160); 99 | if (isascii(c)) 100 | *vga_address = c | (CURRENT_ATTRIB << 8); 101 | } 102 | 103 | void vga_kputs(char* s, int x, int y) { 104 | int i = 0; 105 | while (*s != 0) { 106 | vga_kputc(*s, x+=2, y); 107 | s++; 108 | 109 | } 110 | } 111 | 112 | void vga_puts(char* s) { 113 | int i = 0; 114 | while (*s != 0) { 115 | vga_putc(*s); 116 | *s++; 117 | 118 | } 119 | } 120 | 121 | // Automatically update text position, used in vga_puts 122 | void vga_putc(char c) { 123 | if (c == '\n') { 124 | CURRENT_Y += 1; 125 | CURRENT_X = 0; 126 | return; 127 | } 128 | if (c == '\b') { 129 | CURRENT_X -= 2; 130 | vga_kputc(' ', CURRENT_X, CURRENT_Y); 131 | return; 132 | } 133 | if (c == '\t') { 134 | while(CURRENT_X % 16) 135 | CURRENT_X++; 136 | CURRENT_X += 2; 137 | 138 | if (CURRENT_X >= 160) { 139 | CURRENT_X = 0; 140 | CURRENT_Y += 1; 141 | } 142 | return; 143 | } 144 | if (c=='\q') { 145 | 146 | } 147 | vga_kputc(c, CURRENT_X, CURRENT_Y); 148 | CURRENT_X += 2; 149 | if (CURRENT_X >= 160) { 150 | CURRENT_X = 0; 151 | CURRENT_Y += 1; 152 | } 153 | vga_scroll(); 154 | 155 | } 156 | 157 | void vga_pretty(char* s, int color) { 158 | int start_x = CURRENT_X; 159 | int start_y = CURRENT_Y; 160 | 161 | vga_puts(s); 162 | 163 | vga_overwrite_color(color, start_x, start_y, 80, CURRENT_Y); 164 | 165 | } 166 | 167 | void printx(char* msg, uint32_t i) { 168 | vga_puts(msg); 169 | vga_puts(itoa(i, 16)); 170 | vga_putc('\n'); 171 | } --------------------------------------------------------------------------------