【问题标题】:8086 OS-less programming; segmentation8086 无操作系统编程;分割
【发布时间】:2015-02-23 04:02:59
【问题描述】:

伙计们,这是一个很难回答的问题,因为它涉及很多硬件细节,所以我想把它放到 EE.SE 上,但主要关注的是编程,所以我决定放在这里。

我最近非常怀念(以及渴望回到 CPU 内在函数),所以我决定自制一个 8086 微型计算机板。假设我熟悉 x86 汇编(在一定程度上,正如您将看到的那样)并且我已经知道如何将我的代码放到计算机板上,让我们来解决实际问题。出于了解的目的,我正在使用 NASM,尽管我还没有完全掌握它的语法。

很明显,8086 工作在模式(实模式还没有被称为实模式)的前 1,024 个字节在开始时为 255 个 2+2 字节中断向量分开,所以实际的指令列表从 0x3FF 开始.

这里的问题是因为系统内存分段的怪癖,以及我可能正在编写一个 BIOS 的事实,从系统的角度来看。是否必须设置段寄存器,如果是,我如何确定要放什么?假设我使用 EEPROM 或某种形式的 Flash 来存储我的代码,所以我有类似的东西:

section .text
org 0x0000
    ; Interrupt vectors reserved
    ivt: times 1024 db 0
main:
    cli      ; Clear out interrupts because no addresses are defined yet
             ; Problems HERE.
             ; Set up interrupt addresses

我知道这可能非常糟糕,而且很可能是明显错误的语法,但它说明了我想要表达的观点。我是否必须通过mov CS, blahblahblah 之类的方式手动设置分段寄存器,如果是这样,我如何确定代码主体中不同段/部分出现的地址?

这个问题的标题提到了这样一个事实:虽然我已经做了很多谷歌搜索,但我一生都找不到对 8086 的无操作系统编程的参考。所有来源我可以假设我正在为一个已经设置并计算出中断向量和段等的系统编写代码,而我正在尝试制作一个从头开始做所有事情的仿冒微控制器。

【问题讨论】:

    标签: assembly nasm x86-16


    【解决方案1】:

    8086 使用非常简单的形式分段,其中每个内存引用都基于四个段寄存器之一,CSDSSSES。这意味着无论指令中是否明确,每次内存访问都始终使用分段。为了解决内存引用,CPU 将相应段寄存器中的值乘以 16 并将其添加到 16 位偏移量,从而得到 20 位物理地址。这就是现代英特尔处理器中所谓的实模式分段。

    CS 寄存器确定代码段的基数。所有指令提取都在此段中完成,位于IP 寄存器提供的偏移量处。正如 Nathan Fellman 的回答表明CS:IP 在处理器初始化期间加载了FFFF:0000,给出了FFFF0h 的声明物理地址,所以你需要在这个地址有一个 EEPROM 或其他东西。正如您的问题所指出的,您可能还希望在中断向量表的物理地址空间的开头有一些表单内存。

    您在哪里找到其他任何东西都取决于您。您需要加载DS 寄存器,以便它指向要存储大部分数据的位置,因为大多数内存操作数默认使用此段。您可能还需要一个堆栈,因此您还需要加载具有合适值的SS(和SP)。如果需要,您可以将与 DS 相同的值加载到 SS 中。 ES 寄存器不需要加载任何特定值,因为只有少数指令隐式使用它(MOVSSCASCMPS)。您可能希望将它免费用作“额外”暂存段寄存器来访问除CSDSSS 引用的内存区域之外的内存区域。

    请注意,假设您拥有真正的 Intel 8086 或 80186 处理器。如果您实际上有一个只想在实模式下使用的 80286 或更高版本的处理器,那么起始地址将会不同。如果你有某种克隆 8086 处理器,你应该查阅它的数据表,看看它是否也有什么不同。

    【讨论】:

      【解决方案2】:

      在我看来,您是在询问将引导代码放在哪里。

      开机时,直接退出reset,CS(代码段)有这个值:

      • 选择器:0ffffh
      • 基地:0ffff0h

      IP(指令指针)的值是00000h

      添加CS.baseIP 得到0ffff0h 的起点。

      请注意,这并没有给您留下太多的工作空间 - 在您耗尽内存之前只有 16 个字节,但这足以让您在想要放置代码的任何地方进行远跳转。

      【讨论】:

      • 如果我有误解,请纠正我,但如果这是真的,那意味着处理器内存的顶部是 4GB,8086 无法通过物理或其他方式寻址。
      • @blasthash:你是对的。我是根据我对 80386 的了解来回答的。我更新了我的答案。
      • 在 80286 之前使用 CPU,CPU 始终处于“实模式”,这意味着“base”段始终为 10h*selector。这些 CPU 不知道“限制”,因此可以对地址 seg:0FFFFh 进行 16 位访问;但是,在这种情况下,8086、80186 和现代 CPU 的行为不同,因此您不应该这样做。对于 >= 100000h 的地址,第 20 位被切断(因此 FFFF:FFFF 是地址 00FFEFh,而不是 10FFEFh)。
      • 由于今天的节日欢呼,我花了一些时间,但我认为我最初的措辞并不像应有的那样清晰。简而言之,我正在研究如何 a) 以某种方式构造我的程序集以允许我找出段,以及 b) 如何以编程方式设置这些段,而无需编写将在修订时更改的固定地址。这是否说明了我遇到的问题更好?
      • 这是一个更直接的问题-因为您说在地址空间的最顶部分配了 16 个字节,即 8 个操作码的空间-是否可以将代码段重定向到那里,在远跳转之前,这样我就可以将我的代码直接放在中断向量地址之后?
      【解决方案3】:

      ...我已经做了很多谷歌搜索,我一生都找不到关于 8086 的无操作系统编程的参考...

      对于无操作系统、无 BIOS 的 8086 编程,您可以使用一些 BIOS 源代码作为有价值的信息来源。喜欢这个:

      http://bochs.sourceforge.net/cgi-bin/lxr/source/bios/rombios.c#L11661

      ...
      // 版权所有 (C) 2002 MandrakeSoft S.A.
      ...
      // 用于 Bochs/Plex86/QEMU 仿真环境的 ROM BIOS
      ...

      .org 0xfff0 ; Power-up Entry Point
        jmp 0xf000:post
        ...
      post:
        xor ax, ax
         ...
      normal_post:
      ; case 0: normal startup
      
        cli
        mov  ax, #0xfffe
        mov  sp, ax
        xor  ax, ax
        mov  ds, ax
        mov  ss, ax
        ...
      

      另见:

      • Combined Volume Set of Intel® 64 and IA-32 Architectures Software Developer’s Manuals

        • 9.1.4 执行的第一条指令

          硬件复位后获取并执行的第一条指令位于物理地址FFFFFFF0H。该地址比处理器最高物理地址低 16 个字节。包含软件初始化代码的EPROM必须位于这个地址...

        • 9.7 实地址模式操作的软件初始化

          在硬件复位(通过上电或RESET# 引脚的断言)之后,处理器被置于实地址模式并开始从物理地址FFFFFFF0H 执行软件初始化代码。软件初始化代码必须首先设置处理基本系统功能所需的数据结构,例如用于处理中断和异常的实模式IDT。如果处理器要保持在实地址模式...

          如果处理器要在保护模式下运行...

      【讨论】:

        猜你喜欢
        • 2011-10-31
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-02-09
        • 2010-10-17
        • 2011-03-22
        • 2010-09-18
        • 2017-12-25
        相关资源
        最近更新 更多