[英]Trouble with Assembly: Creating a Bootloader
I just started an Operating Systems class and have run into a wall on the infamous bootloader lab. 我刚刚启动了一个操作系统类,并在臭名昭着的bootloader实验室中遇到了障碍。 One part of the assignment is to create a 512-byte bootloader in Assembly capable of loading a given kernel, more or less from scratch. 分配的一部分是在Assembly中创建一个512字节的引导加载程序,能够从头开始或多或少地加载给定的内核。 Here's the code I've worked on so far: 这是我到目前为止所做的代码:
# 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"
Now, my code prints all of the messages it is supposed to, but when it is time to jump into the kernel, it's clearly just not doing it properly (the kernel doesn't display a confirmation message). 现在,我的代码打印了它应该的所有消息,但是当它是时候跳进内核时,它显然没有正确地执行它(内核不显示确认消息)。
My code compiles, but I feel there must be an error somewhere either in: 我的代码编译,但我觉得必须在某处出现错误:
Can anyone help me out by telling me what's wrong? 谁能告诉我什么是错的,可以帮助我吗?
You are apparently loading the code at address 0:0x1000
( es=0
, bx=0x1000
) but jumping to 0x1000:0
( ljmp $0x1000, $0x0
). 您显然在地址0:0x1000
处加载代码0:0x1000
( es=0
, bx=0x1000
)但跳转到0x1000:0
( ljmp $0x1000, $0x0
)。 That won't work since the first is physical address 0x1000 but the second is 0x10000 (because in real mode you have to multiply segment by 16). 这不起作用,因为第一个是物理地址0x1000但第二个是0x10000(因为在实模式中你必须将段乘以16)。 Make them match. 让它们匹配。
There may be other errors, learn to use a debugger or you'll be asking for help every minute. 可能存在其他错误,学习使用调试器或者您每分钟都会寻求帮助。
Also, please keep the formatting such that we can easily copy-paste the whole code for testing ourselves (or provide a pastebin link too). 另外,请保留格式,以便我们可以轻松地复制粘贴整个代码以进行自我测试(或者也提供一个pastebin链接)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.