Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- eval :; if [ $# -gt 1 ]; then xxd -p -r | dd conv=notrunc bs=1 seek=0$2 of=$1; fi; exit
- ; asmsyntax=nasm for vim
- ; bl.asm
- ;
- ; This is a bootloader that fits into the MBR. It iterates through every
- ; partition until it finds one that is marked bootable. If the partition's
- ; type is 0x8a (from AiR-Boot) it loads a Linux bzImage. Otherwise it
- ; chainloads the first sector.
- ;
- ; The bootloader supports partitions starting at above or being larger than
- ; 2 TiB using an extension to the partition table where if bit 6 (0x40) of
- ; the 'status' field is set, the fields 'chs' and 'chs_end' become the higher
- ; bytes of the lba start address and size, respectively. I know of no
- ; partitioning tool which supports this, however.
- ;
- ; The code being limited to 446 bytes, no configuration is supported. Since
- ; you can't pass any parameters to the kernel, you have to configure it by
- ; manually editing the fields of its header in the bzImage file. The short
- ; shell script line above helps with this.
- ;
- ; $ echo aa bb | sh bl.asm <file> <offset>
- ;
- ; This will write the two bytes 0xaa 0xbb to the file <file> at offset
- ; <offset> (in decimal). Trying to boot without setting a root device will
- ; give you some lines like:
- ;
- ; 0300 36065 hda driver: ide-gd
- ; 0301 16033 hda1
- ;
- ; To boot from device 0301, do:
- ;
- ; $ echo 01 03 | sh bl.asm bzImage 508 # little-endian
- ;
- ; That should be all you need, but all of the header fields are available in
- ; Documentation/x86/boot.txt of the kernel sources.
- ;
- ; To install:
- ; # nasm bl.asm
- ; # dd conv=notrunc if=bl of=/dev/drive
- ;
- ; We also have to enable the boot signature as bl.asm doesn't contain it or it
- ; would overwrite the partition table.
- ; # echo 55aa | sh bl.asm /dev/drive 510
- ;
- ; Installing the kernel:
- ; # fdisk /dev/device # Mark the partition bootable and set its type to 0x8a.
- ; # dd conv=notrunc if=bzImage of=/dev/device_partition
- ;
- ; You also have to make sure that the kernel partition has the bootable flag on
- ; and has partition type 0x8a. The warning about an ancient bootloader is
- ; normal. Don't use this on kernels older than 2.6.14.
- ;
- ; An 'e' is printed if your BIOS lacks LBA support or there is no bootable
- ; partition. A hang can mean that your computer lacks fast A20 or that the
- ; kernel overwrote reserved memory. Try making your kernel smaller. I get
- ; roughly 7 MiB on my hardware but unlimited in QEMU (a recent bzImage can be
- ; anything between 2 and 30 MiB.
- [BITS 16]
- [ORG 0x7e00]
- PE equ 1
- BOOTABLE equ 0x80
- BIG equ 0x40
- ; Describes a disc address packet for int 13h extended read sectors from drive.
- struc dap
- .size resb 1
- .res0 resb 1
- .len resb 1
- .res1 resb 1
- .offset resw 1
- .segment resw 1
- .lba resq 1
- endstruc
- ; Describes a record in the MBR partition table
- struc prec
- .status resb 1
- .chs resb 3
- .type resb 1
- .chs_end resb 3
- .lba resd 1
- .lba_end resd 1
- endstruc
- ; The first part of the bzImage header. See Linux Documentation/x86/boot.txt.
- struc bzImage
- .code resb 0x1f1
- .setup_sects resb 1
- .root_flags resw 1
- .syssize resd 1
- .ram_size resw 1
- .vid_mode resw 1
- .root_dev resw 1
- .boot_flag resw 1
- .jump resb 2
- .header resd 1
- .version resw 1
- endstruc
- ; dl remains the boot device (usually 0x80) throughout the code.
- intro:
- ; Set up segments and stack.
- xor ax, ax
- mov ds, ax
- mov es, ax
- mov ss, ax
- mov sp, 0x9c00
- ; Move code out of the way for chainloading (to just after this, 0x7e00)
- mov cx, 0x100
- lea si, [ds:0x7c00]
- lea di, [es:0x7e00]
- rep movsw
- ; Move to proper code
- jmp 0x0:start
- start:
- ; Check for BIOS LBA support
- mov ah, 0x41
- mov bx, 0x55aa
- int 0x13
- jc no_pc
- ; Fast A20 enable.
- in al, 0x92
- or al, 0x02
- out 0x92, al
- ; Enable unreal mode, allowing us to access all 4 GiB of memory.
- cli
- push ds
- push es
- lgdt [gdt]
- ; Enable protected mode
- mov eax, cr0
- or al, PE
- mov cr0, eax
- ; Load ds segment register
- mov bx, 0x08
- mov ds, bx
- mov es, bx
- ; Leave protected mode
- and al, ~PE
- mov cr0, eax
- pop es
- pop ds
- sti
- load_mbr:
- ; Try to boot one of the four primary partitions.
- xor ecx, ecx
- xor edi, edi
- mov cx, 4
- mov bx, partitions
- .try:
- mov al, [bx+prec.type]
- test al, al
- jz .next
- cmp al, 0x05
- je .extended
- ; Primary partition. Try loading.
- call load_partition
- jmp .next
- .ext_err:
- call pop_lba
- jmp .ext_out
- .extended:
- ; This is an extended partition. Iterate through all logical partitions.
- pusha
- call push_lba
- call add_lba
- ; LBA is the first EBR at this point.
- call push_lba
- jmp .ext_first
- .ext_next:
- ; LBA is the first EBR and the bx record is the link partition entry.
- call push_lba
- call add_lba
- .ext_first:
- ; Load EBR.
- mov cl, 1
- mov di, 0x1200
- call push_lba
- call read_sects
- jc .ext_err
- call pop_lba
- mov bx, 0x1200+0x1be
- call load_partition
- call pop_lba
- add bx, prec_size
- cmp byte[bx+prec.type], 0
- jne .ext_next
- .ext_out:
- call pop_lba
- popa
- .next:
- add bx, prec_size
- loop .try
- ; There is no bootable OS (no partition marked bootable).
- ; The computer hardware is unsupported (BIOS A20 or LBA missing).
- no_pc:
- ; Print an 'e'.
- mov ax, 0x0e65
- int 0x10
- ; Wait for a key press.
- xor ax, ax
- int 0x16
- ; Reboot.
- int 0x19
- jmp $
- ; Destroys bp
- push_lba:
- pop bp
- push dword[LBA]
- push dword[LBA+4]
- push bp
- ret
- ; Destroys bp
- pop_lba:
- pop bp
- pop dword[LBA+4]
- pop dword[LBA]
- push bp
- ret
- ; We have, in bx, a primary or logical partition record.
- load_partition:
- ; Add the start sector from the partition record to [LBA]. We add instead of
- ; just replace because logical partitions have an offset relative to the
- ; start of the extended partition.
- call add_lba
- xor ecx, ecx
- mov cl, 1
- xor edi, edi
- ; Check bootable flag
- test byte[bx+prec.status], BOOTABLE
- jz .out
- ; Check for linux bzImage partition (type 0x8a, first defined by AiR-Boot).
- cmp byte[bx+prec.type], 0x8a
- jne .chainload
- ; Load kernel boot sector and bzImage header.
- mov edi, 0x90000
- call read_sects
- jc .out
- ; Load rest of kernel real-mode setup code to 0x90200.
- a32 mov cl, [0x90000+bzImage.setup_sects]
- call read_sects
- jc .out
- ; Load protected-mode kernel to 0x100000.
- a32 mov ecx, [0x90000+bzImage.syssize]
- shr ecx, 5
- inc ecx
- mov edi, 0x100000
- call read_sects
- jc .out
- ; Invoke kernel.
- mov ax, 0x9000
- mov ds, ax
- mov es, ax
- mov ss, ax
- jmp 0x9020:0x00
- .chainload:
- ; Generic partition; chainload.
- mov di, 0x7c00
- call read_sects
- jc .out
- ; We could check for 55aa here but we don't care.
- jmp 0x7c0:0x00
- .out:
- ret
- .ebr_adr db 0x1200/0x200
- ; Add partition (at bx) start sector to [LBA]. Destroys eax.
- add_lba:
- mov eax, [bx+prec.lba]
- add [LBA], eax
- ; Save carry for adc below.
- lahf
- xor eax, eax
- test byte[bx+prec.status], BIG
- jz .simple
- ; Extended partition offset. Use the three bytes traditionally reserved for
- ; CHS as the upper bytes of the LBA if bit 6 (0x40) in prec.status is set.
- mov eax, [bx+prec.chs]
- and eax, 0x00ffffff
- .simple:
- sahf
- adc [LBA+4], eax
- ret
- read_sects:
- ; Read ecx sectors of drive dl starting at [LBA] to the buffer at edi. edi
- ; and [LBA] are updated. ecx and esi are destroyed.
- .sector:
- call read_sector
- jc .out
- push ecx
- ; Move sector data from low memory (0x1000) to edi.
- mov esi, 0x1000
- mov ecx, 0x200/4
- ; edi is also updated by this.
- a32 rep movsd
- ; Increment qword[LBA], one word at a time.
- mov si, LBA-2
- .next:
- add si, 2
- mov ax, [si]
- inc ax
- mov [si], ax
- jz .next
- pop ecx
- a32 loop .sector
- .out:
- ret
- read_sector:
- ; Read a sector from hard drive dl into 0x1000. Specify sector by
- ; directly changing [LBA].
- pusha
- mov cx, 5
- .retry:
- mov ah, 0x42
- mov si, read_dap
- int 0x13
- jnc .out
- loop .retry
- .out:
- popa
- ret
- read_dap istruc dap
- at dap.size, db 0x10
- at dap.len, db 1
- at dap.offset, dw 0x1000
- at dap.segment, dw 0x0
- iend
- LBA equ read_dap+dap.lba
- gdt:
- ; This is the unused null descriptor. It doubles as the lgdt argument.
- dw .end - gdt - 1
- dd gdt
- dw 0
- .flat:
- ; Flat descriptor
- dw 0x07ff, 0x0000, 0x9200, 0x00c0
- .end:
- ; Make sure the boot code won't be too long.
- times 446-($-$$) db 0
- partitions:
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement