nightloader/stage_1/utility.asm

271 lines
4.7 KiB
NASM

section .text
initialize_video_mode:
.prolog:
push ax
; set the video mode correctly
xor ah, ah ; bios-function (set video mode)
mov al, 3 ; video mode with 80x25 characters
int 0x10
.epilog:
pop ax
ret
; cx: len_buffer
; si: buffer
; dl: start_x NOTE: Will contain the end of the text on-screen
; dh: start_y NOTE: Will contain the end of the text on-screen
print_string:
.prolog:
push di
push cx
push bx
push ax
xor di, di ; character index
.printing_loop:
.set_cursor_position:
mov ah, 0x02
mov bh, 0
int 0x10
.write_character:
push cx ; save len_buffer
; get the current character
mov bx, si
add bx, di
mov al, [bx]
; al now contains the current character
; set the other needed interrupt values
mov ah, 0x0a ; wanted function (write character at cursor position)
mov bh, 0 ; page number
mov cx, 1 ; repetitions of character
int 0x10 ; call bios basic draw functions
pop cx ; restore len_buffer
inc dl ; go to next column
; go to a new line if needed
cmp dl, 80
jb .no_new_line_needed
xor dl, dl
inc dh ; increase column
.no_new_line_needed:
inc di ; go to next character
; go further if the string-printing hasn't been finished
cmp di, cx
jb .printing_loop
.epilog:
pop ax
pop bx
pop cx
pop di
ret
; ds: source
; es: destination
; dx: len_to_copy
mem_copy:
push ax
push bx
push cx
push dx
xor cx, cx
mov di, dx
; ax: first region's value
; bx: address at index
; cx: byte_index
; dx: second region's value
.loop:
; retrieve the source byte at the current index
mov bx, cx
mov dx, [bx]
; swap the two segments
; here, ax and bx are used differently.
mov ax, es
mov bx, ds
mov ds, ax
mov es, bx
mov [bx], cx
; swap the two segments back
mov ax, es
mov bx, ds
mov ds, ax
mov es, bx
inc cx
; if the end has NOT been reached
cmp cx, di
jb .loop ; => continue
ret
; ds: region_1
; es: region_2
; dx: len_regions
; ax: result
mem_equals:
push bx
push cx
push dx
push di
xor cx, cx
mov di, dx
; ax: first region's value
; bx: address at index
; cx: byte_index
; dx: second region's value
.loop:
mov bx, cx
mov dx, [bx]
; swap the two segments
; here, ax and bx are used differently.
mov ax, es
mov bx, ds
mov ds, ax
mov es, bx
mov bx, cx
mov ax, [bx]
cmp ax, dx
; swap the two segments back
mov ax, es
mov bx, ds
mov ds, ax
mov es, bx
; jump accordingly to the comparison above
jne .not_equal
inc cx
cmp cx, di ; if the loop needs to continue
jb .loop ; (if the end is NOT reached yet)
; it goes here if the two regions are completely equal
pop di
pop dx
pop cx
pop bx
mov ax, 1
ret
.not_equal:
pop di
pop dx
pop cx
pop bx
mov ax, 0
ret
; ax: start_sector (upper)
; bl: start_sector (lower)
; cx: wanted_sector_count
; dh: drive
; si: buffer_address (upper)
; di: buffer_address (lower)
load_sectors:
; INNER WORKING:
;
; This function first checks if it needs to load sectors going over
; a cylinder boundary and loads to that cylinder boundary first continuing
; in 63-sector - parts after that until the last, < 63-sectors part is read.
;
; This is done because some systems don't like reading over the boundaries
; between the cylinders.
;
; The actual part loading the data is in .read_from_disk, it's no different
; from the first read to the other reads. It just gets different arguments
; from 1).load_first_sectors, and 2) .load_further_sectors
;
.prolog:
push ax
push bx
push cx
push dx
push si
xor si, si ; current sector index
.load_first_sectors:
; ah: EMPTY
; al: num_sectors_to_read
; bx: EMPTY
; ch: cylinder
; cl: sector
; dh: head
; dl: drive
.read_from_disk:
; set es:bx to the address in bytes to which the output should be written.
mov bx, si
shr bx, 9
mov ah, 0x02
int 0x13
.load_further_sectors:
.epilog: