monogon-dev / monogon

The Monogon Monorepo. May contain traces of peanuts and a ✨pure Go Linux userland✨. Work in progress!
https://monogon.tech
Apache License 2.0
378 stars 9 forks source link

No MBR stub in installer / Metropolis #142

Open q3k opened 2 years ago

q3k commented 2 years ago

When a user starts the installer (or Metropolis - but that generally shouldn't happen) without EFI boot, the firmware simply reports the image as not bootable, which can be slightly confusing.

We should add an MBR stub to our generated bootable images that lets the user know they should run with EFI (boot) enabled.

q3k commented 2 years ago

Messed around with this a bit.

1660933791

1660933847

I'll productionize this later once I have an idea of how to assemble real mode x86 code cleanly in our build system.

Here's a nasm snippet:

org 7c00h

start:
    jmp main

times 90-($-$$) db 0

; si: string data, null terminated
; di: start offset
writestring:
    mov al, [si]
    or al, al
    jz writestring_done
    inc si
    mov byte [fs:di], al
    add di, 2
    jmp writestring
writestring_done:
    ret

; si: rle encoded data (high bit == color, lower 7: length)
; di: start offset
writegfx:
    mov al, [si]
    or al, al
    jz writegfx_done
    inc si

    mov cl, al
    and cx, 0b01111111
    shr al, 7

writegfx_nextinner:
    or al, al
    jz writegfx_space
    mov byte [fs:di], 'M'
writegfx_space:
    add di, 2
    sub cx, 1
    jz writegfx
    jmp writegfx_nextinner
writegfx_done:
    ret

main:
    xor ax, ax
    mov ds, ax

    ; set mode 3 (text 80x25, 16 color)
    mov ax, 0x3
    int 0x10

    ; set up fs segment to point at framebuffer
    mov ax, 0xb800
    mov fs, ax

    mov di, 4
    mov si, logo
    call writegfx

    mov di, 3400
    mov si, line1
    call writestring

    mov di, 3544
    mov si, line2
    call writestring

end:
    jmp end

%include "logo.asm"

line1:
    db "Hi there! Didn't see you coming in.", 0

line2:
    db "Unfortunately, Metropolis can only boot in UEFI mode.", 0

times 510-($-$$) db 0
db 0x55
db 0xAA

logo.asm is generated by the following Python snippet (which does some jank RLE):

import sys

from PIL import Image

im = Image.open("logo.png")
assert im.size == (80, 20)

linear = []
for y in range(20):
    for x in range(80):
        px = im.getpixel((x, y))
        linear.append(px)

# RLE
rle = []
while len(linear) > 0:
    val = linear[0]
    l = 1
    for i in range(1, len(linear)):
        if linear[i] != val:
            break
        l += 1
    L = l
    while l > 0:
        block = l
        if block > 127:
            block = 127
        rle.append((val << 7) | block)
        l -= block
    linear = linear[L:]
rle.append(0)
#assert len(rle) < 128

print("logo: db " + ", ".join([f"0x{r:02x}" for r in rle]))