Matruck
Matruck

Reputation: 11

Why is my bootloader not working on recent laptops?

I want to do a simple bootloader from scratch. I want it to be able to boot on usb on a recent laptop, meaning it has UEFI boot but theoretically it supports Legacy boot.

So I wrote a little assembly code, which just prints "hello world", and compiled it with nasm -f bin boot.asm -o boot.com Then I built the diskette from the binary with dd. The diskete worked fine with qemu-system-x86_64. I transfered it to the MBR of a usb stick formatted as FAT32 using dd if=boot.bin of=/dev/sda. But when booting on it with my recent computer, the usb doesn't show up in the bootable devices.

I tried to : - boot it on Qemu (with qemu-system-x86_64 -hdb /dev/sda) successfully - boot it on a really old computer with a intel Pentium 4 processor and everything worked as expected. - enable legacy mode in the bios options - disable secure boot - boot it on another computer, where the usb stick shows up in bootable devices, but nothing is printed.

I found it on internet, so the assembly should be correct

;; A tiny, working bootloader for x86 PCs. Has a few subroutines
;; so it's slightly less useless than just printing "hello world".
;;
;; writeup here: http://joebergeron.io/posts/post_two.html
;;
;; Joe Bergeron, 2016.
;;
    bits 16

    mov ax, 07C0h
    mov ds, ax
    mov ax, 07E0h       ; 07E0h = (07C00h+200h)/10h, beginning of stack segment.
    mov ss, ax
    mov sp, 2000h       ; 8k of stack space.

    call clearscreen

    push 0000h
    call movecursor
    add sp, 2

    push msg
    call print
    add sp, 2

    cli
    hlt

clearscreen:
    push bp
    mov bp, sp
    pusha

    mov ah, 07h     ; tells BIOS to scroll down window
    mov al, 00h     ; clear entire window
        mov bh, 07h         ; white on black
    mov cx, 00h         ; specifies top left of screen as (0,0)
    mov dh, 18h     ; 18h = 24 rows of chars
    mov dl, 4fh     ; 4fh = 79 cols of chars
    int 10h         ; calls video interrupt

    popa
    mov sp, bp
    pop bp
    ret

movecursor:
    push bp
    mov bp, sp
    pusha

    mov dx, [bp+4]      ; get the argument from the stack. |bp| = 2, |arg| = 2
    mov ah, 02h         ; set cursor position
    mov bh, 00h     ; page 0 - doesn't matter, we're not using double-buffering
    int 10h

    popa
    mov sp, bp
    pop bp
    ret

print:
    push bp
    mov bp, sp
    pusha
    mov si, [bp+4]      ; grab the pointer to the data
    mov bh, 00h         ; page number, 0 again
    mov bl, 00h     ; foreground color, irrelevant - in text mode
    mov ah, 0Eh         ; print character to TTY
 .char:
    mov al, [si]        ; get the current char from our pointer position
    add si, 1       ; keep incrementing si until we see a null char
    or al, 0
    je .return          ; end if the string is done
    int 10h             ; print the character if we're not done
    jmp .char       ; keep looping
 .return:
    popa
    mov sp, bp
    pop bp
    ret


msg:    db "Oh boy do I sure love assembly!", 0

    times 510-($-$$) db 0
    dw 0xAA55

I want to be able to boot the usb on my recent computer, running a i7-8550U processor and UEFI/Legacy compatible. For the moment, the usb stick doesn't show up in bootable devices.

EDIT : Thank you for your replies ! I tried to set the Bios Parameter Block (BPB) by adding this piece of code :


ORG 0
BITS 16

jmp near start

db "MYBOOT  "      
dw 512           
db 1                
dw 1          
db 2             
dw 512                    
dw 65535          
db 0xf8     
dw 20      
dw 63            
dw 16    
dd 0            
dd 0        
db 0x29  
dd 0xffff  
db 0         
db 0         
db "NO NAME    "
db "FAT32   "

start:
   blablabla (see above)

and the usb stick now shows up on the ubuntu desktop (I noticed that it disapear if I use something else than 'jmp near start' like 'jmp short start') But it still doesn't want to appear in my bios boot menu.. I really don't know why it doesn't want to see it at this point. I have Bios version F.23, maybe there is a special way to do it with this bios ?

Upvotes: 1

Views: 676

Answers (1)

Michael Petch
Michael Petch

Reputation: 47633

I can't place this in a comment, and I will amend this to be a proper answer if any of this helps. The code provided MAY actually be a solution to the problem too. This is based on a similar set of circumstances with a newer BIOS as was discovered on OSDev Forum discussion a number of months ago.

Can you try to compile and build an MBR using this and see if your BIOS recognizes the drive as bootable? It contains a self-referencing partition table if you happen to be booting on partitioned media. Not sure what USB media your BIOS is emulating and wish to have you simply test this out to see if it prints:

Hello, world!

The code:

bits 16
org 0x7c00

boot_start:
    xor ax, ax                  ; DS=0 since we use ORG 0x7c00. 0x0000<<4+0x7c00=0x7c00
    mov ds, ax
    mov es, ax

    ; If you will be reading data into memory outside of 0x7c00 to 0x7dff
    ; then you want to set the stack SS:SP - uncomment these lines
    ; mov ss, ax                ; Stack at 0x0000:0x7c00
    ; mov sp, 0x7c00            ;     Just below bootloader

    cld                         ; Forward movement of string instructions
                                ;     (MOVSB, SCASB, etc)

    mov si, HelloWorldMsg       ; Print hello world
    call print_string

end_loop:                       ; Loop forever to terminate
    hlt
    jmp end_loop

; Function: print_string
;           Display a string to the console on display page 0
;
; Inputs:   SI = Offset of address to print
; Clobbers: AX, BX, SI

print_string:
    mov ah, 0x0e                ; BIOS tty Print
    xor bx, bx                  ; Set display page to 0 (BL)
    jmp .getch
.repeat:
    int 0x10                    ; print character
.getch:
    lodsb                       ; Get character from string
    test al,al                  ; Have we reached end of string?
    jnz .repeat                 ;     if not process next character
.end:
    ret

HelloWorldMsg:   db "Hello, world!", 0x0d, 0x0a, 0

times 446-($-$$) db 0   ; Pad with 0s up until first partition entry
part1_entry:
db 0x80                 ; 0x80 = Active boot partition, 0x00=inactive
db 0x00, 0x01, 0x00     ; CHS of first absolute sector (MBR) of hard drive
                        ;     Head=0, Sector=1, Cylinder=0
db 0x0c                 ; Partition type (has to be non-zero)
                        ;     0x0c = Win 95 FAT32 (LBA)
db 0x00, 0x01, 0x00     ; CHS of last absolute sector (MBR) of hard drive
                        ;     Head=0, Sector=1, Cylinder=0
                        ;     We are effectively saying Size of partition is 1 sector
dd 0x0                  ; LBA of first absolute sector (0=MBR)
dd 0x1                  ; Number of sectors in partition. We set it to 1 but if you
                        ;     wish you could set it to the number of sectors on the disk

times 510-($-$$) db 0   ; Pad remainder of boot sector up to boot signature. This zeroes
                        ;     partition entries 2,3,4 effectively making them inactive

dw 0xAA55               ; The standard PC boot signature after partition table

This code may not make your drive visible or even boot and output anything, however the results can help narrow down the problem space. Part of me thinks there is a possibility that there is more than just a BPB issue given how your BIOS is reacting.

Upvotes: 1

Related Questions