mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-26 01:20:25 +00:00
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
This commit is contained in:
parent
d5a9f4596b
commit
ee4d7c18c8
Notes:
sideshowbarker
2024-07-19 14:51:34 +09:00
Author: https://github.com/awesomekling Commit: https://github.com/SerenityOS/serenity/commit/ee4d7c18c8a
7 changed files with 81 additions and 293 deletions
3
Kernel/.gitignore
vendored
3
Kernel/.gitignore
vendored
|
@ -1,7 +1,6 @@
|
|||
*.o
|
||||
*.d
|
||||
.floppy-image
|
||||
Boot/boot.bin
|
||||
Boot/boot.ao
|
||||
kernel
|
||||
kernel.map
|
||||
_fs_contents
|
||||
|
|
64
Kernel/Boot/boot.S
Normal file
64
Kernel/Boot/boot.S
Normal file
|
@ -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."
|
|
@ -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
|
|
@ -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
|
||||
|
||||
|
|
|
@ -136,7 +136,7 @@ VFS* vfs;
|
|||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
[[noreturn]] void init()
|
||||
extern "C" [[noreturn]] void init()
|
||||
{
|
||||
cli();
|
||||
|
||||
|
|
|
@ -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. */
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
Loading…
Reference in a new issue