x86内存管理

来源:互联网 发布:php代码去除图片水印 编辑:程序博客网 时间:2024/05/22 10:30
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:
  Magic:   7f 45 4c 46 02 0101 00 00 00 00 00 00 00 00 00 
  Class:                        ELF64
  Data:                         2's complement, little endian
  Version:                       1(current)
  OS/ABI:                       UNIX - System V
  ABI Version:                   0
  Type:                         EXEC (Executable file)
  Machine:                       AdvancedMicro Devices X86-64
  Version:                       0x1
  Entry point address:            0x400460
  Start of program headers:        64 (bytes into file)
  Start of section headers:        4432 (bytes into file)
  Flags:                        0x0
  Size of this header:             64(bytes)
  Size of program headers:         56 (bytes)
  Number of program headers:       9
  Size of section headers:         64 (bytes)
  Number of section headers:       30
  Section header string table index: 27


#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
{
  text PT_LOAD ;
}
SECTIONS
{
  . = __XEN_VIRT_START + 0x100000;

  _start = .;
  _stext = .;
  .text : {
*(.text)
*(.fixup)
*(.gnu.warning)
} :text = 0x9090

  _etext = .;

  .rodata : { *(.rodata) *(.rodata.*) }:text

  . = ALIGN(32);
  __start___ex_table = .;
  __ex_table : { *(__ex_table) } :text
  __stop___ex_table = .;

  . = ALIGN(32);             
  __start___pre_ex_table = .;
  __pre_ex_table : { *(__pre_ex_table) }:text
  __stop___pre_ex_table = .;

  .data : {
*(.data)
CONSTRUCTORS
} :text

  . = ALIGN(128);
  .data.read_mostly : { *(.data.read_mostly)} :text

  . = ALIGN(4096);
  __init_begin = .;
  _sinittext = .;
  .init.text : { *(.init.text) } :text
  _einittext = .;
  .init.data : { *(.init.data) } :text
  . = ALIGN(32);
  __setup_start = .;
  .init.setup : { *(.init.setup) }:text
  __setup_end = .;
  __initcall_start = .;
  .initcall.init : { *(.initcall1.init) }:text
  __initcall_end = .;
  __xsm_initcall_start =.; 
  .xsm_initcall.init : {*(.xsm_initcall.init) } :text
  __xsm_initcall_end = .;
  . = ALIGN(PAGE_SIZE);
  __init_end = .;

  __per_cpu_shift = PERCPU_SHIFT;
  __per_cpu_start = .;
  .data.percpu : { *(.data.percpu) }:text
  __per_cpu_data_end = .;
  . = __per_cpu_start + (NR_CPUS <<PERCPU_SHIFT);
  . = ALIGN(PAGE_SIZE);
  __per_cpu_end = .;

  __bss_start = .;
  .bss : {
. = ALIGN(STACK_SIZE);
*(.bss.stack_aligned)
. = ALIGN(PAGE_SIZE);
*(.bss.page_aligned)
*(.bss)
} :text
  _end = . ;

 
  /DISCARD/ : {
*(.exit.text)
*(.exit.data)
*(.exitcall.exit)
*(.eh_frame)
}

 
  .stab 0 : { *(.stab) }
  .stabstr 0 : { *(.stabstr) }
  .stab.excl 0 : { *(.stab.excl) }
  .stab.exclstr 0 : { *(.stab.exclstr)}
  .stab.index 0 : { *(.stab.index) }
  .stab.indexstr 0 : { *(.stab.indexstr)}
  .comment 0 : { *(.comment) }
}


从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
原创粉丝点击