I'm writing a 16-bit x86 Assembly OS and I'm developing the program execution. The execution I've designed is different, because I want the kernel to execute the code (so it can have more control on what the program wants to do, so if it wants to overwrite the drive A: the user would be informed), not the CPU. So I'm writing the exec.asm
file with the function that will read the program and execute the correspondent instruction. I'll leave you the source code before explaining my problem.
dload.asm
DLOAD:
PUSHA
MOV AH, 0X02
MOV AL, 0X04
MOV CH, 0X00
MOV CL, 0X02
MOV DH, 0X00
MOV DL, BL
MOV BX, 0X0000
MOV ES, BX
MOV BX, 0X7E00
INT 0X13
JC DERRR
DSUCC:
POPA
MOV AL, 0X00
RET
DERRR:
POPA
MOV AL, 0X01
RET
print.asm
PRINT_CHR:
PUSHA
MOV AH, 0X0E
MOV AL, [BX]
INT 0X10
POPA
RET
PRINT_STR:
PUSHA
MOV AH, 0X0E
PRINT_STR_LOOP:
MOV AL, [BX]
CMP AL, 0X00
JE END_PRINT_STR
INT 0X10
INC BX
JMP PRINT_STR_LOOP
END_PRINT_STR:
POPA
RET
screen.asm
SHOW_BASIC_SCREEN:
PUSHA
MOV AH, 0X0E
MOV BX, PNAME_OFFSET
MOV CX, 0X14
SHOW_PNAME:
MOV AL, [BX]
CMP CX, 0X00
JE SHOW_PNAME_END
INT 0X10
INC BX
DEC CX
JMP SHOW_PNAME
SHOW_PNAME_END:
MOV AL, '='
INT 0X10
INT 0X10
MOV CX, 0X12
AFTER_PNAME_SPACES:
MOV AL, ' '
CMP CX, 0X00
JE END_SPACING
INT 0X10
DEC CX
JMP AFTER_PNAME_SPACES
END_SPACING:
MOV AL, '='
INT 0X10
INT 0X10
MOV AL, ' '
INT 0X10
MOV AL, '}'
INT 0X10
MOV CX, 0X24
SHOW_INPUT_SPACE:
MOV AL, ' '
CMP CX, 0X00
JE END_INPUT_SPACE
INT 0X10
DEC CX
JMP SHOW_INPUT_SPACE
END_INPUT_SPACE:
MOV CX, 0X16
CLOSE_PNAME:
MOV AL, '='
CMP CX, 0X00
JE CLOSE_PNAME_END
INT 0X10
INC BX
DEC CX
JMP CLOSE_PNAME
CLOSE_PNAME_END:
MOV CX, 0X12
CLOSE_SPACES:
MOV AL, ' '
CMP CX, 0X00
JE CLOSE_SPACES_END
INT 0X10
DEC CX
JMP CLOSE_SPACES
CLOSE_SPACES_END:
MOV CX, 0X28
CLOSE_INPUT:
MOV AL, '='
CMP CX, 0X00
JE CLOSE_INPUT_END
INT 0X10
DEC CX
JMP CLOSE_INPUT
CLOSE_INPUT_END:
POPA
RET
PNAME_OFFSET EQU 0X9000
setc.asm
_SETC:
MOV AH, 0X02
MOV AL, 0X00
MOV BH, 0X00
INT 0X10
RET
cscr.asm
CSCR:
PUSHA
MOV CX, BX
MOV AH, 0X0E
CSCR_LOOP:
MOV AL, 0X0A
CMP CX, 0X00
JE CSCR_END
INT 0X10
DEC CX
JMP CSCR_LOOP
CSCR_END:
MOV AH, 0X02
MOV BH, 0X00
MOV DH, 0X00
MOV DL, 0X00
INT 0X10
POPA
RET
exec.asm
EXEC_INC:
INC BX
EXEC:
PUSHA
MOV BX, 0X02
CALL CSCR
CALL SHOW_BASIC_SCREEN
POPA
MOV AL, [BX]
CMP AL, 0X00
JE _0X00
CMP AL, 0X50
JE _0X50
CMP AL, 0X51
JE _0X51
CMP AL, 0X49
JE _0X49
CMP AL, 0X4A
JE _0X4A
CMP AL, 0X3C
JE _0X3C
CMP AL, 0X52
JE _0X52
CMP AL, 0X53
JE _0X53
CMP AL, 0X3E
JE _0X3E
CMP AL, 0X7F
JE _0X7F
JMP EXEC_ERR
_0X50:
PUSHA
MOV DH, 0X03
MOV DL, 0X00
CALL _SETC
POPA
INC BX
MOV AH, 0X0E
MOV AL, [BX]
INT 0X10
JMP EXEC_INC
_0X51:
PUSHA
MOV DH, 0X03
MOV DL, 0X00
CALL _SETC
POPA
INC BX
MOV AH, 0X0E
_0X51_LOOP:
MOV AL, [BX]
CMP AL, 0X00
JE EXEC_INC
INT 0X10
INC BX
JMP _0X51_LOOP
_0X49:
PUSHA
MOV DH, 0X00
MOV DL, 0X2D
CALL _SETC
MOV AH, 0X00
MOV BX, INPUT_ADDR
INT 0X16
MOV [BX], BYTE AL
POPA
JMP EXEC_INC
_0X4A:
PUSHA
MOV DH, 0X00
MOV DL, 0X2D
CALL _SETC
MOV BX, INPUT_ADDR
_0X4A_LOOP:
MOV AH, 0X00
INT 0X16
CMP AL, 0XD
JE _0X4A_END
CMP AL, 0X7F
JE _0X4A_DEL
MOV [BX], BYTE AL
MOV AH, 0X0E
INT 0X10
INC BX
JMP _0X4A_LOOP
_0X4A_DEL:
DEC BX
MOV [BX], BYTE 0X00
JMP _0X4A_LOOP
_0X4A_END:
MOV [BX], BYTE 0X00
POPA
JMP EXEC_INC
_0X3C:
INC BX
MOV AH, [BX]
INC BX
MOV AL, [BX]
PUSHA
MOV BX, PADDR
MOV [BX], BYTE AH
INC BX
MOV [BX], BYTE AL
POPA
JMP EXEC_INC
_0X52:
PUSHA
MOV DH, 0X03
MOV DL, 0X00
CALL _SETC
MOV BX, PADDR
MOV AH, [BX]
INC BX
MOV AL, [BX]
MOV BX, AX
MOV AH, 0X0E
MOV AL, [BX]
INT 0X10
POPA
JMP EXEC_INC
_0X53:
PUSHA
MOV DH, 0X03
MOV DL, 0X00
CALL _SETC
MOV BX, PADDR
MOV AH, [BX]
INC BX
MOV AL, [BX]
MOV BX, AX
MOV AH, 0X0E
_0X53_LOOP:
MOV AL, [BX]
CMP AL, 0X00
JE _0X53_END
INT 0X10
INC BX
JMP _0X53_LOOP
_0X53_END:
POPA
JMP EXEC_INC
_0X3E:
MOV BX, PADDR
MOV AH, [BX]
INC BX
MOV AL, [BX]
MOV BX, AX
ADD BX, 0X9000
JMP EXEC
_0X7F:
PUSHA
MOV DH, 0X00
MOV DL, 0X00
CALL _SETC
MOV BX, 0X19
CALL CSCR
POPA
JMP EXEC_INC
_0X00:
RET
EXEC_ERR:
MOV DH, 0X03
MOV DL, 0X00
CALL _SETC
MOV BX, EXEC_ERR_MSG
CALL PRINT_STR
EXEC_ERR_MSG:
DB "Error executing program.", 0X0A, 0X0D, "Unrecognized instruction code.", 0X0A, 0X0D, 0X00
PADDR EQU 0X8C00
boot.asm
[ORG 0X7C00]
MOV BP, 0XF000
MOV SP, BP
__MAIN:
MOV BX, DSKL_MSG
CALL PRINT_STR
MOV BL, DL
CALL DLOAD
CMP AL, 0X01
JE __ERR
MOV BX, DONE_DSKL_MSG
CALL PRINT_STR
MOV BX, KSTART_MSG
CALL PRINT_STR
JMP KOFFSET
__ERR:
MOV BX, ERRR_DSKL_MSG
CALL PRINT_STR
JMP __END
DSKL_MSG:
DB "Loading disk at 0x0000:0x7e00...", 0X0A, 0X0D, 0X00
DONE_DSKL_MSG:
DB "Disk loaded successfully at 0x0000:0x7e00.", 0X0A, 0X0D, 0X00
ERRR_DSKL_MSG:
DB "Fatal: unable to read disk. Cannot load kernel and boot the system.", 10, 13, 0
KSTART_MSG:
DB "Starting kernel... ", 0X0A, 0X0D, 0X00
KOFFSET EQU 0X7E00
%INCLUDE "print.asm"
%INCLUDE "dload.asm"
__END:
JMP $
TIMES 510 - ( $ - $$ ) DB 0X0
DW 0XAA55
kernel.asm
[ORG 0X7E00]
__KSTART:
MOV BX, KSTARTED_MSG
CALL PRINT_STR
MOV BX, 25
CALL CSCR
__MAIN:
MOV BX, 0X02
CALL CSCR
MOV [0X9000], BYTE 'P'
MOV [0X9001], BYTE 'A'
MOV [0X9002], BYTE 'R'
MOV [0X9003], BYTE 'R'
MOV [0X9004], BYTE 'O'
MOV [0X9005], BYTE 'T'
MOV [0X9006], BYTE ' '
MOV [0X9007], BYTE ' '
MOV [0X9008], BYTE ' '
MOV [0X9009], BYTE ' '
MOV [0X900A], BYTE ' '
MOV [0X900B], BYTE ' '
MOV [0X900C], BYTE ' '
MOV [0X900D], BYTE ' '
MOV [0X900E], BYTE ' '
MOV [0X901F], BYTE ' '
MOV [0X9010], BYTE ' '
MOV [0X9011], BYTE ' '
MOV [0X9012], BYTE ' '
MOV [0X9013], BYTE ' '
MOV [0X9014], BYTE 0X4A
MOV [0X9015], BYTE 0X3C
MOV [0X9016], BYTE 0X8A
MOV [0X9017], BYTE 0X00
MOV [0X9018], BYTE 0X53
MOV [0X9019], BYTE 0X7F
MOV [0X901A], BYTE 0X3C
MOV [0X901B], BYTE 0X00
MOV [0X901C], BYTE 0X14
MOV [0X901D], BYTE 0X3E
MOV [0X901E], BYTE 0X00
CALL SHOW_BASIC_SCREEN
MOV BX, 0X9014
CALL EXEC
KSTARTED_MSG:
DB "Kernel started successfully.", 0X0A, 0X0D, 0X00
INPUT_ADDR EQU 0X8A00
%INCLUDE "print.asm"
%INCLUDE "cscr.asm"
%INCLUDE "screen.asm"
%INCLUDE "setc.asm"
%INCLUDE "exec.asm"
JMP $
EXEC is running a program at 0x9014.
Today I've written the 0X7F instruction (for clearing the screen) in the exec.asm
file. Now it works, but something changed in the 0X50, 0X51, 0X52 and 0X53 instructions (respectively to print a char, to print a string, a char pointed by BX and a null-terminating string pointed by BX). At the starting of these instructions you can see this snippet:
PUSHA
MOV DH, 0X03
MOV DL, 0X00
CALL _SETC
POPA
which is used to set the cursor at the 4th line in the screen, but for some reason it's been bypassed since I've added the 0X7F instruction. Even if I store a big number in DH (the register that is used to store the row in which the cursor has to be moved), if called the printing function prints my char or my string at the 3rd line.
I use NASM to compile boot.asm
and kernel.asm
to two separate files, boot.bin
and kernel.bin
, and so I copy the two files into another one, main.bin
, (using the Windows CMD command copy boot.bin/b+kernel.bin/b main.bin
) which is the bootable one that I boot using Bochs Emulator 2.8.
I hope you could understand my problem (if you need more info tell me and I'll edit the post with the necessary info)!
You're executing command 0x53 right before command 0x7F.
_0X7F: PUSHA MOV DH, 0X00 MOV DL, 0X00 CALL _SETC MOV BX, 0X19 CALL CSCR
Because of the number 0X19 (25 in decimal), the screen will scroll 1 line off at the top. The text that was printed at the 4th row (3) is now at the 3rd row (2).