Sitemap

Building an OS from Scratch (Day 2: Reading Files from Disk and Accepting User Input.)

5 min readJun 5, 2025

--

🔧 What We’re Doing Today

Welcome back! It’s been a while since our first post on February 10, 2025, where we printed our first “Hello World” from the bootloader.

Today, we’re taking a step forward by reading a file from disk, and accepting user input from the keyboard. That means we’re introducing:

  • Basic file table logic
  • Reading sectors from the disk
  • A mini text input prompt
  • Dynamic messages like Hello your username is:Adarsh,

⚙️ Tools Used

Same as before:

  • NASM for assembling code
  • QEMU for emulation
  • Text editor (Nano or VS Code)
  • WSL / Linux terminal

📁 Directory Structure

TWZ/
├── src/
│ └── main.asm
├── build/
│ ├── main.bin
│ └── floppy.img

🧠 Concept Overview

Today’s bootloader will:

  1. Load itself to memory
  2. Load a file table from sector 2
  3. Check if the file “HELLO” exists
  4. Load the content of that file into memory
  5. Print the content using BIOS
  6. Ask for the user’s name
  7. Display a greeting with that name

📜 File Table Format

Stored at sector 2.
Each entry is:

filename (8 bytes) | size (1 byte) | start_sector (1 byte)

So to look for a file named “HELLO”, we just compare the first 8 bytes of each entry in memory with 'HELLO '.

🧾 Assembly Code

org 0x7C00
bits 16

start:
jmp main

a; =============================
; Print string pointed by SI
; =============================
puts:
push si
push ax
.print:
lodsb
or al, al
jz .done
mov ah, 0x0E
int 0x10
jmp .print
.done:
pop ax
pop si
ret

; =============================
; Get a key from keyboard (result in AL)
; =============================
getchar:
mov ah, 0x00
int 0x16
ret

; =============================
; Read a line into ES:DI
; Max 32 chars, terminates on Enter
; =============================
read_line:
xor cx, cx
.next_char:
call getchar
cmp al, 0x0D ; Enter key?
je .done

; Echo the character
mov ah, 0x0E
int 0x10
stosb
inc cx
cmp cx, 32
jne .next_char
.done:
mov al, 0
stosb
ret

; =============================
; Read sector into ES:BX
; DL = sector number
; =============================
read_sector:
push ax
push dx
mov ah, 0x02
mov al, 1
mov ch, 0
mov cl, dl
inc cl ; Convert to 1-based
mov dh, 0
mov dl, 0x00
int 0x13
pop dx
pop ax
ret

main:
xor ax, ax
mov ds, ax
mov es, ax
mov ss, ax
mov sp, 0x7C00

; === Print boot message ===
mov si, msg_boot
call puts

; === Read file table from sector 2 ===
mov bx, 0x8000
mov dl, 2
call read_sector

; === Search for file "HELLO" ===
mov si, 0x8000
mov di, filename
mov cx, 8
repe cmpsb
jne notfound

; === Load the file ===
mov al, [si] ; size
mov dl, [si+1] ; start sector
mov bx, 0x9000
call read_sector

; === Print file content ===
mov si, 0x9000
call puts

; === Ask for user input ===
mov si, newline
call puts
mov si, msg_prompt
call puts

mov di, 0x9100
mov es, ax
call read_line

; === Final greeting ===
mov si, newline
call puts

mov si, msg_hello
call puts

mov ax, es
mov ds, ax
mov si, 0x9100
call puts

mov si, newline
call puts

mov si, msg_tail
call puts

hang:
jmp hang

notfound:
mov si, msg_nf
call puts
jmp hang

; =============================
; Data
; =============================
filename: db 'HELLO '
msg_boot: db 'Booting OS...', 0x0D, 0x0A, 0
msg_nf: db 'File Not Found!', 0x0D, 0x0A, 0
msg_prompt: db 'Enter your name: ', 0
msg_hello: db 'Hello your username is: ', 0
msg_tail: db 0x0D, 0x0A, 'welcome to the', 0x0D, 0x0A, 0
newline: db 0x0D, 0x0A, 0

times 510 - ($ - $$) db 0
dw 0xAA55org 0x7C00
bits 16

start:
jmp main

; Print string at SI
puts:
push si
push ax
.loop:
lodsb
or al, al
jz .done
mov ah, 0x0E
int 0x10
jmp .loop
.done:
pop ax
pop si
ret

; Get a character from keyboard
getchar:
mov ah, 0x00
int 0x16
ret

; Read up to 32 characters to ES:DI
read_line:
xor cx, cx
.next:
call getchar
cmp al, 0x0D
je .done
mov ah, 0x0E
int 0x10
stosb
inc cx
cmp cx, 32
jne .next
.done:
mov al, 0
stosb
ret

; Read 1 sector from DL into ES:BX
read_sector:
push ax
push dx
mov ah, 0x02
mov al, 1
mov ch, 0
mov cl, dl
inc cl
mov dh, 0
mov dl, 0x00
int 0x13
pop dx
pop ax
ret

main:
xor ax, ax
mov ds, ax
mov es, ax
mov ss, ax
mov sp, 0x7C00

mov si, msg_boot
call puts

; Load file table from sector 2
mov bx, 0x8000
mov dl, 2
call read_sector

; Search for 'HELLO'
mov si, 0x8000
mov di, filename
mov cx, 8
repe cmpsb
jne notfound

; Found! Load file
mov al, [si]
mov dl, [si+1]
mov bx, 0x9000
call read_sector

; Print file
mov si, 0x9000
call puts

; Ask name
mov si, newline
call puts
mov si, msg_prompt
call puts

mov di, 0x9100
call read_line

; Greet user
mov si, newline
call puts
mov si, msg_hello
call puts
mov si, 0x9100
call puts
mov si, msg_tail
call puts

hang:
jmp hang

notfound:
mov si, msg_nf
call puts
jmp hang

; --- Data ---
filename: db 'HELLO '
msg_boot: db 'Booting OS...', 0x0D, 0x0A, 0
msg_nf: db 'File Not Found!', 0x0D, 0x0A, 0
msg_prompt: db 'Enter your username: ', 0
msg_hello: db 'Hello ', 0
msg_tail: db ', welcome to the OS!', 0x0D, 0x0A, 0
newline: db 0x0D, 0x0A, 0

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

🛠️ Compile & Run

nasm -f bin src/main.asm -o build/main.bin
dd if=/dev/zero of=build/floppy.img bs=512 count=2880
dd if=build/main.bin of=build/floppy.img bs=512 count=1 conv=notrunc
printf 'HELLO \x01\x03' | dd of=build/floppy.img bs=512 seek=2 conv=notrunc
printf 'Welcome to my OS!\r\n\x00' | dd of=build/floppy.img bs=512 seek=3 conv=notrunc
qemu-system-x86_64 -fda build/floppy.img
You should see

📘 What You Learned Today

  • Loading extra sectors (file table & data)
  • Comparing file names
  • Reading user input
  • Printing dynamic messages
  • Expanding bootloader functionality

🔮 What’s Next?

On Day 3, we’ll:

  • Add multiple file support
  • Print a menu of files
  • Let the user choose which file to read!

--

--

Adarsh Kumar
Adarsh Kumar

Written by Adarsh Kumar

I'm Adarsh. Cyber-security student,CTF player . Team TheWiz( @thewizx01 )

No responses yet