Buddy_Zhang1 发表于 2018-01-19 15:08

一个函数介绍逻辑地址,虚拟地址,线性地址和物理地址如何转换

本帖最后由 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 = &current->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);
}

nswcfd 发表于 2018-01-23 17:12

赞,学习了!

43.    /* violation COW */
44.    var = 'A';

这两行的目的是什么?

Buddy_Zhang1 发表于 2018-01-25 16:37

回复 2# nswcfd

我的测试代码运行的 x86 环境是配置成回写的,也就是写时复制,对指定地址进行一次写操作防止缺页发生,我当时加这行代码的时候是这么想的,也是在看 Intel 手册上有说过这种情况。

_nosay 发表于 2018-01-26 08:54

nice, zan !

nswcfd 发表于 2018-02-02 21:06

回复 3# Buddy_Zhang1

多谢,了解了。

剑魂箫心 发表于 2018-03-23 16:21

原来我也是这么认为的,不过现在我认为线性地址和虚拟地址是一个东西,前者是intel术语,后者是内核术语,不必区分。
页: [1]
查看完整版本: 一个函数介绍逻辑地址,虚拟地址,线性地址和物理地址如何转换