自定义操作系统中未显示内核消息:引导加载程序或内核问题?

问题描述 投票:0回答:1

重要提示

有人也遇到了同样的问题这里。我尝试删除 read_disk 函数中的

mov dl, 0
但仍然不起作用。这家伙似乎还有一个重置功能,当他在打印字符串时遇到空字符时,它会重置软盘。我认为这个功能不是必需的,因为我已经删除了
mov dl, 0
。但是,我怀疑重置功能是必要的。

我正在构建一个操作系统,并遇到一个挑战,引导加载程序成功打印其消息,但内核的消息未显示。这是一个细分:

设置:

汇编器和环境:

  • 带有 -f bin 选项的 NASM
  • 在 qemu-system-i386 上测试
  • 环境:带有 Xlaunch 的 Windows Subsystem for Linux (WSL)(尽管我怀疑这不相关)

文件:

bootloader.asm

[org 0x7c00]
[bits 16]

jmp main

_message_read_err:  db 'Error in reading floppy!', 0
_message_boot:      db 'Booting SSoS...', 0
_sectors_per_track: dw 18
_head_count:        dw 2
_kernel_start_LBA:  dw 1
_kernel_size:       dw 1
_stack_ptr_addr:    dw 0x7b00
_es_start:          dw 0x7c0

; Arguments:
;     None
; Returns:
;     None
; Used registers:
;     ax, ds, ss, sp, es, si
main:
    mov ax, 0 ; can't write to ds and ss directly
    mov ds, ax 
    mov ss, ax 
    mov sp, [_stack_ptr_addr] ; stack pointer

    mov ax, [_es_start] ; address * 16 = real address -> 0x7c0 * 16 (dec) = 0x7c00
    mov es, ax 

    mov si, _message_boot
    call puts

    ; Converting LBA to CHS
    mov ax, [_kernel_start_LBA]
    call LBA_to_CHS ; after this call, CH, CL, and DH will have cylinder, sector, and head values

    mov bx, 0x200
    mov al, [_kernel_size] ; number of sectors to read
    call read_disk

    jmp far [es:bx]

; Arguments:
;     si - Points to the string to be printed
; Returns:
;     None
; Used registers:
;     ah, al
puts:
.begin:
    mov ah, 0x0E
    lodsb 
    cmp al, 0
    je .done
    int 10h
    jmp .begin
.done:
    ret

; Arguments:
;     ax - Contains the LBA value to be converted
; Returns:
;     ch - Cylinder value
;     cl - Sector value
;     dh - Head value
; Used registers:
;     ax, dx, cx, ch, dh, cl
LBA_to_CHS:
    ; Save original LBA value
    push ax

    ; Compute Cylinder (LBA / (heads * sectors per track))
    ; AX = LBA, DX = 0 (from division)
    xor dx, dx
    mov cx, [_head_count]
    mul cx
    div word [_sectors_per_track]
    mov ch, al

    ; Temp now in AX. (LBA % (heads * sectors per track))
    ; Compute Head (Temp / sectors per track)
    div word [_sectors_per_track]
    mov dh, al

    ; Compute Sector (Temp % sectors per track + 1)
    ; AL already contains the remainder from the previous div
    ; which is Temp % sectors per track
    inc al
    mov cl, al

    ; Restore original LBA value
    pop ax
    ret

; Arguments:
;     bx - Address to load the data
;     ch, cl, dh - CHS values
;     al - Number of sectors to read
; Returns:
;     None
; Used registers:
;     ax, dl, si
read_disk:
    push ax
    mov ax, 4
.retry:
    dec ax
    cmp ax, 0
    je .read_error

    mov ah, 02h
    mov dl, 0
    int 13h
    jc .retry
    pop ax
    ret 

.read_error:
    mov si, _message_read_err
    call puts

    cli
    hlt

times 510-($-$$) db 0

dw 0aa55h

内核.asm

[org 0x7E00]
[bits 16]

jmp main

_message: db 'Hello from kernel!', 0

main:
    mov si, _message
    call puts

    cli
    hlt

puts:
    mov ah, 0x0E
.begin:
    lodsb 
    cmp al, 0
    je .done
    int 10h
    jmp .begin
.done:
    ret

生成文件

BUILD_DIR = build
SRC_DIR = src
IMG_NAME = dev

dev: image
    qemu-system-i386 -fda $(BUILD_DIR)/$(IMG_NAME).img

image: $(BUILD_DIR)/bootloader.bin $(BUILD_DIR)/kernel.bin
    @dd if=$(BUILD_DIR)/bootloader.bin of=$(BUILD_DIR)/$(IMG_NAME).img bs=512
    @dd if=$(BUILD_DIR)/kernel.bin of=$(BUILD_DIR)/$(IMG_NAME).img bs=512 seek=1
    @truncate -s 1440k $(BUILD_DIR)/$(IMG_NAME).img
    @hexdump -C $(BUILD_DIR)/$(IMG_NAME).img
    @objdump -b binary -m i8086 -M intel -D build/dev.img

clean:
    rm -f $(BUILD_DIR)/bootloader.bin $(BUILD_DIR)/kernel.bin

$(BUILD_DIR)/%.bin: $(SRC_DIR)/%.asm
    nasm $^ -f bin -o $@

bootloader.asm 中常量的详细信息:

  • _stack_ptr_addr:设置为0x7b00,因为它在引导加载程序下是256字节。我相信这是一个安全的位置,因为堆栈向下增长。
  • _es_start:设置为 0x7c0,因此实际物理地址(在实模式下)等于 0x7c00 — 引导加载程序的加载地址。我跳转到内核时偏移了0x200,与内核的加载地址相匹配。 为了清楚起见,第一条指令出现在字节 0x200 处。

问题:

启动时,显示“Booting SSoS...”消息,但内核显示“Hello from kernel!”消息不是。

观察与假设:

请阅读上面的重要说明。 我怀疑问题可能出在引导加载程序中的 read_disk 函数中。 尽管没有显示错误消息,但 qemu-system-i386 命令似乎不寻常。 _sectors_per_track 和驱动器编号(read_disk 函数中的寄存器 dl)等常量似乎是准确的。然而,即使我尝试了不同的磁盘读取方法,问题仍然出现。

寻求帮助:

我知道这是一个复杂且低级的主题,需要对操作系统有深入的了解。这就是为什么我感谢所有试图帮助我的人。非常感谢!

我尝试了不同的读取软盘的方法(例如直接使用 CHS 寻址读取),但都不起作用。我还仔细检查了我的常量并查看了图像的可拆卸性,但一切似乎都是正确的。我查看了其他代码,但我的代码似乎(几乎除了它不是那么完美)相同。

assembly x86 kernel bootloader osdev
1个回答
-1
投票

我在

%include "kernel.asm"
之前添加了
jmp main
到 bootloader.asm。

然后 nasm 打印错误消息:

kernel.asm:1: error: program origin redefined
bootloader.asm:23: error: label `main' inconsistently redefined
kernel.asm:8: info: label `main' originally defined here
bootloader.asm:52: error: label `puts' inconsistently redefined
kernel.asm:15: info: label `puts' originally defined here
bootloader.asm:53: error: label `puts.begin' inconsistently redefined
kernel.asm:17: info: label `puts.begin' originally defined here
bootloader.asm:60: error: label `puts.done' inconsistently redefined
kernel.asm:23: info: label `puts.done' originally defined here

所以我更改了 kernel.asm 中的标签

jmp main1

_message: db 'Hello from kernel!', 0

main1:
    mov si, _message
    call puts1

    cli
    hlt

puts1:
    mov ah, 0x0E
.begin1:
    lodsb 
    cmp al, 0
    je .done1
    int 10h
    jmp .begin1
.done1:
    ret

并删除了线条

[org 0x7E00]
[bits 16]

结果:

© www.soinside.com 2019 - 2024. All rights reserved.