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.