2015-09-19 139 views
4

我在我的自定義引導加載程序中的代碼將內存從地址0x8E00的512字節緩衝區複製到高內存,0x100000和更高。這在一些計算機上運行良好,並且在其他計算機上崩潰(我假設出現三重故障)。此代碼在Bochs x86仿真器中也可以正常工作。引導加載程序代碼有時會崩潰(三重故障?)計算機

我試圖用rep movsb替換定製段偏移複製循環,將esiedi設置爲適當的地址,並在某些計算機上找到這也是錯誤的。是否有任何之所以這會失敗?

Bootload.asm:

; Portions of this code are under the MikeOS license, as follows: 
; 
; ================================================================== 
; Copyright (C) 2006 - 2014 MikeOS Developers -- http://mikeos.sourceforge.net 
; 
; All rights reserved. 
; 
; Redistribution and use in source and binary forms, with or without 
; modification, are permitted provided that the following conditions are met: 
; 
; * Redistributions of source code must retain the above copyright 
;  notice, this list of conditions and the following disclaimer. 
; 
; * Redistributions in binary form must reproduce the above copyright 
;  notice, this list of conditions and the following disclaimer in the 
;  documentation and/or other materials provided with the distribution. 
; 
; * Neither the name MikeOS nor the names of any MikeOS contributors 
;  may be used to endorse or promote products derived from this software 
;  without specific prior written permission. 
; 
; THIS SOFTWARE IS PROVIDED BY MIKEOS DEVELOPERS AND CONTRIBUTORS "AS IS" 
; AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
; IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
; ARE DISCLAIMED. IN NO EVENT SHALL MIKEOS DEVELOPERS BE LIABLE FOR ANY 
; DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 
; SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
; CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 
; OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 
; USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
; ================================================================== 

BOOTLOADER_SECTORS equ 3    ; includes first sector, loaded by 

BIOS 

; a boot sector that enters 32-bit protected mode 
     BITS 16 
     ORG 0x7c00 

     jmp short bootloader_start  ; Jump past disk description section 
     nop        ; Pad out before disk description 


; ------------------------------------------------------------------ 
; Disk description table, to make it a valid floppy 
; Note: some of these values are hard-coded in the source! 
; Values are those used by IBM for 1.44 MB, 3.5" diskette 

OEMLabel    db "OLIVEOS " ; Disk label 
BytesPerSector   dw 512   ; Bytes per sector 
SectorsPerCluster  db 1   ; Sectors per cluster 
ReservedForBoot   dw BOOTLOADER_SECTORS ; Reserved sectors for boot record 
NumberOfFats   db 2   ; Number of copies of the FAT 
RootDirEntries   dw 224   ; Number of entries in root dir 
             ; (224 * 32 = 7168 = 14 sectors to read) 
LogicalSectors   dw 2880   ; Number of logical sectors 
MediumByte    db 0F0h   ; Medium descriptor byte 
SectorsPerFat   dw 9   ; Sectors per FAT 
SectorsPerTrack   dw 18   ; Sectors per track (36/cylinder) 
Sides     dw 2   ; Number of sides/heads 
HiddenSectors   dd 0   ; Number of hidden sectors 
LargeSectors   dd 0   ; Number of LBA sectors 
DriveNo     dw 0   ; Drive No: 0 
Signature    db 41   ; Drive signature: 41 for floppy 
VolumeID    dd 00000000h ; Volume ID: any number 
VolumeLabel    db "OLIVEOS "; Volume Label: any 11 chars 
FileSystem    db "FAT12 " ; File system type: don't change! 

     KERNEL_OFFSET equ 0x100000  ; kernel load offset 
     STACK_LOCATION equ 0x7c00  ; stack location 
     MEM_MAP_ENTRIES equ 0x5000  ; memory map length offset 
     MEM_MAP_OFFSET equ 0x5004  ; memory map offset 

bootloader_start: 
     ; NOTE: A few early BIOSes are reported to improperly set DL 

     cmp dl, 0 
     je no_change 
     mov [BOOT_DRIVE], dl   ; Save boot device number 
     mov ah, 8      ; Get drive parameters 
     int 13h 
     jc disk_error 
     and cx, 3Fh      ; Maximum sector number 
     mov [SectorsPerTrack], cx  ; Sector numbers start at 1 
     movzx dx, dh     ; Maximum head number 
     add dx, 1      ; Head numbers start at 0 - add 1 for total 
     mov [Sides], dx 

no_change: 
     mov eax, 0      ; Needed for some older BIOSes 

     cli 
     xor ax, ax      ; make AX zero 
     mov ds, ax      ; so we point our segment registers to zero 
     mov es, ax 
     mov fs, ax 
     mov gs, ax 
     mov ss, ax 

     jmp 0x0000:bootloader_landing ; far jump to clear cs to 0 

bootloader_landing: 
     mov bp, STACK_LOCATION   ; set up stack 
     mov sp, bp 

     sti 

     mov si, MSG_STARTING_BOOTLOADER 
     call bios_print_string 

     call load_bootloader   ; load the rest of the bootloader (if we don't do it first, 
             ; something is very likely going to mess up) 

     pusha 
     mov di, MEM_MAP_OFFSET 
     jmp bios_get_memory    ; get memory map for kernel 
bios_get_memory_return: 
     popa 

     mov bp, STACK_LOCATION   ; set up stack again (bios_get_memory trashed our stack) 
     mov sp, bp 

     jmp second_stage    ; transfer control to second stage! 

; loads the rest of this bootloader 
load_bootloader: 
     mov bx, second_stage   ; read to 0x7e00 (right after this 512 byte code segment) 
     mov al, BOOTLOADER_SECTORS-1 ; sectors to read 
     mov dl, [BOOT_DRIVE]   ; drive 
     mov cl, 0x02     ; start sector 
     mov ch, 0x00     ; cylinder 
     mov dh, 0x00     ; head 
     mov ah, 0x02     ; BIOS read sector function 

     push ax       ; store AX on stack so later we can recall 
             ; how many sectors were request to be read, 
             ; even if it is altered in the meantime 

     int 0x13      ; call BIOS 

     jc disk_error     ; jump if error (carry flag set) 

     pop dx       ; restore from stack (was AX before) 
     cmp dl, al      ; if AL (sectors read) != DH (sectors expected) 
     jne disk_error     ;  display error message 

     ret 

; displays error message and hangs 
disk_error: 
     mov si, DISK_ERROR_MSG 
     call bios_print_string 

     sti 
.halt: 
     hlt 
     jmp .halt 

; ----------------------------------------------------------------- 
; BOOTLOADER SUBROUTINES: 
; 
bios_print_string: 
     pusha 

     mov ah, 0x0e     ; int 10h teletype function 

.repeat: 
     lodsb       ; Get char from string 

     cmp al, 0 
     je .done      ; If char is zero, end of string 

     int 0x10      ; Otherwise, print it 
     jmp .repeat      ; And move on to next char 

.done: 
     popa 
     ret 

; prints 16 bit hex value from AX 
bios_print_2hex: 
     push cx 

     mov cx, 16-4 
.repeat:   
     push ax 

     shr ax, cl 
     and ax, 0xf 
     cmp ax, 9 
     jle .print 

     add ax, 'A'-'9'-1 

.print: 
     add ax, '0' 
     mov ah, 0x0e 
     int 0x10 

     pop ax 

     cmp cx, 0 
     je .done 

     sub cx, 4 
     jmp .repeat; 
.done: 
     pop cx 
     ret 

; prints 32 bit hex value from AX 
bios_print_4hex: 
     push eax 

     shr eax, 16 
     call bios_print_2hex 

     pop eax 
     and eax, 0xffff 
     call bios_print_2hex 

     ret 

; global variables 
BOOT_DRIVE  db 0 
MSG_STARTING_BOOTLOADER db "OliveOS", 0 
MSG_STARTING_SECOND_STAGE db " has started!", 0 
MSG_READING  db ".", 0 
MSG_READING2 db "!", 0 
DISK_ERROR_MSG db "Disk read error!", 0 
MSG_REG_DUMP db 0xD, 0xA, "INTERNAL REG DUMP", 0xD, 0xA, 0 
NEWLINE   db 0xD, 0xA, 0 

; bootsector padding 
times 510-($-$$) db 0 
dw 0xaa55 

     BITS 16 

second_stage: 
     mov si, MSG_STARTING_SECOND_STAGE 
     call bios_print_string 

     ;call bios_enable_a20 
     call load_kernel 

     jmp switch_to_pm    ; switch to protected mode, we won't return from here 

     BITS 32 
; this is where we arrive after switching to and initializing protected mode 
begin_pm: 
     call kbd_enable_a20 
     call fast_enable_a20 

     call CODE_SEG:KERNEL_OFFSET  ; now call the kernel! 

.halt: 
     hlt        ; hang 
     jmp .halt 

     BITS 16 

load_dest: 
     dd  KERNEL_OFFSET 

; loads the kernel from the floppy image 
load_kernel:   
     mov ax, BOOTLOADER_SECTORS  ; start logical sector 
     mov cx, 200      ; number of sectors to read 

.continue: 
     cmp cx, 0 
     je .done 

     pusha 
     mov ebx, 0x8E00     ; write to 0x8E00 a temporary 512 byte buffer 
     call bios_disk_load    ; load bytes to buffer 

     mov si, MSG_READING 
     call bios_print_string 
     popa 

     pusha       ; copy bytes in buffer to destination 
     call switch_to_unreal   ; switch to unreal mode to access high memory 

     mov cx, 0x200     ; copy 512 bytes 
     mov ebx, 0x8E00     ; read from 0x8E00 
     mov edx, dword [load_dest]  ; load destination address 

.copy: 
     cmp cx, 0 
     je .done_copying 

     mov eax, dword [fs:ebx] 
     mov dword [fs:edx], eax   ; commenting out this line (the actual write) will work on any computer 

     add ebx, 4 
     add edx, 4 

     sub cx, 4 
     jmp short .copy 

.done_copying: 
     call switch_to_real    ; switch back to real mode 
     popa 

     add dword [load_dest], 0x200 ; add 512 bytes to output pointer 
     inc ax       ; increment logical sector 
     dec cx       ; decrement loop counter 

     jmp .continue     ; continue reading 
.done:  
     ret 

;sets up LBA address in AX for INT 13H 
logical_int13_setup: 
     push bx 
     push ax 

     mov bx, ax      ; Save logical sector 

     mov dx, 0      ; First the sector 
     div word [SectorsPerTrack] 
     add dl, 0x01     ; Physical sectors start at 1 
     mov cl, dl      ; Sectors belong in CL for int 13h 
     mov ax, bx 

     mov dx, 0      ; Now calculate the head 
     div word [SectorsPerTrack] 
     mov dx, 0 
     div word [Sides] 
     mov dh, dl      ; Head/side 
     mov ch, al      ; Track 

     pop ax 
     pop bx 

     mov dl, byte [BOOT_DRIVE]  ; Set correct device 

     ret 

;bios_disk_load: loads logical sector in AX to ES:BX 
bios_disk_load: 
     call logical_int13_setup  ; setup our parameters 

     mov ah, 0x2      ; INT 0x13 function 
     mov al, 0x1      ; load 1 sector 

     int 0x13 

     jc disk_error     ; jump if error (carry flag set) 

     cmp al, 1      ; if AL (sectors read) != 1 (sectors expected) 
     jne disk_error     ;  display error message 

     ret 

bios_reg_dump: 
     pusha 

     mov si, MSG_REG_DUMP 
     call bios_print_string 

     mov si, .MSG_AX 
     call bios_print_string 
     call bios_print_4hex 
     mov si, NEWLINE 
     call bios_print_string 

     mov si, .MSG_BX 
     call bios_print_string 
     mov eax, ebx 
     call bios_print_4hex 
     mov si, NEWLINE 
     call bios_print_string 

     mov si, .MSG_CX 
     call bios_print_string 
     mov eax, ecx 
     call bios_print_4hex 
     mov si, NEWLINE 
     call bios_print_string 

     mov si, .MSG_DX 
     call bios_print_string 
     mov eax, edx 
     call bios_print_4hex 
     mov si, NEWLINE 
     call bios_print_string 

     mov si, .MSG_CS 
     call bios_print_string 
     mov eax, cs 
     call bios_print_4hex 
     mov si, NEWLINE 
     call bios_print_string 

     mov si, .MSG_DS 
     call bios_print_string 
     mov eax, ds 
     call bios_print_4hex 
     mov si, NEWLINE 
     call bios_print_string 

     mov si, .MSG_ES 
     call bios_print_string 
     mov eax, es 
     call bios_print_4hex 
     mov si, NEWLINE 
     call bios_print_string 

     mov si, .MSG_FS 
     call bios_print_string 
     mov eax, fs 
     call bios_print_4hex 
     mov si, NEWLINE 
     call bios_print_string 

     mov si, .MSG_GS 
     call bios_print_string 
     mov eax, gs 
     call bios_print_4hex 
     mov si, NEWLINE 
     call bios_print_string 

     popa 
     ret 

     .MSG_AX db "EAX: 0x", 0 
     .MSG_BX db "EBX: 0x", 0 
     .MSG_CX db "ECX: 0x", 0 
     .MSG_DX db "EDX: 0x", 0 
     .MSG_CS db "CS: 0x", 0 
     .MSG_DS db "DS: 0x", 0 
     .MSG_ES db "ES: 0x", 0 
     .MSG_FS db "FS: 0x", 0 
     .MSG_GS db "GS: 0x", 0 

%include "source/bootload/gdt.asm" 
%include "source/bootload/protected_mode.asm" 
%include "source/bootload/memory.asm" 

times (BOOTLOADER_SECTORS*512)-($-$$) db 0 

注:斷層代碼bios_print_string常規,作爲完美的作品在其他地方。

回答

5

我找到了我的問題的答案。寫入mov dword [fs:edx], eax失敗,不是因爲fsedx包含無效的段和地址,而是因爲在寫入地址0x100000和更高的地址之前未啓用A20行。相反,它在之後被啓用

一些BIOS,如Bochs,已經設置了允許代碼運行的A20行。其他人沒有設置A20行,因此寫入地址爲模0x100000,地址爲0x000000和更高。這是IVT(中斷向量表)存儲在內存中的地方,如果被覆蓋,可以輕鬆地從未處理的中斷創建三重故障並導致計算機崩潰或掛起。解決方案?在寫入高地址之前設置A20行。