0

我刚开始上操作系统课程,但在臭名昭著的引导加载程序实验室遇到了障碍。任务的一部分是在 Assembly 中创建一个 512 字节的引导加载程序,能够或多或少地从头开始加载给定的内核。这是我到目前为止工作的代码:

# bootblock.s

# .equ symbol, expression
# These directives set the value of the symbol to the expression

.equ    BOOT_SEGMENT,0x07c0

.equ    DISPLAY_SEGMENT,0xb800

.text               # Code segment

.globl    _start    # The entry point must be global

.code16             # Real mode


# Start

_start:

    jmp over


# OS Size

os_size:
    # Area reserved for createimage to write the OS size

    .word   0

    .word   0


# Routines to print a zero terminated string pointed to by esi
# Overwrites:   AX, DS, BX

print:

    movw  $BOOT_SEGMENT,%ax
    movw  %ax,%ds

print_loop:

    lodsb
    cmpb  $0,%al
    je  print_done
    movb  $14,%ah
    movl  $0x0002,%ebx
    int  $0x10
    jmp  print_loop

print_done:

    retw


# Over is where the magic happens

over:


    movl $messagetest, %esi
    call print
    movl $hellostring, %esi
    call print

    # Allocating the stack
    movw $0x0, %ax
    movw %ax, %ss
    movw $0xffff, %sp

    # Booting up at 0x07c0
    movw $BOOT_SEGMENT, %ax
    movw %ax, %ds
    movl $messageboot, %esi
    call print

    # Resetting the disk drive, setting %dl and calling int 0x13
    movb $0x0, %ah
    movb $0x80, %dl
    int $0x13

    # Make says my .os_size = 9 sectors. Setting %al = 9
    movb $0x09, %al

    # %cl controls which sector to read from. Setting %cl = 2
    movb $0x02, %cl 

    # %dh/%ch control head numbers. I'm not sure how they work; setting them to zero
    movb $0x0, %dh
    movb $0x0, %ch

    # Setting the drive number to 0x80 (Hard drive)
    movb $0x80, %dl

    # Time to set es:bx to read from the correct place (0:1000)
    movw $0x0, %bx
    movw %bx, %es
    movw $0x1000, %bx

    # Setting %ah = 2 and calling int 0x13 again (Read Sectors)
    movb $0x02, %ah
    int $0x13

    # Setting %ds = 0. I don't think it can be done directly.
    movw $0x0, %ax
    movw %ax, %ds

    # Kernel jump
    movl $messageready, %esi
    call print
    ljmp $0x1000, $0x0

    # Displaying error message, if any
    movl $messageerror, %esi
    call print


# Rebooting the OS

reboot:

    movl $messagereboot, %esi
    call print
    movb $0, %ah
    int $0x16
    movb $0, %ah
    int $0x19


# Infinite loop 

forever:

    hlt
    jmp forever


# Error handling

error:

    movl $messageerror, %esi
    call print


# Test messages

hellostring:

    .asciz  "Hi Professor.\n\n\r"

messagetest:

    .asciz "\nTesting Bootblock!\n\r"

messageboot:

    .asciz "Booting up... \n\r "

messageready:

    .asciz "\b>> Jumping into the Kernel... \n\r"

messagereboot:

    .asciz "Press any key to reboot the OS!\n\r"

messageerror:

    .asciz "Unknown error!\n\r"

现在,我的代码打印了它应该打印的所有消息,但是当需要跳转到内核时,它显然没有正确执行(内核不显示确认消息)。

我的代码可以编译,但我觉得某处一定有错误:

  1. 我如何分配堆栈空间,或者
  2. 在调用 INT 0x13 之前如何设置寄存器

任何人都可以通过告诉我出了什么问题来帮助我吗?

4

1 回答 1

2

您显然是在地址0:0x1000( es=0, bx=0x1000) 处加载代码,但跳转到0x1000:0( ljmp $0x1000, $0x0)。这行不通,因为第一个是物理地址 0x1000 但第二个是 0x10000(因为在实模式下您必须将段乘以 16)。让他们匹配。

可能还有其他错误,请学习使用调试器,否则您每分钟都会寻求帮助。

另外,请保持格式,以便我们可以轻松复制粘贴整个代码以进行测试(或也提供 pastebin 链接)。

于 2013-09-11T23:16:24.790 回答