You must login to view /gokrazy/internal/commit/cd6fdff7bb1ee08cd95aa24647a802255d6a6f73.
The GitHub option should be usable for most people, it only links via username.

Files
internal/mbr/bootloader.asm
Michael Stapelberg 6ab9fef830 bootloader: fix 15/16 MB kernel size limit
The adc instruction fix was contributed by abbeyj on lobsters (thank you!).

fixes https://github.com/gokrazy/gokrazy/issues/248
2024-08-27 21:00:26 +02:00

252 lines
5.3 KiB
NASM

; Minimal Linux Bootloader
; ========================
; @ author: Sebastian Plotz
; @ version: 1.0
; @ date: 24.07.2012
; Copyright (C) 2012 Sebastian Plotz
; Minimal Linux Bootloader is free software: you can redistribute it and/or modify
; it under the terms of the GNU General Public License as published by
; the Free Software Foundation, either version 3 of the License, or
; (at your option) any later version.
; Minimal Linux Bootloader is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
; GNU General Public License for more details.
; You should have received a copy of the GNU General Public License
; along with Minimal Linux Bootloader. If not, see <http://www.gnu.org/licenses/>.
; Memory layout
; =============
; 0x07c00 - 0x07dff Mininal Linux Bootloader
; + partition table
; + MBR signature
; 0x10000 - 0x17fff Real mode kernel
; 0x18000 - 0x1dfff Stack and heap
; 0x1e000 - 0x1ffff Kernel command line
; 0x20000 - 0x2fdff temporal space for
; protected-mode kernel
; base_ptr = 0x10000
; heap_end = 0xe000
; heap_end_ptr = heap_end - 0x200 = 0xde00
; cmd_line_ptr = base_ptr + heap_end = 0x1e000
; [bits 16] is not necessary when using `nasm bootloader.asm`
; but it becomes necessary when switching to `nasm -f elf32 bootloader.asm`
[bits 16]
; org 0x7c00 is necessary when using `nasm bootloader.asm`
; but it stops working when switching to `nasm -f elf32 bootloader.asm`
;org 0x7c00
cli
xor ax, ax
mov ds, ax
mov ss, ax
mov sp, 0x7c00 ; setup stack ...
mov ax, 0x1000
mov es, ax
sti
read_cmdline:
mov eax, 0x0001 ; load one sector
xor bx, bx ; no offset
mov cx, 0x1e00 ; load Kernel command line at 0x1e000
mov esi, cmd_lba
call read_from_hdd
read_kernel_bootsector:
mov eax, 0x0001 ; load one sector
xor bx, bx ; no offset
mov cx, 0x1000 ; load Kernel boot sector at 0x10000
mov esi, current_lba
call read_from_hdd
read_kernel_setup:
xor eax, eax
mov al, [es:0x1f1] ; no. of sectors to load
cmp ax, 0 ; 4 if setup_sects = 0
jne read_kernel_setup.next
mov ax, 4
.next:
mov bx, 512 ; 512 byte offset
mov cx, 0x1000
mov esi, current_lba
call read_from_hdd
check_version:
cmp word [es:0x206], 0x204 ; we need protocol version >= 2.04
jb error
test byte [es:0x211], 1
jz error
set_header_fields:
mov byte [es:0x210], 0xe1 ; set type_of_loader
or byte [es:0x211], 0x80 ; set CAN_USE_HEAP
mov word [es:0x224], 0xde00 ; set heap_end_ptr
;mov byte [es:0x226], 0x00 ; set ext_loader_ver
mov byte [es:0x227], 0x01 ; set ext_loader_type (bootloader id: 0x11)
mov dword [es:0x228], 0x1e000 ; set cmd_line_ptr
cld ; copy cmd_line
read_protected_mode_kernel:
mov edx, [es:0x1f4] ; edx stores the number of bytes to load
shl edx, 4
.loop:
cmp edx, 0
je run_kernel
cmp edx, 0xfe00 ; less than 127*512 bytes remaining?
jb read_protected_mode_kernel_2
mov eax, 0x7f ; load 127 sectors (maximum)
xor bx, bx ; no offset
mov cx, 0x2000 ; load temporary to 0x20000
mov esi, current_lba
call read_from_hdd
mov cx, 0x7f00 ; move 65024 bytes (127*512 byte)
call do_move
sub edx, 0xfe00 ; update the number of bytes to load
add word [gdt.dest], 0xfe00
adc byte [gdt.dest+2], 0
adc byte [gdt.dest+5], 0
jmp short read_protected_mode_kernel.loop
read_protected_mode_kernel_2:
mov eax, edx
shr eax, 9
test edx, 511
jz read_protected_mode_kernel_2.next
inc eax
.next:
xor bx, bx
mov cx, 0x2000
mov esi, current_lba
call read_from_hdd
mov ecx, edx
shr ecx, 1
call do_move
run_kernel:
cli
mov ax, 0x1000
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
mov sp, 0xe000
jmp 0x1020:0
;; read_from_hdd:
;; ax: count in 512-byte sectors [1, 127]
;; bx: destination: offset
;; cx: destination: segment
;; esi: lba pointer (typically current_lba)
read_from_hdd:
push edx
mov [dap.count], ax
mov [dap.offset], bx
mov [dap.segment], cx
mov edx, [esi]
mov [dap.lba], edx
add [esi], eax ; update current_lba
mov ah, 0x42
mov si, dap
mov dl, 0x80 ; first hard disk
int 0x13
jc error
pop edx
ret
do_move:
push edx
push es
xor ax, ax
mov es, ax
mov ah, 0x87
mov si, gdt
int 0x15
jc error
pop es
pop edx
ret
error:
mov si, error_msg
; This used to be a loop, but we needed space for fixing
; https://github.com/gokrazy/gokrazy/issues/248, so now
; only the first letter (E) is printed on error.
msg_loop:
lodsb
mov ah, 0xe
mov bx, 7
int 0x10
;; fall-through to reboot
;;
;; (The padding is here just to reach 440 bytes.)
nop
reboot:
xor ax, ax
int 0x16
int 0x19
jmp 0xf000:0xfff0 ; BIOS reset code
; Global Descriptor Table
gdt:
times 16 db 0
dw 0xffff ; segment limit
.src:
dw 0
db 2
db 0x93 ; data access rights
dw 0
dw 0xffff ; segment limit
.dest:
dw 0
db 0x10 ; load protected-mode kernel to 100000h
db 0x93 ; data access rights
dw 0
times 16 db 0
; Disk Address Packet
dap:
db 0x10 ; size of DAP
db 0 ; unused
.count:
dw 0 ; number of sectors
.offset:
dw 0 ; destination: offset
.segment:
dw 0 ; destination: segment
.lba:
dd 0 ; low bytes of LBA address
dd 0 ; high bytes of LBA address
error_msg db 'er', 0 ; /* FIXME: newline */
current_lba dd 8218 ; initialize to first LBA address
cmd_lba dd 8218 ; initialize to LBA address of cmdline.txt