diff --git a/stage_1/utility.asm b/stage_1/utility.asm index 3ff0d87..e04262e 100644 --- a/stage_1/utility.asm +++ b/stage_1/utility.asm @@ -1,6 +1,203 @@ 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 (lower) ; bl: start_sector (upper) ; cx: sector_count @@ -14,28 +211,40 @@ load_sectors: push bx push cx push dx - + push si xor si, si ; current sector index -; sets the arguments for the first run of '.load_data' -; which loads until the first CHS - cylinder boundary -.set_first_load_args: - - ; the first read only reads up to the next cylinder boundary, - ; but potentially less (if not that many sectors have been requested) - - ; TODO================================================================================ - mov bx, sp - add bx, 4 - mov cx, [bx] ; get sector count - sub cx, si ; cx = num_missing_sectors - mov bx, sp - mov bx, [bx] - cmp cx, bx - js .load_data ; if there are more sectors needed after the - ; next cylinder boundary + ; calculate the distance (in sectors) to the next cylinder boundary + + ; get the index of the current cylinder + and ax, 0b00111111 ; extract only the sector index + mov bx, 64 ; get the maximum number of sectors + 1 + sub bx, ax ; invert the result; 1 becomes 63; 63 becomes 1 + cmp ax, 63 + jne .is_not_on_full_cylinder_boundary + + ; if it's indeed on a full cylinder boundary, the first_read-part is unimportant + mov ax, 0 + set_load_args + +.is_not_on_full_cylinder_boundary: + + + + ; cx still contains the entry-point's wanted sector_count + ; ax now contains the distance to the next cylinder boundary + + cmp cx, ax + jbe .load_data + + ; it gets here if there are more sectors needed after the + ; next cylinder boundary + ; if the number of sectors + ; which are wanted (sector_count) is above the + ; distance to the next cylinder boundary + ; if not that many sectors are needed, just read as ; many sectors as are needed in total mov cx, bx @@ -53,22 +262,26 @@ load_sectors: mov cx, [bx] sub cx, si ; cx = num_missing_sectors - cmp cx, 64 - js .load_data - ; if this goes here, there are more than 64 sectors missing - ; -> clamp them to 64 so they can be loaded. - mov cl, 64 - jmp .load_data ; redundant + cmp cx, 63 + jbe .add_num_missing_sectors_to_sector_index + + ; if this goes here, there are more than 63 sectors + ; still missing to be loaded + ; -> clamp them to 63 so they can be loaded. + mov cl, 63 + jmp .load_data + +.add_num_missing_sectors_to_sector_index: + + add si, cx ; loads at most 64 sectors from the disk into the main memory ; ax: scratchpad -; bx: start_sector (low part) -; ch: start_sector (high part) +; bx: start_sector (high part) +; ch: start_sector (low part) ; cl: num_sectors .load_data: - mov bx, sp - mov ah, 0x02 mov al, cl mov dl, [bx] ; drive @@ -86,12 +299,13 @@ load_sectors: mov cx, [bx] ; sector_count cmp si, cx - js .set_load_args + jb .set_load_args .epilog: + pop si pop dx pop cx pop bx