标签: osdev

操作系统通常如何管理内核内存和页面处理?

我正在研究内核设计,我有一些关于分页的问题.

到目前为止我的基本想法是:每个程序都有自己的(或者它认为)4G内存,减去我保留的程序可以调用的内核函数的某个部分.因此,操作系统需要找出一些方法来加载程序在操作期间需要使用的内存中的页面.

现在,假设我们拥有无限的内存和处理器时间,我可以加载/分配程序写入或读取的任何页面,因为它使用页面错误来查找不存在(或被换出)的页面,因此操作系统可以快速分配它们或交换它们.但在现实世界中,我需要优化这个过程,这样我们就不会有一个程序不断消耗它所触及的所有内存.

所以我想我的问题是,操作系统通常如何解决这个问题?我最初的想法是创建一个程序调用set/free页面的函数,然后它可以自己进行内存管理,但程序通常是这样做的,还是编译器认为它有自由的统治?此外,编译器如何处理需要分配相当大的内存段的情况?我是否需要提供一个试图按顺序为其提供X页的功能?

这显然不是一个特定于语言的问题,但我偏爱标准C并且对C++很好,所以我希望任何代码示例都在那个或汇编中.(程序集不应该是必需的,我完全打算使用尽可能多的C代码,并作为最后一步进行优化.)

另一件事应该更容易回答:一般如何处理程序需要调用的内核函数?只有拥有一组内存区域(我正在考虑虚拟空间的末尾),它包含程序可以调用的大多数基本功能/进程特定内存吗?我的想法就是让内核函数做一些非常花哨的东西并将页面交换出来(这样程序在自己的空间中看不到敏感的内核函数)当程序需要做任何重要的事情,但我不是真的在这一点上关注安全性.

所以我想我比一般的设计理念更担心.我想让内核与GCC完全兼容(不知何故),我需要确保它提供了普通程序所需的一切.

谢谢你的建议.

paging operating-system kernel memory-management osdev

6
推荐指数
2
解决办法
2710
查看次数

C没有stdio,有什么可能吗?

我一直对编程操作系统感兴趣.通过一些不同的网站进行研究,我遇到了一个有趣的概念(换句话说):如果你开始用#include编写你的引导加载程序,你已经犯了一个致命的错误.

我已经通过了K&R,整本书都包含在每节课中.在整个学习C中使用它,我不知道我学到了什么,使用stdio,什么没有.在没有stdio的情况下,你可以用C做什么?

c stdio standard-library osdev bootloader

6
推荐指数
1
解决办法
4129
查看次数

使用LLDT并为其配置GDT

我正在开发一个小型操作系统,它将为每个进程使用单独的本地描述符表.我知道我需要使用该lldt指令从我的GDT加载LDT段.我已经使用有效的GDT在保护模式下运行我的内核,但我无法弄清楚我的LDT的GDT条目应该是什么样子.我知道它的基地址应该指向我的LDT,但我不知道特权级别和其他属性应该是什么.这是代表我的GDT中的LDT条目的NASM代码:

localTable equ $-gdt            ; GDT entry #5 (selector 20h)
dw 0x1FF                        ; limit to 64 descriptors
dw 0x8000                       ; base address
db 0x0
db 0x89                         ; probably incorrect...
db 0x1f                         ; possibly incorrect...
db 0x0
Run Code Online (Sandbox Code Playgroud)

如果您不熟悉NASM语法,则此表条目的基址为0x8000,限制为511(总共512个字节,或64个条目).我在i486程序员的参考手册中已经阅读了关于GDT和LDT的部分,但我无法完全理解我的GDT条目应该是什么样子.

无论如何,我像这样加载LDT:

mov ax, 0x20
lldt ax
Run Code Online (Sandbox Code Playgroud)

此代码使处理器生成一般保护错误(我通过中断处理它).我想知道两件事:

1)我是否在GDT中正确描述了我的LDT?如果没有,需要改变什么?2)LLDT由于LDT本身存在无效选择器,指令是否会失败?我读了LLDT指令规范,在我看来它甚至没有读取LDT的内存,但我只是想确定LLDT没有失败,因为我的LDT数据中有一个拼写错误.

x86 assembly nasm osdev

6
推荐指数
1
解决办法
634
查看次数

识别常规保护错误(x86)上的错误地址

我正在尝试在x86上为一般保护错误(GP#13)编写ISR.我无法从INTEL文档中找出如何找出导致异常的错误地址.我知道对于页面错误异常(GP#14),cr2寄存器保存了错误地址.任何帮助表示赞赏.

x86 operating-system osdev interrupt-handling

6
推荐指数
1
解决办法
4073
查看次数

为什么要在进入保护模式之前在引导加载程序中测试端口0x64?

在我的MIT OS课程(686)中,我发现了一些我不理解的代码。我想了解指令inb $0x64, %al启动 / boot.S。我的理解是它正在从数据端口0x64读一个字节到AL,端口0x64是什么?正在测试哪个设备或机制?我对代码忙中的注释感到困惑吗?评论是什么意思,它指的是什么?

# Enable A20:
#   For fascinating historical reasons (related to the fact that
#   the earliest 8086-based PCs could only address 1MB of physical memory
#   and subsequent 80286-based PCs wanted to retain maximum compatibility),
#   physical address line 20 is tied to low when the machine boots.
#   Obviously this a bit of a drag for us, especially when trying to …
Run Code Online (Sandbox Code Playgroud)

x86 assembly real-mode osdev bootloader

6
推荐指数
1
解决办法
1815
查看次数

奇怪的链接器行为:重定位被截断以适应

我有一个带有两个绝对符号的内核的链接描述文件:_kernel_start_kernel_end.但是,我只收到链接器重定位错误_kernel_end:

In function `kernel::mem::mm::setup_memorymap':
/home/virtlink/kernel/src/mem/mm.rs:25:(.text._ZN3mem2mm15setup_memorymap):
  relocation truncated to fit: R_X86_64_PC32 against symbol `_kernel_end'
  defined in *ABS* section in ./kernel.bin
Run Code Online (Sandbox Code Playgroud)

这里有很多关于这个错误的问题,但我没有找到解决我特定问题的问题.

显然,这个:

_kernel_start = .;
Run Code Online (Sandbox Code Playgroud)

...被视为32位,而这:

. += KERNEL_BASE;
_kernel_end = . - KERNEL_BASE;
Run Code Online (Sandbox Code Playgroud)

...被视为64位.如果我将_kernel_end符号移动到. += KERNEL_BASE线上方,如下所示:

_kernel_end = .;
. += KERNEL_BASE;
Run Code Online (Sandbox Code Playgroud)

......然后再次运作.但我想_kernel_end在我的链接器脚本的末尾.

链接描述文件将引导代码放在内存开头,其余代码放在64位虚拟内存空间的上半部分.它看起来像这样:

OUTPUT_FORMAT(elf64-x86-64)

KERNEL_BASE = 0xFFFFFFFF80000000;

SECTIONS
{
    /* Boot code at 1 MiB */
    . = 1M;
    _kernel_start = .;
    .boot :
    {
        KEEP( *(.multiboot) …
Run Code Online (Sandbox Code Playgroud)

linker relocation osdev rust

6
推荐指数
0
解决办法
548
查看次数

我应该制作自己的操作系统内核ELF还是原始二进制文件?

我已经开始了我的OS开发之旅.人们通常会大声说使用原始二进制而不是ELF(或其他结构化格式)是自定义操作系统中应用程序的常见错误.我可以说,因为ELF提供了额外的好处(存储元信息的地方,如符号表,.debug和.line).但是,让我们考虑内核二进制本身一分钟.它应该是结构化的(如ELF),如果是,为什么?否则写一个ELF加载器并在stage1加载器之后立即挤压它似乎是浪费.

AFAIK Linux内核是一个ELF文件,但我不知道原因.

operating-system kernel elf osdev bootloader

6
推荐指数
1
解决办法
2230
查看次数

启用引导加载程序以加载USB的第二个扇区

我正在学习汇编语言.我写了一个简单的bootloader.测试后,它没有用.这是我的代码:

[bits 16]
[org 0x7c00]

jmp start

data:
wolf_wel_msg db 'Welcome to Bootloader!!!',0x0D,0x0A,0
wolf_kernel_load db 'Loading kernel....',0x0D,0x0A,0
wolf_error_msg db 'Kernel.bin not found!',0x0D,0x0A,0
wolf_error_msg1 db 'Press any key to restart..',0

start:
        mov si, wolf_wel_msg
    call wolf_print

    mov si, wolf_kernel_load
    call wolf_print

    pushf
    stc

    mov ah,00
    mov dl,00
    int 13h

    read_sector:
            mov ax, 0x0
        mov es, ax
        xor bx, bx
            mov ah, 02
        mov al, 01
        mov ch, 01
        mov cl, 02
        mov dh, 00
        mov dl, 00
        int 13h

    jc wolf_error …
Run Code Online (Sandbox Code Playgroud)

assembly osdev bootloader bochs x86-16

6
推荐指数
1
解决办法
1404
查看次数

在组装/编译/链接时构建静态IDT和GDT所需的解决方案

多年来,尤其是在x86操作系统开发中遇到的许多问题都激发了这个问题。最近,有关NASM的一个问题因修改而引起争议。在那种情况下,该人正在使用NASM并遇到汇编时间错误:

移位运算符只能应用于标量值

另一个相关问题是在编译时生成静态IDT时导致错误的GCC代码问题:

初始值设定项元素不是常量

在这两种情况下,此问题都与以下事实有关:IDT条目需要一个指向异常处理程序的地址,而GDT可能需要到另一个结构(如任务段结构(TSS))的基地址。通常这不是问题,因为链接过程可以通过重定位修复程序解析这些地址。对于IDT条目GDT条目,这些字段将基地址/功能地址拆分开。没有重定位类型可以告诉链接程序将位移位,然后按照它们在GDT / IDT条目中的布局方式放置到内存中。彼得·科德斯(Peter Cordes)在这个答案对此作了很好的解释。

我的问题是不是问这个问题是什么,但对于一个请求的功能,以及实用的解决方案的问题。尽管我对此进行了自我回答,但这只是许多可能的解决方案之一。我只要求提出的解决方案满足以下要求:

  • GDT和IDT的地址不应固定为特定的物理或线性地址。
  • 该解决方案至少应能够使用ELF对象和ELF可执行文件。如果它适用于其他格式,那就更好了!
  • 解决方案是否是构建最终可执行文件/二进制文件的过程的一部分都没有关系。如果解决方案在生成可执行文件/二进制文件后需要构建时间处理,那也是可以接受的。
  • GDT(或IDT)在加载到内存后需要显示为完全解析。解决方案必须不需要运行时修复程序。

无效的示例代码

我以传统的引导加载程序1的形式提供了一些示例代码,该示例试图在组装时创建静态IDT和GDT,但是在与组装时会出现以下错误nasm -f elf32 -o boot.o boot.asm

boot.asm:78: error: `&' operator may only be applied to scalar values
boot.asm:78: error: `&' operator may only be applied to scalar values
boot.asm:79: error: `&' operator may only be applied to scalar values
boot.asm:79: error: `&' operator …
Run Code Online (Sandbox Code Playgroud)

x86 assembly nasm ld osdev

6
推荐指数
1
解决办法
105
查看次数

Rustc/LLVM为aarch64生成错误代码,opt-level = 0

我有两个文件组装/编译/链接到minimalistic内核.

的start.s:

    .set CPACR_EL1_FPEN, 0b11 << 20

    .set BOOT_STACK_SIZE, 8 * 1024

    .global __boot_stack
    .global __start
    .global __halt

    .bss
    .align 16
__boot_stack:
    .fill BOOT_STACK_SIZE

    .text
__start:
    /* disable FP and SIMD traps */
    mov x0, #CPACR_EL1_FPEN
    msr cpacr_el1, x0

    /* set stack */
    adr x0, __boot_stack
    add sp, x0, #BOOT_STACK_SIZE

    /* call the Rust entry point */
    bl __boot

__halt:
    /* halt CPU */
    wfi
    b __halt
Run Code Online (Sandbox Code Playgroud)

boot.rs:

#[no_mangle]
pub extern fn __boot() {
    unsafe {
        let ptr = 0x9000000 …
Run Code Online (Sandbox Code Playgroud)

qemu osdev rust arm64

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