Assembly 自定义操作系统中的一般保护

Assembly 自定义操作系统中的一般保护,assembly,operating-system,x86,x86-64,Assembly,Operating System,X86,X86 64,我计划为英特尔64位体系结构编写自己的操作系统,我需要实现通用保护机制。我将不使用虚拟内存或分页,而是使用物理寻址。我还不知道如何具体实施,但我有一个大致的想法,它是这样的: __asm('set DS register to the address and length of segment 1'); for (i=0;i<size_of_segment1;i++) { segment1_data[i]= some_processing(); }

我计划为英特尔64位体系结构编写自己的操作系统,我需要实现通用保护机制。我将不使用虚拟内存或分页,而是使用物理寻址。我还不知道如何具体实施,但我有一个大致的想法,它是这样的:

    __asm('set DS register to the address and length of segment 1');
    for (i=0;i<size_of_segment1;i++) {
        segment1_data[i]= some_processing();
    }
    __asm('set DS register to the address and length of segment 2');
    for (i=0;i<size_of_segment2;i++) {
        segment2_data[i]= some_processing();
    }
  • 启动时,内核将被加载,让我们假设它将启动第一个名为“filemanager”的userland进程,该进程将根据从另一个进程接收到的信号将一些数据保存到磁盘
  • filemanager将有一个代码段、一个堆栈段和一个数据段
  • 在正常操作期间,内核将启动另一个进程,该进程将从可用的物理内存堆中获取内存,管理内核负责的内存
  • 让我们假设,“filemanager”进程需要更多的ram,因为它的数据段已满。它向内核发送一个系统调用以请求另一个数据段。内核将请求的内存块提供给它,该内存块物理上位于不同的位置,并且与第一个段不连续
  • 现在的问题是,应用程序('filemanager')将如何处理2个段?因为据我所知,Intel实施的通用保护机制只能检查存储在“DS”中的当前段的限制。但是对于filemanager,我们现在有两个段。我是否必须在应用程序内部手动从一个段切换到另一个段?编写这样的应用程序会很痛苦 因为你必须写这样的东西:

        __asm('set DS register to the address and length of segment 1');
        for (i=0;i<size_of_segment1;i++) {
            segment1_data[i]= some_processing();
        }
        __asm('set DS register to the address and length of segment 2');
        for (i=0;i<size_of_segment2;i++) {
            segment2_data[i]= some_processing();
        }
    
    \uu asm('set DS register to address and length of segment 1');
    
    对于(i=0;i从另一个角度来看,对于想要访问内存的C程序员来说,这会是什么样子?Kernel.AllocateMemory返回什么?它不能返回64位值,因为它不足以表示段和偏移量(实际上,x64机器现在访问的内存不足2^64字节,因此可以在一些未使用的位中存储段号,但我认为您不想这样做)

    听起来你正在寻找的是一个“远指针”(来自过去的爆炸-参见示例)


    如果您不想手动更改段,那么我看不出您如何逃避支持远指针的编译器修改。请注意,如果您只有两个段,那么您可以使用DS和ES来寻址数据,但即使这样,也需要不同的汇编代码,具体取决于您要使用的段。必须有人进行修改生成此代码的决定权,将由您或编译器决定。

    如果您处于64位模式,则根本没有段寄存器:CS、DS…的内容将被忽略。地址是“平面”中的64位值地址空间。段寄存器用于16位和32位模式,尽管大多数32位操作系统将所有段设置为从地址0开始并跨越4 GB,因此它们可能会永远忘记它们。如果使用段寄存器(这样应用程序代码可能会使用多个“段”),那么在C级别,C编译器必须知道它们,并且“指针”将包括段和偏移量值。设置段寄存器很昂贵,因此如果可以不使用段,性能会更好。这就解释了为什么像Linux或Windows这样的32位操作系统不使用段,相应地,CPU供应商在64位模式下调整并省略了段支持

    那么,真正的问题是:你想在应用程序之间提供内存保护吗?内存保护是指阻止一个进程读取或写入它不应该读取/写入的内存,即另一个进程或内核使用的内存。如果应用程序程序员从不编写带有bug的代码,你可以不使用内存保护的内存(嗯……这有多合理?)“:地址空间被拆分为固定大小的页(x86上每个页4 kB),操作系统在RAM中安装表,告诉MMU每个页的物理位置。分页、基于磁盘的虚拟内存…使用MMU。但也可以使用MMU“just”进行内存保护(您可以对其进行设置,使每个页面的虚拟地址与其物理地址相等,或者如果当前不允许访问该页面,则标记为“缺席”)


    在某些非常特殊的情况下,根本不使用MMU可以提高性能(我知道有人这样做是为了筛选,这是一项面向加密的大型计算工作的一部分:筛选是在1GB阵列中几乎100%的随机内存访问;MMU意味着三次缓存未命中,而不是每次访问一次,因此不使用MMU会使整个过程加快三倍——但这确实是一个优势另一方面,MMU使应用程序开发人员的生活更加轻松,特别是因为它允许每个应用程序都有自己的规范化地址空间(例如,您可以提前编译和链接C代码)

    实现保护内存的方法是通过虚拟内存。为什么不想使用这个?谢谢!我不熟悉“筛分”,是不是一些编程技术?我已经搜索过了,发现“筛子”是由代码播放发布的C++编译器。如果你有更多的信息,将非常感谢。再次感谢!“筛选”是一种在给定范围内查找平滑整数的方法的通用术语——平滑整数是指其素数因子均为“小”的整数。这是分解大整数和求解离散对数算法中的一大步。要点是:这是一种非常特殊的用法,具有不同寻常的内存访问模式,与MMU的交互非常糟糕。对于大多数任务,MMU“便宜”,而且