Int 15/AX=E820h 是用来获取系统中的内存映地址描述符的,操作系统常用来获取内存大小.
PS:内存(Memory)可以是我们平时所说的在主板上的内存条,我们称作Base Memory,也可以是毗边
Base Memory 的并作为普通内存扩展的内存.
首先来了解一下相关的数据结构:
Format of Phoenix BIOS system memory map address range descriptor
(BIOS系统内存映射地址描述符格式,通常在英文中被称作Entry,一个Entry描述一种系统内存信息):
Offset Size Description
00h QWORD base address #系统内存块基地址
08h QWORD length in bytes #系统内存大小
10h DWORD type of address range #内存类型,看下面的(Values for System Memory Map address type )
这个结构块的大小为20
格式:
AX = E820h
EAX = 0000E820h
EDX = 534D4150h ('SMAP')
EBX = continuation value or 00000000h to start at beginning of map
持续值 或者 等于00000000h,以便重map的开头开始scan
ECX = size of buffer for result, in bytes (should be >= 20 bytes)
ES:DI -> buffer for result
Return:
CF clear if successful
EAX = 534D4150h ('SMAP')
ES:DI buffer filled
EBX = next offset from which to copy or 00000000h if all done
ECX = 传送到缓冲区buf的Entry的大小,一般为20个字节,ECX=20
CF set on error
AH = error code (86h)
Reference:
http://www.ctyme.com/intr/rb-1741.htm
除了Base Memory外,他还返回芯片集定义的系统内存地址空洞,而这些空洞是没有被使用的,是
主板内存映射设备和BIOS所保留的.
Values for System Memory Map address type:
01h memory, available to OS
02h reserved, not available (e.g. system ROM, memory-mapped device)
03h ACPI Reclaim Memory (usable by OS after reading ACPI tables)
04h ACPI NVS Memory (OS is required to save this memory between NVS
sessions)
other not defined yet -- treat as Reserved
原理描述:
调用此功能可以从系统某一个地方(这里存放有一个List(列表),这个列表里存放的都是一个个的
Entry)通过设置EBX(20的倍数)的值,然后调用int 0x15就可以讲EBX所指向的Entry拷贝
到ES:DI所指向的内存区)
Linux2.4.10-setup.S中关于内存检测(E820h)注释及流程:
首先了解一下empty_zero_page 都存放些什么东西:
Offset Type Description
------ ---- -----------
0 32 bytes struct screen_info, SCREEN_INFO
ATTENTION, overlaps the following !!!
2 unsigned short EXT_MEM_K, extended memory size in Kb (from int 0x15)
0x20 unsigned short CL_MAGIC, commandline magic number (=0xA33F)
0x22 unsigned short CL_OFFSET, commandline offset
Address of commandline is calculated:
0x90000 + contents of CL_OFFSET
(only taken, when CL_MAGIC = 0xA33F)
0x40 20 bytes struct apm_bios_info, APM_BIOS_INFO
0x80 16 bytes hd0-disk-parameter from intvector 0x41
0x90 16 bytes hd1-disk-parameter from intvector 0x46
0xa0 16 bytes System description table truncated to 16 bytes.
( struct sys_desc_table_struct )
0xb0 - 0x1df Free. Add more parameters here if you really need them.
0x1e0 unsigned long ALT_MEM_K, alternative mem check, in Kb
0x1e8 char number of entries in E820MAP (below)
0x1f1 char size of setup.S, number of sectors
0x1f2 unsigned short MOUNT_ROOT_RDONLY (if !=0)
0x1f4 unsigned short size of compressed kernel-part in the
(b)zImage-file (in 16 byte units, rounded up)
0x1f6 unsigned short swap_dev (unused AFAIK)
0x1f8 unsigned short RAMDISK_FLAGS
0x1fa unsigned short VGA-Mode (old one)
0x1fc unsigned short ORIG_ROOT_DEV (high=Major, low=minor)
0x1ff char AUX_DEVICE_INFO
0x200 short jump to start of setup code aka "reserved" field.
0x202 4 bytes Signature for SETUP-header, ="HdrS"
0x206 unsigned short Version number of header format
Current version is 0x0201...
0x208 8 bytes (used by setup.S for communication with boot loaders,
look there)
0x210 char LOADER_TYPE, = 0, old one
else it is set by the loader:
0xTV: T=0 for LILO
1 for Loadlin
2 for bootsect-loader
3 for SYSLINUX
4 for ETHERBOOT
V = version
0x211 char loadflags:
bit0 = 1: kernel is loaded high (bzImage)
bit7 = 1: Heap and pointer (see below) set by boot
loader.
0x212 unsigned short (setup.S)
0x214 unsigned long KERNEL_START, where the loader started the kernel
0x218 unsigned long INITRD_START, address of loaded ramdisk image
0x21c unsigned long INITRD_SIZE, size in bytes of ramdisk image
0x220 4 bytes (setup.S)
0x224 unsigned short setup.S heap end pointer
0x2d0 - 0x600 E820MAP
0x800 string, 2K max COMMAND_LINE, the kernel commandline as
copied using CL_OFFSET.
Note: this will be copied once more by setup.c
into a local buffer which is only 256 bytes long.
( #define COMMAND_LINE_SIZE 256 )
loader_ok:
# Get memory size (extended mem, kB)
xorl %eax, %eax
movl %eax, (0x1e0)
#ifndef STANDARD_MEMORY_BIOS_CALL
movb %al, (E820NR) # E820NR=0x1e8 number of entries in E820MAP
# Try three different memory detection schemes. First, try
# e820h, which lets us assemble a memory map, then try e801h,
# which returns a 32-bit memory size, and finally 88h, which
# returns 0-64m
# method E820H:
# the memory map from hell. e820h returns memory classified into
# a whole bunch of different types, and allows memory holes and
# everything. We scan through this memory map and build a list
# of the first 32 memory areas, which we return at [E820MAP].
# This is documented at http://www.teleport.com/~acpi/acpihtml/topic245.htm
#define SMAP 0x534d4150
meme820:
xorl %ebx, %ebx # continuation counter
movw $E820MAP, %di # point into the whitelist
# so we can have the bios
# directly write into it.
jmpe820:
movl $0x0000e820, %eax # e820, upper word zeroed
movl $SMAP, %edx # ascii 'SMAP'
movl $20, %ecx # size of the e820rec
pushw %ds # data record.
popw %es
int $0x15 # make the call
jc bail820 # fall to e801 if it fails
cmpl $SMAP, %eax # check the return is `SMAP'
jne bail820 # fall to e801 if it fails
# cmpl $1, 16(%di) # is this usable memory?
# jne again820
# If this is usable memory, we save it by simply advancing %di by
# sizeof(e820rec).
#
good820:
movb (E820NR), %al # up to 32 entries
cmpb $E820MAX, %al
jnl bail820
incb (E820NR)
movw %di, %ax
addw $20, %ax
movw %ax, %di
again820:
cmpl $0, %ebx # check to see if
jne jmpe820 # %ebx is set to EOF
bail820:
通过上面的汇编指令,就把可用内存的Entry描述块顺序放到了empty_zero_page的
0x2d0 - 0x600 E820MAP 处.那么计算内存大小也就不困难了.
Int 15/AX=E801h
reference:http://www.ctyme.com/intr/rb-1739.htm
AX = E801h
Return:
CF clear if successful
AX = extended memory between 1M and 16M, in K (max 3C00h = 15MB)
BX = extended memory above 16M, in 64K blocks
CX = configured memory 1M to 16M, in K
DX = configured memory above 16M, in 64K blocks
CF set on error
Notes: Supported by the A03 level (6/14/94) and later XPS P90 BIOSes, as well as
the Compaq Contura, 3/8/93 DESKPRO/i, and 7/26/93 LTE Lite 386 ROM BIOS.
Supported by AMI BIOSes dated 8/23/94 or later. On some systems, the BIOS returns
AX=BX=0000h; in this case, use CX and DX instead of AX and BX. This interface is
used by Windows NT 3.1, OS/2 v2.11/2.20, and is used as a fall-back by newer
versions if AX=E820h is not supported. This function is not used by MS-DOS 6.0
HIMEM.SYS when an EISA machine (for example with parameter /EISA)
(see also MEM F000h:FFD9h), or no Compaq machine was detected, or parameter
/NOABOVE16 was given.
meme801:
stc # fix to work around buggy
xorw %cx,%cx # BIOSes which dont clear/set
xorw %dx,%dx # carry on pass/error of
# e801h memory size call
# or merely pass cx,dx though
# without changing them.
movw $0xe801, %ax
int $0x15
jc mem88
cmpw $0x0, %cx # Kludge to handle BIOSes
jne e801usecxdx # which report their extended
cmpw $0x0, %dx # memory in AX/BX rather than
jne e801usecxdx # CX/DX. The spec I have read
movw %ax, %cx # seems to indicate AX/BX
movw %bx, %dx # are more reasonable anyway...
e801usecxdx:
andl $0xffff, %edx # clear sign extend
shll $6, %edx # and go from 64k to 1k chunks
movl %edx, (0x1e0) # store extended memory size
andl $0xffff, %ecx # clear sign extend
addl %ecx, (0x1e0) # and add lower memory into
# total size.