作为学习练习,我为x86 bios系统编写了一个16位的引导程序。它在QEMU上似乎运行良好。我将其添加到用于旧式amd-turion计算机(x86_64)的驱动器上,当我尝试引导该计算机时,它将进入BIOS屏幕,然后黑屏上的光标闪烁。
我的问题是,QEMU的x86仿真器和绝对使用BIOS而不是UEFI的真实x86(64位)计算机之间可能有什么区别?我是否需要针对实际计算机而不是QEMU编写代码?是我将信息复制到驱动器的方式吗?计算机是否采用了某些硬件级别的安全性规定?
我知道它在VirtualBox上也不起作用。
看来加载第二阶段是有问题的(通过在真实硬件上成功地打印第一阶段的字符)。
我的第一阶段引导程序使用以下文件中的代码:
stage_one.asm
[bits 16]
[org 0x7c00]
LOAD_ADDR: equ 0x9000 ; This is where I'm loading the 2nd stage in RAM.
start:
xor ax, ax ; nullify ax so we can set
mov ds, ax ; ds to 0
mov sp, bp ; relatively out of the way
mov bp, 0x8000 ; set up the stack
call disk_load ; load the new instructions
; at …Run Code Online (Sandbox Code Playgroud) 我是操作系统开发的新手,我很好奇我在开发自己的bootloader时遇到的问题.我的操作系统将以汇编语言编写,并将以16位实模式运行.
我知道堆栈是什么,我的印象是它向下扩展到内存中.如果我错了,请纠正我.我知道如何从软盘中将基本内核加载到内存中,我不相信这是问题所在.
我遇到的问题是我不确定在哪里放置堆栈并将内核加载到内存中.我试过像这样创建我的堆栈,我遇到了问题:
mov ax, 0x0000
mov ss, ax
mov sp, 0xFFFF
Run Code Online (Sandbox Code Playgroud)
我正在加载我的内核0x1000:0x0000.当我推送并稍后在我的函数中弹出易失性寄存器时print,我的内核只是第二次挂起call print.这是我的print功能:
print:
push ax
push bx
push cx
mov al, [si]
cmp al, 0
je p_Done
cmp al, 9
je p_Tab
mov ah, 0xE
int 0x10
cmp al, 10
je p_NewLine
p_Return:
inc si
jmp print
p_Tab:
xor cx, cx
p_Tab_Repeat:
cmp cx, 8
je p_Return
mov ah, 0xE
mov al, " " …Run Code Online (Sandbox Code Playgroud) 尝试使用基索引表达式在 16 位实模式下操作内存会导致编译错误:
movw $0xd000, -2(%sp)
movw $0, -4(%sp)
movw $1, -6(%sp)
Run Code Online (Sandbox Code Playgroud)
编译为
gcc -c -Wa,--32 $(DIR_BS_SRC)/mbr.S -o $(DIR_BS_SRC)/mbr.o
ld -nostdlib --oformat binary --Ttext 0x7c00 $(DIR_BS_SRC)/mbr.o -o $(DIR_B$
Run Code Online (Sandbox Code Playgroud)
产生以下错误:
bootsector/src/mbr.S:20: Error: `-2(%sp)' is not a valid base/index expression
bootsector/src/mbr.S:21: Error: `-4(%sp)' is not a valid base/index expression
bootsector/src/mbr.S:22: Error: `-6(%sp)' is not a valid base/index expression
Run Code Online (Sandbox Code Playgroud)
我认为这是有效的语法,即使在 16 位实模式下也是如此?
我刚刚为我的操作系统完成了一个非常简单的引导加载程序,现在我正在尝试切换到保护模式并跳转到内核.
内核存在于第二个扇区(在引导加载程序之后)并且打开.
任何人都可以帮我解决我的代码吗?我添加了评论,以显示我的困惑在哪里.
谢谢.
BITS 16
global start
start:
; initialize bootloader and stack
mov ax, 0x07C0
add ax, 288
mov ss, ax
mov sp, 4096
mov ax, 0x07C0
mov ds, ax
call kernel_load
hlt
kernel_load:
mov si, k_load
call print
mov ax, 0x7C0
mov ds, ax
mov ah, 2
mov al, 1
push word 0x1000
pop es
xor bx, bx
mov cx, 2
mov dx, 0
int 0x13
jnc .kjump
mov si, k_fail
call print
ret
.kjump:
mov si, …Run Code Online (Sandbox Code Playgroud) 我一直在用C编写内核.我一直在使用GCC交叉编译器,在Windows系统上编写并以16位实模式为目标.我没有可用于编写内核的C库.我已经开始使用一些代码来假设将字符直接打印到屏幕上.这是一个函数来自kernel.c:
int main()
{
char *src = (char *)0xB8000000L;
*src = 'M';
src += 2;
*src = 'D';
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我使用GCC编译了我的代码,并使用参数-m16生成将在实模式下运行的代码.我使用这些命令来生成我的kernel.bin:
gcc -ffreestanding -c -m16 kernel.c -o kernel.o
ld -Ttext 0x10000 -o kernel.pe kernel.o
objcopy -O binary kernel.pe kernel.bin
Run Code Online (Sandbox Code Playgroud)
Stack Overflow用户Michael Petch解决了我的链接器问题,但评论代码本身是不正确的.他发表了这样的评论:
除链接器问题外,您是否尝试将旧的TurboC/MSVC 16位代码转换为GCC?我发现(char*)0xB8000000L可疑.如果它是一个真正的16位C编译器,它可能是好的,如果它是(char far*)0xB8000000L.GCC不是一个真正的16位C编译器,并没有旧式远指针的概念.所以,即使你得到这个代码进行编译,这可能不会做你认为它做的,我假设从-m16选项与GCC你正在尝试创建一个实模式16位内核(而不是保护模式一个) )?
我一直在尝试printf在C中为我自己的操作系统实现自己的类似功能.我上面提供的代码只是我理解的一小部分.我在程序集中创建了一个bootloader(8086).
迈克尔是对的吗?如果是这样,我该如何解决这个问题并直接写入视频内存0xb8000?
我想写一个bootloader,它只是打印"Hello World!" 在屏幕上,我不知道为什么我的字节混淆了.我正在尝试用AT&T语法编写它(请不要推荐英特尔语法)并尝试将本教程中的代码转换为AT&T语法.
现在这里是我的bootloader的相当短的代码:
start:
.code16 #real mode
.text
.org 0x0
.globl _main
_main:
movw hello, %si
movb $0x0e, %ah
loophere:
lodsb
or %al, %al #is al==0 ?
jz halt #if previous instruction sets zero flag jump to halt
int $0x10 #run bios interrupt 0x10 (ah is set to 0x0e so a character is displayed)
jmp loophere
halt:
cli
hlt
hello: .ascii "Hello world!\0"
filloop:
.fill (510-(.-_main)),1,0 #I hope this works. Fill bootloader with 0's until byte 510 …Run Code Online (Sandbox Code Playgroud) 我想在下面的问题中了解AX寄存器的内容,我不明白我怎么知道示例中的[5000h]或[DI]是什么.
寄存器和存储器的状态定义为:
CS=3000 [53000]=BBBB [33000]=6666 [13000]=1111
DS=1000 [54000]=CCCC [34000]=7777 [14000]=2222
SS=5000 [55000]=DDDD [35000]=8888 [15000]=3333
DI=7000 [56000]=EEEE [36000]=9999 [16000]=4444
BP=4000 [57000]=FFFF [37000]=AAAA [17000]=5555
Run Code Online (Sandbox Code Playgroud)
AX中的每个指令的值是多少
MOV AX, [DI]MOV AX, [5000h]MOV AX, [BP+2000h]LEA AX, [BP+1000h]我在 MS-DOS 中进行了大量的汇编编程试验。我读过 Windows 3.1 充当 DOS 程序的 DPMI 主机,并且 DPMI 使用中断 31h 进行函数调用。
所以让我们试一试。我在 Windows 3.1 中打开 DOS 提示符...
C:\WINDOWS>debug
-a100
23A4:0100 mov ax,0400
23A4:0103 int 31
23A4:0105
-r
AX=0000 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=23A4 ES=23A4 SS=23A4 CS=23A4 IP=0100 NV UP EI PL NZ NA PO NC
23A4:0100 B80004 MOV AX,0400
-p
AX=0400 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=23A4 ES=23A4 SS=23A4 CS=23A4 IP=0103 NV UP EI PL NZ NA PO NC
23A4:0103 CD31 INT …Run Code Online (Sandbox Code Playgroud) 我的目标是使用 Int 16 指令能够使用箭头键在程序中上下移动,直到我的用户决定按退出键。我是否在循环中使用以下代码读取多个按键并在末尾添加终止条件,或者是否缺少某些内容?
Mov ah,00
int 16
Run Code Online (Sandbox Code Playgroud) [org 0x7c00]
mov bp, 0x8000 ; set the stack safely away from us
mov sp, bp
mov bx, 0x9000 ; es:bx = 0x0000:0x9000 = 0x09000
Run Code Online (Sandbox Code Playgroud)
正如你可以在注释中看到它说:es:bx = 0x0000:0x9000 = 0x09000。寄存器ES和BX之间有什么关系?该代码仅设置寄存器BX,但注释显示寄存器ES也被设置?
real-mode ×10
assembly ×8
x86 ×6
bootloader ×4
x86-16 ×4
nasm ×2
osdev ×2
bare-metal ×1
bios ×1
dos ×1
kernel ×1
qemu ×1
stack ×1
windows-3.1 ×1