2

I create a small os (not finished) only with assembly 16 bit that works with qemu-system-i386.

But now i want to test it on a real machine and in case of errors make it compatible with a real PC.

This is the os

Makefile:

boot = bootloader.asm
kernel = kernel.asm

boot_o = bootloader.bin
kernel_o = kernel.bin

bin = myos.bin

asm_compiler = nasm
qemu = qemu-system-i386

compile:
    $(asm_compiler) -f elf32 -g $(boot) -o $(boot_o)
    $(asm_compiler) -f elf32 -g $(kernel) -o $(kernel_o)
    ld -m elf_i386 -nmagic -T linker.ld -o $(bin) $(boot_o) $(kernel_o)

run:
    $(qemu) -fda $(bin)

clean:
    -rm $(boot_o)
    -rm $(kernel_o)
    -rm $(bin)

linker.ld:

OUTPUT_FORMAT(binary)
ENTRY(_start)

SECTIONS
{
    . = 0x7c00;

    bootloader :
    {
        bootloader.bin (.boot);
    }

    kernel :
    {
        kernel.bin (.kernel);
    }

    /DISCARD/ :
    {
        *(.bss*);
        *(COMMON*);
    }
}

bootloader.asm:

bits 16

section .boot
global _start

_start:
    cli
        
    xor ax, ax
    mov ds, ax
    mov es, ax
        
    mov ss, ax
    mov sp, 0x9000

    mov bx, 0x7e00
    mov al, 1
    mov dh, 0
    mov dl, 0
    mov ch, 0
    mov cl, 2
    mov ah, 2
    int 0x13

    pusha

    mov ax, 0x0700  ; function 07, AL=0 means scroll whole window
    mov bh, 0x07    ; character attribute = white on black
    mov cx, 0x0000  ; row = 0, col = 0
    mov dx, 0x184f  ; row = 24 (0x18), col = 79 (0x4f)
    int 10h         ; call BIOS video interrupt

    popa

    pusha

    mov ah, 0x02
    xor dx, dx
    int 10h

    mov si, boot_msg
    mov ah, 0x0e
    boot_characterLoop:
        lodsb
        or al, al
        jz continue
        int 10h

    jmp boot_characterLoop
    continue:
        mov ah, 0x86
        mov cx, 0xF
        mov dx, 0x4240
        int 15h
        int 15h
        int 15h

    popa

    jmp 0x7e00

boot_msg: db "The os is correctly loaded"

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

kernel.asm:

bits 16


section .kernel
global _start_kernel

_start_kernel:

    mov ax, 0x3
    int 10h

    commandLoop:

        mov si, user
        call print

        mov di, input_string
        call input

        ifCommand:
            cld
            mov si, C_shutdown
            mov di, input_string
            mov cx, CL_shutdown
            repe cmpsb
            jz thenCommandShutdown
            
            cld
            mov si, C_reboot
            mov di, input_string
            mov cx, CL_reboot
            repe cmpsb
            jz thenCommandReboot

            cld
            mov si, C_clear
            mov di, input_string
            mov cx, CL_clear
            repe cmpsb
            jz thenCommandClear

            jmp elseCommand

        thenCommandShutdown:
            call shutdown

        thenCommandReboot:
            call reboot
        
        thenCommandClear:
            call clearScreen
            jmp commandLoop

        elseCommand:
            mov si, input_string
            call print
            mov si, cmdNotFound
            call print
            call newLine
            jmp commandLoop

    exit:
        cli
        hlt


;- Includes --------------------+
%include "lib/console.asm" ;    |
%include "lib/system.asm"  ;    |
;-------------------------------+

;- Variables ----------------------------------+
user: db "user >> ", 0                    ;    |
input_string: times 20 db 0               ;    |
cmdNotFound: db ": command not found!", 0 ;    |
;----------------------------------------------+


;- Commands Variables ------------------------------+
;                                                   |
C_shutdown:  db "shutdown", 0   ;                   |
CL_shutdown  equ $ - C_shutdown ;                   |
;                                                   |
C_reboot:    db "reboot", 0     ;                   |
CL_reboot    equ $ - C_reboot   ;                   |
;                                                   |
C_clear:     db "clear", 0      ;                   |
CL_clear     equ $ - C_clear    ;                   |
;---------------------------------------------------+

times 512-($-$$) db 0

How I can do? Do i need grub? (I use ubuntu 22.04.02 LTS) ps. sorry for the grammar but I am italian and I am only 14

2 Answers2

2

The easiest way would be to write your OS image to a USB thumb drive, and then boot the machine from that.

Plug in your thumb drive, then run dmesg to look at the kernel log and see the name of the new device. It will probably be sdb (SCSI Drive B).

Double check that you're writing to the right device, otherwise you'll trash your installation!

Then:

$ sudo dd if=myos.bin of=/dev/sdv

You'll need to make sure your target machine is configured:

  1. To boot in legacy (non-UEFI) mode.
  2. SecureBoot is disabled.
  3. The USB drive is high in the boot priority list.

Good luck!

Jonathon Reinhart
  • 132,704
  • 33
  • 254
  • 328
  • When I go into the bios I can't find the usb-pen in the available boot – Federico Occhiochiuso Jul 29 '23 at 14:59
  • @FedericoOcchiochiuso: If you create a bootable USB device with a known-good method (like downloading an Ubuntu or Arch Linux live image, and using one of the recommended tools for putting it onto a USB stick), does that show up as bootable? But modern live-USB images are probably UEFI compatible, so maybe look for an old image from before the UEFI days, if you want to test that you have your computer's BIOS set up to boot legacy 16-bit MBRs from USB (usually CSM = Compatibility Support Modules). Your code is definitely legacy 16-bit, not UEFI, so you need to boot that way. – Peter Cordes Jul 29 '23 at 20:14
  • @PeterCordes If I put the iso created with grub, the bios detect him. But the os doesn't work because I don't know how to start my os with grub. – Federico Occhiochiuso Jul 30 '23 at 13:34
  • 2
    @FedericoOcchiochiuso: Did you enable CSM in your BIOS settings? If not, then it won't detect devices as bootable even if they have the `dw 0xAA55` in the last 2 bytes of the first 512-byte sector. (Also, how are you trying to boot? If from a USB flash drive, you shouldn't make an ISO image, just a disk image with the MBR at the start. Try a [mcve] with just a bootloader that prints something on its own, without depending on other loading other sectors.) – Peter Cordes Jul 30 '23 at 17:13
2

With moving away from qemu and working on a 'real machine' come some changes that qemu probably took care of for you:

  • your present code uses a hard-coded 0 for the drive number in DL. A real BIOS passes the correct drive number to you in the DL register. You must use that number in your ReadDiskSector function 02h.
  • your present code expects reading the disk to be successful first time. On real hardware things don't always work first time. You should try several times and abort on failure if things don't work at all.
  • your present code positions the cursor with no regard for any display page number in BH. A real BIOS supports 8 display pages when the screen is in the default mode 3 (80 x 25 16-color text). Use mov bh, 0 in the call to the SetCursorPosition function 02h.
    cld
    xor  ax, ax
    mov  ds, ax
    mov  es, ax
    mov  ss, ax
    mov  sp, 9000h

    mov  di, 5        ; Allow 5 tries
TryNext:
    mov  dh, 0        ; CHS = (0,0,2), DL is drive number from BIOS
    mov  cx, 0002h
    mov  bx, 7E00h    ; ES:BX is buffer
    mov  ax, 0201h    ; BIOS.ReadDiskSector
    int  13h          ; -> AX CF
    jnc  Loaded
    mov  ah, 00h      ; BIOS.ResetDiskSystem
    int  13h          ; -> AH CF
    dec  di
    jnz  TryNext
Exit:
    cli
    hlt
    jmp  Exit
Loaded:

To grub or not to grub

I'm on a DOS/Windows system using BIOS firmware, so neither Ubuntu nor UEFI firmware.

Whenever I need to test a hobby OS, I put it on a 3.5" floppy disk that I can insert in an external floppy drive plugged into an USB port. The only thing I have to make sure is that the external device is highest in the boot order (so before the hard drive and/or optical drive). There's a BIOS setup setting for that.
Instead of a floppy disk (easiest), I could just put it on an USB stick and have the BIOS pretend that the stick is a floppy disk.

Sep Roland
  • 33,889
  • 7
  • 43
  • 76
  • 2
    Michael Petch's tips for general bootloader development is a good canonical answer covering a lot of issues - [Boot loader doesn't jump to kernel code](https://stackoverflow.com/a/32705076) . But I think the OP's problem is they're not seeing a boot option to even try to boot their code, probably because they haven't enabled legacy BIOS booting. On a UEFI BIOS, that's CSM = Compat Support Modules. – Peter Cordes Jul 30 '23 at 17:08
  • I can put the bin file in the usb stick? I tried it once and it didn't work, neither bios nor ubuntu file manager recognized the stick – Federico Occhiochiuso Jul 31 '23 at 09:41