x86支持两种运行模式:
1.实模式
2.保护模式
x86根据两种不同的运行模式,有三种不同的内存管理方式:
1.实模式下,通过偏移地址加段寄存器值直接访问物理地址
2.保护模式下有两种内存管理方式:
段式管理:使用段寄存器作为索引,寻找GDT中相应的表项,获得该段的基址,逻辑地址作为偏移与基址相加,就得到物理地址。
地址分为两层:逻辑地址、物理地址
页式管理:首先通过GDT将逻辑地址转换成线性地址,在通过页目录表和页表将线性地址转换成物理地址。
地址分为三层:逻辑地址、线性地址、物理地址。此处的逻辑地址相当于段式管理的物理地址。
实模式 --> 保护模式
将CR0的位0置位,即将PE位设为1.有两种方法:
使用lmsw指令:
mov %cr0, �x
inc %ax
lmsw %ax
使用mov指令:
mov %cr0, �x
inc �x
mov �x, %cr0
此时为段式管理机制,线性地址等于物理地址
段式管理 --> 页式管理
将CR0的位31置位,即将PG置1.方法:
mov %cr0, �x
or �x, $0x80000000
mov �x, %cr0
理解逻辑地址,我们从elf文件格式入手,看看xen的连接器脚本文件:
elf文件格式:
文件头
程序表头
程序段
节表头
文件头其实是个结构,用readelf -h 查看信息如下:
ELF Header:
#include
#include
#include
#undef ENTRY
#undef ALIGN
OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64")
OUTPUT_ARCH(i386:x86-64)
ENTRY(start)
PHDRS
{
}
SECTIONS
{
*(.text)
*(.fixup)
*(.gnu.warning)
} :text = 0x9090
*(.data)
CONSTRUCTORS
} :text
. = ALIGN(STACK_SIZE);
*(.bss.stack_aligned)
. = ALIGN(PAGE_SIZE);
*(.bss.page_aligned)
*(.bss)
} :text
*(.exit.text)
*(.exit.data)
*(.exitcall.exit)
*(.eh_frame)
}
}
从head.S查看逻辑地址到线性地址的变换:
13 #define sym_phys(sym)
((sym) - __XEN_VIRT_START)
63 gdt_boot_descr:
64
.word
6*8-1
65
.long
sym_phys(trampoline_gdt)
66
67 __start:
68
cld
69
cli
70
71
72
lgdt
%cs:sym_phys(gdt_boot_descr)
#lgdt可以在保护模式下调用,此时cs值估计为0x0010
73
mov
$BOOT_DS,�x
#BOOT_DS
0x0018
74
mov
�x,%ds
75
mov
�x,%es
76
mov
�x,%ss
64位cpu使用四级页表寻址:PML4E,PDPE、PDE、PTE
xen中l2、l3、l4分别对应PDE、PDPE、PML4E