一个函数介绍逻辑地址,虚拟地址,线性地址和物理地址如何转换
本帖最后由 Buddy_Zhang1 于 2018-01-19 15:44 编辑下面函数用于介绍 逻辑地址,虚拟地址,线性地址和物理地址的转换过程:
github 地址:https://github.com/BiscuitOS/BiscuitOS
原理来自 Intel X86 官方手册 -- 系统编程卷 -- Segmentation and Paging Section
/*
* Logical Address Mechanism on MMU
*
* (C) 2018.01 BiscuitOS <buddy.zhang@aliyun.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/kernel.h>
#include <linux/head.h>
#include <linux/sched.h>
#include <test/debug.h>
static char var = "BiscuitOS";
/*
* Logical address convent to physical address
*/
static void logic_to_physic(void)
{
struct logic_addr la;
unsigned long virtual, linear, physic;
unsigned long base, limit;
unsigned long cs, ds, cr3, cr4;
unsigned char cpl, dpl;
struct desc_struct *desc;
unsigned long PDE, PTE;
/* Obtain specific segment selector */
__asm__ ("movl %%cs, %0\n\r"
"movl %%ds, %1"
: "=r" (cs), "=r" (ds));
/* Establish a logical address */
la.offset = (unsigned long)&var;
la.sel = ds;
/* Obtain virtual address */
virtual = la.offset;
/* violation COW */
var = 'A';
/* Uses the offset in the segment selector to locate the segment
* descriptor for the segment in the GDT or LDT and reads it into
* the processor. (This step is needed only when a new segment selector
* is loaded into a segment register.) */
if ((la.sel >> 2) & 0x1)
desc = ¤t->ldt;
else
desc = &gdt;
/* Examines the segment descriptor to check the access rights and range
* of the segment to insure that the segment is accessible and that
* offset is within the limit of the segment */
base= get_base(*desc);
limit = get_limit(*desc) * 4096;
if (la.offset > limit)
panic("Out of segment\n");
cpl = cs & 0x3;
dpl = desc->b >> 13 & 0x3;
if (cpl > dpl)
panic("Trigger #GP");
/* Obtain linear address on flat-protect model */
linear = base + la.offset;
/* Obtain physical address of pgdir from CR3 register, the contents of
* 'cr3' is point to the physical of pg_dir, so refers it as a pointer. */
__asm__ ("movl %%cr3, %0" : "=r" (cr3));
/* A 4-KByte naturally aligned page directory is located at the
* physical address specified in bits 31:12 of CR3. A page directory
* comprises 1024 32-bit entries (PDEs). A PDE is selected using
* the physical address defined as follow:
*
* -- Bits 39:32 are all 0
* -- Bits 31:12 are from CR3.
* -- Bits 11:2are bits 31:22 of the linear address
* -- Bits1:0are 0.
*
* Becasue a PDE is identified using bits 31:22 of the linear address,
* it control access to a 4-Mbytes region of the linear-address space.
* Use of the PDE depends on CR4.PSE and PDE's PS flag (bit 7)*/
PDE =((unsigned char)(((cr3 >> 12) & 0xFFFFF) << 12) +
(((linear >> 22) & 0x3FF) << 2)) & 0xFFFFFFFC;
/* Another way to compute PDE:
* PDE = (unsigned long *)cr3 */
__asm__ ("movl %%cr4, %0" : "=r" (cr4));
if (((cr4 >> 4) & 0x1) && ((PDE >> 4) & 0x1)) {
/* If CR4.PSE = 1 and the PDE's PS flag is 1, the PDE maps a 4-MByte
* page. The final physical address is computed as follows:
*
* -- Bits 39:32 are bits 20:13 of the PDE.
* -- Bits 31:22 are bits 31:22 of the PDE.
* -- Bits 21:0are from the original linear address.
*/
PTE = 0x0; /* No complete on BiscuitOS */
} else if (!((cr4 >> 4) & 0x1) && !((PDE >> 4) & 0x1)) {
/* If CR4.PSE = 0 or the PDE's PS flag is 0, a 4-KByte naturally
* aligned page table is located at the physical address specified
* in bits 31:12 of the PDE. A page table comprises 1024 32-bit
* entries (PTEs). A PTE is selected using the physical address
* defined as follows:
*
* -- Bits 39:32 are all 0
* -- Bits 31:12 are from the PDE.
* -- Bits 11:2are bits 21:12 of the linear address.
* -- Bits1:0are 0.
*/
PTE = (unsigned long)((unsigned char *)(
((*(unsigned long *)PDE >> 12) & 0xFFFFF) << 12) +
(((linear >> 12) & 0x3FF) << 2)) & 0xFFFFFFFC;
/* Anther way to compute PTE:
* PTE = (unsigned long *)PDE[(linear >> 12) & 0x3FF] */
}
/* Because a PTE is identified using bits 31:12 of the linear address,
* every PTE maps a 4-KByte page. The final physical address is
* computed as follows:
*
* -- Bits 39:32 are all 0
* -- Bits 31:12 are from the PTE.
* -- Bits 11:0are from the original linear address.
*/
physic = (unsigned long)(unsigned char *)(
((*(unsigned long *)PTE >> 12) & 0xFFFFF) << 12) +
(linear & 0xFFF);
printk("Logical Address: %#x:%#x\n", la.sel, la.offset);
printk("Virtual Address: %#x\n", virtual);
printk("LinearAddress: %#x\n", linear);
printk("PhysicAddress: %#x\n", physic);
printk("Original:%s\n", la.offset);
printk("Translate: %s\n", physic);
} 赞,学习了!
43. /* violation COW */
44. var = 'A';
这两行的目的是什么?
回复 2# nswcfd
我的测试代码运行的 x86 环境是配置成回写的,也就是写时复制,对指定地址进行一次写操作防止缺页发生,我当时加这行代码的时候是这么想的,也是在看 Intel 手册上有说过这种情况。
nice, zan ! 回复 3# Buddy_Zhang1
多谢,了解了。
原来我也是这么认为的,不过现在我认为线性地址和虚拟地址是一个东西,前者是intel术语,后者是内核术语,不必区分。
页:
[1]