summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJoursoir <chat@joursoir.net>2021-09-28 00:35:39 +0000
committerJoursoir <chat@joursoir.net>2021-09-28 00:35:39 +0000
commit894e61508a09841f9b4a8e81fdd265b2a9eef1fc (patch)
tree346af4fdd5354eaae4ac1b8428809365e185f54b
parentcb7e9420202c64360224a800409e11244657d55b (diff)
downloadmfsos-894e61508a09841f9b4a8e81fdd265b2a9eef1fc.tar.gz
mfsos-894e61508a09841f9b4a8e81fdd265b2a9eef1fc.tar.bz2
mfsos-894e61508a09841f9b4a8e81fdd265b2a9eef1fc.zip
x86/boot: transform one-stage to two-stage bootloader
bootsect.s is first stage bootloader, it loads setup.s setup.s is second stage bootloader, it saves system data and loads kernel to $KERNADDR, then jump to 32-bit startup code
-rw-r--r--arch/x86/boot/bootsect.s128
-rw-r--r--arch/x86/boot/setup.s111
2 files changed, 135 insertions, 104 deletions
diff --git a/arch/x86/boot/bootsect.s b/arch/x86/boot/bootsect.s
index 3410131..a6e274e 100644
--- a/arch/x86/boot/bootsect.s
+++ b/arch/x86/boot/bootsect.s
@@ -1,137 +1,57 @@
-.code16 # Tell GAS to generate 16 bit code
+/*
+ bootsect.s is loaded at 0x7c00 (BIOS likes always to load the boot
+ sector to this address). It is first stage bootloader, it has one
+ task - loads setup.s (second stage) to 0x90000 and jumps there.
+*/
-.global _start # Make the symbol visible to ld
+.code16 # Tell GAS to generate 16 bit code
.include "bios.inc"
+.include "rm_seg.inc"
-# Define some constants for the GDT segment descriptor offsets
-.set CODESEG, gdt_code - gdt_start
-.set DATASEG, gdt_data - gdt_start
-
-.set SYSSEG, 0x1000 # Historical load address
-.set MAGIC, 0xAA55
-
-.section .text.bootentry # Code that will start executing at
- # special address (specified in linker)
+.global _start # Make the symbol visible to ld
_start:
jmp $0x0, $_start2 # Normalize the start address
# CS = 0 and IP = _start2
_start2:
- mov %cs, %ax # AX = CS = 0 (see above)
- mov %ax, %ds # Zero segment registers
+ mov $SDATASEG, %ax # We will store the boot drive at
+ mov %ax, %ds # $SDATASEG in the first byte
+ mov $SETUPSEG, %ax # Do it for disk read routine (see below)
mov %ax, %es
- mov %ax, %ss
- mov %ax, %sp
cld # Set direction flag for incrementing
- mov %dl, boot_drive # BIOS stores our boot drive in DL,
+ mov %dl, (0) # BIOS stores our boot drive in DL,
# so we remember it
+ mov %cs, %ax # AX = CS = 0 (see above)
+ mov %ax, %ds # Zero data segment register
- BIOS_PRINT $boot_real_mode_msg
-
-load_kernel: # Load our kernel
- BIOS_PRINT $boot_load_kern_msg
+load_setup:
+ BIOS_PRINT $load_setup_msg # The routine uses only AX register
mov $0x02, %ah # Set BIOS read sector routine
- mov boot_drive, %dl # Read drive number from $boot_drive
mov $0x00, %ch # Select cylinder 0
mov $0x00, %dh # Select head 0 [has a base of 0]
mov $0x02, %cl # Select sector 2 (next after the
# boot sector) [has a base of 1]
- mov $0x01, %al # Read 1 sectors
- mov $SYSSEG, %bx # Load sectors to ES:BX (0:$SYSSEG)
+ mov $SETUPLEN, %al # Read $SETUPLEN sectors
+ mov $0x0, %bx # Load sectors to ES:BX ($SETUPSEG:0)
int $0x13 # Start reading from drive
jc disk_error # If carry flag set, bios failed to read
- # FIXME: we must compare different register
- cmp %al, %al # If AL(sect. read) != <>(sect. expected)
- jne disk_error # then return disk error
-
-switch_to_pm:
- BIOS_PRINT $boot_prot_mode_msg
- cli # Switch of interrupt until we have set
- # up the protected mode interrupt vector
- lgdt gdt_descriptor # Load our global descriptor table
-
- mov %cr0, %eax # Set the first bit of CR0
- or $0x01, %eax # to make the switch to protected mode
- mov %eax, %cr0
-
- # Make a far jump to our 32-bit code.
- # This also forces the CPU to flush its cache of pre-fetched
- # and real-mode decoded instructions, which can cause problems
- jmp $CODESEG, $init_pm
+ # Make a far jump to our setup code
+ jmp $SETUPSEG, $0x0
disk_error:
BIOS_PRINT $disk_error_msg
jmp .
-.code32
-init_pm:
- mov $DATASEG, %ax # Point segment registers to the
- mov %ax, %ds # data selector we defined in our GDT
- mov %ax, %es
- mov %ax, %ss
- mov %ax, %fs
- mov %ax, %gs
-
- mov $0x90000, %ebp # Update stack position so it is right
- mov %ebp, %esp # at the top of the free space.
-
- jmp . # infinite loop
-
-# Global Descriptor Table (contains 8-byte entries)
-gdt_start:
-gdt_null: # The mandatory null descriptor
- .quad 0x0
-
-gdt_code: # The code segment descriptor
- # Base = 0x0, limit = 0xfffff
- # 1st flags: (present)1 (privilege)00 (descriptor type)1 -> b1001
- # Type flags: (code)1 (conforming)0 (readable)1 (accessed)0 -> b1010
- # 2nd flags: (granularity)1 (size)1 (64-bit seg)0 (AVL)0 -> b1100
- .word 0xffff # Limit (bits 0-15)
- .word 0x0 # Base (bits 0-15)
- .byte 0x0 # Base (bits 16-23)
- .byte 0b10011010 # 1st flags, type flags
- .byte 0b11001111 # 2nd flags, limit (bits 16-19)
- .byte 0x0 # Base (bits 24-31)
-
-gdt_data: # the data segment descriptor
- # Same as code segment except for the type flags:
- # Type flags: (code)0 (direction)0 (writable)1, (accessed)0 -> b0010
- # P.S: direction bit: 0 the segment grows up
- .word 0xffff # Limit (bits 0-15)
- .word 0x0 # Base (bits 0-15)
- .byte 0x0 # Base (bits 16-23)
- .byte 0b10010010 # 1st flags, type flags
- .byte 0b11001111 # 2nd flags, limit (bits 16-19)
- .byte 0x0 # Base (bits 24-31)
-gdt_end:
-
-# Global variables
-boot_drive:
- .byte 0
-
-gdt_descriptor:
- # The 6-byte GDT structure containing:
- # - GDT size, 2 bytes (size always less one of the real size):
- .word gdt_end - gdt_start - 1
- # - GDT address, 4 bytes:
- .long gdt_start
-
-boot_real_mode_msg:
- .asciz "Started mfsos in 16-bit real mode\r\n"
-
-boot_prot_mode_msg:
- .asciz "Entering 32-bit protected mode\r\n"
-
-boot_load_kern_msg:
- .asciz "Loading kernel into memory\r\n"
+load_setup_msg:
+ .asciz "Loading setup sectors\r\n"
disk_error_msg:
.asciz "Disk read error!"
# Bootsector padding
.space 512 - 2 - (. - _start), 0
-.word MAGIC
+boot_flag:
+ .word 0xAA55
diff --git a/arch/x86/boot/setup.s b/arch/x86/boot/setup.s
new file mode 100644
index 0000000..2a0ab15
--- /dev/null
+++ b/arch/x86/boot/setup.s
@@ -0,0 +1,111 @@
+/*
+ setup.s is second stage bootloader loaded at 0x90200 (by
+ first stage), is responsible for getting the system data
+ from the BIOS.
+
+ System data puts at special place: 0x90000-0x901FF.
+*/
+
+.code16 # Tell GAS to generate 16 bit code
+
+.include "bios.inc"
+.include "rm_seg.inc"
+
+# Define some constants for the GDT segment descriptor offsets
+.set CODESEG, gdt_code - gdt_start
+.set DATASEG, gdt_data - gdt_start
+
+.global _start # Make the symbol visible to ld
+_start:
+ mov $SDATASEG, %ax
+ mov %ax, %ds
+ mov $KERNSEG, %ax
+ mov %ax, %es
+
+ BIOS_PRINT $get_data_msg
+ # TODO: get memory size
+ # TODO: get video infos
+
+load_kernel: # Load our kernel
+ BIOS_PRINT $boot_load_kern_msg
+
+ mov $0x02, %ah # Set BIOS read sector routine
+ mov (0), %dl # Read drive boot
+ mov $0x00, %ch # Select cylinder 0
+ mov $0x00, %dh # Select head 0 [has a base of 0]
+ mov $0x02+SETUPLEN, %cl # Select sector 2 (next after the
+ # boot sector) [has a base of 1]
+ mov $0x10, %al # Read 16 sectors
+ mov $0x00, %bx # Load sectors to ES:BX ($KERNSEG:0)
+ int $0x13 # Start reading from drive
+ jc disk_error # If carry flag set, bios failed to read
+
+switch_to_pm:
+ BIOS_PRINT $boot_prot_mode_msg
+ cli # Switch of interrupt until we have set
+ # up the protected mode interrupt vector
+ lgdt gdt_descriptor # Load our global descriptor table
+
+ mov %cr0, %eax # Set the first bit of CR0
+ or $0x01, %eax # to make the switch to protected mode
+ mov %eax, %cr0
+
+ # Make a far jump to our 32-bit code.
+ # This also forces the CPU to flush its cache of pre-fetched
+ # and real-mode decoded instructions, which can cause problems
+ jmp $CODESEG, $KERNADDR
+
+disk_error:
+ BIOS_PRINT $disk_error_msg
+ jmp .
+
+# Global Descriptor Table (contains 8-byte entries)
+gdt_start:
+gdt_null: # The mandatory null descriptor
+ .quad 0x0
+
+gdt_code: # The code segment descriptor
+ # Base = 0x0, limit = 0xfffff
+ # 1st flags: (present)1 (privilege)00 (descriptor type)1 -> b1001
+ # Type flags: (code)1 (conforming)0 (readable)1 (accessed)0 -> b1010
+ # 2nd flags: (granularity)1 (size)1 (64-bit seg)0 (AVL)0 -> b1100
+ .word 0xffff # Limit (bits 0-15)
+ .word 0x0 # Base (bits 0-15)
+ .byte 0x0 # Base (bits 16-23)
+ .byte 0b10011010 # 1st flags, type flags
+ .byte 0b11001111 # 2nd flags, limit (bits 16-19)
+ .byte 0x0 # Base (bits 24-31)
+
+gdt_data: # the data segment descriptor
+ # Same as code segment except for the type flags:
+ # Type flags: (code)0 (direction)0 (writable)1, (accessed)0 -> b0010
+ # P.S: direction bit: 0 the segment grows up
+ .word 0xffff # Limit (bits 0-15)
+ .word 0x0 # Base (bits 0-15)
+ .byte 0x0 # Base (bits 16-23)
+ .byte 0b10010010 # 1st flags, type flags
+ .byte 0b11001111 # 2nd flags, limit (bits 16-19)
+ .byte 0x0 # Base (bits 24-31)
+gdt_end:
+
+# Global variables
+gdt_descriptor:
+ # The 6-byte GDT structure containing:
+ # - GDT size, 2 bytes (size always less one of the real size):
+ .word gdt_end - gdt_start - 1
+ # - GDT address, 4 bytes:
+ .word gdt_start, 0x9
+
+get_data_msg:
+ .asciz "Getting the system data from the BIOS\r\n"
+
+boot_prot_mode_msg:
+ .asciz "Entering 32-bit protected mode\r\n"
+
+boot_load_kern_msg:
+ .asciz "Loading kernel into memory\r\n"
+
+disk_error_msg:
+ .asciz "Disk read error!"
+
+.space (512 * SETUPLEN) - (. - _start), 0