Page 1 of 1

int20h

Posted: Wed Aug 25, 2004 11:00 pm
by DIGO_RP
Does anybody knows how do I implement INT20h on my OS?

Can be ASM or C, any help are welcome!

RE:int20h

Posted: Wed Aug 25, 2004 11:00 pm
by ASHLEY4
This is how to do int 20h and 21h in your realmode OS.
[code]
;---------------------------------------------------------------------------
; MiOS bootsector
; It loads the kernel.bin file from the disk, (FAT Filesystem)
;
; This code is based on PicoDOS
;
; Copyright 2000 Hector Facundo Arena

%define STARTADDR 100h


[org 0h]

start:
            jmp short real_start
            nop

OEM             DB      'MiOSBOOT' ; OEM identifier (8)
BPS             DW      512 ; bytes per sector
SPC             DB      1 ; sector(s) per cluster
Reserved        DW      4 ; reserved sectors
FATs            DB      2 ; number of fats
RootEntries     DW      224 ; number of root entries
TotalSectors    DW      2880 ; total sectors of the disk
MediaType       DB      240 ; media descriptor: 240 = FD standard 1.44MB
FATSectors      DW      9 ; sectors per fat
SPT             DW      18 ; sectors per track
HPC             DW      2 ; number of heads
Hidden          DD      0 ; hidden sectors
TotalSectorsBig DD      0 ; unused (FAT32)
DriveNumber     DB      0 ; drive number
Unused          DB      0 ;
XBS             DB      41              ; signature
SerialNumber    DW 1234h,5678h ; serial number
VolumeLabel     DB      'NO NAME    ' ; volume label
FileSystem      DB      'FAT12   ' ; file system type (standard)

real_start:
RootStart:
cli
        nop
RootLen:
; we copy the boot sector at 0050:0000
     mov ax, 07C0h
Sector:
     mov ds, ax
Count:
     mov ax, 050h
temp:
        mov es, ax
end_memory:
        xor si, si
top_memory:
        xor di, di
     mov cx, 256

     cld
        rep movsw
     jmp 0050h:start2

start2:

mov ax, 9000h
     mov ss, ax
     mov sp, 0                     ; set stack at 9000h:0000

        mov ax, cs                      ; set DS and ES
     mov ds, ax
     mov es, ax
sti                             ; enable interrupts

        ; save boot drive:
        mov byte [DriveNumber], dl

        ; reset drive
        xor ax, ax
        int 13h

        ; first load the three other sectors (at the end)
        mov ax, 0203h
        mov cx, 2                     ; ch = 0 (track), cl = 2 (sector)
        mov bx, end_first
        int 13h

        jnc .good
        ; there was an error, try again:
        xor ax, ax
        int 13h                         ; reset disk

        mov ax, 0203h                   ; and read again
        int 13h

        jc near error                   ; error ? yes then stop.

.good:
        ; check for end signature:
        cmp word [end_boot], 5678h
        jne near error

        ; good, now load the executable file in memory at: STARTADDR:0000

; find the root directory
        xor ax, ax
        mov al, byte [FATs]
        mov bx, word [FATSectors]
        mul bx
        add ax, word [Hidden]
        adc ax, word [Hidden+2]
        add ax, word [Reserved]
        mov word [RootStart], ax ; save result for later

        pusha ; save registers

; now find the file entry (and cluster number)
        mov ax, 9000h ; put root directory at 9000h:0000
        mov es, ax

        mov ax, 32                      ;\
        mul word [RootEntries] ; |-> ax = (32*RootEntries)/512
        div word [BPS]                  ;/

        mov cx, ax
        mov word [RootLen], ax
        mov ax, word [RootStart]

.again:
xor bx, bx
        push es
        push ax
        push cx
                                        ; read one sector into ES:BX
        call read_sect
        xor bx, bx
.1:
        mov di, bx ; di = root entry pointer
        mov cx, 11
        mov si, filename ; compare file name
        rep cmpsb
        je found_file

        add bx, 32 ; not found, next entry
        cmp bx, word [BPS] ; end of sector ?
        je .2
        jmp .1

.2:
pop cx
        pop ax
        pop es

        inc ax ; next
        loopnz .again

jmp near error ; not found, error

found_file:
        ; the file has been found!
        pop cx
        pop ax
        pop es

        mov di, 01Ah ; get start cluster number
        add di, bx
        push bx
        mov ax, word [es:di]

        ; convert cluster "ax" into sectors
        xor bx, bx
        mov bl, byte [SPC]
        mul bx
        mov word [Sector], ax

        pop bx ; get location of directory entry
        mov di, 01Ch
        add di, bx ; get file size
        mov ax, word [es:di] ; low word
        xor dx, dx                      ; convert size in sectors
        mov bx, word [BPS]
        div bx
        inc ax
mov word [Count], ax ; save number of sectors to load(lo)

        mov ax, word [es:di+2] ; high word (64KB)
        shl ax, 7 ; 512*128 = 64*1024
add word [Count], ax ; save number of sectors to load(hi)

        popa ; restore registers

        mov ax, word [RootLen]
        add ax, word [Sector]
        add ax, word [RootStart]
        sub ax, 2
        mov cx, word [Count]

pusha
        mov si, load_msg
        call print

        shr cx, 1
        mov ax, cx
        xor cx, cx
        call printDec
        mov si, bytes_msg
        call print

        popa

        mov bx, STARTADDR                    ; load the file at STARTADDR:0000
        mov es, bx
nextsector:
pusha
        push es

        xor bx, bx
        call read_sect                       ; read a sector to ES:BX

        pop es
        popa

        mov bx, es
        add bx, 20h
        mov es, bx
        inc ax                               ; increment logical sector number
        loopnz nextsector                    ; until cx = 0

done:
jmp end_first ; call the routine of the second
         ; sector and install DOS emulation

;----------------------------------------------------------------------------
;input: ES:BX = buffer, AX = logical sector
read_sect:
        mov si, word [SPT] ; divide logical sector by track size
        div si
        inc dl ; sector begins at 1
mov byte [temp], dl

        xor dx, dx
        div word [HPC] ; logical track in ax
        mov dh, byte [DriveNumber]
        xchg dl, dh
        mov cx, ax
        xchg cl, ch
        shl cl, 6
        or cl, byte [temp]

        mov di, 5
.retry:
        mov ax, 0201h
        int 13h

        jnc .good

        ; reset drive
xor ax, ax
        int 13h

        dec di
        jnz .retry

        jmp near error
.good:
ret

;----------------------------------------------------------------------------
; print a message
; ds:si = pointer to the string (0-ended)
print
        mov ah, 0Eh
.again:
lodsb
        or al, al
        jz .done
int 10h
        jmp .again
.done:
ret

;----------------------------------------------------------------------------
error:
       mov si, error_msg
        call print

        jmp reboot

filename db 'KERNEL  BIN'

load_msg  db "Loading MiOS... ", 0
bytes_msg db " KB", 13, 10, 0
error_msg db 7, 13, 10, "Disk error.", 13, 10, 0

; align and set good signature for the BIOS
times ($$-$+510) db 0
     dw 0xAA55
;*** END OF FIRST SECTOR *******************

end_first:

start_second:
mov ax, es
        shr ax, 2
        inc ax
        shl ax, 2
        mov word [end_memory], ax ; save (to know free memory)

        int 12h ; get ram size (in KB)
        ; convert in paragraphs: (*64)
        shl ax, 6
        mov word [top_memory], ax

call install_int
        call reloc_file

        ; jump to the file
mov ax, word [exe_SS]
        mov ss, ax
        mov ax, word [exe_SP]
        mov sp, ax

mov ax, word [exe_CS]
        mov ds, ax
        mov es, ax

        ; far jump
        db 0EAh
exe_IP dw 100h
exe_CS dw STARTADDR-10h


exe_SS dw STARTADDR-10h
exe_SP dw 100h

;----------------------------------------------------------------------------
install_int:
push ds
        cli

        xor ax, ax
        mov ds, ax ; set int 20h
        mov word [ds:20h*4], int20 ; (terminate com files)
        mov word [ds:20h*4+2], cs

        mov word [ds:21h*4], int21 ; and int 21h (DOS)
        mov word [ds:21h*4+2], cs

        sti
        pop ds
ret

;----------------------------------------------------------------------------
reloc_file:
push ds
        mov ax, STARTADDR
        mov es, ax
        xor di, di


        cmp word [es:di], 'MZ'
        jne .exit

        ; yes it's a "MZ" .EXE file
        ; calculate "image base"
        add ax, word [es:di+8]

        mov cx, word [es:di+6] ; number of relocations items
        jcxz .done

        push di

        mov di, word [es:di+18h]
.reloc:
mov si, word [es:di] ; get item OFS in SI
        mov dx, word [es:di+2] ; get item SEG in DX
        add dx, ax
        mov ds, dx
        add word [ds:si], ax ; relocate it
        add di, 4
        loop .reloc

        push cs
        pop ds

        pop di

.done:
        ; set up some variables
        mov word [exe_CS], ax           ; CS

        mov ax, word [es:di+14h] ; IP
        mov word [exe_IP], ax

mov ax, word [es:di+0Eh] ; SS
        mov word [exe_SS], ax

        mov ax, word [es:di+10h] ; SP
        mov word [exe_SP], ax

.exit:
        pop ds
ret

;----------------------------------------------------------------------------
halt:
        mov si, halt_msg
        call print

;----------------------------------------------------------------------------
reboot:
mov si, reboot_msg
        call print

        xor ax, ax ; wait a key
        int 16h

        mov ax, 0E0Ah ; new line
        int 10h
        mov ax, 0E0Dh
        int 10h

        int 19h ; reboot

halt_msg db 13, 10, "That's all...", 13, 10, 0
reboot_msg db "Press any key to reboot...", 0


;----------------------------------------------------------------------------
;* int 20H: terminate .COM program.
;----------------------------------------------------------------------------

int20:
push cs
        pop ax
        mov ds, ax
        mov es, ax
jmp halt

;----------------------------------------------------------------------------
;* int 21H: DOS emulation
;----------------------------------------------------------------------------
int21:
sti ; enables interrupts

cmp ah, 0
        je near _func00 ; terminate program

        cmp ah, 25h
        je near _func25                 ; set int vec

        cmp ah, 35h
        je near _func35 ; get int vec

cmp ah, 48h
        je near _func48 ; alloc ram memory

        cmp ah, 4Ch
        je near _func4C ; terminate program

        jmp int21_error

;----------------------------------------------------------------------------
; terminate program
_func00:
jmp near int20

;----------------------------------------------------------------------------
; write string; input es:dx = string (ended with '$')
_func09:
push bx
        mov bx, dx
.next:
mov al, byte [es:bx]
        cmp al, '$'
        je .done
        call chrout
        inc bx
        jmp .next
.done:
pop bx
mov al, '$'
        jmp int21_exit

;----------------------------------------------------------------------------
; set interrupt vector
_func25:
cmp al, 19h ; do not allow to change int 19h (for rebooting)
        je near int21_error

        cli
        xor ah, ah
        shl ax, 2

        push si
        push bx
        push es

        mov si, ax
        xor bx, bx
        mov es, bx

        mov word [es:si], dx ; offset
        mov bx, ds
        mov word [es:si+2], bx ; segment

        pop es
        pop bx
        pop si
        sti

jmp int21_exit

;----------------------------------------------------------------------------
; get interrupt vector
_func35:
        push ds
        push si

xor ah, ah
        shl ax, 2
        mov si, ax

        xor bx, bx
        mov ds, bx ; DS = 0

        mov bx, word [ds:si+2] ; segment
        push bx
        mov bx, word [ds:si] ; offset

        pop es ; get segment

        pop si
        pop ds


jmp int21_exit

;----------------------------------------------------------------------------
; alloc ram memory
_func48:
mov ax, word [cs:end_memory]
        add ax, bx
        cmp ax, word [cs:top_memory]
        jg .error
        mov word [cs:top_memory], ax

.error:
mov bx, word [cs:top_memory] ; return in bx free paragraphs
        sub bx, word [cs:end_memory]
stc
jmp int21_error

;----------------------------------------------------------------------------
_func4C:
jmp near int20

int21_error:
mov ax, 0FFFFh
int21_exit:
iret

;----------------------------------------------------------------------------
;Print Decimal (Routine from Swarm OS)
;  ax value to display
;_____________________________________________________________________________

printDec:
pusha

mov bx,10000
call .digit
mov bx,1000
call .digit
mov bx,100
call .digit
mov bx,10
call .digit

add al,'0'
call chrout

        popa
ret


;Print decimal digit
.digit:
xor dx, dx
div bx ;ax=quotient
add al,'0'

cmp al,'0' ;Is digit a 0?
jne .l2 ; no, skip leading zero test
jecxz .l3 ;Suppress 0 if no characters printed yet

.l2 call chrout
.l3 mov ax,dx ;ax=remainder
ret

;----------------------------------------------------------------------------
; write a character to the screen
; input: al = ascii code for the character
chrout:
pusha
cmp al, 9
je .tabchar
        mov ah, 0Eh
        int 10h
        popa
        ret
.tabchar:
; expand tab character (8 spaces)
        mov al, ' '
        call chrout
        call chrout
        call chrout
        call chrout
        call chrout
        call chrout
        call chrout
        call chrout
        popa
        ret


; align to 2KB-2
times ($$-$+2048-2) db 0
end_boot:
dw 5678h ; end signature

;*** FIRST FAT *****************************
; now we put the first FAT:
  db 240
  dw 0xFFFF
  times (512*9)-3 db 0

;*** SECOND FAT ****************************
; the same for the second FAT:
  db 240
  dw 0xFFFF
  times (512*9)-3 db 0

;*** ROOT ENTRIES **************************
; and now the root entries:
  times 224*32 db 0

_end:

[/code]

\\\\||////
(@@)
ASHLEY4.

RE:int20h

Posted: Wed Aug 25, 2004 11:00 pm
by DIGO_RP
thanks so much! :-)