标签: osdev

更高的半内核初始化

在初始化我的内核时,我需要做一些事情:1)需要启用分页,2)物理内存管理器需要从grub解析内存映射,以及3)各种启动代码需要访问需要的数据留在那里以后(例如GDT,IDT,内存管理结构).

这些步骤之间的依赖性让我发疯.对于较高的一半,内核在其虚拟地址处链接,因此我提出的选项是1)在汇编中启用分页,这将涉及遵循所有多引导指针(在汇编中),因此它们仍然可以访问到物理内存管理器,然后将它们全部取消映射,2)将启动代码链接到其物理地址,然后执行一些指针操作以访问其物理地址处的内核结构,或者3)不要使用更高的一半核心.

还涉及引导物理内存管理器而不知道编译时的物理内存量.我很确定在分配第一个结构时我必须小心避免所有的多引导结构,或者先使用它们然后不要担心覆盖它们(虽然我仍然需要处理模块和这种方法可能涉及在设置物理内存管理器时将多引导表复制到我需要的已知位置.

这些问题是我到目前为止避免使用更高半内核的原因.有没有人有一个很好的系统来解决这些依赖关系?也许这个GDT技巧的一些变化是访问其链接/虚拟地址的内核和物理地址的多重引导表,或使用某种预定义的页表来避免上述问题,可能涉及PSE?

bootstrapping kernel osdev virtual-memory

5
推荐指数
1
解决办法
2000
查看次数

多核/ NUMA上的CPUID

我正在为我的爱好操作系统研究CPU检测和一般环境检测代码.有没有需要多次调用CPUID的情况?也就是说,如果系统有多个内核,操作系统是否需要在每个内核上调用CPUID?NUMA也是如此.

无论是AMD英特尔 CPUID手册都对这个不清楚.在osdev wiki上有一篇文章提到调用CPUID称为检测CPU拓扑,但是我的阅读并不清楚CPUID需要调用的时间和次数.

x86 osdev low-level cpuid

5
推荐指数
1
解决办法
1096
查看次数

内核模式和内存保护

在操作系统用户模式应用程序的虚拟地址空间是私有的,一个应用程序不能更改属于另一个应用程序的数据.每个应用程序都是独立运行的,如果应用程序崩溃,则崩溃仅限于该应用程序.其他应用程序和操作系统不受崩溃的影响

为什么在内核模式OS不保护内存和BOSD发生?

operating-system kernel osdev

5
推荐指数
1
解决办法
2577
查看次数

简单C引导程序/内核的问题

最近我对编写自己真正基本的操作系统感兴趣.我写了(嗯,复制)一些基本的程序集,它建立了一个堆栈并做了一些基本的事情,这似乎工作正常,但是试图将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)

c x86 kernel nasm osdev

5
推荐指数
1
解决办法
1475
查看次数

组装-读取虚拟磁盘的下一个扇区

作为世界上任何一个程序员,至少有一次他/她一生都在尝试创建自己的“革命性”,新的,唯一的操作系统。: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)

assembly osdev sector hard-drive x86-16

5
推荐指数
1
解决办法
2513
查看次数

无法跳转或调用在0x8000加载的内核

我正在尝试开发一个操作系统.设计是这样的:我有一个加载在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)

x86 assembly nasm osdev

5
推荐指数
1
解决办法
507
查看次数

从Rust调用一个原始地址

我在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的东西

function-pointers osdev rust

5
推荐指数
1
解决办法
1475
查看次数

是否可以在不映射内核的情况下将进程映射到内存中?

OSDev维基说:

在每个用户进程中映射内核是传统的并且通常很好

那为什么呢?这个过程不能单独映射到内存吗?映射内核有什么好处,这不会浪费空间吗?

此外,是否可以从用户空间访问内核空间,为什么我会这样做?

x86 assembly memory-management osdev linux-kernel

5
推荐指数
1
解决办法
707
查看次数

没有仿真启动操作系统

我正在使用无仿真启动操作系统,正如您在无仿真启动中所知道的那样,启动映像可以是任何(实模式)二进制可执行代码。

我在操作系统上使用两阶段引导加载程序,首先我加载第一阶段,第二阶段遇到问题,当引导加载程序尝试加载OS映像时,它需要CD / DVD驱动器的设备号来制作BIOS来电

问题是:我应该使用哪个设备号?

我在某些PC上尝试过0x81(第一个IDE从属)和 0x82(第二个IDE主控)在其他计算机上却无法使用

x86 operating-system dvd osdev bootloader

5
推荐指数
1
解决办法
193
查看次数

了解预处理器宏中的内联汇编与函数中的内联汇编

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)

如果要使用CLISTI关闭(然后重新打开)外部中断,并按顺序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)

c x86 gcc inline-assembly osdev

5
推荐指数
1
解决办法
121
查看次数