- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我想制作一个玩具操作系统,但我陷入了引导加载程序阶段。我只是想写一个非常简单的引导加载程序来加载我的主要C代码,我不太喜欢x86汇编,发生的事情是在第二阶段引导加载程序中,切换到 protected /32位模式后,我调用我的kmain()
c使用 extern
关键字的函数似乎会进入某种无限重启循环,或者 qemu 崩溃并出现此错误“尝试在 RAM 或 ROM 之外的 0x000a0000 处执行代码”
我还有一些基于 x86 汇编程序的函数来将文本打印到屏幕上,如果使用这些函数,效果很好,但是调用 extern c 函数会导致上述错误
“流程”是这样的bootloader.asm(第一阶段引导加载程序)->Stage2.asm(第二阶段引导加载程序)->kmain.cpp在Stage2.asm中设置GDT、堆栈、A20以启动保护模式/32位模式,然后调用extern kmain函数。kmain() c++文件仅尝试将一个带有颜色的字符写入VGA缓冲区
我在 UBuntu 18.04 主机上,使用 nasm 进行汇编,使用 gcc 进行链接和 c 编译,使用 qemu 来测试这个所谓的操作系统
这些是我用来构建和运行的命令
nasm -f elf bootload.asm -o bootload.o
nasm -f elf Stage2.asm -o stage2.o
gcc -m32 stage2.o bootload.o kmain.cpp -o kernel.bin -g -nostdlib -ffreestanding -std=c++11 -mno-red-zone -fno-exceptions -nostdlib -fno-rtti -Wall -Wextra -Werror -T linker.ld
qemu-system-i386 -fda kernel.bin
这是我的bootloader.asm
[bits 16]
section .boot
global boot
boot:
hello: db "Hello world!",0
mov si,hello
mov ah,0x0e
.loop:
lodsb
or al,al
jz diskboot
int 0x10
jmp .loop
diskboot:
mov ax,0x800
mov es,ax
xor bx,bx
mov ah,0x2
mov al,0x1
mov ch,0x0
mov cl,0x2
mov dh,0x0
int 0x13
jmp 0x800:0
Stage2.asm
section .kernel
bits 16
jmp main ; go to start
;*******************************************************
; Preprocessor directives
;*******************************************************
%include "stdio.inc" ; basic i/o routines
%include "Gdt.inc" ; Gdt routines
%include "A20.inc" ; A20 enabling
;*******************************************************
; Data Section
;*******************************************************
LoadingMsg db 0x0D, 0x0A, "Searching for Operating System...", 0x00
main:
cli ; clear interrupts
xor ax, ax ; null segments
mov ds, ax
mov es, ax
mov ax, 0x9000 ; stack begins at 0x9000-0xffff
mov ss, ax
mov sp, 0xFFFF
sti ; enable interrupts
call InstallGDT ; install our GDT
call EnableA20_KKbrd_Out
mov si, LoadingMsg
call Puts16
EnterStage3:
cli ; clear interrupts
mov eax, cr0 ; set bit 0 in cr0--enter pmode
or eax, 1
mov cr0, eax
jmp CODE_DESC:Stage3 ; far jump to fix CS
bits 32
Stage3:
mov ax, DATA_DESC
mov ds, ax
mov ss, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ebp, 0x90000
mov esp, ebp
extern kmain
call kmain
cli
hlt
msg db 0x0A, "<[ OS Development Series Tutorial 10 ]>", 0x0A, 0
A20.inc
;********************************************
; Enable A20 address line
;
; OS Development Series
;********************************************
%ifndef __A20_INC_67343546FDCC56AAB872_INCLUDED__
%define __A20_INC_67343546FDCC56AAB872_INCLUDED__
bits 16
;----------------------------------------------
; Enables a20 line through keyboard controller
;----------------------------------------------
EnableA20_KKbrd:
cli
push ax
mov al, 0xdd ; send enable a20 address line command to controller
out 0x64, al
pop ax
ret
;--------------------------------------------
; Enables a20 line through output port
;--------------------------------------------
EnableA20_KKbrd_Out:
cli
pusha
call wait_input
mov al,0xAD
out 0x64,al ; disable keyboard
call wait_input
mov al,0xD0
out 0x64,al ; tell controller to read output port
call wait_output
in al,0x60
push eax ; get output port data and store it
call wait_input
mov al,0xD1
out 0x64,al ; tell controller to write output port
call wait_input
pop eax
or al,2 ; set bit 1 (enable a20)
out 0x60,al ; write out data back to the output port
call wait_input
mov al,0xAE ; enable keyboard
out 0x64,al
call wait_input
popa
sti
ret
; wait for input buffer to be clear
wait_input:
in al,0x64
test al,2
jnz wait_input
ret
; wait for output buffer to be clear
wait_output:
in al,0x64
test al,1
jz wait_output
ret
;--------------------------------------
; Enables a20 line through bios
;--------------------------------------
EnableA20_Bios:
pusha
mov ax, 0x2401
int 0x15
popa
ret
;-------------------------------------------------
; Enables a20 line through system control port A
;-------------------------------------------------
EnableA20_SysControlA:
push ax
mov al, 2
out 0x92, al
pop ax
ret
%endif
Gdt.inc
;*************************************************
; Gdt.inc
; -GDT Routines
;
; OS Development Series
;*************************************************
%ifndef __GDT_INC_67343546FDCC56AAB872_INCLUDED__
%define __GDT_INC_67343546FDCC56AAB872_INCLUDED__
bits 16
;*******************************************
; InstallGDT()
; - Install our GDT
;*******************************************
InstallGDT:
cli ; clear interrupts
pusha ; save registers
lgdt [toc] ; load GDT into GDTR
sti ; enable interrupts
popa ; restore registers
ret ; All done!
;*******************************************
; Global Descriptor Table (GDT)
;*******************************************
gdt_data:
dd 0 ; null descriptor
dd 0
; gdt code: ; code descriptor
dw 0FFFFh ; limit low
dw 0 ; base low
db 0 ; base middle
db 10011010b ; access
db 11001111b ; granularity
db 0 ; base high
; gdt data: ; data descriptor
dw 0FFFFh ; limit low (Same as code)10:56 AM 7/8/2007
dw 0 ; base low
db 0 ; base middle
db 10010010b ; access
db 11001111b ; granularity
db 0 ; base high
end_of_gdt:
toc:
dw end_of_gdt - gdt_data - 1 ; limit (Size of GDT)
dd gdt_data ; base of GDT
; give the descriptor offsets names
%define NULL_DESC 0
%define CODE_DESC 0x8
%define DATA_DESC 0x10
%endif ;__GDT_INC_67343546FDCC56AAB872_INCLUDED__
linker.ld
ENTRY(boot)
OUTPUT_FORMAT("binary")
SECTIONS {
. = 0x7c00;
.boot :
{
*(.boot)
}
. = 0x7dfe;
.sig : {
SHORT(0xaa55);
}
. = 0x8000;
.kernel : AT(0x7e00) /* place immediately after the boot sector */
{
*(.kernel)
*(.text)
*(.rodata)
*(.data)
*(.bss)
*(COMMON)
}
kernel_sectors = (SIZEOF(.kernel) + 511) / 512;
/DISCARD/ : {
*(.eh_frame)
}
}
kmain.cpp
extern "C" void kmain()
{
unsigned char* vga = (unsigned char*) 0xb8000;
vga[0] = 'S';
vga[1] = 0x09;
for(;;);
}
编辑:添加stdio.inc
%ifndef __STDIO_INC_67343546FDCC56AAB872_INCLUDED__
%define __STDIO_INC_67343546FDCC56AAB872_INCLUDED__
;==========================================================
;
; 16 Bit Real Mode Routines
;==========================================================
;************************************************;
; Puts16 ()
; -Prints a null terminated string
; DS=>SI: 0 terminated string
;************************************************;
bits 16
Puts16:
pusha ; save registers
.Loop1:
lodsb ; load next byte from string from SI to AL
or al, al ; Does AL=0?
jz Puts16Done ; Yep, null terminator found-bail out
mov ah, 0eh ; Nope-Print the character
int 10h ; invoke BIOS
jmp .Loop1 ; Repeat until null terminator found
Puts16Done:
popa ; restore registers
ret ; we are done, so return
;==========================================================
;
; 32 Bit Protected Mode Routines
;==========================================================
bits 32
%define VIDMEM 0xB8000 ; video memory
%define COLS 80 ; width and height of screen
%define LINES 25
%define CHAR_ATTRIB 63 ; character attribute (White text on light blue background)
_CurX db 0 ; current x/y location
_CurY db 0
;**************************************************;
; Putch32 ()
; - Prints a character to screen
; BL => Character to print
;**************************************************;
Putch32:
pusha ; save registers
mov edi, VIDMEM ; get pointer to video memory
;-------------------------------;
; Get current position ;
;-------------------------------;
xor eax, eax ; clear eax
;--------------------------------
; Remember: currentPos = x + y * COLS! x and y are in _CurX and _CurY.
; Because there are two bytes per character, COLS=number of characters in a line.
; We have to multiply this by 2 to get number of bytes per line. This is the screen width,
; so multiply screen with * _CurY to get current line
;--------------------------------
mov ecx, COLS*2 ; Mode 7 has 2 bytes per char, so its COLS*2 bytes per line
mov al, byte [_CurY] ; get y pos
mul ecx ; multiply y*COLS
push eax ; save eax--the multiplication
;--------------------------------
; Now y * screen width is in eax. Now, just add _CurX. But, again remember that _CurX is relative
; to the current character count, not byte count. Because there are two bytes per character, we
; have to multiply _CurX by 2 first, then add it to our screen width * y.
;--------------------------------
mov al, byte [_CurX] ; multiply _CurX by 2 because it is 2 bytes per char
mov cl, 2
mul cl
pop ecx ; pop y*COLS result
add eax, ecx
;-------------------------------
; Now eax contains the offset address to draw the character at, so just add it to the base address
; of video memory (Stored in edi)
;-------------------------------
xor ecx, ecx
add edi, eax ; add it to the base address
;-------------------------------;
; Watch for new line ;
;-------------------------------;
cmp bl, 0x0A ; is it a newline character?
je .Row ; yep--go to next row
;-------------------------------;
; Print a character ;
;-------------------------------;
mov dl, bl ; Get character
mov dh, CHAR_ATTRIB ; the character attribute
mov word [edi], dx ; write to video display
;-------------------------------;
; Update next position ;
;-------------------------------;
inc byte [_CurX] ; go to next character
; cmp byte [_CurX], COLS ; are we at the end of the line?
; je .Row ; yep-go to next row
jmp .done ; nope, bail out
;-------------------------------;
; Go to next row ;
;-------------------------------;
.Row:
mov byte [_CurX], 0 ; go back to col 0
inc byte [_CurY] ; go to next row
;-------------------------------;
; Restore registers & return ;
;-------------------------------;
.done:
popa ; restore registers and return
ret
;**************************************************;
; Puts32 ()
; - Prints a null terminated string
; parm\ EBX = address of string to print
;**************************************************;
Puts32:
;-------------------------------;
; Store registers ;
;-------------------------------;
pusha ; save registers
push ebx ; copy the string address
pop edi
.loop:
;-------------------------------;
; Get character ;
;-------------------------------;
mov bl, byte [edi] ; get next character
cmp bl, 0 ; is it 0 (Null terminator)?
je .done ; yep-bail out
;-------------------------------;
; Print the character ;
;-------------------------------;
call Putch32 ; Nope-print it out
;-------------------------------;
; Go to next character ;
;-------------------------------;
inc edi ; go to next character
jmp .loop
.done:
;-------------------------------;
; Update hardware cursor ;
;-------------------------------;
; Its more efficiant to update the cursor after displaying
; the complete string because direct VGA is slow
mov bh, byte [_CurY] ; get current position
mov bl, byte [_CurX]
call MovCur ; update cursor
popa ; restore registers, and return
ret
;**************************************************;
; MoveCur ()
; - Update hardware cursor
; parm/ bh = Y pos
; parm/ bl = x pos
;**************************************************;
bits 32
MovCur:
pusha ; save registers (aren't you getting tired of this comment?)
;-------------------------------;
; Get current position ;
;-------------------------------;
; Here, _CurX and _CurY are relitave to the current position on screen, not in memory.
; That is, we don't need to worry about the byte alignment we do when displaying characters,
; so just follow the forumla: location = _CurX + _CurY * COLS
xor eax, eax
mov ecx, COLS
mov al, bh ; get y pos
mul ecx ; multiply y*COLS
add al, bl ; Now add x
mov ebx, eax
;--------------------------------------;
; Set low byte index to VGA register ;
;--------------------------------------;
mov al, 0x0f
mov dx, 0x03D4
out dx, al
mov al, bl
mov dx, 0x03D5
out dx, al ; low byte
;---------------------------------------;
; Set high byte index to VGA register ;
;---------------------------------------;
xor eax, eax
mov al, 0x0e
mov dx, 0x03D4
out dx, al
mov al, bh
mov dx, 0x03D5
out dx, al ; high byte
popa
ret
;**************************************************;
; ClrScr32 ()
; - Clears screen
;**************************************************;
bits 32
ClrScr32:
pusha
cld
mov edi, VIDMEM
mov cx, 2000
mov ah, CHAR_ATTRIB
mov al, ' '
rep stosw
mov byte [_CurX], 0
mov byte [_CurY], 0
popa
ret
;**************************************************;
; GotoXY ()
; - Set current X/Y location
; parm\ AL=X position
; parm\ AH=Y position
;**************************************************;
bits 32
GotoXY:
pusha
mov [_CurX], al ; just set the current position
mov [_CurY], ah
popa
ret
%endif ;__STDIO_INC_67343546FDCC56AAB872_INCLUDED__
最佳答案
stdio.inc
具有已在 32 位保护模式下使用 x86 汇编器写入 VGA 帧缓冲区的函数,这些函数与我也尝试写入帧缓冲区的 C 代码冲突。删除 stdio.inc 及其函数的所有引用已经解决了该问题我现在可以写入 VGA 缓冲区并使用 C 代码在屏幕上显示彩色文本。
关于c - 外部 C 代码无法从两阶段 x86 引导加载程序执行?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60640575/
我有一个“有趣”的问题,即以两种不同的方式运行 wine 会导致: $> wine --version /Applications/Wine.app/Contents/Resources/bin/wi
我制作了这个网络抓取工具来获取网页中的表格。我使用 puppeteer (不知道 crontab 有问题)、Python 进行清理并处理数据库的输出 但令我惊讶的是,当我执行它时 */50 * * *
JavaScript 是否被调用或执行取决于什么?准确地说,我有两个函数,它们都以相同的方式调用: [self.mapView stringByEvaluatingJavaScriptFromStri
我目前正在使用 python 做一个机器学习项目(这里是初学者,从头开始学习一切)。 只是想知道 statsmodels 的 OLS 和 scikit 的 PooledOlS 使用我拥有的相同面板数据
在使用集成对象模型 (IOM) 后,我可以执行 SAS 代码并将 SAS 数据集读入 .Net/C# 数据集 here . 只是好奇,使用 .Net 作为 SAS 服务器的客户端与使用 Enterpr
有一些直接的 jQuery 在单击时隐藏打开的 div 未显示,但仍将高度添加到导航中以使其看起来好像要掉下来了。 这个脚本工作正常: $(document).ready(funct
这个问题已经有答案了: How do I compare strings in Java? (23 个回答) 已关闭 4 年前。 这里是 Java 新手,我正在使用 NetBeans 尝试一些简单的代
如果我将它切换到 Python 2.x,它执行 10。这是为什么? 训练逻辑回归模型 import keras.backend as
我有两个脚本,它们包含在 HTML 正文中。在第一个脚本中,我初始化一个 JS 对象,该对象在第二个脚本标记中引用。 ... obj.a = 1000; obj.
每当我运行该方法时,我都会收到一个带有数字的错误 以下是我的代码。 public String getAccount() { String s = "Listing the accounts";
我已经用 do~while(true) 创建了我的菜单;但是每次用户输入一个数字时,它不会运行程序,而是再次显示菜单!你怎么看? //我的主要方法 public static void main(St
执行命令后,如何让IPython通知我?我可以使用铃声/警报还是通过弹出窗口获取它?我正在OS X 10.8.5的iTerm上运行Anaconda。 最佳答案 使用最新版本的iTerm,您可以在she
您好,我刚刚使用菜单栏为 Swing 编写了代码。但是问题出现在运行中。我输入: javac Menu.java java Menu 它没有给出任何错误,但 GUI 没有显示。这是我的源代码以供引用:
我觉得这里缺少明显的东西,但是我看不到它写在任何地方。 我使用Authenticode证书对可执行文件进行签名,但是当我开始学习有关它的更多信息时,我对原样的值(value)提出了质疑。 签名的exe
我正在设计一个应用程序,它使用 DataTables 中的预定义库来创建数据表。我想对数据表执行删除操作,为此应在按钮单击事件上执行 java 脚本。 $(document).ready(functi
我是 Haskell 新手,如果有人愿意帮助我,我会很高兴!我试图让这个程序与 do while 循环一起工作。 第二个 getLine 命令的结果被放入变量 goGlenn 中,如果 goGlenn
我有一个用 swing 实现迷你游戏的程序,在主类中我有一个循环,用于监听游戏 map 中的 boolean 值。使用 while 实现的循环不会执行一条指令,如果它是唯一的一条指令,我不知道为什么。
我正在尝试开发一个连接到 Oracle 数据库并执行函数的 Java 应用程序。如果我在 Eclipse 中运行该应用程序,它可以工作,但是当我尝试在 Windows 命令提示符中运行 .jar 时,
我正在阅读有关 Java 中的 Future 和 javascript 中的 Promises 的内容。下面是我作为示例编写的代码。我的问题是分配给 future 的任务什么时候开始执行? 当如下行创
我有一个常见的情况,您有两个变量(xSpeed 和 ySpeed),当它们低于 minSpeed 时,我想将它们独立设置为零,并在它们都为零时退出。 最有效的方法是什么?目前我有两种方法(方法2更干净
我是一名优秀的程序员,十分优秀!