Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2150562
  • 博文数量: 438
  • 博客积分: 3871
  • 博客等级: 中校
  • 技术积分: 6075
  • 用 户 组: 普通用户
  • 注册时间: 2011-09-10 00:11
个人简介

邮箱: wangcong02345@163.com

文章分类

全部博文(438)

文章存档

2017年(15)

2016年(119)

2015年(91)

2014年(62)

2013年(56)

2012年(79)

2011年(16)

分类: LINUX

2016-11-01 00:20:21

1. 内核的生成过程
1.1 vmlinux的生成过程
  1. ld -m elf_i386 -T./arch/i386/vmlinux.lds -e stext arch/i386/kernel/head.o arch/i386/kernel/init_task.o init/main.o init/version.o \
  2.         --start-group \
  3.         arch/i386/kernel/kernel.o arch/i386/mm/mm.o kernel/kernel.o mm/mm.o fs/fs.o ipc/ipc.o \
  4.          drivers/char/char.o drivers/block/block.o drivers/misc/misc.o drivers/net/net.o drivers/media/media.o drivers/char/agp/agp.o drivers/char/drm/drm.o drivers/ide/idedriver.o drivers/scsi/scsidrv.o drivers/cdrom/driver.o drivers/sound/sounddrivers.o drivers/pci/driver.o drivers/pcmcia/pcmcia.o drivers/net/pcmcia/pcmcia_net.o drivers/video/video.o drivers/usb/usbdrv.o \
  5.         net/network.o \
  6.         /work/os/linux-2.4.12/arch/i386/lib/lib.a /work/os/linux-2.4.12/lib/lib.a /work/os/linux-2.4.12/arch/i386/lib/lib.a \
  7.         --end-group \
  8.         -o vmlinux
1.2 链接脚本./arch/i386/vmlinux.lds
  1. /* ld script to make i386 Linux kernel
  2.  * Written by Martin Mares <mj@atrey.karlin.mff.cuni.cz>;
  3.  */
  4. OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
  5. OUTPUT_ARCH(i386)
  6. ENTRY(_start)
  7. SECTIONS
  8. {
  9.   . = 0xC0000000 + 0x100000;
  10.   _text = .;            /* Text and read-only data */
  11.   .text : {
  12.     *(.text)
  13.     *(.fixup)
  14.     *(.gnu.warning)
  15.     } = 0x9090
  16.   .text.lock : { *(.text.lock) }    /* out-of-line lock text */

  17.   _etext = .;            /* End of text section */

  18.   .rodata : { *(.rodata) *(.rodata.*) }
  19.   .kstrtab : { *(.kstrtab) }

  20.   . = ALIGN(16);        /* Exception table */
  21.   __start___ex_table = .;
  22.   __ex_table : { *(__ex_table) }
  23.   __stop___ex_table = .;

  24.   __start___ksymtab = .;    /* Kernel symbol table */
  25.   __ksymtab : { *(__ksymtab) }
  26.   __stop___ksymtab = .;

  27.   .data : {            /* Data */
  28.     *(.data)
  29.     CONSTRUCTORS
  30.     }

  31.   _edata = .;            /* End of data section */

  32.   . = ALIGN(8192);        /* init_task */
  33.   .data.init_task : { *(.data.init_task) }

  34.   . = ALIGN(4096);        /* Init code and data */
  35.   __init_begin = .;
  36.   .text.init : { *(.text.init) }
  37.   .data.init : { *(.data.init) }
  38.   . = ALIGN(16);
  39.   __setup_start = .;
  40.   .setup.init : { *(.setup.init) }
  41.   __setup_end = .;
  42.   __initcall_start = .;
  43.   .initcall.init : { *(.initcall.init) }
  44.   __initcall_end = .;
  45.   . = ALIGN(4096);
  46.   __init_end = .;

  47.   . = ALIGN(4096);
  48.   .data.page_aligned : { *(.data.idt) }

  49.   . = ALIGN(32);
  50.   .data.cacheline_aligned : { *(.data.cacheline_aligned) }

  51.   __bss_start = .;        /* BSS */
  52.   .bss : {
  53.     *(.bss)
  54.     }
  55.   _end = . ;

  56.   /* Sections to be discarded */
  57.   /DISCARD/ : {
  58.     *(.text.exit)
  59.     *(.data.exit)
  60.     *(.exitcall.exit)
  61.     }

  62.   /* Stabs debugging sections. */
  63.   .stab 0 : { *(.stab) }
  64.   .stabstr 0 : { *(.stabstr) }
  65.   .stab.excl 0 : { *(.stab.excl) }
  66.   .stab.exclstr 0 : { *(.stab.exclstr) }
  67.   .stab.index 0 : { *(.stab.index) }
  68.   .stab.indexstr 0 : { *(.stab.indexstr) }
  69.   .comment 0 : { *(.comment) }
  70. }







linux-2.4.12/arch/i386/kernel/head.S
  1. /*
  2.  * linux/arch/i386/head.S -- the 32-bit startup code.
  3.  *
  4.  * Copyright (C) 1991, 1992 Linus Torvalds
  5.  *
  6.  * Enhanced CPU detection and feature setting code by Mike Jagdis
  7.  * and Martin Mares, November 1997.
  8.  */

  9. .text
  10. #include <linux/config.h>
  11. #include <linux/threads.h>
  12. #include <linux/linkage.h>
  13. #include <asm/segment.h>
  14. #include <asm/page.h>
  15. #include <asm/pgtable.h>
  16. #include <asm/desc.h>

  17. #define OLD_CL_MAGIC_ADDR    0x90020
  18. #define OLD_CL_MAGIC        0xA33F
  19. #define OLD_CL_BASE_ADDR    0x90000
  20. #define OLD_CL_OFFSET        0x90022
  21. #define NEW_CL_POINTER        0x228    /* Relative to real mode data */

  22. /*
  23.  * References to members of the boot_cpu_data structure.
  24.  */

  25. #define CPU_PARAMS    SYMBOL_NAME(boot_cpu_data)
  26. #define X86        CPU_PARAMS+0
  27. #define X86_VENDOR    CPU_PARAMS+1
  28. #define X86_MODEL    CPU_PARAMS+2
  29. #define X86_MASK    CPU_PARAMS+3
  30. #define X86_HARD_MATH    CPU_PARAMS+6
  31. #define X86_CPUID    CPU_PARAMS+8
  32. #define X86_CAPABILITY    CPU_PARAMS+12
  33. #define X86_VENDOR_ID    CPU_PARAMS+28

  34. startup_32:                       -->看head.S时一定要记住,head.S被链接在了0xc0100000
  35.     cld                           -->0010:00100000 (unk. ctxt): cld  ; fc
  36. //ds=es=fs=gs=内核代码段
  37.     movl $(__KERNEL_DS),%eax
  38.     movl %eax,%ds
  39.     movl %eax,%es
  40.     movl %eax,%fs
  41.     movl %eax,%gs
  42. #ifdef CONFIG_SMP
  43.     orw %bx,%bx      -->完全没看懂这个是啥意思
  44.     jz 1f            -->这儿跳过 

  45. 1:
  46. #endif
  47. //在include/asm-i386/page.h中定义了PAGE_OFFSET=0xC0000000
  48. //pg0=0xC0102000,empty_zero_page=c0104000
  49. //下面一段的作用是在0x102000-0x104000建立页目录表映射了[0-8M]的内存空间
  50.     movl $pg0-__PAGE_OFFSET,%edi
  51.     movl $007,%eax                 -->0x07的意思是PRESENT+RW+USER(存在+可读写+任意用户都可访问)
  52. 2:  stosl
  53.     add $0x1000,%eax
  54.     cmp $empty_zero_page-__PAGE_OFFSET,%edi
  55.     jne 2b

  56. //swapper_pg_dir=c0101000,目录址cr3=0x101000,并开启分页机制
  57. //这儿注意swapper_pg_dir可不是空的,是预先设置好了页目录表项的值0x102007与0x103007
  58. 3:
  59.     movl $swapper_pg_dir-__PAGE_OFFSET,%eax   
  60.     movl %eax,%cr3          -->cr3=0x101000
  61.     movl %cr0,%eax          -->cr0设1,
  62.     orl $0x80000000,%eax
  63.     movl %eax,%cr0          
  64.     jmp 1f                  -->线
  65. 1:
  66.     movl $1f,%eax
  67.     jmp *%eax               -->0010:0010005c (unk. ctxt): jmp eax   -->还是用的物理地址
  68. 1:                          -->下面有详细分析虚拟地址到物理地址的变换过程
  69.     lss stack_start,%esp    -->0010:c010005e (unk. ctxt): lss esp, ds:0xc0100224 -->使

  70. #ifdef CONFIG_SMP
  71.     orw %bx,%bx
  72.     jz 1f                   -->这儿跳过
  73.     pushl $0
  74.     popfl
  75.     jmp checkCPUtype
  76. 1:
  77. #endif CONFIG_SMP

  78. /*
  79.  * Clear BSS first so that there are no surprises...
  80.  * No need to cld as DF is already clear from cld above...
  81.  */
  82. //清BSS
  83.     xorl %eax,%eax
  84.     movl $ SYMBOL_NAME(__bss_start),%edi
  85.     movl $ SYMBOL_NAME(_end),%ecx
  86.     subl %edi,%ecx
  87.     rep
  88.     stosb

  89. //将中断处理函数全部设为ignore_int
  90.     call setup_idt
  91. /*
  92.  * Initialize eflags. Some BIOS's leave bits like NT set. This would
  93.  * confuse the debugger if this code is traced.
  94.  * XXX - best to initialize before switching to protected mode.
  95.  */
  96.     pushl $0
  97.     popfl
  98. /*
  99.  * Copy bootup parameters out of the way. First 2kB of
  100.  * _empty_zero_page is for boot parameters, second 2kB
  101.  * is for the command line.
  102.  *
  103.  * Note: %esi still has the pointer to the real-mode data.
  104.  */
  105. //将将0x90000处的4K字节复制到empty_zero_page=0x104000的,其中esi它从compressed/head.S中进来时esi=0x00090000
  106. //其中前2K字节是boot的参数,后2K字节是command_line
  107.     movl $ SYMBOL_NAME(empty_zero_page),%edi
  108.     movl $512,%ecx
  109.     cld
  110.     rep
  111.     movsl
  112.     xorl %eax,%eax
  113.     movl $512,%ecx
  114.     rep               -->rep movsd dword ptr es:[edi], dword ptr ds:[esi]
  115.     stosl
  116.     movl SYMBOL_NAME(empty_zero_page)+NEW_CL_POINTER,%esi
  117.     andl %esi,%esi
  118.     jnz 2f            # New command line protocol
  119.     cmpw $(OLD_CL_MAGIC),OLD_CL_MAGIC_ADDR
  120.     jne 1f
  121.     movzwl OLD_CL_OFFSET,%esi
  122.     addl $(OLD_CL_BASE_ADDR),%esi
  123. 2:
  124.     movl $ SYMBOL_NAME(empty_zero_page)+2048,%edi
  125.     movl $512,%ecx
  126.     rep
  127.     movsl
  128. 1:
  129. checkCPUtype:
  130.     //中间省略这个checkCPUtype的过程
  131.     
  132.     call check_x87
  133.     incb ready
  134.     lgdt gdt_descr                   //重新加载gdt
  135.     lidt idt_descr                   //重新加载idt
  136.     ljmp $(__KERNEL_CS),$1f          //使gdt生效
  137. 1:    movl $(__KERNEL_DS),%eax       //修改了gdt之后重新初始化各个段寄存器# reload all the segment registers
  138.     movl %eax,%ds                    # after changing gdt.
  139.     movl %eax,%es
  140.     movl %eax,%fs
  141.     movl %eax,%gs
  142. #ifdef CONFIG_SMP
  143.     movl $(__KERNEL_DS), %eax        -->重新设置ss,搞不懂为什么不能用lss了?
  144.     movl %eax,%ss        # Reload the stack pointer (segment only)
  145. #else
  146.     lss stack_start,%esp    # Load processor stack
  147. #endif
  148.     xorl %eax,%eax
  149.     lldt %ax                -->ldt_base=0x00000000
  150.     cld                    # gcc2 wants the direction flag cleared at all times
  151. #ifdef CONFIG_SMP
  152.     movb ready, %cl    
  153.     cmpb $1,%cl
  154.     je 1f                  -->跳到1f  # the first CPU calls start_kernel all other CPUs call initialize_secondary
  155.     call SYMBOL_NAME(initialize_secondary)    -->不执行这个
  156.     jmp L6
  157. 1:
  158. #endif
  159.     call SYMBOL_NAME(start_kernel)            -->终于到C语言的start_kernel了
  160. L6:
  161.     jmp L6            # main should never return here, but
  162.                 # just in case, we know what happens.

  163. ready:    .byte 0

  164. /*
  165.  * setup_idt
  166.  *
  167.  * sets up a idt with 256 entries pointing to
  168.  * ignore_int, interrupt gates. It doesn't actually load
  169.  * idt - that can be done only after paging has been enabled
  170.  * and the kernel moved to PAGE_OFFSET. Interrupts
  171.  * are enabled elsewhere, when we can be relatively
  172.  * sure everything is ok.
  173.  */
  174. setup_idt:
  175.     lea ignore_int,%edx
  176.     movl $(__KERNEL_CS << 16),%eax
  177.     movw %dx,%ax        /* selector = 0x0010 = cs */
  178.     movw $0x8E00,%dx    /* interrupt gate - dpl=0, present */

  179.     lea SYMBOL_NAME(idt_table),%edi
  180.     mov $256,%ecx
  181. rp_sidt:
  182.     movl %eax,(%edi)
  183.     movl %edx,4(%edi)
  184.     addl $8,%edi
  185.     dec %ecx
  186.     jne rp_sidt
  187.     ret
  188. //lss 后esp: 0xc027a000
  189. ENTRY(stack_start)                                    -->c0265a80 D init_tasks
  190.     .long SYMBOL_NAME(init_task_union)+8192           -->c0278000 D init_task_union  -->c027a000 A __init_begin
  191.     .long __KERNEL_DS                

  192. /* This is the default interrupt "handler" :-) */
  193. int_msg:
  194.     .asciz "Unknown interrupt\n"
  195.     ALIGN
  196. ignore_int:
  197.     cld
  198.     pushl %eax
  199.     pushl %ecx
  200.     pushl %edx
  201.     pushl %es
  202.     pushl %ds
  203.     movl $(__KERNEL_DS),%eax
  204.     movl %eax,%ds
  205.     movl %eax,%es
  206.     pushl $int_msg
  207.     call SYMBOL_NAME(printk)
  208.     popl %eax
  209.     popl %ds
  210.     popl %es
  211.     popl %edx
  212.     popl %ecx
  213.     popl %eax
  214.     iret

  215. /*
  216.  * The interrupt descriptor table has room for 256 idt's,
  217.  * the global descriptor table is dependent on the number
  218.  * of tasks we can have..
  219.  */
  220. #define IDT_ENTRIES    256
  221. #define GDT_ENTRIES    (__TSS(NR_CPUS))


  222. .globl SYMBOL_NAME(idt)
  223. .globl SYMBOL_NAME(gdt)

  224.     ALIGN
  225.     .word 0
  226. idt_descr:
  227.     .word IDT_ENTRIES*8-1        # idt contains 256 entries
  228. SYMBOL_NAME(idt):
  229.     .long SYMBOL_NAME(idt_table)

  230.     .word 0
  231. gdt_descr:
  232.     .word GDT_ENTRIES*8-1
  233. SYMBOL_NAME(gdt):
  234.     .long SYMBOL_NAME(gdt_table)

  235. /*
  236.  * This is initialized to create an identity-mapping at 0-8M (for bootup
  237.  * purposes) and another mapping of the 0-8M area at virtual address
  238.  * PAGE_OFFSET.
  239.  */
  240. //页目录表size=4096,有1024项=768+256
  241. .org 0x1000
  242. ENTRY(swapper_pg_dir)
  243.     .long 0x00102007
  244.     .long 0x00103007
  245.     .fill BOOT_USER_PGD_PTRS-2,4,0
  246.     /* default: 766 entries */
  247.     .long 0x00102007                   -->页目录表的第768项就是0xC0000000开妈的虚拟地址
  248.     .long 0x00103007
  249.     /* default: 254 entries */
  250.     .fill BOOT_KERNEL_PGD_PTRS-2,4,0

  251. //页表size=4096*2,1个页表能映射4M,2个页表映射8M内存,以上代码看出是映射了物理地址[0-8M]的内存
  252. .org 0x2000
  253. ENTRY(pg0)

  254. .org 0x3000
  255. ENTRY(pg1)

  256. /*
  257.  * empty_zero_page must immediately follow the page tables ! (The
  258.  * initialization loop counts until empty_zero_page)
  259.  */

  260. .org 0x4000
  261. ENTRY(empty_zero_page)

  262. .org 0x5000

  263. /*
  264.  * Real beginning of normal "text" segment
  265.  */
  266. ENTRY(stext)
  267. ENTRY(_stext)

  268. /*
  269.  * This starts the data section. Note that the above is all
  270.  * in the text section because it has alignment requirements
  271.  * that we cannot fulfill any other way.
  272.  */
  273. .data

  274. ALIGN
  275. /*
  276.  * This contains typically 140 quadwords, depending on NR_CPUS.
  277.  *
  278.  * NOTE! Make sure the gdt descriptor in head.S matches this if you
  279.  * change anything.
  280.  */
  281. ENTRY(gdt_table)
  282.     .quad 0x0000000000000000    /* NULL descriptor */
  283.     .quad 0x0000000000000000    /* not used */
  284.     .quad 0x00cf9a000000ffff    /* 0x10 kernel 4GB code at 0x00000000 */
  285.     .quad 0x00cf92000000ffff    /* 0x18 kernel 4GB data at 0x00000000 */
  286.     .quad 0x00cffa000000ffff    /* 0x23 user 4GB code at 0x00000000 */
  287.     .quad 0x00cff2000000ffff    /* 0x2b user 4GB data at 0x00000000 */
  288.     .quad 0x0000000000000000    /* not used */
  289.     .quad 0x0000000000000000    /* not used */
  290.     /*
  291.      * The APM segments have byte granularity and their bases
  292.      * and limits are set at run time.
  293.      */
  294.     .quad 0x0040920000000000    /* 0x40 APM set up for bad BIOS's */
  295.     .quad 0x00409a0000000000    /* 0x48 APM CS code */
  296.     .quad 0x00009a0000000000    /* 0x50 APM CS 16 code (16 bit) */
  297.     .quad 0x0040920000000000    /* 0x58 APM DS data */
  298.     .fill NR_CPUS*4,8,0        /* space for TSS's and LDT's */
  299.         
  300. /*
  301.  * This is to aid debugging, the various locking macros will be putting
  302.  * code fragments here. When an oops occurs we'd rather know that it's
  303.  * inside the .text.lock section rather than as some offset from whatever
  304.  * function happens to be last in the .text segment.
  305.  */
  306. .section .text.lock
  307. ENTRY(stext_lock)

附录1.bochs调试kernel/head.S中断点的设置
  1. <bochs:1> lb 0x100000              -->在1M
  2. <bochs:2> c
  3. (0) Breakpoint 1, 0x00100000 in ?? ()
  4. Next at t=92855571
  5. (0) [0x000000100000] 0010:00100000 (unk. ctxt): cld ; fc   -->第1的cld是compressed/head.S
  6. <bochs:3> c
  7. (0) Breakpoint 1, 0x00100000 in ?? ()
  8. Next at t=174491593
  9. (0) [0x000000100000] 0010:00100000 (unk. ctxt): cld ; fc    -->第2的cld才是kernel/head.S
附录2:刚进入arch/i386/kernel/head.S之前与之后gdt的对比
a. 刚进入head.S时的gdt
  1. <bochs:4> n
  2. Next at t=174491594
  3. (0) [0x000000100001] 0010:00100001 (unk. ctxt): mov eax, 0x00000018 ; b818000000
  4. <bochs:5> sreg
  5. es:0x0018, dh=0x00cf9300, dl=0x0000ffff, valid=31
  6.     Data segment, base=0x00000000, limit=0xffffffff, Read/Write, Accessed
  7. cs:0x0010, dh=0x00cf9b00, dl=0x0000ffff, valid=1
  8.     Code segment, base=0x00000000, limit=0xffffffff, Execute/Read, Non-Conforming, Accessed, 32-bit
  9. ss:0x0018, dh=0x00cf9300, dl=0x0000ffff, valid=31
  10.     Data segment, base=0x00000000, limit=0xffffffff, Read/Write, Accessed
  11. ds:0x0018, dh=0x00cf9300, dl=0x0000ffff, valid=31
  12.     Data segment, base=0x00000000, limit=0xffffffff, Read/Write, Accessed
  13. fs:0x0018, dh=0x00cf9300, dl=0x0000ffff, valid=1
  14.     Data segment, base=0x00000000, limit=0xffffffff, Read/Write, Accessed
  15. gs:0x0018, dh=0x00cf9300, dl=0x0000ffff, valid=1
  16.     Data segment, base=0x00000000, limit=0xffffffff, Read/Write, Accessed
  17. ldtr:0x0000, dh=0x00008200, dl=0x0000ffff, valid=1
  18. tr:0x0000, dh=0x00008b00, dl=0x0000ffff, valid=1
  19. gdtr:base=0x00090a8b, limit=0x8000
  20. idtr:base=0x00000000, limit=0x0
  21. <bochs:9> info gdt
  22. Global Descriptor Table (base=0x00090a8b, limit=32768):
  23. GDT[0x00]=??? descriptor hi=0x00000000, lo=0x00000000
  24. GDT[0x01]=??? descriptor hi=0x00000000, lo=0x00000000
  25. GDT[0x02]=Code segment, base=0x00000000, limit=0xffffffff, Execute/Read, Non-Conforming, Accessed, 32-bit
  26. GDT[0x03]=Data segment, base=0x00000000, limit=0xffffffff, Read/Write, Accessed
b.第二次设置了gdt,在start_kernel之前的gdt
  1. info gdt
  2. Global Descriptor Table (base=0xc0263000, limit=1119):
  3. GDT[0x00]=??? descriptor hi=0x00000000, lo=0x00000000
  4. GDT[0x01]=??? descriptor hi=0x00000000, lo=0x00000000
  5. GDT[0x02]=Code segment, base=0x00000000, limit=0xffffffff, Execute/Read, Non-Conforming, Accessed, 32-bit
  6. GDT[0x03]=Data segment, base=0x00000000, limit=0xffffffff, Read/Write, Accessed
  7. GDT[0x04]=Code segment, base=0x00000000, limit=0xffffffff, Execute/Read, Non-Conforming, 32-bit
  8. GDT[0x05]=Data segment, base=0x00000000, limit=0xffffffff, Read/Write
  9. GDT[0x06]=??? descriptor hi=0x00000000, lo=0x00000000
附录3: 页表的内容

  上图出自《Linux内核完全注释》

a. 1个页表项可以映射4K的内存,0x102000-0x104000=0x2000=8192个字节
     8192个字节有8192/4=2K个页表项,所以总共映射了2K*4K=8M的内存
b. 页目表[0x102000-0x104000]的内容如下 --> 映射内存起始[0-8M]
  1. <bochs:70> xp /2060wx 0x102000
  2. [bochs]:
  3. 0x00102000 <bogus+ 0>:    0x00000007    0x00001007    0x00002007    0x00003007
  4. 0x00102010 <bogus+ 16>:    0x00004007    0x00005007    0x00006007    0x00007007
  5. ....
  6. 0x00103fe0 <bogus+ 8160>:    0x007f8007    0x007f9007    0x007fa007    0x007fb007
  7. 0x00103ff0 <bogus+ 8176>:    0x007fc007    0x007fd007    0x007fe007    0x007ff007
  8. 0x00104000 <bogus+ 8192>:    0x00000000    0x00000000    0x00000000    0x00000000
附录4. 详细分析虚拟地址到物进地址的过程-->以0xc010005e为例

                     上图出自赵炯的《Linux内核完全注释V3.0.pdf》
c010005e=11000000000100000000000001011110
a.页目录表找到页表的过程
  a.1 高10位--> 1100000000=768=0x300   -->页目录表的第768项是0xc010005e的页目录项
   a.2 cr3+768*4=0x101000+0xC00=0x101C00
   a.3 则0x101C00地址的内容为page_table的地址
  1. <bochs:25> xp /1024wx 0x101000
  2. 0x00101000 <bogus+ 0>:     0x00102007    0x00103007    0x00000000    0x00000000
  3. 0x00101010 <bogus+ 16>:    0x00000000    0x00000000    0x00000000    0x00000000
  4. 0x00101020 <bogus+ 32>:    0x00000000    0x00000000    0x00000000    0x00000000
  5. ....
  6. 0x00101c00 <bogus+ 3072>:    0x00102007    0x00103007    0x00000000    0x00000000
  7. 0x00101c10 <bogus+ 3088>:    0x00000000    0x00000000    0x00000000    0x00000000
  8. 0x00101c20 <bogus+ 3104>:    0x00000000    0x00000000    0x00000000    0x00000000
  9. 0x00101ff0 <bogus+ 4080>:    0x00000000    0x00000000    0x00000000    0x00000000
0xc010005e的页表基地址是0x00102007-->后12位无效-->所以最终的地址是0x0x00102000

b.由页表找到物理地址的过程
  b.1 0100000000=256=0x100   -->页表的第256项是0xc010005e的页表项
  b.2 在page_table中的偏移是256*4=1024=0x400
  b.3 页表项=页表基地址+页表内的偏移=0x00102000+0x400=0x102400
  1. <bochs:27> xp /2060wx 0x102000
  2. 0x001023f0 <bogus+ 1008>:    0x000fc007    0x000fd007    0x000fe007    0x000ff007
  3. 0x00102400 <bogus+ 1024>:    0x00100007    0x00101007    0x00102007    0x00103007
  4. 0x00102410 <bogus+ 1040>:    0x00104007    0x00105007    0x00106007    0x00107007
则0x00100007-->后12位无效-->所以最终的页帧地址是0x00100000

c.最终的物理地址
 c.1 后12位000001011110=94=0x5E
 c.2 物理地址=页帧地址+页内偏称=0x00100000+0x5E=0x0010005E

d.综上
虚拟地址c010005e--->物理地址0x0010005E
阅读(1489) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~