在过去的一周里,我一直在开发一个简单的操作系统用于学习目的和......"有趣".虚拟盒和NASM,我实际上开始了一个非常好的开始.最后,我决定通过臭名昭着的Brokenthorn教程,直到从文件系统加载,我还想开发一个引导加载程序(在点击512字节的墙之后很难).
有了一些HexFiend恶作剧和一些空白的FAT16图像,我最终得到了BPB.通过一些额外的程序集hackery(基础是Brokenthorn的教程,第6部分),我还使用我的bootloader进行文件加载,它从我的虚拟磁盘加载适当命名的'boot'文件(使用dd if =/dev/zero of = boot.img bs = 512 count = 2880)
那么,问题是什么呢?当我通过USB记忆棒(在这种情况下,/ dev/disk3,其中编译的文件是boot.bin)加载到实际硬件时,我看到的是:
dd bs=512 count=1 if=compiled/boot.bin of=/dev/disk3
Run Code Online (Sandbox Code Playgroud)
这是预期的输出(在VirtualBox中):

与实际输出相比(在旧笔记本电脑上)

'-' indicates a sector is being loaded
'_' indicates a sector was loaded
'!' indicates all of the desired sectors were loaded properly
'R' indicates a read error
'T' indicates the FAT table is being loaded
'D' indicates the FAT table was loaded properly
'F' means the file is being located (or …Run Code Online (Sandbox Code Playgroud) 我使用 GNU 汇编器和 AT&T 语法编写了我的第一个引导加载程序。它应该打印hello world到屏幕上,然后通知用户按任意键将导致重新启动。只有按下某个键后才会启动重新启动。我的引导加载程序代码不等待按键,并在打印信息后自动重新启动。为什么此代码不等待击键,我该如何修复它?
我的引导扇区代码:
#generate 16-bit code
.code16
#hint the assembler that here is the executable code located
.text
.globl _start;
#boot code entry
_start:
jmp _boot #jump to boot code
welcome: .asciz "Hello, World\n\r" #here we define the string
AnyKey: .asciz "Press any key to reboot...\n\r"
.macro mWriteString str #macro which calls a function to print a string
leaw \str, %si
call .writeStringIn
.endm
#function to print the string
.writeStringIn:
lodsb
orb %al, %al …Run Code Online (Sandbox Code Playgroud) 我试图编写一个引导加载程序以在 dos-box 中使用我编写了以下代码
[BITS 16] ;tell the assembler that its a 16 bit code
[ORG 0x7C00] ;Origin, tell the assembler that where the code will
;be in memory after it is been loaded
JMP $ ;infinite loop
TIMES 510 - ($ - $$) db 0 ;fill the rest of sector with 0
DW 0xAA55 ; add boot signature at the end of bootloader
Run Code Online (Sandbox Code Playgroud)
我试图通过以下命令使用 nasm 组装它
nasm -f elf myfile.asm
Run Code Online (Sandbox Code Playgroud)
然后我看到那个错误
错误:无法识别的指令 [ORG]
我使用的是ubuntu 14.04 LTS,nasm的版本是2.10.09
今天终于到了火花板边缘板;-)
按照这个写得很好的指南:https : //codelabs.developers.google.com/codelabs/sparkfun-tensorflow/#3 我在尝试使用uart_wired_update.py脚本在 Ambiq 上刷写代码时遇到了以下 NoResponseError张量流示例
opprud$ python3 tensorflow/lite/experimental/micro/tools/make/downloads/AmbiqSuite-Rel2.0.0/tools/apollo3_scripts/uart_wired_update.py -b 115200 /dev/cu.usbserial-1430 -r 1 -f main_nonsecure_wire.bin -i 6
MOJ/Connecting with Corvette over serial port /dev/cu.usbserial-1430...
Sending Hello.
No response for command 0x00000000
Traceback (most recent call last):
File "tensorflow/lite/experimental/micro/tools/make/downloads/AmbiqSuite-Rel2.0.0/tools/apollo3_scripts/uart_wired_update.py", line 336, in <module>
main()
File "tensorflow/lite/experimental/micro/tools/make/downloads/AmbiqSuite-Rel2.0.0/tools/apollo3_scripts/uart_wired_update.py", line 38, in main
connect_device(ser)
File "tensorflow/lite/experimental/micro/tools/make/downloads/AmbiqSuite-Rel2.0.0/tools/apollo3_scripts/uart_wired_update.py", line 58, in connect_device
response = send_command(hello, 88, ser)
File "tensorflow/lite/experimental/micro/tools/make/downloads/AmbiqSuite-Rel2.0.0/tools/apollo3_scripts/uart_wired_update.py", line 235, in send_command
raise NoResponseError
__main__.NoResponseError
Run Code Online (Sandbox Code Playgroud)
我的设置:
最近经常使用闪存 ROM,我发现在芯片的内部闪存以及外部 SPI 闪存设备中,扇区的大小通常都是这样的:
我很好奇为什么起始地址空间的扇区比后面的地址小。我怀疑使用引导加载程序之类的东西会更方便。由于引导加载程序通常小于 128k,因此这将允许引导加载程序写入前 2 或 3 个扇区。这使得主空间应用程序有更多的扩展空间,因为要对其进行编程,我们需要从新扇区的开头开始。如果我们只有 128k 大小的扇区,那么我们基本上就会浪费128k - bootloader_size空间。
我的怀疑正确吗?或者这样做还有其他原因吗?真的很想知道这里的设计决策是什么。
我正在尝试编写自己的操作系统内核,但在引导加载程序和(即将成为)我的内核(用 C 编写的)之间正确连接时遇到了一些问题。
我有以下代码...
src/bootloader.asm
; Allows our code to be run in real mode.
BITS 16
extern kmain
section .text
global _start
_start:
jmp Start
; Moves the cursor to row dl, col dh.
MoveCursor:
mov ah, 2
mov bh, 0
int 10h
ret
; Prints the character in al to the screen.
PrintChar:
mov ah, 10
mov bh, 0
mov cx, 1
int 10h
ret
; Set cursor position to 0, 0.
ResetCursor:
mov dh, 0
mov dl, …Run Code Online (Sandbox Code Playgroud) 我将kexec压缩为一个二进制文件,并将其编写为x86_64 ELF。运行正常。
由于它是64位二进制文件,因此我知道处理器必须处于64位长模式。这需要使用分页,所以我知道必须打开分页。
我的问题是,这些页表的状态是什么?是否有某些区域(例如我加载的二进制文件)可以保证进行身份映射?是否所有可用的RAM标识都已映射?由于启用了分页,因此页面在哪里?
执行完kexec'之后,我想对整个地址空间进行身份映射。为此,我需要在我知道物理地址的地址处构建一些页表结构,然后将该结构的地址写入CR3。
如果我知道加载到内存中的小精灵二进制文件是身份映射的,则可以在其中静态构建页表,然后进行无缝切换。如果kexec之后没有标识映射的页面,则需要关闭分页,退出long模式,然后进行设置,然后重新进入long 64位模式。
谢谢!
假设我想将堆栈初始化为S字节大小。
我想选择堆栈的基本位置,B以便随着堆栈从 向下增长B,我最终不会覆盖引导加载程序或 BIOS 使用的任何代码或其他内存。
由于我自己编写引导加载程序(并且初始 MBR 扇区被加载到线性地址0x7c00),防止与引导加载程序发生冲突似乎是一个仔细规划的问题。
我如何知道 BIOS 代码所在的位置,以及我的堆栈是否可能覆盖 BIOS 正在使用的任何内存?
另外,是否可以保证初始ss:sp值指向哪里,以及在不设置新值的情况下可以安全使用多少堆栈空间?
我正在尝试制作一个适用于两种架构的引导加载程序:x86 和 PDP-11。主操作系统是为 PDP-11 兼容机器编写的,但从 x86 启动也应该可以工作,启动模拟器。
AFAIK,如果最后两个字节是, x86 加载第一个磁盘扇区0x7c00并跳转到那里。相反,如果第一个命令是且最后两个字节是 ,则 PDP-11 兼容机将第一个扇区加载到(八进制)并执行它。然而,由于一些硬件细节的原因,加载的数据实际上是颠倒的——例如,x86 读取的数据,另一台机器读取的数据。在这种情况下,这在某种程度上是一个功能,因为如果我制作最后两个字节,它们将适用于两台机器。0x55 0xaa0o20000NOP0xaa 0x550x120xed0x55 0xaa
总之,PDP-11兼容机需要前两个字节包含NOP命令,即0o000240,或0x00a0。数据被反转,因此 x86 实际上会读取0xff5f。
0x5f是 x86 中的真实命令。不幸的是,它是pop di. AFAIK,sp和ss值都没有指定,所以这个命令读取谁知道什么。
我的问题是:
0x0000:0x0000or 0xffff:0xffff?ss:sp指向读取不安全的内存映射硬件寄存器?如果是的话,如果我读了它们,会发生什么更糟糕的事情?我不想意外损坏笔记本电脑。ss:sp指向不可用的内存,即可能pop di触发总线错误?如果是,BIOS 将如何从中恢复,即它将重新启动、显示消息或执行其他操作?我正在为 Nucleo-F429ZI 编写引导加载程序。我有两个不同的 STM32 项目,一个用于引导加载程序本身,另一个用于从引导加载程序跳转的应用程序。
引导加载程序的链接器脚本
MEMORY
{
CCMRAM (xrw) : ORIGIN = 0x10000000, LENGTH = 64K
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 32K
FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 32K
}
Run Code Online (Sandbox Code Playgroud)
应用程序的链接器脚本
_estack = ORIGIN(RAM) + LENGTH(RAM);
MEMORY
{
CCMRAM (xrw) : ORIGIN = 0x10000000, LENGTH = 64K
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 192K
FLASH (rx) : ORIGIN = 0x8008000, LENGTH = 64K
}
Run Code Online (Sandbox Code Playgroud)
我没有忘记设置应用程序的闪光偏移。
system_stm32f4xx.c(在应用程序项目中)
#define VECT_TAB_BASE_ADDRESS FLASH_BASE // 0x8000000
#define …Run Code Online (Sandbox Code Playgroud)