; number of sectors to be read for the kernel itself ; (note: the first sector gets loaded by the BIOS, the ; next 5 sectors are read by the simple stage 1 loader, ; so subtract 6 here!) NOF_LOAD_SECTORS equ 169 ; data sections used for reading the kernel from disk SECTORS_PER_CYLINDER: db 0x3F ; detect parameters enters the correct value here (sectors + 1) ; if detection fails, force int13 to read ahead NOF_HEADS: db 0x01 ; number of heads + 1 SECTORS_TO_LOAD: db NOF_LOAD_SECTORS ; load NOF_LOAD_SECTORS sectors in total CURRENT_SECTOR: db 7 ; first sector after stage 2 CURRENT_CYLINDER: db 0 CURRENT_HEAD: db 0 ; detect disk geometry ; IN dl: drive detect_disk_geometry: mov dx, 0 mov es, dx mov ah, 0x08 int 0x13 jc .error jmp .ok .error: mov si, DISK_ERROR call print_string mov dh, 0 mov dl, ah call print_hex ret .ok: add dh, 1 mov [NOF_HEADS], BYTE dh call print_hex mov dx, cx call print_hex and cl, 0x3F add cl, 1 mov [SECTORS_PER_CYLINDER], BYTE cl ret probe_and_fix_disk_geometry: mov cl, 0x1 ; from 1 to 63 mov BYTE [SECTORS_PER_CYLINDER], cl .loop: mov dl, [BOOT_DRIVE] mov ah, 0x02 ; read sectors from drive mov al, 1 ; read 1 sector mov cl, BYTE [SECTORS_PER_CYLINDER] mov ch, BYTE 0 mov dh, BYTE 0 int 0x13 jnc .next_sector ; on error, remeber cl being the highest sector .fix_heads: cmp [NOF_HEADS], BYTE 0 ; 0 heads, the BIOS is playing tricks to us! je .illegal_heads jmp .end .illegal_heads: mov [NOF_HEADS], BYTE 1 jmp .end .next_sector: mov cl, BYTE [SECTORS_PER_CYLINDER] inc cl ; next sector mov BYTE [SECTORS_PER_CYLINDER], cl cmp cl, 0x40 ; to a max of 63, if so, this is the default jbe .loop jmp .fix_heads .end: ret ; read the whole stage2 and kernel from the disk ; IN dl: drive to read from read_from_disk: mov bx, 0x0880 ; where to store the data mov es, bx mov bx, 0x0 ; 3072 bytes after first sector .read_next_sector: call read_one_sector_from_disk sub [SECTORS_TO_LOAD], BYTE 1 ; one less to load cmp [SECTORS_TO_LOAD], BYTE 0 ; finished? je .finished add bx, 0x200 ; advance write buffer position add [CURRENT_SECTOR], BYTE 1 ; next sector mov ch, [SECTORS_PER_CYLINDER] cmp [CURRENT_SECTOR], ch ; after the end of the current track? je .next_head jmp .read_next_sector .next_head: shr bx, 4 ; make it a segment offset.. mov ax, es add ax, bx mov es, ax ; ..and add it to ES mov bx, 0x0 ; we also reset bx and update es to avoid hitting the 64k wrap around point mov [CURRENT_SECTOR], BYTE 1 ; start from first sector again add [CURRENT_HEAD], BYTE 1 ; advance head mov ch, [NOF_HEADS] cmp [CURRENT_HEAD], ch ; after the number of heads? je .next_track jmp .read_next_sector .next_track: mov [CURRENT_HEAD], BYTE 0 ; start from head 0 again add [CURRENT_CYLINDER], BYTE 1 ; advance track jmp .read_next_sector .finished: ret ; Read one sector after the other, if we get illegal parameter ; errors we assume we have gone over the limit of number of ; sectors per cylinder. This avoids to probe for this number with ; shacky BIOS functions or with probing (as LILO does). It's not ; very efficient though.. ; IN dl: drive to read from read_one_sector_from_disk: mov ah, 0x02 ; read sectors from drive mov al, 1 ; read 1 sector mov ch, BYTE [CURRENT_CYLINDER] mov dh, BYTE [CURRENT_HEAD] mov dl, BYTE [BOOT_DRIVE] mov cl, BYTE [CURRENT_SECTOR] int 0x13 jc .read_error cmp al, 1 ; 1 sector read? jne .short_read ; if not, short read mov al, '.' call print_char ret .read_error: mov si, DISK_ERROR call print_string mov dh, 0 mov dl, ah call print_hex jmp $ .short_read: mov si, SHORT_READ call print_string jmp $ kill_motor: mov dx, 0x3F2 mov al, 0x00 out dx, al ret