Ver código fonte

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
Andreas Kling 6 anos atrás
pai
commit
ee4d7c18c8
7 arquivos alterados com 81 adições e 293 exclusões
  1. 1 2
      Kernel/.gitignore
  2. 64 0
      Kernel/Boot/boot.S
  3. 0 252
      Kernel/Boot/boot.asm
  4. 9 17
      Kernel/Makefile
  5. 1 1
      Kernel/init.cpp
  6. 2 17
      Kernel/linker.ld
  7. 4 4
      Kernel/run

+ 1 - 2
Kernel/.gitignore

@@ -1,7 +1,6 @@
 *.o
 *.o
 *.d
 *.d
-.floppy-image
-Boot/boot.bin
+Boot/boot.ao
 kernel
 kernel
 kernel.map
 kernel.map
 _fs_contents
 _fs_contents

+ 64 - 0
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."

+ 0 - 252
Kernel/Boot/boot.asm

@@ -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

+ 9 - 17
Kernel/Makefile

@@ -1,5 +1,4 @@
 KERNEL_OBJS = \
 KERNEL_OBJS = \
-       _start.o \
        init.o \
        init.o \
        kmalloc.o \
        kmalloc.o \
        StdLib.o \
        StdLib.o \
@@ -65,12 +64,10 @@ AK_OBJS = \
     ../AK/FileSystemPath.o \
     ../AK/FileSystemPath.o \
     ../AK/StdLibExtras.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
 KERNEL = kernel
-BOOTLOADER = Boot/boot.bin
-IMAGE = .floppy-image
 ARCH_FLAGS =
 ARCH_FLAGS =
 STANDARD_FLAGS = -std=c++17 -nostdinc++ -nostdlib -nostdinc
 STANDARD_FLAGS = -std=c++17 -nostdinc++ -nostdlib -nostdinc
 KERNEL_FLAGS =
 KERNEL_FLAGS =
@@ -87,9 +84,10 @@ CXXFLAGS = -MMD -MP $(WARNING_FLAGS) $(OPTIMIZATION_FLAGS) $(KERNEL_FLAGS) $(FLA
 #CXX = clang $(CLANG_FLAGS)
 #CXX = clang $(CLANG_FLAGS)
 CXX = i686-elf-g++
 CXX = i686-elf-g++
 LD = i686-elf-ld
 LD = i686-elf-ld
+AS = i686-elf-as
 LDFLAGS = -T linker.ld
 LDFLAGS = -T linker.ld
 
 
-all: $(KERNEL) $(IMAGE) kernel.map
+all: $(KERNEL) kernel.map
 
 
 kernel.map: kernel
 kernel.map: kernel
 	@echo "MKMAP $@"; sh mkmap.sh
 	@echo "MKMAP $@"; sh mkmap.sh
@@ -97,20 +95,14 @@ kernel.map: kernel
 $(KERNEL): $(OBJS)
 $(KERNEL): $(OBJS)
 	@echo "LD $@"; $(LD) $(LDFLAGS) -o $@ -Ttext 0x10000 $(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:
 .cpp.o:
 	@echo "CXX $<"; $(CXX) $(CXXFLAGS) -o $@ -c $<
 	@echo "CXX $<"; $(CXX) $(CXXFLAGS) -o $@ -c $<
 
 
--include $(OBJS:%.o=%.d)
+%.ao: %.S
+	@echo "AS $@"; $(AS) -o $@  $<
+
+-include $(CXX_OBJS:%.o=%.d)
 
 
 clean:
 clean:
-	@echo "CLEAN"; rm -f $(KERNEL) $(OBJS) $(BOOTLOADER) $(IMAGE) *.d
+	@echo "CLEAN"; rm -f $(KERNEL) $(OBJS) *.d
 
 

+ 1 - 1
Kernel/init.cpp

@@ -136,7 +136,7 @@ VFS* vfs;
     ASSERT_NOT_REACHED();
     ASSERT_NOT_REACHED();
 }
 }
 
 
-[[noreturn]] void init()
+extern "C" [[noreturn]] void init()
 {
 {
     cli();
     cli();
 
 

+ 2 - 17
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
 SECTIONS
 {
 {
-	/* Begin putting sections at 1 MiB, a conventional place for kernels to be
-	   loaded at by the bootloader. */
 	. = 0x10000;
 	. = 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)
 	.text BLOCK(4K) : ALIGN(4K)
 	{
 	{
-        _start.o
+        Boot/boot.ao
 		*(.multiboot)
 		*(.multiboot)
 		*(.text)
 		*(.text)
 	}
 	}
 
 
-	/* Read-only data. */
 	.rodata BLOCK(4K) : ALIGN(4K)
 	.rodata BLOCK(4K) : ALIGN(4K)
 	{
 	{
 		*(.rodata)
 		*(.rodata)
 	}
 	}
 
 
-	/* Read-write data (initialized) */
 	.data BLOCK(4K) : ALIGN(4K)
 	.data BLOCK(4K) : ALIGN(4K)
 	{
 	{
 		*(.data)
 		*(.data)
 	}
 	}
 
 
-	/* Read-write data (uninitialized) and stack */
 	.bss BLOCK(4K) : ALIGN(4K)
 	.bss BLOCK(4K) : ALIGN(4K)
 	{
 	{
 		*(COMMON)
 		*(COMMON)
 		*(.bss)
 		*(.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. */
 }
 }

+ 4 - 4
Kernel/run

@@ -7,17 +7,17 @@ if [ "$1" = "b" ]; then
     bochs -q -f .bochsrc
     bochs -q -f .bochsrc
 elif [ "$1" = "qn" ]; then
 elif [ "$1" = "qn" ]; then
     # ./run qn: qemu without network
     # ./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
 elif [ "$1" = "qtap" ]; then
     # ./run qtap: qemu with tap
     # ./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
 else
     # ./run: qemu with user networking
     # ./run: qemu with user networking
     qemu-system-i386 -s -m $ram_size \
     qemu-system-i386 -s -m $ram_size \
         -object filter-dump,id=hue,netdev=breh,file=e1000.pcap \
         -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 \
         -netdev user,id=breh,hostfwd=tcp:127.0.0.1:8888-192.168.5.2:8888 \
         -device e1000,netdev=breh \
         -device e1000,netdev=breh \
-        -drive format=raw,file=.floppy-image,if=floppy \
-        -drive format=raw,file=_fs_contents
+        -kernel kernel \
+        -hda _fs_contents
 fi
 fi