; vi:filetype=nasm ts=8 sts=8 sw=8: bits 16 section .boot STACKTOP equ 7b00h DRIVENO_ADDR equ 7bf0h LOADADDR equ 7e00h extern _boot2_size start: cli ; setup stack and the rest of the segment registers xor ax, ax mov ss, ax mov sp, STACKTOP mov ds, ax mov es, ax mov fs, ax mov gs, ax ; dl: drive number, save it mov [DRIVENO_ADDR], dl call get_drive_chs mov si, newline_str call putstr ; load the second stage boot loader and jump there mov bx, LOADADDR ; es:bx <- destination mov cx, _boot2_size add cx, 511 shr cx, 9 ; cx <- binsize in sectors mov [binsize_sect], cx xor cx, cx .loadsect_loop: inc cx ; start from sector 1 (after boot sector) call read_sector ; inc dest addr by 512 add bx, 512 jnz .skipsegbump ; offset rolled over, bump es to the next 64k mov ax, es add ax, 1000h mov es, ax .skipsegbump: cmp cx, [binsize_sect] jnz .loadsect_loop ; done loading mov si, newline_str call putstr jmp LOADADDR get_drive_chs: push es mov ah, 8 mov dl, [DRIVENO_ADDR] xor di, di int 13h pop es jnc .success ret .success: xor ax, ax mov al, ch ; low 8 bits of max cylinder mov ah, cl ; bits 6,7 high bits of max cylinder rol ah, 2 and ax, 3ffh inc ax ; inc to make it number of cylinders mov [num_cylinders], ax and cx, 3fh ; bits 0-5: sect_per_track mov [sect_per_track], cx ; dh: max head number shr dx, 8 mov [heads_mask], dl inc dx mov [num_heads], dx ret ; read_sector expects a linear sector number in cx, converts it to CHS ; and loads the sector at es:bx read_sector: mov byte [read_retries], 3 .read_try: push cx ; save linear sector number ; calculate track (sidx / sectors_per_track) mov ax, cx xor dx, dx mov cx, [sect_per_track] div cx mov cx, ax ; save the remainder push dx ; head in dh mov dh, cl and dh, [heads_mask] ; cylinder (track/heads) in ch [0-7] and cl[6,7]<-[8,9] push dx xor dx, dx mov word cx, [num_heads] div cx pop dx ; restore sidx % sectors_per_track to dx mov cx, ax rol cx, 8 ror cl, 2 and cl, 0xc0 ; sector num cl[0-5] is sidx % sectors_per_track + 1 pop ax inc al or cl, al ; ah = 2 (read), al = 1 sectors mov ax, 0201h mov byte dl, [DRIVENO_ADDR] int 13h jnc .success dec word [read_retries] jz .failed ; error detected, reset controller and retry xor ah, ah int 13h pop cx ; we push that at the top of the loop jmp .read_try .failed: jmp abort_read .success: mov al, '.' call putchar pop cx ret abort_read: mov si, rderr_str call putstr cli hlt putstr: mov al, [si] inc si cmp al, 0 jz .done call putchar jmp putstr .done: ret putchar: mov ah, 0eh mov bl, 7 int 10h ret global sect_per_track sect_per_track: dw 18 global num_cylinders num_cylinders: dw 80 global num_heads num_heads: dw 2 global heads_mask heads_mask: db 1 read_retries: db 0 binsize_sect: dw 0 rderr_str: db 'read error',13,10,0 newline_str: db 13,10,0 bootend: times 510-($-$$) db 0 dw 0xaa55