16-bit Real Mode jmp to specific position seems to freeze os

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
User avatar
Kirdow
Member
Member
Posts: 35
Joined: Sun Sep 06, 2015 2:20 pm
Libera.chat IRC: Kirdow
Location: Sweden

16-bit Real Mode jmp to specific position seems to freeze os

Post by Kirdow »

So, I've had this problem for around 2 - 3 days now, and still can't find the solution. I have tried everything I can think of. I've tried logging the variables and RAM values to see if there is anything wrong, but yet no success.

So I'm pretty new to operating system development. I've just worked on it for around half a year. My project is to make a Graphics OS in 16-bit Real Mode and Text Mode, while supporting file access using FAT12. I'm working on this on Windows XP x86 running in VirtualBox on a Windows 10 host. And to run the OS I run a virtualbox inside Windows XP with a floppy image.

I will start with posting my code (you might recognize alot of this code from MikeOS as I watched a Tinker Nut video showing this).
boot.asm

Code: Select all

	BITS 16
	
	jmp short boot_start	; Jump past disk description
	nop						; Disk description has to be at index 3, so we add this.
	
; Disk description table, this makes it a valid floppy

OEMLabel				db "KIRDBOOT"		; Disk label
BytesPerSector			dw 512				; Bytes per sector
SectorsPerCluster		db 1				; Sectors per cluster
ReservedForBoot			dw 1				; Reserved sectors for the boot record
NumberOfFats			db 2				; Numbers of copies of the FAT
RootDirEntries			dw 224				; Number of entries in root dir
LogicalSectors			dw 2880				; Number of logical sectors
MediumByte				db 0F0h				; Medium descriptor byte
SectorsPerFat			dw 9				; Sectors per FAT
SectorsPerTrack			dw 18				; Sectors per track
Sides					dw 2				; Number of sides/heads
HiddenSectors			dd 0				; Number of hidden sectors
LargeSectors			dd 0				; Number of LBA sectors
DriveNo					dw 0				; Drive No: 0
Signature				db 41				; Drive signature: 41 for floppy
VolumeID				dd 0x2F987802		; Volume ID: any number
VolumeLabel				db "KIRDOS     "	; Volume Label: any 11 chars
FileSystem				db "FAT12   "		; File system type: don't change!

; ---------------------------------------------------------------
; Main bootloader code

boot_start:
	mov ax, 07C0h					; Set up 4K of stack space above buffer
	add ax, 544						; 8k buffer = 512 paragraphs + 32 paragraphs (loader)
	cli								; Disable interrupts while changing stack
	mov ss, ax
	mov sp, 4096
	sti								; Restore interrupts
	
	mov ax, 07C0h					; Set data segment to where we're loaded
	mov ds, ax
	
	; NOTE: A few early BIOSes are reported to improperly set DL
	
	cmp dl, 0
	je no_change
	mov [bootdev], dl				; Save boot device number
	mov ah, 8						; Get dribe parameters
	int 13h
	jc fatal_disk_error
	and cx, 3Fh						; Maximum sector number
	mov [SectorsPerTrack], cx		; Sector numbers start at 1
	movzx dx, dh					; Maximum head number
	add dx, 1						; Head numbers start at 0 - add 1 for total
	mov [Sides], dx
	
no_change:
	mov eax, 0						; Needed for some older BIOSes
	

; First we need to load the root directory from the disk. Technical details:
; Start of root = ReservedForBoot + NumberOfFats * SectorsPerFat = logical 19
; Number of root = RootDirEntries * 32 bytes/entry / 512 bytes/sector = 14
; Start of user data = (start of root) + (number of root) = logical 33

floppy_ok:							; Ready to read first block of data
	mov ax, 19						; Root dir starts at logical sector 19
	call l2hts
	
	mov si, buffer					; Set ES:BX to point to our buffer (see end of code)
	mov bx, ds
	mov es, bx
	mov bx, si
	mov ah, 2						; Params for int 13h: read floppy sectors
	mov al, 14						; And read 14 of them
	
	pusha							; Prepare to enter loop
	
	
read_root_dir:
	popa							; In case registers are altered by int 13h
	pusha
	
	stc								; A few BIOSes do not set properly on error
	int 13h							; Read sectors using BIOS
	
	jnc search_dir					; If read went OK, skip ahead
	call reset_floppy				; Otherwise, reset floppy controller and try again
	jnc read_root_dir				; Floppy reset OK?
	
	jmp reboot						; If not, fatal double error
	
	
search_dir:
	popa
	
	mov ax, ds						; Root dir is now in [buffer]
	mov es, ax						; Set DI to this info
	mov di, buffer
	
	mov cx, word [RootDirEntries]	; Search all (224) entries
	mov ax, 0						; Searching at offset 0
	
	
next_root_entry:
	xchg cx, dx						; We use CX in the inner loop...
	
	mov si, kern_filename			; Start searching for kernel filename
	mov cx, 11
	rep cmpsb
	je found_file_to_load			; Pointer DI will be at offset 11
	
	add ax, 32						; Bumb searched entries by 1 (32 bytes per entry)
	
	mov di, buffer					; Point to next entry
	add di, ax
	
	xchg dx, cx						; Get the original CX back
	loop next_root_entry
	
	mov si, file_not_found			; If kernel is not found, bail out
	call print_string
	jmp reboot
	
	
found_file_to_load:					; Fetch cluster and load FAT into RAM
	mov ax, word [es:di+0Fh]		; Offset 11 + 15 = 26, contains 1st cluster
	mov word [cluster], ax
	
	mov ax, 1						; Sector 1 = first sector of first FAT
	call l2hts
	
	mov di, buffer					; ES:BX points to our buffer
	mov bx, di
	
	mov ah, 2						; int 13h params: read (FAT) sectors
	mov al, 9						; All 9 sectors of 1st FAT
	
	pusha							; Prepare to enter loop
	
	
read_fat:
	popa							; In case registers are altered by int 13h
	pusha
	
	stc
	int 13h							; Read sectors using the BIOS
	
	jnc read_fat_ok					; If read went OK, skip ahead
	call reset_floppy				; Otherwise, reset floppy controller and try again
	jnc read_fat					; Floppy reset OK?
	

; ***************************************************************
fatal_disk_error:
; ***************************************************************
	mov si, disk_error				; If not, print error message and reboot
	call print_string
	jmp reboot						; Fatal double error
	
	
read_fat_ok:
	popa
	
	mov ax, 2000h					; Segment where we'll load the kernel
	mov es, ax
	mov bx, 0
	
	mov ah, 2						; int 13h floppy read params
	mov al, 1
	
	push ax							; Save in case we (or int calls) lose it
	
; Now we must load the FAT from the disk. Here's how we find out where it starts:
; FAT cluster 0 = media descriptor = 0F0h
; FAT cluster 1 = filler cluster = 0FFh
; Cluster start = ((cluster number) - 2) * SectorsPerCluster + (start of user)
;				= (cluster number) + 31

load_file_sector:
	mov ax, word [cluster]			; Convert sector to logical
	add ax, 31
	
	call l2hts						; Make appropriate params for int 13h
	
	mov ax, 2000h					; Set buffer past what we've already read
	mov es, ax
	mov bx, word [pointer]
	
	pop ax							; Save in case we (or int calls) lose it
	push ax
	
	stc
	int 13h
	
	jnc calculate_next_cluster		; If there's no error....
	
	call reset_floppy				; Otherwise, reset floppy and retry
	jmp load_file_sector
	
	
	; In the FAT, cluster values are stored in 12 bits, so we have to
	; do a bit of maths to work out whether we're dealing with a byte
	; and 4 bits of the next byte -- or the last 4 bits of one byte
	; and then the subsequent byte!
	
calculate_next_cluster:
	mov ax, [cluster]
	mov dx, 0
	mov bx, 3
	mul bx
	mov bx, 2
	div bx							; DX = [cluster] mod 2
	mov si, buffer
	add si, ax						; AX = word in FAT for the 12 bit entry
	mov ax, word [ds:si]
	
	or dx, dx						; If DX = 0 [cluster] is even; if DX = 1 then it's odd
	
	jz even							; If [cluster] is even, drop last 4 bits of word
									; with next cluster; if odd, drop first 4 bits
									
odd:
	shr ax, 4						; Shift out first 4 bits (they belong to another entry)
	jmp short next_cluster_cont
	
	
even:
	and ax, 0FFFh					; Mast out final 4 bits
	
	
next_cluster_cont:
	mov word [cluster], ax			; Store cluster
	
	cmp ax, 0FF8h					; FF8h = end of file marker in FAT12
	jae end
	
	add word [pointer], 512			; Increase buffer pointer 1 sector length
	jmp load_file_sector
	
	
end:								; We've got the file to load!
	pop ax							; Clean up the stack (AX was pushed earlier)
	mov dl, byte [bootdev]			; Provide kernel with boot device info
	
	jmp 2000h:0000h					; Jump to entry point of loaded kernel!
	

; ---------------------------------------------------------------
; BOOTLOADER SUBROUTINES

reboot:
	mov ax, 0
	int 16h							; Wait for keystroke
	mov ax, 0
	int 19h							; Reboot the system
	
	
print_string:						; Output string in SI to screen
	pusha
	
	mov ah, 0Eh						; int 10h teletype function
	
.repeat:
	lodsb							; Get char from string
	cmp al, 0
	je .done						; If char is zero, end of string
	int 10h							; Otherwise, print it
	jmp short .repeat
	
.done:
	popa
	ret
	
	
reset_floppy:						; IN: [bootdev] = boot device; OUT: carry set on error
	push ax
	push dx
	mov ax, 0
	mov dl, byte [bootdev]
	stc
	int 13h
	pop dx
	pop ax
	ret
	
	
l2hts:								; Calculate head, track and sector settings for int 13h
									; IN: logical sector in AX, OUT: correct registers for int 13h
	push bx
	push ax
	
	mov bx, ax						; Save logical sector
	
	mov dx, 0						; First the sector
	div word [SectorsPerTrack]
	add dl, 01h						; Physical sectors start at 1
	mov cl, dl						; Sectors belong in CL for int 13h
	mov ax, bx
	
	mov dx, 0						; Now calculate the head
	div word [SectorsPerTrack]
	mov dx, 0
	div word [Sides]
	mov dh, dl						; Head/side
	mov ch, al						; Track
	
	pop ax
	pop bx
	
	mov dl, byte [bootdev]			; Set correct device
	
	ret
	
	
; ---------------------------------------------------------------
; STRINGS AND VARIABLES

	kern_filename					db "KRNLDR  SYS"		; KirdOS kernel filename
	
	disk_error						db "Floppy error! Press any key...", 0
	file_not_found					db "KRNLDR.SYS not found!", 0
	
	bootdev							db 0					; Boot device number
	cluster							dw 0					; Cluster of the file we want to load
	pointer							dw 0					; Pointer into Buffer, for loading kernel
	
	
; ---------------------------------------------------------------
; END OF BOOT SECTOR AND BUFFER START

	times 510-($-$$) db 0			; Pad remainter of boot sector with zeros
	dw 0AA55h						; Boot signature (DO NOT CHANGE!)
	
	
buffer:								; Disk buffer begins (8k after this, stack starts)


; ===============================================================

kernel.asm (assembled with nasm using bin format, and named krnldr.sys):

Code: Select all

	BITS 16
	%DEFINE OS_VER '0.2.0.1'			; OS version number
	%DEFINE OS_NAME 'KirdOS'
	
	disk_buffer	equ 24576
	

os_call_vectors:
	jmp os_main					; 0000h -- Called from bootloader
	jmp os_print_string			; 0003h
	jmp os_clear_screen			; 0006h
	jmp os_move_cursor			; 0009h
	jmp os_get_cursor_pos		; 000Ch
	jmp os_show_cursor			; 000Fh
	jmp os_hide_cursor			; 0012h
	jmp os_print_newline		; 0015h
	jmp os_get_file_list		; 0018h
	jmp os_string_length		; 001Bh
	jmp os_string_reverse		; 001Eh
	jmp os_string_uppercase		; 0021h
	jmp os_string_lowercase		; 0024h
	jmp os_string_compare		; 0027h
	jmp os_seed_random			; 002Ah
	jmp os_get_random			; 002Dh
	jmp os_pause				; 0030h
	jmp os_fatal_error			; 0033h
	jmp os_wait_for_key			; 0036h
	jmp os_check_for_key		; 0039h
	jmp os_get_line				; 003Ch
	jmp os_files_count			; 003Fh
	
	
; ---------------------------------------------------------------
; START OF KERNEL CODE

os_main:
	cli				; Clear interrupts
	mov ax, 0
	mov ss, ax		; Set stack segment and pointer
	mov sp, 0FFFFh
	sti				; Restore interrupts
	
	cld				
	
	mov ax, 2000h			; Sets segments to match kernel location in RAM
	mov ds, ax
	mov es, ax
	mov fs, ax
	mov gs, ax
	
	cmp dl, 0
	je no_change
	mov [bootdev], dl			; Save boot device number
	push es
	mov ah, 8					; Get drive parameters
	int 13h
	pop es
	and cx, 3Fh					; Maximum sector number
	mov [SecsPerTrack], cx		; Sectors number start at 1
	movzx dx, dh				; Maximum head humber
	add dx, 1					; Head numbers start at 0 - add 1 for total
	mov [Sides], dx
	
no_change:
	mov ax, 1003h				; Set text output with certain attributes
	mov bx, 0					; to be bright, and not blinking
	int 10h
	
	call os_seed_random
	
	mov si, win_msg_none
	mov word [win_msg], si
	
	jmp main_loop
	
	
main_loop:
	call os_clear_screen
	
	call os_draw_screen
	
	jmp .main_loop_pause
.main_loop_keys:
	
	call os_wait_for_key
	
	cmp ax, 0
	jg .check_key
	
.main_loop_pause:
	
	mov ax, 5
	call os_pause
	jmp .main_loop_keys
	
.check_key:
	mov dl, byte [var_win_id]
	cmp dl, 1
	je .ck_apps
	
	cmp dl, 3
	je .ck_shutdown
	
.ck_home:
	cmp al, '1'
	je .cmd_apps
	
	cmp al, '2'
	je .cmd_terminal
	
	cmp al, '3'
	je .cmd_shutdown
.ck_done:
	jmp main_loop
.ck_apps:
	cmp ah, KEY_UP
	je .ckapps_up
	
	cmp ah, KEY_DOWN
	je .ckapps_down
	
	cmp ah, KEY_ENTER
	je .ckapps_enter
	
	cmp ah, KEY_RETURN
	je .ckapps_enter
	
	jmp main_loop
	
.ck_shutdown:
	jmp main_loop

.cmd_apps:
	mov byte [var_win_id], 1
	jmp main_loop
.cmd_terminal:
	mov byte [var_win_id], 0
	jmp main_loop
.cmd_shutdown:
	mov byte [var_win_id], 3
	jmp main_loop
	
.ckapps_up:
	mov cx, word [var_app_index]
	dec cx
	cmp cx, 0
	jl .ckapps_up_l
	mov word [var_app_index], cx
	jmp main_loop
.ckapps_up_l:
	call os_files_count
	dec ax
	mov word [var_app_index], ax
	jmp main_loop

.ckapps_down:
	mov cx, word [var_app_index]
	inc cx
	call os_files_count
	cmp cx, ax
	jge .ckapps_down_g
	mov word [var_app_index], cx
	jmp main_loop
.ckapps_down_g:
	mov cx, 0
	mov word [var_app_index], cx
	jmp main_loop
	
.ckapps_enter:
	mov cx, word [var_app_index]
	mov ax, .buffer
	call os_get_file_list
	mov si, .buffer
	mov di, .filename
.ckapps_more:
	lodsb
	cmp cx, 0
	je .ckapps_store
	cmp al, ','
	jne .ckapps_more
	dec cx
	jmp .ckapps_more
.ckapps_store:
	cmp al, ','
	je .ckapps_load
	stosb
	jmp .ckapps_more
.ckapps_load:
	mov si, .filename
	call os_file_exists
	jnc .not_found
	
	mov si, .filename
	mov di, kern_file_name
	call os_string_compare
	jc .no_kernel_execute
	
	push si
	
	mov bx, si
	mov ax, si
	call os_string_length
	mov si, bx
	add si, ax
	
	dec si
	dec si
	dec si
	
	mov di, bin_ext
	mov cx, 3
	rep cmpsb
	jne .not_bin_extension
	
	pop si
	mov ax, si
	mov cx, 32768
	call os_load_file
	
	jmp .execute_bin_program
	
.not_found:
	call os_clear_screen
	mov si, no_file_found
	call os_print_string
	call os_wait_for_key
	jmp main_loop

.no_kernel_execute:
	mov si, kernexec_warn_msg
	call os_print_string
	mov si, press_any_key_msg
	call os_print_string
	call os_wait_for_key
	jmp main_loop
	
.not_bin_extension:
	pop si
	mov si, binonly_msg
	call os_print_string
	mov si, press_any_key_msg
	call os_print_string
	call os_wait_for_key
	jmp main_loop
	
.execute_bin_program:
	call os_clear_screen 			; Clear screen before running
	
	mov ax, 0
	mov bx, 0
	mov cx, 0
	mov dx, 0
	mov si, 0
	mov di, 0
	
	call 32768						; Run the program. Program must end with 'ret'
	
	call os_clear_screen
	jmp main_loop
	
	.filename			times 13 db 0
	.buffer				times 1024 db 0

testdbg:
	jmp 0003h
	
clear_reg:
	mov ax, 0
	mov bx, 0
	mov cx, 0
	mov dx, 0
	mov si, 0
	mov di, 0
	ret
	
app_selector:
	popa
	mov si, os_init_msg
	call os_print_string
	call os_print_newline
	mov si, os_version_msg
	call os_print_string
	call os_print_newline
	
	call os_draw_screen
	
	jmp $
	
	
file_selector:
	pusha
	mov word [.filename], 0
	
	mov ax, .buffer				; Get comma-separated list of filenames
	call os_get_file_list
	
	mov si, .files_str
	call os_print_string
	mov si, .buffer
	call os_print_string
	call os_print_newline
	
	mov si, .enter_file
	call os_print_string
	mov si, buffer
	call os_get_line
	mov si, buffer
	mov ax, buffer
	call os_string_length
	call os_int_to_string
	mov si, ax
	call os_print_string
	call os_print_newline
	mov si, buffer
	call os_file_exists
	jnc .not_found
	
	mov si, buffer					; Did the user try to run 'KRNLDR.SYS'?
	mov di, kern_file_name
	call os_string_compare
	jc no_kernel_execute			; Show an error message if so
	
	push si							; Save filename temporarily
	
	mov bx, si
	mov ax, si
	call os_string_length
	mov si, bx
	add si, ax						; SI not points to end of filename...
	
	dec si
	dec si
	dec si							; ...and now to start of extension!
	
	mov di, bin_ext
	mov cx, 3
	rep cmpsb						; Are final 3 chars 'BIN'?
	jne not_bin_extension			; If not, ask again
	
	pop si							; Restore filename
	mov ax, si
	mov cx, 32768					; Where to load the program file
	call os_load_file				; Load filename prnted by AX
	
	jmp execute_bin_program
	
.not_found:
	call os_clear_screen
	mov si, no_file_found
	call os_print_string
	jmp file_selector
	
	
	.filename				times 12 db 0
	.buffer					times 1024 db 0
	.sbuffer				times 64 db 0
	.char_print				db 0
	.files_str				db "Files on disk: ", 0
	.enter_file				db "Execute program: ", 0
	
	
	
execute_bin_program:
	call os_clear_screen		; Clear screen before running
	
	mov ax, 0					; Clear all registers
	mov bx, 0
	mov cx, 0
	mov dx, 0
	mov si, 0
	mov di, 0
	call 32768					; Call the extenral program code
								; Loaded at second 32K segment
								; (program mus end with 'ret')
								
	call os_clear_screen		; When finished, clear screen
	jmp app_selector			; and go back to the program list
	
no_kernel_execute:				; Warn about trying to executring kernel!
	mov si, kernexec_warn_msg
	call os_print_string
	mov si, press_any_key_msg
	call os_print_string
	push ax
	call os_wait_for_key
	pop ax
	
	jmp app_selector
	
not_bin_extension:
	mov si, binonly_msg
	call os_print_string
	mov si, press_any_key_msg
	call os_print_string
	push ax
	call os_wait_for_key
	pop ax
	
	jmp app_selector
	
; ---------------------------------------------------------------
; SYSTEM VARIABLES -- Settings for programs and system calls

	kernexec_warn_msg			db "You cannot execute the kernel", 13, 10, 0
	binonly_msg					db "You can only executre .BIN files", 13, 10, 0
	press_any_key_msg			db "Press any key to continue...", 13, 10, 0
	
	kern_file_name				db 'KRNLDR.SYS', 0
	bin_ext						db 'BIN', 0
	
	no_file_found				db "Program was not found", 13, 10, 0
	
	os_init_msg					db "Welcome to ",OS_NAME, 0
	os_version_msg				db "Version ", OS_VER, 0
	os_msg						db OS_NAME, 0
	
	test_str					db "Does show up?", 13, 10, 0
	
	win_msg						dw 0
	win_msg_none				db "No Menu Command", 0
	win_msg_apps				db "Menu Apps", 0
	win_msg_term				db "Menu Term", 0
	win_msg_shutdown			db "Menu Shutdown", 0
	
	var_win_id					db 0					; Window type ID
	var_app_index				dw 0					; App list index
	
	buffer			   times 64 db 0


; ---------------------------------------------------------------
; FEATURES -- Code to pull into the kernel
	%INCLUDE "features/cli.asm"
	%INCLUDE "features/disk.asm"
	%INCLUDE "features/keyboard.asm"
	%INCLUDE "features/math.asm"
	%INCLUDE "features/misc.asm"
	%INCLUDE "features/screen.asm"
	%INCLUDE "features/string.asm"
	
	
; ===============================================================
; END OF KERNEL
; ===============================================================
	
At the bottom of the kernel I keep my include statements, I will not post all source files as I know they are working

screen.asm:

Code: Select all

; ---------------------------------------------------------------
; os_print_string -- Displays text
; IN: SI = message location (zero-terminated string)
; OUT: Nothing (registers preserved)

os_print_string:
	pusha
	
	mov ah, 0Eh						; int 10h teletype function
	
.repeat:
	lodsb							; Get char from string
	cmp al, 0
	je .done						; If char is zero, end of string
	
	int 10h							; Otherwise, print it
	jmp .repeat						; And move on to the next char
	
.done:
	popa
	ret
	
	
; ---------------------------------------------------------------
; os_clear_screen -- Clears the screen to background
; IN/OUT: Nothing (registers preserved)

os_clear_screen:
	pusha
	
	mov dx, 0						; Position cursor at top-left
	call os_move_cursor
	
	mov ah, 6						; Scroll full-screen
	mov al, 0						; Normal white on black
	mov bh, 7						;
	mov cx, 0						; Top-left
	mov dh, 24						; Bottom-right
	mov dl, 79
	int 10h
	
	popa
	ret
	
	
; ---------------------------------------------------------------
; os_move_cursor -- Moves cursor in text mode
; IN: DH, DL = row, column; OUT: Nothing (registers preserved)

os_move_cursor:
	pusha
	
	mov bh, 0
	mov ah, 2
	int 10h							; BIOS interrupt to move cursor
	
	popa
	ret
	
	
; ---------------------------------------------------------------
; os_get_cursor_pos -- Return position of text cursor
; OUT: DH, DL = row, column

os_get_cursor_pos:
	pusha
	
	mov bh, 0
	mov ah, 3
	int 10h							; BIOS interrupt to get cursor position
	mov [.tmp], dx
	popa
	mov dx, [.tmp]
	ret
	
	
	.tmp dw 0
	
	
; ---------------------------------------------------------------
; os_show_cursor -- Turns on cursor in text mode
; IN/OUT: Nothing

os_show_cursor:
	pusha
	
	mov ch, 6
	mov cl, 7
	mov ah, 1 
	mov al, 3
	int 10h
	
	popa
	ret
	
	
; ---------------------------------------------------------------
; os_hide_cursor -- Turns off cursor in text mode
; IN/OUT: Nothing

os_hide_cursor:
	pusha
	
	mov ch, 32
	mov ah, 1
	mov al, 3							; Must be video mode for buggy BIOSes!
	int 10h
	
	popa
	ret
	
	
; ---------------------------------------------------------------
; os_print_newline -- Reset cursor to start of next line
; IN/OUT: Nothing (registers preserved)

os_print_newline:
	pusha
	
	mov ah, 0Eh							; BIOS output char code
	
	mov al, 13
	int 10h
	mov al, 10
	int 10h
	
	popa
	ret
	
	
; ---------------------------------------------------------------
; os_draw_horiz_line -- Draw a horizontal line on the screen
; IN: AX = line type (1 for double (-), otherwise single (=))
; OUT: Nothing (registers preserved)

os_print_horiz_line:
	pusha
	
	mov cx, ax							; Store line type param
	mov al, 196							; Default is single-line code
	
	cmp cx, 1							; Was double-line specified in AX?
	jne .ready
	mov al, 205							; If so, here's the code
	
.ready:
	mov cx, 0							; Counter
	mov ah, 0Eh							; BIOS output char routine
	
.restart:
	int 10h
	inc cx
	cmp cx, 80							; Drawn 80 chars yet?
	je .done
	jmp .restart
	
.done:
	popa
	ret
	
	
; ---------------------------------------------------------------
; os_draw_block == render block of specified color
; IN: BL/DL/DH/SI/DI = color/start X pos/start Y pos/width/finish Y pos

os_draw_block:
	pusha
	
.more:
	call os_move_cursor					; Move to block starting position
	
	mov ah, 09h							; Draw color sections
	mov bh, 0
	mov cx, si
	mov al, ' '
	int 10h
	
	
	mov ax, 0
	mov al, dh							; Get current Y position into DL
	cmp ax, di							; Reached finishing point (DI)?
	jne .more_inc						; If not, keep drawing

	popa
	ret
	
.more_inc:
	inc dh								; Get ready for next line
	jmp .more
	
	
; ---------------------------------------------------------------
; os_draw_background -- Draws the default background of KirdOS
; IN: Nothing; OUT: AX = String containing current time

os_draw_background:
	pusha
	
	call os_clear_screen
	
	; Draw default frame
	
	
	mov bl, 80h
	mov dl, 0
	mov dh, 1
	mov si, 80
	mov di, 1
	call os_draw_block
	mov bl, 70h
	mov dl, 0
	mov dh, 0
	mov si, 80
	mov di, 0
	call os_draw_block
	mov bl, 70h
	mov dl, 0
	mov dh, 2
	mov si, 80
	mov di, 24
	call os_draw_block
	
	; Draw OS and Version
	
	mov dh, 0
	mov dl, 0
	call os_move_cursor
	mov bl, 2Fh
	mov si, os_msg
	call os_print_string
	mov ax, os_version_msg
	call os_string_length
	mov dx, 79
	sub dx, ax
	call os_move_cursor
	mov bl, 2Fh
	mov si, os_version_msg
	call os_print_string
	
	; Draw Clock
	
	mov bx, .time
	call os_get_time_string
	mov ax, bx
	call os_string_length
	mov dx, 79
	sub dx, ax
	mov dh, 1
	call os_move_cursor
	mov si, .time
	mov bl, 70h
	call os_print_string
	
	popa
	mov ax, .time
	ret
	
	.time		times 10 db 0
	

; ---------------------------------------------------------------
; os_draw_menu -- Draws a menu for KirdOS
; IN/OUT: Nothing

os_draw_menu:
	pusha
	
	mov dh, 1
	mov dl, 0
	call os_move_cursor
	mov bl, 80h
	mov si, .menu_1
	call os_print_string
	mov si, .space
	call os_print_string
	mov si, .menu_2
	call os_print_string
	mov si, .space
	call os_print_string
	mov si, .menu_3
	call os_print_string
	
	popa
	ret
	
	.menu_1			db "1.APPS", 0
	.menu_2			db "2.TERM", 0
	.menu_3			db "3.SHUTDOWN", 0
	.space			db ' ', 0
	
	
; ---------------------------------------------------------------
; os_draw_windows -- Draws the windows for KirdOS
; IN: SI = Message; OUT: Nothing

os_draw_windows:
	pusha
	
	; Draw welcome
	
	mov dl, 80
	mov ax, .welcome_msg
	call os_string_length
	sub dl, al
	mov cl, dl
.loop1:
	cmp cl, 1
	jle .loop1end
	dec dl
	sub cl, 2
	jmp .loop1
.loop1end:
	mov dh, 4
	call os_move_cursor
	mov bl, 70h
	mov si, .welcome_msg
	call os_print_string
	
	mov dl, 80
	mov ax, .welcome_msg_by
	call os_string_length
	sub dl, al
	mov cl, dl
.loop2:
	cmp cl, 1
	jle .loop2end
	dec dl
	sub cl, 2
	jmp .loop2
.loop2end:
	mov dh, 5
	call os_move_cursor
	mov bl, 70h
	mov si, .welcome_msg_by
	call os_print_string
	call os_print_newline
	
	; Draw Debug
	
	; Draw current windows
	
	push ax
	mov al, byte[var_win_id]
	
	cmp al, 0
	je .cont_end
	
	cmp al, 1
	je .window_apps
	
	cmp al, 3
	je .window_shutdown
.cont_end:
	pop ax
	
	popa
	ret
	
.window_apps:
	mov dl, 40
	sub dl, 12
	mov dh, 3
	mov bl, 80h
	mov si, 24
	mov di, 22
	call os_draw_block
	add dl, 2
	add dh, 2
	sub si, 4
	sub di, 3
	mov bl, 70h
	call os_draw_block
	mov dl, 40
	sub dl, 6
	mov dh, 3
	call os_move_cursor
	mov bl, 80h
	mov si, .select_app
	call os_print_string
	
	; Draw Debug
	
	mov dl, 0
	mov dh, 3
	call os_move_cursor
	mov ax, word [var_app_index]
;	call os_int_to_string
	mov bl, 70h
	mov si, ax
;	call os_print_string
	
.setup_applist:
	call os_get_file_list
	push cx
	push ax
	mov si, ax
	mov cl, 4
	jmp .newline
.more:
	lodsb
	cmp al, 20h
	jl .donelist
	cmp al, ','
	je .newline
	mov ah, 0Eh
	int 10h
	jmp .more
.newline:
	add cl, 1
	mov dl, 31
	mov dh, cl
	call os_move_cursor
	jmp .more
	
.donelist:
	pop ax
	pop cx
	
	pusha
	mov ax, word [var_app_index]
	mov dl, 30
	mov dh, al
	add dh, 5
	call os_move_cursor
	mov ah, 0Eh
	mov al, '>'
	int 10h
	popa
	
	jmp .cont_end
	
.window_shutdown:
	
	jmp .cont_end
	
	.welcome_msg			db "Welcome to ",OS_NAME, 0
	.welcome_msg_by			db "Written by Kirdow in Assembly", 0
	
	.select_app				db "Select File ", 0
	
	.ptr					dw 0				; Pointer to string location
	.ptr_c					dw 0				; Skipped values count
	.line					db 0
	.eof					db 0
	
	.buffer					times 1024 db 0
	.file_buffer			times 13 db 0
	.file_row				db 0
	
; ---------------------------------------------------------------
; os_draw_screen -- Main renderer for KirdOS
; IN: Nothing; OUT: AX = String containing current time

os_draw_screen:
	pusha
	
	call os_draw_background
	call os_draw_menu
	call os_draw_windows
	
	mov dh, 24
	mov dl, 0
	call os_move_cursor
	
	mov word [.time], ax
	popa
	mov ax, word [.time]
	ret
	
	.time			dw 0
	
	
; ---------------------------------------------------------------
; os_list_dialog -- Shows a list dialog to the user
; IN: AX = Question string, SI = Comma separated string of values
; OUT: AX = String containing value

os_list_dialog:
	ret
Then we have some programs, this problem applies to all programs, and I will just post the one I'm testing it with.
helowrld.asm:

Code: Select all

; ---------------------------------------------------------------
; Hello World program

	BITS 16
	%INCLUDE "kirdosdev.inc"
	ORG 32768
	
; ---------------------------------------------------------------
; Start

start:
	mov si, hellow_str
	call os_print_string
	call os_wait_for_key
	mov si, enter_name
	call os_print_string
	mov si, buffer
	call os_get_line
	mov BYTE [si], 0
	push si
	mov si, hello_name
	call os_print_string
	pop si
	mov si, buffer
	call os_print_string
	call os_print_newline
	mov si, exit_string
	call os_print_string
	call os_wait_for_key
	ret

; ---------------------------------------------------------------
; Variables

hellow_str					db "Hello World and welcome to first program", 13, 10, 0
exit_string					db "Press any key to exit Hello World...", 13, 10, 0
enter_name					db "What's your name? ", 0
hello_name					db "Hello, ", 0

buffer						times 64 db 0

; ---------------------------------------------------------------
; main

helowrld.asm, like all other programs, include a file with macros and preprocessors for nasm including predefined positions for kernel calls.
these positions refer to the os_call_vectors in the top of kernel.asm
kirdosdev.inc:

Code: Select all

; ---------------------------------------------------------------
; Include file for KirdOS program development
; ---------------------------------------------------------------

; ---------------------------------------------------------------
; IMPARTANT LOCATIONS

os_main							equ 0000h		; Where the OS code starts

; ---------------------------------------------------------------
; KEYS

%DEFINE KEY_UP		72
%DEFINE KEY_DOWN	80
%DEFINE KEY_LEFT	75
%DEFINE KEY_RIGHT	77

%DEFINE KEY_ESC		27
%DEFINE KEY_ENTER	13


; ---------------------------------------------------------------
; SYSTEM CALLS

; Screen control

os_print_string					equ 0003h	; SI = zero-terminated string location
os_clear_screen					equ 0006h	; (Nothing used)
os_move_cursor					equ 0009h	; DH, DL = row, column
os_get_cursor_pos				equ 000Ch	; OUT: DH = row, DL = column
os_show_cursor					equ 000Fh	; (Nothing used)
os_hide_cursor					equ 0012h	; (Nothing used)
os_print_newline				equ 0015h	; (Nothing used)

; Keyboard control

os_wait_for_key					equ 0036h	; Returns AL = key pressed
os_check_for_key				equ 0039h	; Returns AL = key pressed
os_get_line						equ 003Ch	; IN/OUT: SI = 64 byte buffer input

; String control

os_string_length				equ 001Bh	; AX = string loc, returns AL = length
os_string_reverse				equ 001Eh	; SI = string location
os_string_uppercase				equ 0021h	; AX = zero-terminated string
os_string_lowercase				equ 0024h	; AX = zero-terminated string
os_string_compare				equ 0027h	; SI, DI = strings, carry set if same

; Math control

os_get_random					equ 002Dh	; IN: AX, BX = low, high; OUT: CX = num

; Misc OS functions

os_pause						equ 0030h	; AX = 10ths of second to wait
os_fatal_error					equ 0033h	; AX = error string location
So, these are the only files I need in this post.

So to describe my problem and what I've found when trying to fix it.
So my bootloader is fine, that one just loads the kernel as a file on the FAT12 Floppy. It then loads it to ram
position 2000h and jumps to that position using jmp 2000h:0000h
Then in the start of the kernel it sets up the required segments.
in the main_loop function it first clears the screen with a function in screen.asm which is further up in this post.
after that it draws the screen.
then it jumps to a subfunction (.label) which freeze the os for 0.55 seconds and then continues where it was.
It then waits for the user to press a key, and also checks if the key pressed is greater than zero, if it is, it handles the inputted key. If it is zero though, it just waits for a new key to be pressed.
then it checks the value of var_win_id, which is a variable telling which window is currently open. If the apps window is open, it jumps to .ck_apps (which is short for .check_keys_apps) and checks the input there. If the value is 3, it jumps to the .ck_shutdown label which currently just goes back to the main loop instead of shutting down. If there is no window open, it just checks if the user pressed any of the keys 1 - 3 which is command. For example if user press the '1' key, it sets var_win_id to 1, which would again run .ck_apps if a key is pressed.
We're gonna take a look in .ck_apps.
.ck_apps has 3 (or 4, but the last 2 just checks the same key but 2 different versions) keys which it checks. UP, DOWN and ENTER/RETURN. Up and Down just cycle thru the files to choose from the Floppy, listed in a list box. If the user press ENTER though, it jumps to .ckapps_enter, which copies the filename selected into a variable. Note that alot of the following uses subfunctions, which has a . in front of the label. I wouldn't recommend doing this though, but I had to do it I remember for a thing to work, so I will keep it like that for now. but anyawy after the filename is copied, it continues in .ckapps_load, which first checks if the file exists. I haven't posted any of the diskmanagement code as I know they work correctly. if the file contains, it then checks if the filename is KRNLDR.SYS, which would be the kernel, and if it is, it would prompt the user it can't run the kernel, and then go back to redrawing the os and wait for a key. But if the file selected isn't the kernel, it then checks if the extension is .bin, which is the currently only extension which can get executed. if the file is a .bin file, it then loads the file to 32768 (or 0x8000). This is confirmed too that it loads the file to ram. after it has loaded the file, it jumps to .execute_bin_extension, which clears the screen, resets the registers ax, bx, cx, dx, si and di to 0. then runs "call 32768" to call the program code. after the program is done, it clears the screen and goes back to the beginning of main_loop.

So, in the program code (helowrld.asm), it firsts moves hellow_str to si, which is a pointer to a string declared in the bottom of the program code. After that it run os_print_string, which is defined in kirdosdev.inc as "os_print_string equ 0003h". What happens next is that the os just freeze, and nothing more happens. This is where I though the program wasn't actually loaded. So I tried comparing values in the program (using the position in ram where the program is, and declaring values in the program code with "db <byte>"), both from the kernel, and program, and logging them to the user (when I log it to the user from the program, I just copied the code from the kernel into the program code), which actually both gave the correct result. Which means the program actually loads and gets executed. Then I try something else, I check the call vectors to see if they are different depending on if the kernel or the program is running. But they were still the same.
I then tried to jump to the call vectors from within the kernel. And what do I find, I find that the code actually freezes. I wrote "call os_print_string" on a value, which then print the value I entered in si register. I then wrote "call 0003h", which refers to some code saying "jmp os_print_string", and this time it doesn't print the value, instead it freezes again. So appearently, I suppose, there's some problem with the call vectors. I then tried putting a label before the "jmp os_print_string" code and calling that one. Same thing there, it freezes.

I then tried decompiling, and found that the call vector for 0003h say "jmp word 0x16d8". So I went to byte number 0x16d8, and checked the code to see if it were something else than the os_print_string function. What do I find out? I found out that it is the os_print_string function, which is what it should be. This is where my ideas stop. I've tried what I could, I've compared the code with the code from MikeOS, and all the critical parts are the same. So now I have no clue anymore how to fix this.
Octocontrabass
Member
Member
Posts: 5587
Joined: Mon Mar 25, 2013 7:01 pm

Re: 16-bit Real Mode jmp to specific position seems to freez

Post by Octocontrabass »

Kirdow wrote:

Code: Select all

os_call_vectors:
	jmp os_main					; 0000h -- Called from bootloader
	jmp os_print_string			; 0003h
It looks like you're expecting near jumps. Are you sure NASM isn't generating any short jumps?
User avatar
Kirdow
Member
Member
Posts: 35
Joined: Sun Sep 06, 2015 2:20 pm
Libera.chat IRC: Kirdow
Location: Sweden

Re: 16-bit Real Mode jmp to specific position seems to freez

Post by Kirdow »

Octocontrabass wrote:
Kirdow wrote:

Code: Select all

os_call_vectors:
	jmp os_main					; 0000h -- Called from bootloader
	jmp os_print_string			; 0003h
It looks like you're expecting near jumps. Are you sure NASM isn't generating any short jumps?
I checked the code from the MikeOS, copied it over and tried that, and that actually works fine, no problems. Yet it uses the same code for the call vectors.
I also disassembled the code and saw

Code: Select all

jmp os_main
gets turned into

Code: Select all

jmp word 0x48
. I'm not sure if that's a near jump of far jump though. and as I'm not really sure what near/short jump means, could you give a quick explaination?
alexfru
Member
Member
Posts: 1112
Joined: Tue Mar 04, 2014 5:27 am

Re: 16-bit Real Mode jmp to specific position seems to freez

Post by alexfru »

Kirdow wrote:I'm not sure if that's a near jump of far jump though. and as I'm not really sure what near/short jump means, could you give a quick explaination?
There are several different encodings for "jmp label/offset" and "j<condition> label/offset" instructions. The shortest one has an 8-bit offset and therefore has a reach of +/-128 bytes (approx). This is a short jump. Longer ones have word-sized offsets (that is, 16-bit or 32-bit depending on whether it's 16-bit code or 32-bit code) and therefore a longer reach of +/-32768 or +/-2GB bytes (approx). This is a near jump (near actually means that the jump does not change the code segment). See your instruction set manual for details. Starting with version 2.03 (if I'm not mistaken) NASM tries to use the shortest encoding by default. And so unless you explicitly tell NASM to use a short or a near jump in some way, you may end up with both. Normally, this is not a problem. But in cases like yours, where you expect jumps to be of a certain length because they are part of a table, you need to do something about it.
User avatar
Kirdow
Member
Member
Posts: 35
Joined: Sun Sep 06, 2015 2:20 pm
Libera.chat IRC: Kirdow
Location: Sweden

Re: 16-bit Real Mode jmp to specific position seems to freez

Post by Kirdow »

alexfru wrote:
Kirdow wrote:I'm not sure if that's a near jump of far jump though. and as I'm not really sure what near/short jump means, could you give a quick explaination?
There are several different encodings for "jmp label/offset" and "j<condition> label/offset" instructions. The shortest one has an 8-bit offset and therefore has a reach of +/-128 bytes (approx). This is a short jump. Longer ones have word-sized offsets (that is, 16-bit or 32-bit depending on whether it's 16-bit code or 32-bit code) and therefore a longer reach of +/-32768 or +/-2GB bytes (approx). This is a near jump (near actually means that the jump does not change the code segment). See your instruction set manual for details. Starting with version 2.03 (if I'm not mistaken) NASM tries to use the shortest encoding by default. And so unless you explicitly tell NASM to use a short or a near jump in some way, you may end up with both. Normally, this is not a problem. But in cases like yours, where you expect jumps to be of a certain length because they are part of a table, you need to do something about it.
I tried changing the os_call_vectors to near jumps, but that just made the same result. Note though, even though it's 30k distance between the program and kernel, it still fails if the kernel itself uses a call vector, even though that would be much less distance. Or maybe I'm wrong.
Octocontrabass
Member
Member
Posts: 5587
Joined: Mon Mar 25, 2013 7:01 pm

Re: 16-bit Real Mode jmp to specific position seems to freez

Post by Octocontrabass »

Have you examined the jump table using a hex editor? You should be able to easily see which jmp opcodes the assembler is generating; 0xEB is a short jump and 0xE9 is a near jump.
User avatar
Kirdow
Member
Member
Posts: 35
Joined: Sun Sep 06, 2015 2:20 pm
Libera.chat IRC: Kirdow
Location: Sweden

Re: 16-bit Real Mode jmp to specific position seems to freez

Post by Kirdow »

Octocontrabass wrote:Have you examined the jump table using a hex editor? You should be able to easily see which jmp opcodes the assembler is generating; 0xEB is a short jump and 0xE9 is a near jump.
They all start with E9
User avatar
Kirdow
Member
Member
Posts: 35
Joined: Sun Sep 06, 2015 2:20 pm
Libera.chat IRC: Kirdow
Location: Sweden

Re: 16-bit Real Mode jmp to specific position seems to freez

Post by Kirdow »

Ok, progress done. Though not solved yet. I tried pasting this code near the start but after all the needed setting up:

Code: Select all

	mov si, bin_ext
	call 0003h
	call os_wait_for_key
bin_ext is a byte pointer declared like this:

Code: Select all

bin_ext     db "BIN", 0
the second line is pointing to one of the call vectors at the top which looks like:

Code: Select all

jmp os_print_string
which is to be noted, a near jump.
The last line is just a function which hangs the os until user press a key. I included that so I would be able to see the BIN output if it succeed before it redraws.

So I used NASM's disassemble and ran it on my kernel file using

Code: Select all

ndisasm krnldr.sys -k 512,6502
This will disassemble the first 512 bytes and cut of the rest.
So the jmp os_print_string is located at 0x03 in the file
I then tried to add this code I wrote earlier in at different positions, narrowing down to a specific point where it screws up.
I then found 2 spots near eachother where it works on the first one but not the second.
So the first code is on the working one.
The working one:

Code: Select all

	BITS 16
	
	%DEFINE OS_VER '0.2.0.1'			; OS version number
	%DEFINE OS_NAME 'KirdOS'
	
	disk_buffer	equ 24576
	

os_call_vectors:
	jmp os_main					; 0000h -- Called from bootloader
	jmp os_print_string			; 0003h
	jmp os_clear_screen			; 0006h
	jmp os_move_cursor			; 0009h
	jmp os_get_cursor_pos		; 000Ch
	jmp os_show_cursor			; 000Fh
	jmp os_hide_cursor			; 0012h
	jmp os_print_newline		; 0015h
	jmp os_get_file_list		; 0018h
	jmp os_string_length		; 001Bh
	jmp os_string_reverse		; 001Eh
	jmp os_string_uppercase		; 0021h
	jmp os_string_lowercase		; 0024h
	jmp os_string_compare		; 0027h
	jmp os_seed_random			; 002Ah
	jmp os_get_random			; 002Dh
	jmp os_pause				; 0030h
	jmp os_fatal_error			; 0033h
	jmp os_wait_for_key			; 0036h
	jmp os_check_for_key		; 0039h
	jmp os_get_line				; 003Ch
	jmp os_files_count			; 003Fh
	
	
; ---------------------------------------------------------------
; START OF KERNEL CODE

os_main:
	cli				; Clear interrupts
	mov ax, 0
	mov ss, ax		; Set stack segment and pointer
	mov sp, 0FFFFh
	sti				; Restore interrupts
	
	cld				
	
	mov ax, 2000h			; Sets segments to match kernel location in RAM
	mov ds, ax
	mov es, ax
	mov fs, ax
	mov gs, ax
	
	cmp dl, 0
	je no_change
	mov [bootdev], dl			; Save boot device number
	push es
	mov ah, 8					; Get drive parameters
	int 13h
	pop es
	and cx, 3Fh					; Maximum sector number
	mov [SecsPerTrack], cx		; Sectors number start at 1
	movzx dx, dh				; Maximum head humber
	add dx, 1					; Head numbers start at 0 - add 1 for total
	mov [Sides], dx
	
no_change:
	mov ax, 1003h				; Set text output with certain attributes
	mov bx, 0					; to be bright, and not blinking
	int 10h
	
	call os_seed_random
	
	
	
	mov si, win_msg_none
	mov word [win_msg], si
	
	jmp main_loop
	
	
main_loop:
	call os_clear_screen
	
	
	call os_draw_screen
	
	jmp main_loop_pause
main_loop_keys:
	
	call os_wait_for_key
	
	cmp ax, 0
	jg check_key
	
main_loop_pause:
	
	mov ax, 5
	call os_pause
	jmp main_loop_keys
	
check_key:
	mov si, bin_ext
	call 0003h        ; this is where it works
	call os_wait_for_key
	mov dl, byte [var_win_id]
	cmp dl, 1
	je ck_apps
	
	cmp dl, 3
	je ck_shutdown
	
ck_home:
	cmp al, '1'
	je cmd_apps
	
	cmp al, '2'
	je cmd_terminal
	
	cmp al, '3'
	je cmd_shutdown
ck_done:
	jmp main_loop
ck_apps:
	cmp ah, KEY_UP
	je ckapps_up
	
	cmp ah, KEY_DOWN
	je ckapps_down
	
	cmp ah, KEY_ENTER
	je ckapps_enter
	
	cmp ah, KEY_RETURN
	je ckapps_enter
	
	jmp main_loop
	
ck_shutdown:
	jmp main_loop

as you can see that's where it starts to check key input, and the position in the file is 0xAC, which is 0xA9 distance from what it calls.
Though we try the next position, it freezes the os completly when it uses the same function, as I said in my first post:

Code: Select all

	BITS 16

	%DEFINE OS_VER '0.2.0.1'			; OS version number
	%DEFINE OS_NAME 'KirdOS'
	
	disk_buffer	equ 24576
	

os_call_vectors:
	jmp os_main					; 0000h -- Called from bootloader
	jmp os_print_string			; 0003h
	jmp os_clear_screen			; 0006h
	jmp os_move_cursor			; 0009h
	jmp os_get_cursor_pos		; 000Ch
	jmp os_show_cursor			; 000Fh
	jmp os_hide_cursor			; 0012h
	jmp os_print_newline		; 0015h
	jmp os_get_file_list		; 0018h
	jmp os_string_length		; 001Bh
	jmp os_string_reverse		; 001Eh
	jmp os_string_uppercase		; 0021h
	jmp os_string_lowercase		; 0024h
	jmp os_string_compare		; 0027h
	jmp os_seed_random			; 002Ah
	jmp os_get_random			; 002Dh
	jmp os_pause				; 0030h
	jmp os_fatal_error			; 0033h
	jmp os_wait_for_key			; 0036h
	jmp os_check_for_key		; 0039h
	jmp os_get_line				; 003Ch
	jmp os_files_count			; 003Fh
	
	
; ---------------------------------------------------------------
; START OF KERNEL CODE

os_main:
	cli				; Clear interrupts
	mov ax, 0
	mov ss, ax		; Set stack segment and pointer
	mov sp, 0FFFFh
	sti				; Restore interrupts
	
	cld				
	
	mov ax, 2000h			; Sets segments to match kernel location in RAM
	mov ds, ax
	mov es, ax
	mov fs, ax
	mov gs, ax
	
	cmp dl, 0
	je no_change
	mov [bootdev], dl			; Save boot device number
	push es
	mov ah, 8					; Get drive parameters
	int 13h
	pop es
	and cx, 3Fh					; Maximum sector number
	mov [SecsPerTrack], cx		; Sectors number start at 1
	movzx dx, dh				; Maximum head humber
	add dx, 1					; Head numbers start at 0 - add 1 for total
	mov [Sides], dx
	
no_change:
	mov ax, 1003h				; Set text output with certain attributes
	mov bx, 0					; to be bright, and not blinking
	int 10h
	
	call os_seed_random
	
	
	
	mov si, win_msg_none
	mov word [win_msg], si
	
	jmp main_loop
	
	
main_loop:
	call os_clear_screen
	
	
	call os_draw_screen
	
	jmp main_loop_pause
main_loop_keys:
	
	call os_wait_for_key
	
	cmp ax, 0
	jg check_key
	
main_loop_pause:
	
	mov ax, 5
	call os_pause
	jmp main_loop_keys
	
check_key:
	mov dl, byte [var_win_id]
	cmp dl, 1
	je ck_apps
	
	cmp dl, 3
	je ck_shutdown
	
ck_home:
	cmp al, '1'
	je cmd_apps
	
	cmp al, '2'
	je cmd_terminal
	
	cmp al, '3'
	je cmd_shutdown
ck_done:
	jmp main_loop
ck_apps:
	mov si, bin_ext
	call 0003h          ; here it freezes completly
	call os_wait_for_key
	cmp ah, KEY_UP
	je ckapps_up
	
	cmp ah, KEY_DOWN
	je ckapps_down
	
	cmp ah, KEY_ENTER
	je ckapps_enter
	
	cmp ah, KEY_RETURN
	je ckapps_enter
	
	jmp main_loop
	
ck_shutdown:
	jmp main_loop

This time it does not work. What happens now is that it freezes it instead of printing out. And this position is 0xBA, which is 0xB7 distance from its target. So what makes it so that distance 0xA9 works but not 0xB7?
mikegonta
Member
Member
Posts: 229
Joined: Thu May 19, 2011 5:13 am
Contact:

Re: 16-bit Real Mode jmp to specific position seems to freez

Post by mikegonta »

Kirdow wrote:My project is to make a Graphics OS in 16-bit Real Mode and Text Mode...
Just as easy to use the BIOS in 32 bit protected mode with a BIOS extender.
Kirdow wrote:... while supporting file access using FAT12.
Just as easy to use The virtual 1.44MB FAT32 hard drive partition
Kirdow wrote:(you might recognize alot of this code from MikeOS
MikeOS32 is the 32 bit protected mode translation of MikeOS which uses a BIOS extender. It's not FAT32 yet,
but the FAT(ter)12 version would be very easy to convert to FAT32.
Mike Gonta
look and see - many look but few see

https://mikegonta.com
User avatar
Kirdow
Member
Member
Posts: 35
Joined: Sun Sep 06, 2015 2:20 pm
Libera.chat IRC: Kirdow
Location: Sweden

Re: 16-bit Real Mode jmp to specific position seems to freez

Post by Kirdow »

mikegonta wrote:
Kirdow wrote:My project is to make a Graphics OS in 16-bit Real Mode and Text Mode...
Just as easy to use the BIOS in 32 bit protected mode with a BIOS extender.
Kirdow wrote:... while supporting file access using FAT12.
Just as easy to use The virtual 1.44MB FAT32 hard drive partition
Kirdow wrote:(you might recognize alot of this code from MikeOS
MikeOS32 is the 32 bit protected mode translation of MikeOS which uses a BIOS extender. It's not FAT32 yet,
but the FAT(ter)12 version would be very easy to convert to FAT32.
Well. I don't know how you get my goal of making a 16-bit Real Mode and Text Mode with the graphics inspired from MikeOS to go with 32-bit. This response you gave isn't directly helpful in my situation as my goal is to make an os in a more insecure mode (Real Mode) and I guess you probably wanted to tell me 32-bit protected mode is easier when you use your BIOS extender.
When I'm done with this project, I will surely check your BIOS extender for 32-bit protected mode, thanks for your message but for now, this isn't helpful for me.
mikegonta
Member
Member
Posts: 229
Joined: Thu May 19, 2011 5:13 am
Contact:

Re: 16-bit Real Mode jmp to specific position seems to freez

Post by mikegonta »

Kirdow wrote:Well. I don't know how you get my goal of making a 16-bit Real Mode and Text Mode with the graphics inspired from MikeOS to go with 32-bit.
I didn't mention your "goal", I merely alluded to the fact that with a BIOS extender the BIOS can be used in 32 bit PM.
You obviously haven't looked at the MikeOS32 code which is merely a translation of MikeOS - there is no extra code in it to make it PM32
yet it looks and feels exactly like MikeOS - the only difference being PM32.
Kirdow wrote:This response you gave isn't directly helpful in my situation as my goal is to make an os in a more insecure mode (Real Mode) ...
Flat 32GB PM32 is just as "insecure" as RM16 and much simpler without segmentation and memory restrictions.
Classic mode programming in PM32 is the same as RM16 - the BIOS extender takes care of the PM32 stuff in the same way that the PC BIOS takes
care of RM16 and in fact no knowledge of PM32 is even required.
Kirdow wrote:... and I guess you probably wanted to tell me 32-bit protected mode is easier when you use your BIOS extender.
I didn't mention "my" BIOS extender however, since you brought it up there is a link in my signature.
Kirdow wrote:When I'm done with this project, I will surely check your BIOS extender for 32-bit protected mode, thanks for your message but for now, this isn't helpful for me.
Much appreciated, hopefully other beginners who have stumbled into the Real Mode "mode" might bennefit from this post.
Mike Gonta
look and see - many look but few see

https://mikegonta.com
User avatar
Kirdow
Member
Member
Posts: 35
Joined: Sun Sep 06, 2015 2:20 pm
Libera.chat IRC: Kirdow
Location: Sweden

Re: 16-bit Real Mode jmp to specific position seems to freez

Post by Kirdow »

Ok, I managed to get closer to the solution, I think. I tried doing some tests on where the problem first appears.

I added this as part of the code first as a test:

Code: Select all

testlbl:
	mov si, bin_ext			; this will move BIN into si
	call 0003h				; this calls a function at 0x0003 which then does a near jump to os_print_string
							; which has ret at the end. this works, confirmed.
	call os_wait_for_key	; this just waits until a key is pressed, so the user has time to see the
							; text printed out
	jmp testlblcnt			; this jumps to a label which should be placed after the jmp testlbl or
							; je testlbl etc.
	
main_loop:					; this is the beginning of the main loop
	call os_clear_screen	; first it clears the screen
	
	
	call os_draw_screen		; this draws the gui for the os
	
	jmp main_loop_pause		; now it jumps to a part which will freeze the os for 0.55 seconds
main_loop_keys:				; after it's back it does key input.
	
	call os_wait_for_key	; it waits for the user to press a key
	
	cmp ax, 0				; it then checks if there were any key data getting inputted.
	jg check_key			; if it is, it jumps to the check key function
	
main_loop_pause:			; if not, it falls thru to the pause function
	
	mov ax, 5				; it moves 5 into ax register. this means 5 * 110 milliseconds or 0.55 seconds.
	call os_pause			; it runs the pause function
	jmp main_loop_keys		; and then jumps back to the key input function
	
check_key:					; this is where we check for keys

	jmp testlbl						; first in the check key function we try print BIN using the system call
testlblcnt:							; function located at 0x0003

	mov dl, byte [var_win_id]		; we first check if we haveany windows up
	cmp dl, 1						; if the window id is 1, it jumps to the ck_apps function
	je ck_apps						; which means the app list window is shown
	
	cmp dl, 3						; then it checks the same with id 3 which is the shutdown window
	je ck_shutdown
	
ck_home:							; if there were no window open it checks for number keys
									; which is used to open windows
	cmp al, '1'						; the 1 key is for apps window
	je cmd_apps
	
	cmp al, '2'						; the 2 key is for terminal window
	je cmd_terminal
	
	cmp al, '3'						; and the 3 key is for shutdown window
	je cmd_shutdown
ck_done:							; when it's done it jumps back to the main loop start
	jmp main_loop
ck_apps:							; if apps window is open, this part runs
	cmp ah, KEY_UP					; first it checks if the key upp is pressed, if so it runs a code
	je ckapps_up					; piece to go up one line
	
	cmp ah, KEY_DOWN				; if the down is pressed, it instead goes down one line
	je ckapps_down
	
	cmp ah, KEY_ENTER				; the next 2 keys is for the same action, which is to try start
	je ckapps_enter					; selected program
	
	cmp ah, KEY_RETURN
	je ckapps_enter
	
	jmp main_loop					; lastly we jump back to the main loop
	
ck_shutdown:						; as you can see ck_shutdown isn't used currently.
	jmp main_loop					; which means you have to force shutdown the os, by cutting power or
									; closing down the virtual machine if you're using that. but that doesn't
									; matter right now.

cmd_apps:							; so if the user pressed the user pressed the 1 key, it moves 1 to
	mov byte [var_win_id], 1		; the window variable
	jmp main_loop
cmd_terminal:						; if the user press 2, it moves 0 to the window variable
	mov byte [var_win_id], 0
	jmp main_loop
cmd_shutdown:						; and the 3 key moves 3 to the window variable.
	mov byte [var_win_id], 3
	jmp main_loop
This code works when you print out the BIN text in the start of the check key function. note that some of the function calls/jumps isn't within this example, but that doesn't matter right now as those are fully working right now.
Just as a note, the code at RAM position 0x0003 is the following:

Code: Select all

jmp os_print_string
This is a near jump, which works with the first code in this reply.

Though when I tried moving the testlbl jump to the end of the ck_apps label, with the following code, it did not work:

Code: Select all

testlbl:
	mov si, bin_ext			; this will move BIN into si
	call 0003h				; this calls a function at 0x0003 which then does a near jump to os_print_string
							; which has ret at the end. this works, confirmed.
	call os_wait_for_key	; this just waits until a key is pressed, so the user has time to see the
							; text printed out
	jmp testlblcnt			; this jumps to a label which should be placed after the jmp testlbl or
							; je testlbl etc.
	
main_loop:					; this is the beginning of the main loop
	call os_clear_screen	; first it clears the screen
	
	
	call os_draw_screen		; this draws the gui for the os
	
	jmp main_loop_pause		; now it jumps to a part which will freeze the os for 0.55 seconds
main_loop_keys:				; after it's back it does key input.
	
	call os_wait_for_key	; it waits for the user to press a key
	
	cmp ax, 0				; it then checks if there were any key data getting inputted.
	jg check_key			; if it is, it jumps to the check key function
	
main_loop_pause:			; if not, it falls thru to the pause function
	
	mov ax, 5				; it moves 5 into ax register. this means 5 * 110 milliseconds or 0.55 seconds.
	call os_pause			; it runs the pause function
	jmp main_loop_keys		; and then jumps back to the key input function
	
check_key:					; this is where we check for keys

	mov dl, byte [var_win_id]		; we first check if we haveany windows up
	cmp dl, 1						; if the window id is 1, it jumps to the ck_apps function
	je ck_apps						; which means the app list window is shown
	
	cmp dl, 3						; then it checks the same with id 3 which is the shutdown window
	je ck_shutdown
	
ck_home:							; if there were no window open it checks for number keys
									; which is used to open windows
	cmp al, '1'						; the 1 key is for apps window
	je cmd_apps
	
	cmp al, '2'						; the 2 key is for terminal window
	je cmd_terminal
	
	cmp al, '3'						; and the 3 key is for shutdown window
	je cmd_shutdown
ck_done:							; when it's done it jumps back to the main loop start
	jmp main_loop
ck_apps:							; if apps window is open, this part runs
	cmp ah, KEY_UP					; first it checks if the key upp is pressed, if so it runs a code
	je ckapps_up					; piece to go up one line
	
	cmp ah, KEY_DOWN				; if the down is pressed, it instead goes down one line
	je ckapps_down
	
	cmp ah, KEY_ENTER				; the next 2 keys is for the same action, which is to try start
	je ckapps_enter					; selected program
	
	cmp ah, KEY_RETURN
	je ckapps_enter
	
	jmp testlbl						; now we try to the print system call, before we warp back
testlblcnt:							; note that this only runs when there is no up, down or enter key pressed
	jmp main_loop					; lastly we jump back to the main loop start
	
ck_shutdown:						; as you can see ck_shutdown isn't used currently.
	jmp main_loop					; which means you have to force shutdown the os, by cutting power or
									; closing down the virtual machine if you're using that. but that doesn't
									; matter right now.

cmd_apps:							; so if the user pressed the user pressed the 1 key, it moves 1 to
	mov byte [var_win_id], 1		; the window variable
	jmp main_loop
cmd_terminal:						; if the user press 2, it moves 0 to the window variable
	mov byte [var_win_id], 0
	jmp main_loop
cmd_shutdown:						; and the 3 key moves 3 to the window variable.
	mov byte [var_win_id], 3
	jmp main_loop
	
Note that the only difference between these 2 code is the position of where I jump to testlbl, everything else is untouched.

The only thing that is changed in between, which I find, is the var_win_id, which is declared as

Code: Select all

var_win_id					db 0
So with the non working code, it works fine when I use the up and down keys in the ck_apps function, but as soon as I click something else than those 4 specified, it freezes when I run the system call. So right now I'm kind of stuck, I don't know how to solve this, and I have no clue what's causing it. I would be really happy to get an answer and getting this solved.
Post Reply