Disk: Loader | Index | Disk: DIR

Write Your Own OS from Scratch - Chapter 4. Disk

Disk: VOL

In a new file disk.asm we are going to add the following code.

;-------------------------------------------------------
; Convert current drive to drive letter
; Input:
;       None
; Output:
;       AL = Drive Letter 
;-------------------------------------------------------
driveletter:
    mov    al, [drivenumber]
    test   al, byte 080h
    jz     driveletternoadj
    sub    al, 078h
driveletternoadj:
    add    al, 'A'
    ret
		

disk.asm

;=======================================================
; Disk - disk.asm
; -----------------------------------------------------
; Written in NASM
; Written by Marcus Kelly
;=======================================================

;-------------------------------------------------------
; Convert current drive to drive letter
; Input:
;       None
; Output:
;       AL = Drive Letter 
;-------------------------------------------------------
driveletter:
    mov    al, [drivenumber]
    test   al, byte 080h
    jz     driveletternoadj
    sub    al, 078h
driveletternoadj:
    add    al, 'A'
    ret
		

DEMO OS

In demoos.asm we are going to add the VOL command to show us volume information about the disk.

First we will add our string to match for our command.

volstr:         db      "VOL", 0
		

Next we will add a few strings to print with are volume information.

volname:	db	0x0D, 0x0A, " Volume in drive $"
volname2:	db	" is $"
volserial:	db	0x0D, 0x0A, " Volume Serial Number is $"
		

Let's include our new file.

%include "disk.asm"
		

Now we will need our code to show the volume information.

;-------------------------------------------------------
; Volume Info Command
; Input:
;       None
; Output:
;       None
;-------------------------------------------------------
vol:
    push   ax                                           ; Save registers
    push   bx
    push   cx
    push   dx
    push   di
    push   es
    ; read boot sector into scratch
    xor    ax, ax                                       ; Point to scratch area
    mov    es, ax
    mov    bx, 00500h
    xor    dx, dx                                       ; AX = 0
    call   calcchs                                      ; Calculate CHS
    jc     volerror
    call   readsec                                      ; Read sector
    jc     volerror
    ; print data from boot sector
    mov    ah, 009h                                     ; Print string
    mov    dx, volname
    int    021h
    mov    ah, 002h                                     ; drive letter
    call   driveletter
    mov    dl, al
    int    021h
    mov    ah, 009h                                     ; Print string
    mov    dx, volname2
    int    021h
    mov    di, bx                                       ; Print volume label
    add    di, 0002Bh
    mov    cx, 11
vollabelnext:
    mov    dl, [es:di]
    inc    di
    call   stdout
    loop   vollabelnext
    mov    ah, 009h                                     ; Print string
    mov    dx, volserial
    int    021h
    mov    di, bx                                       ; Print serial first part
    add    di, 00029h
    mov    ax, [es:di]
    call   hexwordout
    mov    ah, 002h                                     ; Print -
    mov    dl, '-'
    int    021h
    mov    di, bx                                       ; Print serial second part
    add    di, 027h
    mov    ax, [es:di]
    call   hexwordout
    call   crlf                                         ; Print crlf
volerror:
    pop   es                                            ; Restore registers
    pop   di
    pop   dx
    pop   cx
    pop   bx
    pop   ax
    ret                                                 ; Return from subroutine
		

Then in the main loop we put the code to check if it is this command.

    mov    si, volstr                                   ; Point to command text
    call   cmpcmd                                       ; Compare
    jc     cmdnvol                                      ; Carry set if not equal
    call   vol                                          ; Call function
    jmp    main                                         ; We're done checking
cmdnvol:
		

At the top of main where we print the prompt add the following code. To print the drive letter

    call   driveletter                                  ; Print drive letter
    mov    dl, al
    int    021h
    mov    dl, ':'                                      ; Print ':'
    int    021h
    mov    dl, '\'                                      ; Print '\'
    int    021h
		

Then we replace the following:

version:        db      00Dh, 00Ah, "DEMO OS V0.12"     ; Message to be printed
                db      00Dh, 00Ah, '$'
		

with

version:        db      00Dh, 00Ah, "DEMO OS V0.13"     ; Message to be printed
                db      00Dh, 00Ah, '$'
		

demoos.asm

;=======================================================
; Demo OS - demoos.asm
; -----------------------------------------------------
; Written in NASM
; Written by Marcus Kelly
;=======================================================

%include "loader.asm"

start:
    call   intinit                                      ; Initialize interrupts
    push   ds                                           ; Save DS
    mov    ax, 00FFFh                                   ; Set first MCB
    mov    [mcbfirst], ax                               ; Save first MCB
    mov    ds, ax
    mov    bx, 07000h                                   ; Size to initialize
    call   meminit                                      ; Initialize memory
    pop    ds                                           ; Restore DS
    call   ver

main:
    call   crlf                                         ; Print carriage return / line feed
    mov    ah, 002h                                     ; Service standard output
    call   driveletter                                  ; Print drive letter
    mov    dl, al
    int    021h
    mov    dl, ':'                                      ; Print ':'
    int    021h
    mov    dl, '\'                                      ; Print '\'
    int    021h
    mov    dl, '>'                                      ; Print '>'
    int    021h
    mov    dl, ' '                                      ; Print Space
    int    021h
    mov    ah, 00Ah                                     ; Service string input
    mov    dx, buffer                                   ; Set dx to our buffer
    int    021h
    call   crlf                                         ; Print carriage return / line feed

    mov    di, buffer+2                                 ; Point to the string we typed

    mov    si, verstr                                   ; Point to command text
    call   cmpcmd                                       ; Compare
    jc     cmdnver                                      ; Carry set if not equal
    call   ver                                          ; Call function
    jmp    main                                         ; We're done checking
cmdnver:

    mov    si, clsstr                                   ; Point to command text
    call   cmpcmd                                       ; Compare
    jc     cmdncls                                      ; Carry set if not equal
    call   cls                                          ; Call function
    jmp    main                                         ; We're done checking
cmdncls:

    mov    si, echostr                                  ; Point to command text
    call   cmpcmd                                       ; Compare
    jc     cmdnecho                                     ; Carry set if not equal
    call   echo                                         ; Call function
    jmp    main                                         ; We're done checking
cmdnecho:

    mov    si, mcbstr                                   ; Point to command text
    call   cmpcmd                                       ; Compare
    jc     cmdnmcb                                      ; Carry set if not equal
    call   mcb                                          ; Call function
    jmp    main                                         ; We're done checking
cmdnmcb:

    mov    si, allocstr                                 ; Point to command text
    call   cmpcmd                                       ; Compare
    jc     cmdnalloc                                    ; Carry set if not equal
    call   alloc                                        ; Call function
    jmp    main                                         ; We're done checking
cmdnalloc:

    mov    si, freestr                                  ; Point to command text
    call   cmpcmd                                       ; Compare
    jc     cmdnfree                                     ; Carry set if not equal
    call   free                                         ; Call function
    jmp    main                                         ; We're done checking
cmdnfree:

    mov    si, resizestr                                ; Point to command text
    call   cmpcmd                                       ; Compare
    jc     cmdnresize                                   ; Carry set if not equal
    call   resize                                       ; Call function
    jmp    main                                         ; We're done checking
cmdnresize:

    mov    si, volstr                                   ; Point to command text
    call   cmpcmd                                       ; Compare
    jc     cmdnvol                                      ; Carry set if not equal
    call   vol                                          ; Call function
    jmp    main                                         ; We're done checking
cmdnvol:

    mov    ah, 009h                                     ; Service Print String
    mov    dx, invalid                                  ; Invalid command
    int    021h                                         ; Our Service
    call   crlf                                         ; New line
    jmp    main                                         ; Repeat forever

;-------------------------------------------------------
; Compare Command
; Input:
;      DS:SI = Command String
;      ES:DI = Buffer String
; Output:
;      Carry set if not equal
;      Carry clear if equal
;-------------------------------------------------------
cmpcmd:
    push   ax                                           ; Save registers
    push   si
    push   di
cmpcmdnext:
    mov    al, [es:di]                                  ; Load char from command line 
    inc    di                                           ; Point to next character
    call   toup                                         ; Convert to uppercase
    mov    ah, [ds:si]                                  ; Load char to test against
    inc    si                                           ; Point to next character
    cmp    ah, al                                       ; Compare both characters
    jz     cmpcmdnext                                   ; If they are the same check next
    dec    si                                           ; Adjust to point to last char
    dec    di
    cmp    [ds:si], byte 0                              ; Our test command end should be 0
    jnz    cmpcmdne                                     ; If it isn't not our command
    cmp    [es:di], byte ' '                            ; Our input cmd might be space
    jz     cmpcmde                                      ; If it is this is our command
    cmp    [es:di], byte 00Dh                           ; Our input cmd might be CR
    jz     cmpcmde                                      ; If it is this is our command
    jmp    cmpcmdne                                     ; Otherwise not our command
cmpcmde:
    pop    di                                           ; Restore registers
    pop    si
    pop    ax
    clc                                                 ; Clear carry for match
    ret                                                 ; Return from subroutine
cmpcmdne:
    pop    di                                           ; Restore registers
    pop    si
    pop    ax
    stc                                                 ; Set carry if not a match
    ret                                                 ; Return from subroutine

;-------------------------------------------------------
; Version Command
; Input:
;      None
; Output:
;      AX, DX are Destroyed
;-------------------------------------------------------
ver:
    mov    ah, 009h                                     ; Service string output
    mov    dx, version                                  ; dx is set to offset version
    int    021h                                         ; Call the service
    ret

;-------------------------------------------------------
; Clear Screen Command
; Input:
;      None
; Output:
;      AX is Destroyed
;-------------------------------------------------------
cls:
    mov    ah, 00Fh                                     ; Get video mode
    int    010h
    mov    ah, 000h                                     ; Set video mode
    int    010h                                         ;  this automatically clears the screen
    ret

;-------------------------------------------------------
; Echo Command
; Input:
;      None
; Output:
;      None
;-------------------------------------------------------
echo:
    push   ax                                           ; Save registers
    push   dx
    push   di
    xor    ah, ah                                       ; Clear upper part of ax
    mov    al, [buffer+1]                               ; Get count from buffer
    mov    di, buffer+2                                 ; Get start of buffer
    add    di, ax                                       ; Add for end of buffer
    mov    al, '$'                                      ; Place '$' at end for printing
    mov    [di], al
    mov    ah, 009h                                     ; Service print string
    mov    dx, buffer+7                                 ; Get start of string to print
    int    021h                                         ;    7 to exclude echo
    call   crlf
    pop    di                                           ; Restore regsiters
    pop    dx
    pop    ax
    ret                                                 ; Return from subroutine

;-------------------------------------------------------
; Memory Control Block Command
; Input:
;      None
; Output:
;      AX is Destroyed
;-------------------------------------------------------
mcb:
    push   ax                                           ; Save Registers
    push   dx
    push   ds
    call   crlf                                         ; Print CR / LF
    mov    ax, [mcbfirst]                               ; DS = first mcb
    mov    ds, ax
mcbnext:
    mov    ax, ds                                       ; Print arena segment
    call   hexwordout
    mov    ah, 002h
    mov    dl, ' '                                      ; Print space
    int    021h
    mov    ah, 002h                                     ; Print signature
    mov    dl, [ds:memarena.signature]
    push   dx                                           ; Save signature
    int    021h
    mov    ah, 002h
    mov    dl, ' '                                      ; Print space
    int    021h
    mov    ax, [ds:memarena.owner]                      ; Print owner
    call   hexwordout
    mov    ah, 002h
    mov    dl, ' '                                      ; Print space
    int    021h
    mov    ax, [ds:memarena.size]                       ; Print size
    call   hexwordout
    mov    ah, 002h
    mov    dl, ' '                                      ; Print space
    int    021h
    xor    si, si                                       ; Print name
    mov    cx, 8
mcbnextname:
    mov    dl, [ds:si+memarena.name]                    ; Read name byte
    mov    ah, 002h                                     ; Print name byte
    int    021h
    inc    si                                           ; Increment name byte
    loop   mcbnextname                                  ; Get next name byte
    pop    dx                                           ; Restore signature
    cmp    dl, 'Z'                                      ; Compare to end arena
    jz     mcbdone                                      ;   if yes were done
    call   memarenanext                                 ; Get next arena
    jc     mcbdone                                      ;   failed were done
    call   crlf                                         ; Print CR / LF for next arena
    jmp    mcbnext                                      ; Next arena
mcbdone:
    call   crlf                                         ; Print CR / LF
    pop    ds                                           ; Restore registers
    pop    dx
    pop    ax
    ret                                                 ; Return from subroutine

;-------------------------------------------------------
; Memory Allocate Command
; Input:
;      Command line hex number
; Output:
;       None
;-------------------------------------------------------
alloc:
    push   ax                                           ; Save registers
    push   bx
    push   si
    mov    si, buffer+8                                 ; Get buffer + 8 point to hex input
    call   hexwordin                                    ; Get hex input
    mov    bx, ax                                       ; Allocate input size
    mov    ah, 048h                                     ; Service Allocate
    int    021h
    jc     allocerror
    call   crlf                                         ; Print CR / LF
    call   hexwordout                                   ; Show allocated page start
    call   crlf                                         ; Print CR / LF
allocerror:
    pop    si                                           ; Restore registers
    pop    bx
    pop    ax
    ret                                                 ; Return from subroutine

;-------------------------------------------------------
; Memory Free Command
; Input:
;      Command line hex number
; Output:
;       None
;-------------------------------------------------------
free:
    push   ax                                           ; Save registers
    push   si
    push   es
    mov    si, buffer+7                                 ; Get buffer + 8 point to hex input
    call   hexwordin                                    ; Get hex input
    mov    es, ax                                       ; Free page
    mov    ah, 049h                                     ; Service Free
    int    021h
    jc     freeerror
freeerror:
    pop    es
    pop    si                                           ; Restore registers
    pop    ax
    ret                                                 ; Return from subroutine

;-------------------------------------------------------
; Memory Resize Command
; Input:
;      Command line hex number
; Output:
;       None
;-------------------------------------------------------
resize:
    push   ax                                           ; Save registers
    push   si
    push   es
    mov    si, buffer+9                                 ; Get buffer + 8 point to hex input
    call   hexwordin                                    ; Get hex input
    mov    es, ax                                       ; Free page
    mov    si, buffer+14
    call   hexwordin                                    ; Get hex input
    mov    bx, ax
    mov    ah, 04Ah                                     ; Service Resize
    int    021h
    jc     resizeerror
resizeerror:
    pop    es
    pop    si                                           ; Restore registers
    pop    ax
    ret                                                 ; Return from subroutine

;-------------------------------------------------------
; Volume Info Command
; Input:
;       None
; Output:
;       None
;-------------------------------------------------------
vol:
    push   ax                                           ; Save registers
    push   bx
    push   cx
    push   dx
    push   di
    push   es
    ; read boot sector into scratch
    xor    ax, ax                                       ; Point to scratch area
    mov    es, ax
    mov    bx, 00500h
    xor    dx, dx                                       ; AX = 0
    call   calcchs                                      ; Calculate CHS
    jc     volerror
    call   readsec                                      ; Read sector
    jc     volerror
    ; print data from boot sector
    mov    ah, 009h                                     ; Print string
    mov    dx, volname
    int    021h
    mov    ah, 002h                                     ; drive letter
    call   driveletter
    mov    dl, al
    int    021h
    mov    ah, 009h                                     ; Print string
    mov    dx, volname2
    int    021h
    mov    di, bx                                       ; Print volume label
    add    di, 0002Bh
    mov    cx, 11
vollabelnext:
    mov    dl, [es:di]
    inc    di
    call   stdout
    loop   vollabelnext
    mov    ah, 009h                                     ; Print string
    mov    dx, volserial
    int    021h
    mov    di, bx                                       ; Print serial first part
    add    di, 00029h
    mov    ax, [es:di]
    call   hexwordout
    mov    ah, 002h                                     ; Print -
    mov    dl, '-'
    int    021h
    mov    di, bx                                       ; Print serial second part
    add    di, 027h
    mov    ax, [es:di]
    call   hexwordout
    call   crlf                                         ; Print crlf
volerror:
    pop   es                                            ; Restore registers
    pop   di
    pop   dx
    pop   cx
    pop   bx
    pop   ax
    ret                                                 ; Return from subroutine


%include "io.asm"
%include "int.asm"
%include "mem.asm"
%include "disk.asm"

;-------------------------------------------------------
; Data Area
;-------------------------------------------------------

verstr:         db      "VER", 0
clsstr:         db      "CLS", 0
echostr:        db      "ECHO", 0
mcbstr:         db      "MCB", 0
allocstr:       db      "ALLOC", 0
freestr:        db      "FREE", 0
resizestr:      db      "RESIZE", 0
volstr:         db      "VOL", 0


version:        db      00Dh, 00Ah, "DEMO OS V0.13"     ; Message to be printed
                db      00Dh, 00Ah, '$'

invalid:        db      00Dh, 00Ah, "Invalid Command"   ; Message to be printed
                db      '$'

volname:	db	0x0D, 0x0A, " Volume in drive $"
volname2:	db	" is $"
volserial:	db	0x0D, 0x0A, " Volume Serial Number is $"

buffer:         db      64                              ; Buffer for string input
                db      0
                db      0, 0, 0, 0, 0, 0, 0, 0
                db      0, 0, 0, 0, 0, 0, 0, 0
                db      0, 0, 0, 0, 0, 0, 0, 0
                db      0, 0, 0, 0, 0, 0, 0, 0
                db      0, 0, 0, 0, 0, 0, 0, 0
                db      0, 0, 0, 0, 0, 0, 0, 0
                db      0, 0, 0, 0, 0, 0, 0, 0
                db      0, 0, 0, 0, 0, 0, 0, 0

mcbfirst:       dw      0
		

Modify the disk image

Now lets build our disk. If you are running the previous tutorial in VirtualBox Remember to remove the disk or close virtual box before assembling the disk image.

> nasm demoos.asm -o demoos.bin
> nasm osdisk.asm -o osdisk.img
		

Your osdisk.img can now be loaded with VirtualBox. The result should be as follows:

DEMO OS V0.13

> vol

 Volume in drive A is DEMO OS DSK
 Volume Serial Number is 2394-C726

>
		
Disk: Loader | Index | Disk: DIR

Support This Project On Patreon

Copyright © 2021 Marcus Kelly