mirror of
https://github.com/RGBCube/serenity
synced 2025-07-19 20:17:40 +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
7 changed files with 81 additions and 293 deletions
3
Kernel/.gitignore
vendored
3
Kernel/.gitignore
vendored
|
@ -1,7 +1,6 @@
|
||||||
*.o
|
*.o
|
||||||
*.d
|
*.d
|
||||||
.floppy-image
|
Boot/boot.ao
|
||||||
Boot/boot.bin
|
|
||||||
kernel
|
kernel
|
||||||
kernel.map
|
kernel.map
|
||||||
_fs_contents
|
_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 = \
|
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
|
||||||
|
|
||||||
|
|
|
@ -136,7 +136,7 @@ VFS* vfs;
|
||||||
ASSERT_NOT_REACHED();
|
ASSERT_NOT_REACHED();
|
||||||
}
|
}
|
||||||
|
|
||||||
[[noreturn]] void init()
|
extern "C" [[noreturn]] void init()
|
||||||
{
|
{
|
||||||
cli();
|
cli();
|
||||||
|
|
||||||
|
|
|
@ -1,44 +1,29 @@
|
||||||
/* The bootloader will look at this image and start execution at the symbol
|
ENTRY(start)
|
||||||
designated as the entry point. */
|
|
||||||
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. */
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 \
|
-kernel kernel \
|
||||||
-drive format=raw,file=_fs_contents
|
-hda _fs_contents
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue