diff options
author | Andreas Kling <awesomekling@gmail.com> | 2019-04-01 21:43:07 +0200 |
---|---|---|
committer | Andreas Kling <awesomekling@gmail.com> | 2019-04-01 21:43:07 +0200 |
commit | ee4d7c18c8a1a2d4b43261c751c238f35c90a232 (patch) | |
tree | d5ca240f3a946d971f0e4b3f63ee24660ca33ce2 | |
parent | d5a9f4596b3e1a8ab388ecdc8501f08f25d1a087 (diff) | |
download | serenity-ee4d7c18c8a1a2d4b43261c751c238f35c90a232.zip |
Kernel: Use a multiboot header instead of a convoluted two-part bootloader.
The old bootloader was hilariously complicated, requiring a floppy disk with
the kernel on it, and a hard drive with the file system. This patch removes
the floppy disk from the equation and replaces it with a multiboot header.
This means the kernel can now be booted with qemu-system-i386 -kernel kernel
-rw-r--r-- | Kernel/.gitignore | 3 | ||||
-rw-r--r-- | Kernel/Boot/boot.S | 64 | ||||
-rwxr-xr-x | Kernel/Boot/boot.asm | 252 | ||||
-rw-r--r-- | Kernel/Makefile | 26 | ||||
-rw-r--r-- | Kernel/init.cpp | 2 | ||||
-rw-r--r-- | Kernel/linker.ld | 19 | ||||
-rwxr-xr-x | Kernel/run | 8 |
7 files changed, 81 insertions, 293 deletions
diff --git a/Kernel/.gitignore b/Kernel/.gitignore index 2057bb9bd0..95057be2ee 100644 --- a/Kernel/.gitignore +++ b/Kernel/.gitignore @@ -1,7 +1,6 @@ *.o *.d -.floppy-image -Boot/boot.bin +Boot/boot.ao kernel kernel.map _fs_contents diff --git a/Kernel/Boot/boot.S b/Kernel/Boot/boot.S new file mode 100644 index 0000000000..694d53f9f1 --- /dev/null +++ b/Kernel/Boot/boot.S @@ -0,0 +1,64 @@ +.set MULTIBOOT_MAGIC, 0x1badb002 +.set MULTIBOOT_PAGE_ALIGN, 0x1 +.set MULTIBOOT_MEMORY_INFO, 0x2 +.set MULTIBOOT_VIDEO_MODE, 0x4 +.set multiboot_flags, MULTIBOOT_PAGE_ALIGN | MULTIBOOT_MEMORY_INFO | MULTIBOOT_VIDEO_MODE +.set multiboot_checksum, -(MULTIBOOT_MAGIC + multiboot_flags) + +.section .multiboot +.align 4 + +.long MULTIBOOT_MAGIC +.long multiboot_flags +.long multiboot_checksum + + +/* for MULTIBOOT_MEMORY_INFO */ +.long 0x00000000 /* header_addr */ +.long 0x00000000 /* load_addr */ +.long 0x00000000 /* load_end_addr */ +.long 0x00000000 /* bss_end_addr */ +.long 0x00000000 /* entry_addr */ + +/* for MULTIBOOT_VIDEO_MODE */ +.long 0x00000000 /* mode_type */ +.long 0 /* width */ +.long 0 /* height */ +.long 32 /* depth */ + +.section .stack, "aw", @nobits +stack_bottom: +.skip 32768 +stack_top: + +.section .text + +.global start +.type start, @function + +.extern init +.type init, @function + +start: + mov $stack_top, %esp + + and $-16, %esp + + pushl %esp + pushl %eax /* Multiboot header magic */ + pushl %ebx /* Multiboot header pointer */ + + cli + call init + + pushl $exit_message + call kprintf + + cli + +loop: + hlt + jmp loop + +exit_message: + .asciz "Kernel exited." diff --git a/Kernel/Boot/boot.asm b/Kernel/Boot/boot.asm deleted file mode 100755 index bdcfcb7a74..0000000000 --- a/Kernel/Boot/boot.asm +++ /dev/null @@ -1,252 +0,0 @@ -; asmsyntax=nasm - -[org 0x7c00] -[bits 16] - -boot: - cli - mov ax, 0x8000 - mov ss, ax - mov sp, 0xffff - - push cs - pop ds - xor bx, bx - mov ah, 0x0e - mov si, message - lodsb -.lewp: - int 0x10 - lodsb - cmp al, 0 - jne .lewp - - ; Enable A20 - mov ax, 0x2401 - int 0x15 - - ; HACK: Load the ELF kernel at 0xf000. Assuming that the first - ; LOAD header has a file offset of 0x1000, this puts _start - ; at 0x10000 which we jump to later. - ; This is all quite rickety. - mov bx, 0xf00 - mov es, bx - xor bx, bx - - mov cx, word [cur_lba] -.sector_loop: - call convert_lba_to_chs - - mov ah, 0x02 ; cmd 0x02 - Read Disk Sectors - mov al, 1 ; 1 sector at a time - mov dl, 0 ; drive 0 (fd0) - int 0x13 - - jc fug - - mov ah, 0x0e - mov al, '.' - int 0x10 - - inc word [cur_lba] - mov cx, word [cur_lba] - cmp cx, 900 - jz .sector_loop_end - - mov bx, es - add bx, 0x20 - mov es, bx - xor bx, bx - - jmp .sector_loop - -.sector_loop_end: - - call durk - - ; Turn off the floppy motor. - mov dx, 0x3f2 - xor al, al - out dx, al - - ; Let's look at the ELF header. - mov bx, 0xf00 - mov fs, bx - cmp [fs:0], dword 0x464c457f ; ELF magic: { 0x7f "ELF" } - jne fug - - cmp [fs:24], dword 0x10000 ; Entry should be 0x10000 - jne fug - - mov ebx, dword [fs:28] ; EBX <- program header table - mov ecx, dword [fs:44] ; ECX <- program header count - -; Let's find the BSS and clear it. - -parse_program_header: - cmp [fs:ebx], dword 0x1 ; Is Load segment? - jne .next - - cmp [fs:ebx+24], dword 0x6 ; Is read+write but not execute? - jne .next - - mov edi, [fs:ebx+8] ; EDI <- p_vaddr - add edi, [fs:ebx+16] ; skip over 'p_filesz' bytes (leave them intact) - - push ecx - - sub edi, [fs:ebx+16] ; skip over 'p_filesz' bytes (see above) - - ; Since we're in 16-bit real mode, create a segment address. - mov eax, edi - shr eax, 4 - mov es, ax - and edi, 0xf - - mov ecx, [fs:ebx+20] ; ECX <- p_memsz - xor al, al - rep stosb - - pop ecx - -.next: - add ebx, 32 - loop parse_program_header - -; Okay we're all set to go! - -lets_go: - lgdt [cs:test_gdt_ptr] - - mov eax, cr0 - or al, 1 - mov cr0, eax - - jmp 0x08:pmode - -durk: - push cs - pop ds - xor bx, bx - mov ah, 0x0e - mov si, msg_sectors_loaded - lodsb -.lewp: - int 0x10 - lodsb - cmp al, 0 - jne .lewp - ret - -pmode: -[bits 32] - mov ax, 0x10 - mov ds, ax - mov es, ax - mov fs, ax - mov gs, ax - - mov ss, ax - mov esp, 0x4000 - - xor eax, eax - xor ebx, ebx - xor ecx, ecx - xor edx, edx - xor ebp, ebp - xor esi, esi - xor edi, edi - - jmp 0x10000 - - hlt - -test_gdt_ptr: - dw (test_gdt_end-test_gdt) - dd test_gdt - -test_gdt: - dd 0 - dd 0 - dd 0x0000ffff - dd 0x00cf9a00 - dd 0x0000ffff - dd 0x00cf9200 - dd 0 - dd 0 - dd 0 - dd 0 -test_gdt_end: - -[bits 16] -fug: - xor bx, bx - mov ah, 0x0e - mov si, fug_message - lodsb -.lewp: - int 0x10 - lodsb - cmp al, 0 - jne .lewp - - cli - hlt - -; Input: -; -; AX = LBA -; -; Output: -; -; CX and DH = C/H/S address formatted for Int13,2 - -; CL = sector (LBA % sectors_per_track) + 1 -; -; 1.44M floppy stats: -; (sectors_per_track: 18) -; (heads: 2) -; (sectors: 2880) - -convert_lba_to_chs: - mov ax, cx - - ; AX = LBA/spt, DX = LBA%spt - xor dx, dx - div word [sectors_per_track] - - ; CL = sector (LBA % sectors_per_track) + 1 - mov cl, dl - inc cl - - ; CH = track (LBA / sectors_per_track) / heads - mov ch, al - shr ch, 1 - - ; AX = (LBA/spt)/heads, DX = (LBA/spt)%heads - xor dx, dx - div word [heads] - - ; DH = sector (LBA / sectors_per_track) % heads - mov dh, dl - - ret - -cur_lba: - dw 1 -sectors_per_track: - dw 18 -heads: - dw 2 - -msg_sectors_loaded: - db "done!", 0x0d, 0x0a, 0 - -message: - db "Loading kernel", 0 - -fug_message: - db "FUG!", 0x0d, 0x0a, 0 - -times 510-($-$$) db 0 -dw 0xaa55 diff --git a/Kernel/Makefile b/Kernel/Makefile index c57ac37d9c..98826d5628 100644 --- a/Kernel/Makefile +++ b/Kernel/Makefile @@ -1,5 +1,4 @@ KERNEL_OBJS = \ - _start.o \ init.o \ kmalloc.o \ StdLib.o \ @@ -65,12 +64,10 @@ AK_OBJS = \ ../AK/FileSystemPath.o \ ../AK/StdLibExtras.o -OBJS = $(KERNEL_OBJS) $(VFS_OBJS) $(AK_OBJS) +CXX_OBJS = $(KERNEL_OBJS) $(VFS_OBJS) $(AK_OBJS) +OBJS = $(CXX_OBJS) Boot/boot.ao -NASM = nasm KERNEL = kernel -BOOTLOADER = Boot/boot.bin -IMAGE = .floppy-image ARCH_FLAGS = STANDARD_FLAGS = -std=c++17 -nostdinc++ -nostdlib -nostdinc KERNEL_FLAGS = @@ -87,9 +84,10 @@ CXXFLAGS = -MMD -MP $(WARNING_FLAGS) $(OPTIMIZATION_FLAGS) $(KERNEL_FLAGS) $(FLA #CXX = clang $(CLANG_FLAGS) CXX = i686-elf-g++ LD = i686-elf-ld +AS = i686-elf-as LDFLAGS = -T linker.ld -all: $(KERNEL) $(IMAGE) kernel.map +all: $(KERNEL) kernel.map kernel.map: kernel @echo "MKMAP $@"; sh mkmap.sh @@ -97,20 +95,14 @@ kernel.map: kernel $(KERNEL): $(OBJS) @echo "LD $@"; $(LD) $(LDFLAGS) -o $@ -Ttext 0x10000 $(OBJS) -$(IMAGE): $(KERNEL) $(BOOTLOADER) - @echo "CREATE $@"; cat $(BOOTLOADER) $(KERNEL) > .tmp-floppy-image - @dd if=/dev/zero bs=2M count=1 >> .tmp-floppy-image 2> /dev/null - @dd if=.tmp-floppy-image of=.floppy-image bs=1440k count=1 2>/dev/null - @rm -f .tmp-floppy-image - -$(BOOTLOADER): Boot/boot.asm - @echo "NASM $<"; $(NASM) -f bin -o $@ $< - .cpp.o: @echo "CXX $<"; $(CXX) $(CXXFLAGS) -o $@ -c $< --include $(OBJS:%.o=%.d) +%.ao: %.S + @echo "AS $@"; $(AS) -o $@ $< + +-include $(CXX_OBJS:%.o=%.d) clean: - @echo "CLEAN"; rm -f $(KERNEL) $(OBJS) $(BOOTLOADER) $(IMAGE) *.d + @echo "CLEAN"; rm -f $(KERNEL) $(OBJS) *.d diff --git a/Kernel/init.cpp b/Kernel/init.cpp index d9f4c77d57..c91d5235e3 100644 --- a/Kernel/init.cpp +++ b/Kernel/init.cpp @@ -136,7 +136,7 @@ VFS* vfs; ASSERT_NOT_REACHED(); } -[[noreturn]] void init() +extern "C" [[noreturn]] void init() { cli(); diff --git a/Kernel/linker.ld b/Kernel/linker.ld index c86217cc94..ef808a575c 100644 --- a/Kernel/linker.ld +++ b/Kernel/linker.ld @@ -1,44 +1,29 @@ -/* The bootloader will look at this image and start execution at the symbol - designated as the entry point. */ -ENTRY(_start) +ENTRY(start) -/* Tell where the various sections of the object files will be put in the final - kernel image. */ SECTIONS { - /* Begin putting sections at 1 MiB, a conventional place for kernels to be - loaded at by the bootloader. */ . = 0x10000; - /* First put the multiboot header, as it is required to be put very early - early in the image or the bootloader won't recognize the file format. - Next we'll put the .text section. */ .text BLOCK(4K) : ALIGN(4K) { - _start.o + Boot/boot.ao *(.multiboot) *(.text) } - /* Read-only data. */ .rodata BLOCK(4K) : ALIGN(4K) { *(.rodata) } - /* Read-write data (initialized) */ .data BLOCK(4K) : ALIGN(4K) { *(.data) } - /* Read-write data (uninitialized) and stack */ .bss BLOCK(4K) : ALIGN(4K) { *(COMMON) *(.bss) } - - /* The compiler may produce other sections, by default it will put them in - a segment with the same name. Simply add stuff here as needed. */ } diff --git a/Kernel/run b/Kernel/run index b380e46321..640f7bdb95 100755 --- a/Kernel/run +++ b/Kernel/run @@ -7,17 +7,17 @@ if [ "$1" = "b" ]; then bochs -q -f .bochsrc elif [ "$1" = "qn" ]; then # ./run qn: qemu without network - qemu-system-i386 -s -m $ram_size -device e1000 -drive format=raw,file=.floppy-image,if=floppy -drive format=raw,file=_fs_contents #$@ + qemu-system-i386 -s -m $ram_size -device e1000 -kernel kernel -hda _fs_contents elif [ "$1" = "qtap" ]; then # ./run qtap: qemu with tap - sudo qemu-system-i386 -s -m $ram_size -object filter-dump,id=hue,netdev=br0,file=e1000.pcap -netdev tap,ifname=tap0,id=br0 -device e1000,netdev=br0 -drive format=raw,file=.floppy-image,if=floppy -drive format=raw,file=_fs_contents + sudo qemu-system-i386 -s -m $ram_size -object filter-dump,id=hue,netdev=br0,file=e1000.pcap -netdev tap,ifname=tap0,id=br0 -device e1000,netdev=br0 -kernel kernel -hda _fs_contents else # ./run: qemu with user networking qemu-system-i386 -s -m $ram_size \ -object filter-dump,id=hue,netdev=breh,file=e1000.pcap \ -netdev user,id=breh,hostfwd=tcp:127.0.0.1:8888-192.168.5.2:8888 \ -device e1000,netdev=breh \ - -drive format=raw,file=.floppy-image,if=floppy \ - -drive format=raw,file=_fs_contents + -kernel kernel \ + -hda _fs_contents fi |