skip to Main Content

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

Answers


  1. 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!

    Login or Signup to reply.
  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.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search