Quantcast
Channel: Recent Questions - Stack Overflow
Viewing all articles
Browse latest Browse all 12111

x86 BIOS stage 1 boot code halting after loop from interrupt

$
0
0

I have some x86 BIOS boot code (16 bit real mode):

org 0x7C00                              ; tell compiler where we are located in memorybits 16                                 ; tell compiler that we are in 16 bit mode%define ENDL 0x0D, 0x0A; FAT12 headerjmp short start                         ; jump past FAT12 header and to actual codenop                                     ; no operationBPB_OEM_ID: db 'FADOS0.0'               ; OEM IdentifierBPB_BPS:    dw 512                      ; Bytes per SectorBPB_SPC:    db 1                        ; Sectors per ClusterBPB_RS:     dw 1                        ; Reserved SectorsBPB_FC:     db 2                        ; Number of FATs on the driveBPB_RDE:    dw 0E0h                     ; Root Dir Entry CountBPB_TSC:    dw 2880                     ; Total Sector Count: 2880 * 512 = 1.44MBBPB_MDT:    db 0F0h                     ; Media Descriptor Type: F0 = 3.5" floppy diskBPB_SPF:    dw 9                        ; Sectors Per FATBPB_SPT:    dw 18                       ; Sectors Per TrackBPB_HC:     dw 2                        ; Head CountBPB_HS:     dd 0                        ; Hidden SectorsBPB_LSC:    dd 0                        ; Large Sector CountEBR_DN:     db 0                        ; Drive Number: 0x00 floppy, 0x80 HDD, almost never used            db 0                        ; Windows NT Flags: not used / reservedEBR_SIG:    db 29h                      ; Boot Signature: this tells if the EBR data is presentEBR_VID:    db 12h, 34h, 56h, 78h       ; Volume ID: Drive Serial Number, almost never usedEBR_VL:     db 'FADOS0.0dev'            ; Volume Label: Name of the Drive, it can be whateverEBR_SID:    db 'FAT12   '               ; System Identifier: FAT type; Code section                          start:                                      ; setup data segments                   mov ax, 0                           ; can't set ds/es directly    mov ds, ax                          ; set data segment to 0    mov es, ax                          ; set extra segment to 0    ; setup stack                   mov ss, ax                          ; set stack segment to 0    mov sp, 0x7C00                      ; stack grows downwards from where it is loaded into memory    ; ensure we are loaded into memory in the right location    push es    push word .after    retf.after:                                 ; Get disk info and write it to FAT12 header    mov [EBR_DN], dl                    ; BIOS should set DL to drive number    ; show loading message    mov si, msg_loading                 ; move loading message into si    call print                          ; print message    ; read drive parameters instead of relying on data on formatted disk    push es                             ; save extra segment pointer to stack    mov ah, 08h                         ; move 08 hex into ah    int 13h                             ; call interupt 13 hex    jc floppy_error                     ; if carry flag is set, jump to floppy read error handler    pop es                              ; restore extra segment pointer from stack    and cl, 0x3F                        ; remove top 2 bits    xor ch, ch                          ; set ch to 0    mov [BPB_SPT], cx                   ; sector count    inc dh                              ; add 1 to dh    mov [BPB_HC], dh                    ; head count    ; compute LBA of root directory = reserved + fats * sectors_per_fat    ; note: this section can be hardcoded    mov ax, [BPB_SPF]                   ; move Sectors Per FAT into ax    mov bl, [BPB_FC]                    ; move FAT Count into bl    xor bh, bh                          ; set bh to 0    mul bx                              ; ax = (fats * sectors_per_fat)    add ax, [BPB_RS]                    ; ax = LBA of root directory    push ax                             ; save ax to stack    ; compute size of root directory = (32 * number_of_entries) / bytes_per_sector    mov ax, [BPB_RDE]                   ; move Root Dir Entries into ax    shl ax, 5                           ; ax *= 32    xor dx, dx                          ; dx = 0    div word [BPB_BPS]                  ; number of sectors we need to read    test dx, dx                         ; if dx != 0, add 1    jz .root_dir_after                  ;    inc ax                              ; division remainder != 0, add 1                                        ; this means we have a sector only partially filled with entries.root_dir_after:    ; read root directory    mov cl, al                          ; cl = number of sectors to read = size of root directory    pop ax                              ; ax = LBA of root directory    mov dl, [EBR_DN]                    ; dl = drive number (we saved it previously)    mov bx, buffer                      ; es:bx = buffer    call disk_read                      ; read from disk    ; search for stage 2    xor bx, bx                          ; set bx to 0    mov di, buffer                      ; move buffer into di.search_stage2:    mov si, stage2_bin                  ; move stage2 filename into si    mov cx, 11                          ; compare up to 11 characters    push di                             ; save di to stack    repe cmpsb                          ; repeat while equal; compare ds:si with es:di    pop di                              ; restore di from stack    je .found_stage2                    ; jump to .found_stage2 if equal    add di, 32                          ; add 32 to di    inc bx                              ; add 1 to bx    cmp bx, [BPB_RDE]                   ; compare Root Dir Entries to bx    jl .search_stage2                   ; loop this code block if previous operation returns less than    ; stage 2 not found    jmp stage2_not_found_error          ; jump to floppy error handler.found_stage2:    ; di should have the address to the entry    mov ax, [di + 26]                   ; first logical cluster field (offset 26)    mov [stage2_cluster], ax            ; move ax into stage2 cluster    ; load FAT from disk into memory    mov ax, [BPB_RS]                    ; move Reserved Sectors into ax    mov bx, buffer                      ; move buffer into bx    mov cl, [BPB_SPF]                   ; move Sectors Per FAT into cl    mov dl, [EBR_DN]                    ; move Drive Number into dl    call disk_read                      ; read from disk    ; read stage 2 and process FAT chain    mov bx, STAGE2_LOAD_SEGMENT         ; move stage2 segment into bx    mov es, bx                          ; move bx to extra segment pointer    mov bx, STAGE2_LOAD_OFFSET          ; move stage2 offset into bx.load_stage2_loop:    ; Read next cluster    mov ax, [stage2_cluster]            ; move stage2_cluster into ax    ; not nice :( hardcoded value    add ax, 31                          ; first cluster = (stage2_cluster - 2) * sectors_per_cluster + start_sector                                        ; start sector = reserved + fats + root directory size = 1 + 18 + 134 = 33    mov cl, 1                           ; move 1 into cl    mov dl, [EBR_DN]                    ; move the drive number into dl    call disk_read                      ; read from the disk    add bx, [BPB_BPS]                   ; move Bytes Per Sector into bx    ; compute location of next cluster    mov ax, [stage2_cluster]            ; move stage2_cluster into ax    mov cx, 3                           ; move 3 into cx    mul cx                              ; multiply cx by ax    mov cx, 2                           ; move 2 into cx    div cx                              ; ax = index of entry in FAT, dx = cluster mod 2    mov si, buffer                      ; move buffer into si    add si, ax                          ; add ax to si    mov ax, [ds:si]                     ; read entry from FAT table at index ax    or dx, dx                           ; check if ax is zero    jz .even                            ; if ax is zero jump to .even.odd:    shr ax, 4                           ; shift ax to the right by 4 bits    jmp .next_cluster_after             ; jump to .next_cluster_after.even:    and ax, 0x0FFF                      ; move 0x0FFF into ax.next_cluster_after:    cmp ax, 0x0FF8                      ; subtract ax from 0x0FF8: end of chain    jae .read_finish                    ; jump is result was above or equal    mov [stage2_cluster], ax            ; move the cluster stage2 is located in into ax    jmp .load_stage2_loop               ; jump to the stage 2 loading loop.read_finish:    ; jump to stage 2    mov dl, [EBR_DN]                    ; move boot drive number into dl    mov ax, STAGE2_LOAD_SEGMENT         ; move the stage 2 location into ax: set segment registers    mov ds, ax                          ; move data segment to the stage 2 location    mov es, ax                          ; move extra segment to the stage 2 location    ; jump to the 2nd stage bootloader    jmp STAGE2_LOAD_SEGMENT:STAGE2_LOAD_OFFSET    jmp wait_key_and_reboot             ; should never happen, here just incase    cli                                 ; disable interrupts, this way CPU can't get out of halt state    hlt                                 ; halt processor; Error handlersfloppy_error:    mov si, msg_read_fail               ; move string to print into si    call print                          ; print error    jmp wait_key_and_reboot             ; jump to wait_key_and_rebootstage2_not_found_error:    mov si, msg_stage2_err              ; move string to print into si    call print                          ; print error    jmp wait_key_and_reboot             ; jump to wait_key_and_rebootwait_key_and_reboot:    mov ah, 0                           ; move 0 into ah    int 16h                             ; wait for keypress    jmp 0FFFFh:0                        ; jump to beginning of BIOS, should reboot.halt:    cli                                 ; disable interrupts, this way CPU can't get out of halt state    hlt                                 ; halt processer ; print text to screen; ds:si = pointer to string to printprint:    push si                             ; save si to stack    push ax                             ; save ax to stack    push bx                             ; save bx to stack.loop:    lodsb                               ; loads next character in al    or al, al                           ; verify if next character is null    jz .done                            ; if next character is null then jump to .done    mov ah, 0x0E                        ; call bios interrupt    mov bh, 0                           ; set page number to 0    int 0x10                            ; call interupt 0x10    jmp .loop                           ; loop printing until all characters have been printed.done:    pop bx                              ; restore bx from stack    pop ax                              ; restore ax from stack    pop si                              ; restore si from stack    ret                                 ; return from function; convert an lba address to a chs address; ax = LBA address; returns:; cx = [bits 0-5]: sector number; ch = [bits 6-15]: cylinder; dh = headlba_to_chs:    push ax                             ; save ax to stack    push dx                             ; save ax to stack    xor dx, dx                          ; dx = 0    div word [BPB_SPT]                  ; ax = LBA / SectorsPerTrack                                        ; dx = LBA % SectorsPerTrack    inc dx                              ; dx = (LBA % SectorsPerTrack + 1) = sector    mov cx, dx                          ; cx = sector    xor dx, dx                          ; dx = 0    div word [BPB_HC]                   ; ax = (LBA / SectorsPerTrack) / Heads = cylinder                                        ; dx = (LBA / SectorsPerTrack) % Heads = head    mov dh, dl                          ; dh = head    mov ch, al                          ; ch = cylinder (lower 8 bits)    shl ah, 6    or cl, ah                           ; put upper 2 bits of cylinder in CL    pop ax                              ; restore ax from stack    mov dl, al                          ; restore dl from stack    pop ax                              ; restore ax from stack    ret                                 ; return from function; read from disk; ax = LBA address; cl = number of sectors to read (up to 128); dl = drive number; es:bx = memory address where to store read datadisk_read:    push ax                             ; save ax to stack    push bx                             ; save bx to stack    push cx                             ; save cx to stack    push dx                             ; save dx to stack    push di                             ; save di to stack    push cx                             ; temporarily save CL (number of sectors to read)    call lba_to_chs                     ; compute CHS address    pop ax                              ; al = number of sectors to read    mov ah, 02h                         ; move 02 in hex into ah    mov di, 3                           ; retry count = 5.retry:    pusha                               ; save all registers, we don't know what bios modifies    stc                                 ; set carry flag, some BIOS chips don't set it    int 13h                             ; call interupt 13h: carry flag cleared = success    jnc .done                           ; jump to .done if carry not set    ; read failed    popa                                ; restore all general purpose registers from stack    call disk_reset                     ; reset disk controller    dec di                              ; subtract 1 from di    test di, di                         ; set zero flag if di and di AND to 0    jnz .retry                          ; if result is not zero then retry.fail:    jmp floppy_error                    ; jump to error handler if all attempts failed.done:    popa                                ; restore all general purpose registers from stack    pop di                              ; restore di regitser from stack    pop dx                              ; restore dx register from stack    pop cx                              ; restore cx register from stack    pop bx                              ; restore bx register from stack    pop ax                              ; restore ax register from stack    ret                                 ; return from function; reset disk controller; ah = drive numberdisk_reset:    pusha                               ; push all values in registers to stack    mov ah, 0                           ; move 0 into ah    stc                                 ; set carry flag    int 13h                             ; call interupt 13 in hex    jc floppy_error                     ; jump if carry is set    popa                                ; pop all values from stack    ret                                 ; return from function; data sectionmsg_loading:            db 'LOADING', ENDL, 0msg_read_fail:          db 'DISK READ FAIL', ENDL, 0msg_stage2_err:         db 'STAGE2.BIN NOT FOUND', ENDL, 0stage2_bin:             db 'STAGE2  BIN', ENDL, 0stage2_cluster:         dw 0STAGE2_LOAD_SEGMENT     equ 0x2000STAGE2_LOAD_OFFSET      equ 0times 510-($-$$) db 0                   ; fill remaning space with 0sdw 0AA55h                               ; last 2 bytes of boot sectorbuffer:                                 ; buffer space

It is freezing after calling BIOS interrupt 0x10 to print "LOADING" to the screen (which it does do).I have run it in bochs and it gets stuck in a loop in a function in a BIOS routine, after this loop runs for an indeterminable amount of time, the program halts, seemingly somewhere in BIOS. Can someone help me fix this issue? I can't seem to find any solutions to this issue on my own, so I have come here.

I have tried to remove the printing to screen but it still halts somewhere in BIOS, and nothing is printed so the error handlers most likely didn't kick in on detecting an error, so I am completely lost now.


Viewing all articles
Browse latest Browse all 12111

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>