Basics: Input | Index | Basics: Command

Write Your Own OS from Scratch - Chapter 2. Basics

Basic: Services

We are going to start writing the service code this will activate int 21h and let us hook into our OS from external programs.

In a new file called int.asm we need to add a way to set the service int in the interrupt list. We do that with the following code:

;-------------------------------------------------------
; Interrupt Set
; Input:
;       AL = Interrupt Number
;       DS = Segment of Interrupt
;       DX = Offset of Interrupt
; Output:
;       None
;-------------------------------------------------------
intset:
    push   ax                                           ; Save registers
    push   cx
    push   di
    push   es
    xor    ah, ah                                       ; DI = INT << 2
    mov    cl, 2                                        ; Essentially multiply by 4
    shl    ax, cl
    mov    di, ax                                       ; di is the address of our int
    xor    ax, ax                                       ; ES = 0 The int table is at 00000h
    mov    es, ax
    mov    ax, dx                                       ; Store offset
    stosw
    mov    ax, ds                                       ; Store segment
    stosw
    pop    es                                           ; Restore registers
    pop    di
    pop    cx
    pop    ax
    ret                                                 ; Return from subroutine
		

Next you will need the service hook this is the function that gets called to process our service requests.

;-------------------------------------------------------
; Interrupt Hook
;-------------------------------------------------------
inthook:
    cmp    ah, 002h                                     ; Service 02h: stdout
    jnz    inthookdone02
    call   stdout
    jmp    inthookdone
inthookdone02:
    cmp    ah, 008h                                     ; Service 08h: stdin
    jnz    inthookdone08
    call   stdin
    jmp    inthookdone
inthookdone08:
    cmp    ah, 009h                                     ; Service 09h: strout
    jnz    inthookdone09
    call   strout
    jmp    inthookdone
inthookdone09:
    cmp    ah, 00Ah                                     ; Service 0Ah: strin
    jnz    inthookdone0a
    call   strin
    jmp    inthookdone
inthookdone0a:
    cmp    ah, 025h                                     ; Service 25h: setint
    jnz    inthookdone25
    call   intset
    jmp    inthookdone
inthookdone25:
inthookdone:
    iret
		

Next we need to intialize our services

;-------------------------------------------------------
; Interrupt Initialize
; Input:
;       None
; Output:
;       DX, AX are destroyped
;-------------------------------------------------------
intinit:
    mov    dx, inthook                                  ; Offset to our service routine
                                                        ;    DS should already be the
                                                        ;    correct segment
    mov    al, 021h                                     ; Service 21h
    call   intset                                       ; Set Interrupt 21h
    ret                                                 ; Return from subroutine
		

int.asm

;=======================================================
; Service - int.asm
; -----------------------------------------------------
; Written in NASM
; Written by Marcus Kelly
;=======================================================

;-------------------------------------------------------
; Interrupt Hook
;-------------------------------------------------------
inthook:
    cmp    ah, 002h                                     ; Service 02h: stdout
    jnz    inthookdone02
    call   stdout
    jmp    inthookdone
inthookdone02:
    cmp    ah, 008h                                     ; Service 08h: stdin
    jnz    inthookdone08
    call   stdin
    jmp    inthookdone
inthookdone08:
    cmp    ah, 009h                                     ; Service 09h: strout
    jnz    inthookdone09
    call   strout
    jmp    inthookdone
inthookdone09:
    cmp    ah, 00Ah                                     ; Service 0Ah: strin
    jnz    inthookdone0a
    call   strin
    jmp    inthookdone
inthookdone0a:
    cmp    ah, 025h                                     ; Service 25h: setint
    jnz    inthookdone25
    call   intset
    jmp    inthookdone
inthookdone25:
inthookdone:
    iret

;-------------------------------------------------------
; Interrupt Set
; Input:
;       AL = Interrupt Number
;       DS = Segment of Interrupt
;       DX = Offset of Interrupt
; Output:
;       None
;-------------------------------------------------------
intset:
    push   ax                                           ; Save registers
    push   cx
    push   di
    push   es
    xor    ah, ah                                       ; DI = INT << 2
    mov    cl, 2                                        ; Essentially multiply by 4
    shl    ax, cl
    mov    di, ax                                       ; di is the address of our int
    xor    ax, ax                                       ; ES = 0 The int table is at 00000h
    mov    es, ax
    mov    ax, dx                                       ; Store offset
    stosw
    mov    ax, ds                                       ; Store segment
    stosw
    pop    es                                           ; Restore registers
    pop    di
    pop    cx
    pop    ax
    ret                                                 ; Return from subroutine


;-------------------------------------------------------
; Interrupt Initialize
; Input:
;       None
; Output:
;       DX, AX are destroyped
;-------------------------------------------------------
intinit:
    mov    dx, inthook                                  ; Offset to our service routine
                                                        ;    DS should already be the
                                                        ;    correct segment
    mov    al, 021h                                     ; Service 21h
    call   intset                                       ; Set Interrupt 21h
    ret                                                 ; Return from subroutine
		

Modify Demo OS

At the top change the line:

    xor     ax, ax                                      ; Zero the ax register
		

to

    mov     ax, cs                                      ; Set all segments to code segment
		

Replace the lines:

    push    cs                                          ; Make sure data segment = code segment
    pop     ds
		

with

    call   intinit                                      ; Initialize interrupts
		

Replace the following code:

    mov     dx, version                                 ; dx is set to offset version
    call    strout                                      ; call our string output routine

main:
    call   crlf                                         ; Print carriage return / line feed
    mov    dl, '>'                                      ; Print '>'
    call   stdout
    mov    dl, ' '                                      ; Print Space
    call   stdout
    mov    dx, buffer                                   ; Set dx to our buffer
    call   strin                                        ; Call strin
    call   crlf                                         ; Print carriage return / line feed
    jmp    main                                         ; Repeat forever
		

with

    mov     ah, 009h                                    ; Service string output
    mov     dx, version                                 ; dx is set to offset version
    int     021h                                        ; Call the service

main:
    call   crlf                                         ; Print carriage return / line feed
    mov    ah, 002h                                     ; Service standard output
    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
    jmp    main 
		

Add the line:

%include "int.asm"
		

Change the following lines:

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

to

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

demoos.asm

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

    org     00000h                                      ; Assemble code for this offset

start:
    cli                                                 ; Turn off interrupts
    cld							; Make sure we are going forward
    mov     ax, cs                                      ; Set all segments to code segment
    mov     ds, ax                                      ; Make sure data segment is zero
    mov     es, ax                                      ; Make sure extra segment is zero
    mov     ss, ax                                      ; Make sure stack segment is zero
    mov     sp, 07C00h                                  ; Place stack ptr before boot sector
    sti                                                 ; Turn on interrupts

    call   intinit                                      ; Initialize interrupts

    mov     ah, 009h                                    ; Service string output
    mov     dx, version                                 ; dx is set to offset version
    int     021h                                        ; Call the service

main:
    call   crlf                                         ; Print carriage return / line feed
    mov    ah, 002h                                     ; Service standard output
    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
    jmp    main                                         ; Repeat forever

%include "io.asm"
%include "int.asm"


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

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

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
		

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.04
>
		
Basics: Input | Index | Basics: Command

Support This Project On Patreon

Copyright © 2021 Marcus Kelly