2

我正在用汇编(NASM)编写一个简单的程序。当引导扇区加载时,它必须以兆字节显示计算机中安装的所有内存 (RAM)。加载引导扇区时将没有操作系统(DOS、Windows、Linux),那么我将如何找出总 RAM 大小。我的计算机中有 2 GB RAM。我在互联网上搜索了很多,但找不到解决方案。

是否存在显示内存大小为 2 GB 的 BIOS 中断?在旧计算机中使用了一个中断来显示内存,但它并未显示所有 2 GB。我查了一下,在 Ralph Brown List 中没有解决方案。可能有人对 BIOS 了解更多。如果 BIOS 不提供此功能,那么我可以使用 C/C++ 找出总 RAM 大小吗?并从程序集中调用 C/C++ 代码?将使用 C/C++ 的什么函数来查找总 RAM 大小?

请记住,我的汇编代码会进行冷启动,并且没有操作系统可以为我的代码提供任何便利。

编辑:

我阅读了网站http://wiki.osdev.org/Detecting_Memory_%28x86%29。并决定检查 int 15 是否有效。所以我从这个网站得到了代码并对其进行了编辑以测试 int 15 EAX = E820 是否有效。但它无法正常工作,并且.failed1 中的输出为“F”。'F' 是我为检查“不支持的功能”而制作的测试用例。测试用例是“F”、“G”和“H”。这是代码。

; use the INT 0x15, eax= 0xE820 BIOS function to get a memory map
; inputs: es:di -> destination buffer for 24 byte entries
; outputs: bp = entry count, trashes all registers except esi
do_e820:

   xor ebx, ebx     ; ebx must be 0 to start
   xor bp, bp       ; keep an entry count in bp
   mov edx, 0x0534D4150 ; Place "SMAP" into edx
   mov eax, 0xe820
   mov [es:di + 20], dword 1    ; force a valid ACPI 3.X entry
   mov ecx, 24      ; ask for 24 bytes
   int 0x15
   jc short .failed1    ; carry set on first call means "unsupported function"
   mov edx, 0x0534D4150 ; Some BIOSes apparently trash this register?
   cmp eax, edx     ; on success, eax must have been reset to "SMAP"
   jne short .failed2
   test ebx, ebx        ; ebx = 0 implies list is only 1 entry long (worthless)
   je short .failed3
   jmp short .jmpin

.e820lp:
   mov eax, 0xe820      ; eax, ecx get trashed on every int 0x15 call
   mov [es:di + 20], dword 1    ; force a valid ACPI 3.X entry
   mov ecx, 24      ; ask for 24 bytes again
   int 0x15
   jc short .e820f      ; carry set means "end of list already reached"
   mov edx, 0x0534D4150 ; repair potentially trashed register

.jmpin:
   jcxz .skipent        ; skip any 0 length entries
   cmp cl, 20       ; got a 24 byte ACPI 3.X response?
   jbe short .notext
   test byte [es:di + 20], 1    ; if so: is the "ignore this data" bit clear?
   je short .skipent

.notext:
   mov ecx, [es:di + 8] ; get lower dword of memory region length
   or ecx, [es:di + 12] ; "or" it with upper dword to test for zero
   jz .skipent      ; if length qword is 0, skip entry
   inc bp           ; got a good entry: ++count, move to next storage spot
   add di, 24

.skipent:
   test ebx, ebx        ; if ebx resets to 0, list is complete
   jne short .e820lp

.e820f:
   mov [mmap_ent], bp   ; store the entry count
   clc          ; there is "jc" on end of list to this point, so the carry must be cleared

   mov ah, 0x0E       ; Teletype command
   mov bh, 0x00       ; Page number
   mov bl, 0x07       ; Attributes (7 == white foreground, black background)
   mov al, mmap_ent   ; Character to print
   int 0x10

   ret

.failed1:
   push eax
   push ebx
   mov ah, 0x0E       ; Teletype command
   mov bh, 0x00       ; Page number
   mov bl, 0x07       ; Attributes (7 == white foreground, black background)
   mov al, 70 ; Character 'F' to print
   int 0x10
   pop ebx
   pop eax

   stc          ; "function unsupported" error exit
   ret

.failed2:
   push eax
   push ebx
   mov ah, 0x0E       ; Teletype command
   mov bh, 0x00       ; Page number
   mov bl, 0x07       ; Attributes (7 == white foreground, black background)
   mov al, 71 ; Character 'G' to print
   int 0x10
   pop ebx
   pop eax

   stc          ; "function unsupported" error exit
   ret

.failed3:
   push eax
   push ebx
   mov ah, 0x0E       ; Teletype command
   mov bh, 0x00       ; Page number
   mov bl, 0x07       ; Attributes (7 == white foreground, black background)
   mov al, 72 ; Character 'H' to print
   int 0x10
   pop ebx
   pop eax

   stc          ; "function unsupported" error exit
   ret


   mmap_ent db 0
   failmsg db 0
   failmem db 'Failed', 0
   ;times 512-($-$$) db 0 
   ;dw 0xAA55

编辑:

我使用了 nasm memext.asm -o memext.com -l memext.lst 。使用 MagicISO 制作可启动映像文件 memext.iso 并使用 Windows 磁盘刻录机将其刻录到 DVD/RW。加载 Oracle VM 并创建一个具有 256 Mb RAM、CD/DVD、2GB 硬盘的新虚拟机。用 DVD 引导进行冷启动测试,不打印任何内容。

另外,我打开命令控制台并输入 memext,它给出了“F”作为输出。

4

2 回答 2

4

您需要在 PC(或其他支持 ACPI 的机器)上读取 ACPI 表。

请注意,这不会给您一个数字的总大小,而是给您每个内存区域的内存大小 - 在一台简单的机器上,可能只有两个或三个区域(在0xA0000-0xFFFFF 以及 BIOS 决定放置“PCI-hole”的位置)。

我怀疑将 ACPI 读取器放入单个扇区并不是一件容易的事,考虑到一些引导扇区只有大约 400 字节的可用空间(尽管如果你完全跳过分区表,我想你几乎可以使用所有512 个字节)。

至于“如何调用 C/C++”,你将无法将任何有意义的 C 或 C++ 程序放在少于几个领域。您将需要查看 OS 引导加载程序,并了解它们如何实现编译器的设置(在许多情况下,您还需要特殊工具来生成位于适合加载到内存的特定位置的代码并直接执行)。这个页面可能对此有所帮助(我还没有通读它,它甚至可以告诉你有多少内存): http: //www.codeproject.com/Articles/36907/How-to-develop-your -自己的引导加载程序

于 2013-06-27T09:33:01.383 回答
1

编辑:我的错误,维基是正确的,只是把它留在这里,因为......

看起来维基中有一个错字 - 行:

mov edx,0x0534D4150

应该看起来像:

mov edx,0x050414D53

请注意字节顺序相反(因为 x86 是小端序)。

于 2013-06-28T13:53:46.427 回答