在初始化我的内核时,我需要做一些事情:1)需要启用分页,2)物理内存管理器需要从grub解析内存映射,以及3)各种启动代码需要访问需要的数据留在那里以后(例如GDT,IDT,内存管理结构).
这些步骤之间的依赖性让我发疯.对于较高的一半,内核在其虚拟地址处链接,因此我提出的选项是1)在汇编中启用分页,这将涉及遵循所有多引导指针(在汇编中),因此它们仍然可以访问到物理内存管理器,然后将它们全部取消映射,2)将启动代码链接到其物理地址,然后执行一些指针操作以访问其物理地址处的内核结构,或者3)不要使用更高的一半核心.
还涉及引导物理内存管理器而不知道编译时的物理内存量.我很确定在分配第一个结构时我必须小心避免所有的多引导结构,或者先使用它们然后不要担心覆盖它们(虽然我仍然需要处理模块和这种方法可能涉及在设置物理内存管理器时将多引导表复制到我需要的已知位置.
这些问题是我到目前为止避免使用更高半内核的原因.有没有人有一个很好的系统来解决这些依赖关系?也许这个GDT技巧的一些变化是访问其链接/虚拟地址的内核和物理地址的多重引导表,或使用某种预定义的页表来避免上述问题,可能涉及PSE?
在操作系统用户模式应用程序的虚拟地址空间是私有的,一个应用程序不能更改属于另一个应用程序的数据.每个应用程序都是独立运行的,如果应用程序崩溃,则崩溃仅限于该应用程序.其他应用程序和操作系统不受崩溃的影响
为什么在内核模式OS不保护内存和BOSD发生?
最近我对编写自己真正基本的操作系统感兴趣.我写了(嗯,复制)一些基本的程序集,它建立了一个堆栈并做了一些基本的事情,这似乎工作正常,但是试图将C引入混合中已经搞砸了一切.
我有两个主要的项目文件:loader.s,它是一些创建堆栈并调用我的C函数的NASM,以及包含基本C函数的kernel.c.
我现在的问题基本上是当我运行kernel.bin文件时QEMU冻结了.我猜我的代码有很多问题 - 由于它的极端特异性,这个问题可能不适合StackOverflow格式.我的项目文件如下:
loader.s:
BITS 16 ; 16 Bits
extern kmain ; Our 'proper' kernel function in C
loader:
mov ax, 07C0h ; Move the starting address [7C00h] into 'ax'
add ax, 32 ; Leave 32 16 byte blocks [200h] for the 512 code segment
mov ss, ax ; Set 'stack segment' to the start of our stack
mov sp, 4096 ; Set the stack pointer to the end of our stack [4096 bytes in size]
mov ax, …Run Code Online (Sandbox Code Playgroud) 作为世界上任何一个程序员,至少有一次他/她一生都在尝试创建自己的“革命性”,新的,唯一的操作系统。:D
好吧,我正在使用一个虚拟仿真器(Oracle VM Virtual Box),为此我创建了一个带有vmdk磁盘的新的unknwon操作系统。我喜欢vmdk,因为它们只是纯文件,因此我可以将引导加载程序粘贴到虚拟硬盘的前512个字节上。
现在,我试图读取该虚拟磁盘的下一个扇区,在该扇区上粘贴一个简单的内核,该内核将显示一条消息。
我有两个问题:
我是否在正确读取第二段(前-512字节-被引导程序占用)? 码:
ReadDisk:
mov bx, 0x8000 ; segment
mov es, bx
mov bx, 0x0000 ; offset
mov ah, 0x02 ; read function
mov al, 0x01 ; sectors - this might be wrong, trying to read from hd
mov ch, 0x00 ; cylinder
mov cl, 0x02 ; sector
mov dh, 0x00 ; head
mov dl, 0x80 ; drive - trying to read from hd
int 0x13 ; disk int
jc ReadDisk
jmp [es:bx] ; …Run Code Online (Sandbox Code Playgroud)我正在尝试开发一个操作系统.设计是这样的:我有一个加载在0x7c00的引导程序,它加载第二阶段并在0x7e00跳转到它.第二阶段也处于实模式并且执行许多操作,例如加载gdt,启用A20并切换到保护模式.它还在0x8000处加载一个非常简单的32位内核.现在的问题是我无法调用或jmp到0x8000,因为内核似乎没有加载(我在VirtualBox中进行了内存转储).我已经在第二阶段完成了FAR JMP来设置CS寄存器.我在VirtualBox中测试我的操作系统.
我的启动加载程序的代码:
org 0x7c00
bits 16
Start:
jmp Reset
bpbOEM DB "SKULLOS "
bpbBytesPerSector: DW 512
bpbSectorsPerCluster: DB 1
bpbReservedSectors: DW 1
bpbNumberOfFATs: DB 2
bpbRootEntries: DW 224
bpbTotalSectors: DW 2880
bpbMedia: DB 0xF0
bpbSectorsPerFAT: DW 9
bpbSectorsPerTrack: DW 18
bpbHeadsPerCylinder: DW 2
bpbHiddenSectors: DD 0
bpbTotalSectorsBig: DD 0
bsDriveNumber: DB 0
bsUnused: DB 0
bsExtBootSignature: DB 0x29
bsSerialNumber: DD 0xa0a1a2a3
bsVolumeLabel: DB "MOS FLOPPY "
bsFileSystem: DB "SKFS "
Set: …Run Code Online (Sandbox Code Playgroud) 我在Rust中编写一个操作系统,需要直接调用我正在计算的虚拟地址(类型u32).我希望这相对简单:
let code = virtual_address as (extern "C" fn ());
(code)();
Run Code Online (Sandbox Code Playgroud)
然而,这抱怨演员阵容是非原始的.它建议我使用这个From特性,但我不知道这有多大帮助(尽管我对Rust来说相对较新,所以可能会遗漏一些东西).
error[E0605]: non-primitive cast: `u32` as `extern "C" fn()`
--> src/main.rs:3:16
|
3 | let code = virtual_address as (extern "C" fn ());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
Run Code Online (Sandbox Code Playgroud)
注意:我掌握了一切libcore,但没有移植std,所以不能依赖任何不是no_std的东西
该OSDev维基说:
在每个用户进程中映射内核是传统的并且通常很好
那为什么呢?这个过程不能单独映射到内存吗?映射内核有什么好处,这不会浪费空间吗?
此外,是否可以从用户空间访问内核空间,为什么我会这样做?
我正在使用无仿真启动操作系统,正如您在无仿真启动中所知道的那样,启动映像可以是任何(实模式)二进制可执行代码。
我在操作系统上使用两阶段引导加载程序,首先我加载第一阶段,第二阶段遇到问题,当引导加载程序尝试加载OS映像时,它需要CD / DVD驱动器的设备号来制作BIOS来电
问题是:我应该使用哪个设备号?
我在某些PC上尝试过0x81(第一个IDE从属)和 0x82(第二个IDE主控)在其他计算机上却无法使用
GGC的内联汇编可能难以正确实施且容易出错1。从更高层次的角度来看,内联汇编在内联汇编语句可能发出的指令之外必须考虑一些规则。
该Ç / C ++标准的考虑asm是定义的选项和实施。在GCC中记录了实现定义的行为,包括以下内容:
即使在使用volatile限定符时,也不要期望asm语句序列在编译后会保持完美连续。如果某些指令需要在输出中保持连续,请将它们放在单个多指令asm语句中。
基本的内联汇编或没有任何输出约束的扩展内联汇编都是隐式的volatile。该文档说,易失性不能保证连续的语句将按源代码中的顺序进行排序。该代码没有保证的顺序:
asm ("cli");
asm ("mov $'M', %%al; out %%al, $0xe9" ::: "eax");
asm ("mov $'D', %%al; out %%al, $0xe9" ::: "eax");
asm ("mov $'P', %%al; out %%al, $0xe9" ::: "eax");
asm ("sti");
Run Code Online (Sandbox Code Playgroud)
如果要使用CLI和STI关闭(然后重新打开)外部中断,并按顺序MDP向QEMU调试控制台(端口0xe9)输出一些字母,则不能保证。您可以将它们全部放在单个内联汇编语句中,也可以使用扩展的内联汇编模板将虚拟依赖项传递给每个保证顺序的语句。
为了使事情更易于管理,尤其是众所周知,OS开发人员会围绕此类代码创建方便的包装器。一些开发人员将其用作C预处理器宏。从理论上讲,这看起来很有用:
#define outb(port, value) \
asm ("out %0, %1" \
: \
: "a"((uint8_t)value), "Nd"((uint16_t)port))
#define cli() asm ("cli")
#define sti() asm …Run Code Online (Sandbox Code Playgroud)