搜档网
当前位置:搜档网 › Linux地址空间和mmap内存映射

Linux地址空间和mmap内存映射

Linux地址空间和mmap内存映射
Linux地址空间和mmap内存映射

Linux地址空间和mmap内存映射

进程地址空间

Linux采用虚拟内存技术, 系统中的所有进程之间以虚拟方式共享内存. 对每个进程来说, 它们好像都可以访问整个系统的所有物理内存. 更重要的是, 即使单独一个进程, 它拥有的地址空间也可以远远大于系统物理内存.

进程地址空间由每个进程中的线性地址区组成, 每个进程都有一个32位或64位的平坦(flat)空间, 空间的具体大小取决于体系结构. “平坦”是指地址空间范围是一个独立的连续区间, 通常情况下, 每个进程都有唯一的这种平坦空间, 而且每个进程的地址空间之间互不相干, 两个不同的进程可以在它们各自地址空间的相同地址存放不同的数据. 进程之间也可以选择共享地址空间, 我们称这样的进程为线程.

在地址空间中, 我们更为关心的是进程有权访问的虚拟内存地址区间, 比如0x08048000~0x0804c000. 这些可被访问的合法地址区间被称为内存区域(memory area), 通过内核, 进程可以给自己的地址空间动态地添加或减少内存区域. 进程只能访问有效范围内的虚拟内存地址, 每个内存区域也具有相应进程必须遵循的特定访问属性, 如只读、只写、可执行等属性. 如果一个进程访问了不在有效范围内的地址, 或以不正确的方式访问有效地址, 那么内核就会终止该进程, 并返回”段错误”信息.

内存区域可以包含各种内存对象, 如下:

可执行文件的代码的内存映射, 称为代码段(text section)

可执行文件的已初始化全局变量的内存映射, 称为数据段(data section)

包含未初始化全局变量的零页(也就是bss段)的内存映射, 零页是指页面中的数据全部为0 用于进程用户空间栈的零页的内存映射

C库或动态链接程序等共享库的代码段、数据段和bss也会被载入进程的地址空间

任何内存映射文件

任何共享内存段

任何匿名的内存映射

进程地址空间的任何有效地址都只能位于唯一的区域, 这些内存区域不能相互覆盖. 可以看到, 在执行的进程中, 每个不同的内存片断都对应一个独立的内存区域: 栈、对象代码、全局变量、被映射的文件等.

内核使用内存描述符表示进程的地址空间, 内存描述符由mm_struct结构体表示, 定义在文件中, 该结构包含了和进程地址空间有关的全部信息.

VMA

内存区域由vm_area_struct结构体描述, 定义在文件中, 内存区域在内核中也经常被称作虚拟内存区域或者VMA. VMA标志是一种位标志, 它定义在vm_area_struct结构中的vm_flags子域. 和物理页的访问权限不同, VMA标志反应了内核处理页面所需要遵守的行为准则, 而不是硬件要求. VM_IO标志表示内存区域中包含对设备I/O空间的映射, 该标志通常在设备驱动程序执行mmap()函数进行I/O空间映射时才被设置, 同时该标志也表示该内存区域不能被包含在任何进程的存放转存(core dump)中. VM_RESERVED标志表示内存区域不能被换出, 它也是在设备驱动程序进行映射时被设置. vm_area_struct结构体中的vm_ops域指向与指定内存区域相关的操作函数表, 内核使用表中的方法操作VMA. mmap()和do_mmap()

内核使用do_mmap()函数创建一个新的线性地址区间. 但是说该函数创建一个新VMA并不非常准确, 因为如果创建的地址区间和一个已经存在的地址区间相邻, 并且它们具有相同的

访问权限的话, 那么两个区间将合并为一个. 如果不能合并, 那么就确实需要创建一个新的VMA了. 无论哪种情况, do_mmap()函数都会将一个地址区间加入到进程的地址空间中, 无论是扩展已经存在的内存区域还是创建一个新的区域.

do_mmap()函数声明在文件中, 原型如下:

unsigned long do_mmap(struct file *file, unsigned long addr, unsigned long len, unsigned long prot, unsigned long flag, unsigned long offset);

在用户空间可以通过mmap()系统调用获取内核函数do_mmap()的功能. mmap()系统调用原型如下:

void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t pgoff);

do_munmap()函数从特定的进程地址空间中删除指定地址区间, 该函数在文件中声明:

int do_munmap(struct mm_struct *mm, unsigned long start, size_t len);

系统调用munmap()给用户空间程序提供了一种从自身地址空间中删除指定地址区间的方法, 它和系统调用mmap()的作用相反:

int munmap(void *start, size_t length);

mmap设备操作

对于驱动程序来说, 内存映射可以提供给用户程序直接访问设备内存的能力. 映射一个设备, 意味着使用户空间的一段地址关联到设备内存上. 无论何时, 只要程序在分配的地址范围内进行读取或者写入, 实际上就是对设备的访问.

并不是所有的设备都能进行mmap映射. 例如, 串口设备和其它面向流的设备就无法实现这种映射. mmap的另一个限制是映射都是以PAGE_SIZE为单位的. 内核只能在页表一级处理虚拟地址, 因此, 被映射的区域必须是PAGE_SIZE的整数倍, 而且必须位于起始于PAGE_SIZE整数倍地址的物理内存内. 如果区域的大小不是页大小的整数倍, 内核就通过生成一个稍微大一些的区域来容纳它.

mmap方法是file_operations结构中的一员, 并且在执行mmap系统调用时就会调用该方法. 在调用实际方法之前, 内核会完成很多工作, 而且该方法的原型与系统调用的原型由很大区别. 文件操作声明如下:

int (*mmap) (struct file * filp, struct vm_area_struct *vma);

其中vma参数包含了用于访问设备的虚拟地址区间的信息. 大部分工作已经由内核完成了, 要实现mmap, 驱动程序只要为这一地址范围构造合适的页表即可, 如果需要的话, 还要用一个新的操作集替换vma->vm_ops.

有两种建立页表的方法: 使用remap_page_range函数可一次建立所有的页表, 或者通过nopage方法每次建立一个页表.

构造用于映射一段物理地址的新页表的工作是由remap_page_range完成的, 它的原型如下: int remap_page_range(unsigned long virt_add, unsigned long phys_add, unsigned long size, pgprot_t prot);

remap_page_range有一个有意思的限制, 它只能对保留页和物理内存之外的物理地址给予访问. 也就是说, remap_page_range不允许重映射常规地址(常规物理内存对应的地址), 它会改为映射到零页. 因此, 如果需要映射RAM的话, 只能使用nopage方法.

nopage方法具有如下原型:

struct page (*nopage) (struct vm_area_struct *vma, unsigned long address, int write_access);

当用户进程访问当前不在内存中的VMA页面时, 就会调用关联的VMA操作集中的nopage 函数. 参数address是导致page fault的进程空间的虚拟地址, 该地址向下取整到所在页的起

始地址. 函数nopage必须定位并返回指向用户所期望的页的struct page指针. 这个函数还要调用get_page宏, 以增加它所返回的页面的使用计数:

get_page(struct page *pageptr);

nopage方法在mremap系统调用中非常有用. 应用程序使用mremap来改变映射区域的边界地址, mremap系统调用的原型如下:

void * mremap(void *old_address, size_t old_size , size_t new_size, unsigned long flags);

Linux的mremap实现没有通知驱动程序映射区域的变化, 事实上, 当区域减小时, 它会通过unmap方法通知驱动程序, 但区域变大时, 却没有相应的回调函数可以利用. 换句话说, 在映射区域增长时驱动程序不会得到通知, 因为nopage方法会在将来完成相应的工作. 因此, 如果我们需要支持mremap系统调用, 就必须实现nopage方法.

nopage方法必要的实现步骤如下:

首先计算想得到的物理地址, 然后用__va()将它转换为逻辑地址, 最后用virt_to_page将逻辑地址转成一个struct page, 返回指向这个struct page的指针. 一般来说, 直接从物理地址获得struct page是可能的, 但是这样的代码很难在不同的体系结构之间移植.

下面是对simple.c的简单分析

/*

* Simple - REALL Y simple memory mapping demonstration.

*

* Copyright (C) 2001 Alessandro Rubini and Jonathan Corbet

* Copyright (C) 2001 O'Reilly & Associates

*

* The source code in this file can be freely used, adapted,

* and redistributed in source or binary form, so long as an

* acknowledgment appears in derived source files. The citation

* should list that the code comes from the book "Linux Device

* Drivers" by Alessandro Rubini and Jonathan Corbet, published

* by O'Reilly & Associates. No warranty is attached;

* we cannot take responsibility for errors or fitness for use.

*

* $Id: simple.c,v 1.8 2001/07/18 22:28:18 rubini Exp $

*/

#ifndef __KERNEL__

# define __KERNEL__

#endif

#ifndef MODULE

# define MODULE

#endif

#include

#include

#include /* printk() */

#include /* kmalloc() */

#include

#include /* error codes */

#include /* size_t */

#include

#include "sysdep.h"

static int simple_major = 0;

MODULE_PARM(simple_major, "i");

MODULE_AUTHOR("Jonathan Corbet");

/*

* Forwards for our methods.

*/

int simple_open (struct inode *inode, struct file *filp);

int simple_release(struct inode *inode, struct file *filp);

int simple_remap_mmap(struct file *filp, struct vm_area_struct *vma);

int simple_nopage_mmap(struct file *filp, struct vm_area_struct *vma);

/*

* Our various sub-devices.

*/

/* Device 0 uses remap_page_range */

struct file_operations simple_remap_ops = {

open: simple_open,

release: simple_release,

mmap: simple_remap_mmap,

};

/* Device 1 uses nopage */

struct file_operations simple_nopage_ops = {

open: simple_open,

release: simple_release,

mmap: simple_nopage_mmap,

};

#define MAX_SIMPLE_DEV 2

struct file_operations *simple_fops[MAX_SIMPLE_DEV] = {

&simple_remap_ops,

&simple_nopage_ops,

};

/*

* Open the device; all we have to do here is to up the usage count and set the right fops. */

int simple_open (struct inode *inode, struct file *filp)

{

unsigned int dev = MINOR(inode->i_rdev);

if (dev >= MAX_SIMPLE_DEV)

return -ENODEV;

filp->f_op = simple_fops[dev];

MOD_INC_USE_COUNT;

return 0;

}

/*

* Closing is even simpler.

*/

int simple_release(struct inode *inode, struct file *filp)

{

MOD_DEC_USE_COUNT;

return 0;

}

/*

* Common VMA ops.

*/

void simple_vma_open(struct vm_area_struct *vma)

{ MOD_INC_USE_COUNT; }

void simple_vma_close(struct vm_area_struct *vma)

{ MOD_DEC_USE_COUNT; }

/*

* The remap_page_range version of mmap.

*/

static struct vm_operations_struct simple_remap_vm_ops = {

open: simple_vma_open,

close: simple_vma_close,

};

int simple_remap_mmap(struct file *filp, struct vm_area_struct *vma)

{

unsigned long offset = VMA_OFFSET(vma);

//设备文件的偏移量, 以页为单位, 实际就是设备文件的物理地址

if (offset >= __pa(high_memory) || (filp->f_flags & O_SYNC))

//如果偏移量超过实际物理内存的地址范围, 或者文件标记为同步时vma->vm_flags |= VM_IO;

//设置vm_flags标记为VM_IO, 将VMA标记为一个内存映射的I/O区域vma->vm_flags |= VM_RESERVED;

//VM_RESERVED标记内存区域不能被换出

if (remap_page_range(vma->vm_start,offset,vma->vm_end-vma->vm_start,

vma->vm_page_prot))

return -EAGAIN;

//调用remap_page_range()构建必需的页表, 该函数返回的值通常是0或者一个负的错//误码, 参数vma->vm_start指向需要映射的用户虚拟地址的起始地址, offset指向虚拟//地址所映射的物理地址, vma->vm_end-vma->vm_start是映射区域的大小,

//vma->vm_page_prot是新的VMA所需要的访问控制权限

vma->vm_ops = &simple_remap_vm_ops;

//更新VMA的操作集

simple_vma_open(vma);

//调用VMA操作集中的open函数, 在打开VMA时增加模块的使用计数

return 0;

}

/*

* The nopage version.

*/

struct page *simple_vma_nopage(struct vm_area_struct *vma, unsigned long address, int write_access)

{

struct page *pageptr;

unsigned long physaddr = address - vma->vm_start + VMA_OFFSET(vma);

//获取虚拟地址address所对应的实际物理地址, VMA_OFFSET(vma)是被映射的设备文//件的偏移量, 是VMA映射的起始地址

pageptr = virt_to_page(__va(physaddr));

//首先将physaddr通过__va转换为逻辑地址, 然后用virt_to_page将逻辑地址转换为一//个struct page

get_page(pageptr);

//增加该页面的使用计数

return pageptr;

}

static struct vm_operations_struct simple_nopage_vm_ops = {

open: simple_vma_open,

close: simple_vma_close,

nopage: simple_vma_nopage,

};

int simple_nopage_mmap(struct file *filp, struct vm_area_struct *vma)

{

unsigned long offset = VMA_OFFSET(vma);

if (offset >= __pa(high_memory) || (filp->f_flags & O_SYNC))

vma->vm_flags |= VM_IO;

vma->vm_flags |= VM_RESERVED;

vma->vm_ops = &simple_nopage_vm_ops;

//改变VMA的操作集, 实现了nopage方法

simple_vma_open(vma);

return 0;

}

/*

* Module housekeeping.

*/

static int simple_init(void)

{

int result;

SET_MODULE_OWNER(&simple_remap_ops);

SET_MODULE_OWNER(&simple_nopage_ops);

result = register_chrdev(simple_major, "simple", &simple_remap_ops);

if (result < 0)

{

printk(KERN_W ARNING "simple: unable to get major %d\n", simple_major);

return result;

}

if (simple_major == 0)

simple_major = result;

return 0;

}

static void simple_cleanup(void)

{

unregister_chrdev(simple_major, "simple");

}

module_init(simple_init);

module_exit(simple_cleanup);

linux内存管理子系统 笔记

4-4 linux内存管理子系统 4-4-1 linux内存管理(参考课件) 物理地址:cpu地址总线上寻址物理内存的地址信号,是地址变换的最终结果 逻辑地址:程序代码经过编译后,出现在汇编程序中的地址(程序设计时使用的地址) 线性地址:又名虚拟地址,32位cpu架构下4G地址空间 CPU要将一个逻辑地址转换为物理地址,需要两步: 1、首先CPU利用段式内存管理单元,将逻辑地址转换成线性地址; 2、再利用页式内存管理单元,把线性地址最终转换为物理地址 相关公式: 逻辑地址=段基地址+段内偏移量(段基地址寄存器+段偏移寄存器)(通用的) 16位CPU:逻辑地址=段基地址+段内偏移量(段基地址寄存器+段偏移寄存器) 线性地址=段寄存器的值×16+逻辑地址的偏移部分 物理地址=线性地址(没有页式管理) 32位CPU:逻辑地址=段基地址+段内偏移量(段基地址寄存器+段偏移寄存器) 线性地址=段寄存器的值+逻辑地址的偏移部分 物理地址<——>线性地址(mapping转换) ARM32位:逻辑地址=段基地址+段内偏移量(段基地址寄存器+段偏移寄存器) 逻辑地址=段内偏移量(段基地址为0) 线性地址=逻辑地址=段内偏移量(32位不用乘以32) 物理地址<——>线性地址(mapping转换) ************************!!以下都是x86模式下!!********************************* 一、段式管理 1.1、16位CPU:(没有页式管理) 1.1.1、段式管理的由来: 16位CPU内部有20位地址总线,可寻址2的20次方即1M的内存空间,但16位CPU 只有16位的寄存器,因此只能访问2的16次方即64K。因此就采用了内存分段的管理模式,在CPU内部加入了段寄存器,这样1M被分成若干个逻辑段,每个逻辑段的要求如下: 1、逻辑段的起始地址(段地址)必须是16的整数倍,即最后4个二进制位须全是0 (因此不必保存)。 2、逻辑段的最大容量为64K。 1.1.2、物理地址的形成方式: 段地址:将段寄存器中的数值左移4位补4个0(乘以16),得到实际的段地址。 段偏移:在段偏移寄存器中。 1)逻辑地址=段基地址+段内偏移量(段基地址寄存器+段偏移寄存器) 2)由逻辑地址得到物理地址的公式为:(因为没有页式管理,所以这一步就得到了物理地址)物理地址PA=段寄存器的值×16+逻辑地址的偏移部分(注意!!)(段与段可能会重叠)

室内设计之储存空间设计技巧

室内设计之储存空间设计技巧 随着人们生活水平的提高,物质方面的需求也越来越丰富。因此,家庭中的储藏空间也越来越受重视。 储存空间设计主要是充分利用被忽视的空间,归纳起来主要是对闲置的角落,未被利用的家具空腹,楼梯的下部、侧部和端部,走廊的顶部等空间进行开发利用。住宅条件宽裕的,则可考虑把一个小房间或利用室内的一块空间来设置成独立储藏室。 1.储物空间的位置及时效性 设计储物空间应在如下几方面,认真分析、推敲,才能使其全面、合理、细致。 首先,储存的地点和位置直接关系到储物的使用是否便利,空间使用效率是否高。例如书籍的储存地点宜靠近经常阅读活动的沙发、床头、写字台,使人方便地拿取;化妆、清洁用具的储存地点应靠近洗手间台面、梳妆台面,并且使用者能在洗脸和梳妆时方便地拿到;而调味品的储存地点则宜靠近灶台及进行备餐活动的区域;衣物的储存应靠近卧室。 其次,考虑储物空间的使用效率,指任何一处储存空间利用得是否充分,物品的摆放是否合理。如鞋类的储藏空间的搁板应根据鞋的尺寸形状来设计,以便能更多的储存鞋;衣物的储存应结合各类衣物的特点和尺寸来选择叠放、垂挂的方式;餐具的储存空间则应认真分析各类餐具的规格、尺寸、形状,来决定摆放形式。 此外,还要考虑储存的时间性。一方面是指被储存物品使用周期的考虑,是季节性的还是每周一次,或是永久性珍藏类,或是每日都用的。另一方面,需要考虑储存空间是暂时性还是永久性,以次决定其构造是活动的还是固定。 2.储存空间的形式 储存空间的样式分为开敞式、密闭式和储藏室式三种。 (1)开敞式 开敞式的储存空间则用来陈列具有较强装饰作用值得炫耀的物品,如酒柜用来陈列种类繁多、包装精美的酒具和美酒,书柜则用来展示丰实的藏书以及各类

linux复习题

一单选题 1.最初开发了Linux系统的是() A.Andrew S. Tanwnbaum B.Linus Torvalds C.Ken Thompson D.Dennis Ritchie 2.linux操作系统内核创始人是() A.Bill Gates B.Richard Stallman C.Linus Torvalds D.Dennis Ritchie 3.linux操作系统下有很多应用软件,其中大部分软件包括linux本身属于() A.商业软件 B. 共享软件 C.自由软件 D.其他类型软件 4.Linux系统是一个什么样的操作系统() A.单用户、单任务B.单用户、多任务 C.多用户、单任务D.多用户、多任务 5.Linux 核心的许可证是什么() A.NDA B.GDP C.GPL D.GNU 6.若要将鼠标从VM中释放出来,可按什么键来实现() A. Ctrl + Alt B. Ctrl +Alt +Del C. Ctrl +Alt +Enter D Ctrl +Enter 7.用"rm -i",系统会提示什么来让你确认() A. 命令行的每个选项 B. 是否真的删除 C. 是否有写的权限 D. 文件的位置 8.下列提法中,不属于ifconfig命令作用范围的是() A 配置本地回环地址 B 配置网卡的IP地址 C 激活网络适配器 D 加载网卡到内核中 9.下列文件中,包含了主机名到IP地址的映射关系的文件是() A /etc/HOSTNAME B /etc/hosts C /etc/resolv.conf D /etc/networks 10.在shell中变量的赋值有四种方法,其中,采用name=12的方法称() A 直接赋值B使用read命令 C 使用命令行参数D使用命令的输出 11.显示文件的头部的命令是() A.fdisk B.mount C.head D.man 12.删除不需要的文件的命令是() A.mkdir B.rm C.mv D.remove 13.Linux的根分区的文件系统类型是() A.FAT16 B.FAT32 C.ext3 D.NTFS 14.登录后希望重新加载fstab文件中的所有条目,我们可以以root身份执行哪个命令 () A.mount –d B.mount –c C.mount –a D.mount -b 15.下面不具备循环功能的语句是() A.if B.for C.while D.until 16.内核不包括的子系统是() A 进程管理系统 B 内存管理系统 C 文件管理系统D硬件管理系统 17.对名为fido的文件用chmod 551 fido 进行了修改,则它的许可权是() A -rwxr-xr-x B -rwxr--r-- C -r--r--r-- D -r-xr-x--x

手机内存空间很小了怎么办

手机内存空间很小了怎么办 在有些时候我们的手机内存空间很小了,这该怎么办呢?下面就由小编来为你们简单的介绍手机内存空间很小了的解决方法吧!希望你们喜欢! 手机内存空间很小了的解决方法一: 1、建议您删除一些,不需要的资料,如通话记录、信息、网页浏览记录等。 2、建议您把歌曲、视频等资料存放在外置SD卡中,可以释放手机内存空间。 3、如果以上方式操作还是不行,建议您备份手机资料,然后恢复出厂设置后尝试一下 4、下载的软件,通过“豌豆荚”设置“强制安装到SD卡中”,操作方法: 您可以在电脑上安装一个“豌豆荚”软件,然后把手机的

“USB调试”功能开启,之后用数据线把手机与电脑连接,在连接上“豌豆荚”之后,在“豌豆荚”的设置→手机管理→安装位置选择里面把位置更改成“强制安装到SD卡”,之后用“豌豆荚”软件下载自己需要的软件 第一步ROOT并安装“RE 管理器”。 第二步打开“RE 管理器”??找到“data”??“dalvik-cache”这个文件夹里面的都是系统缓存文件和卸载定制程序留下来的无用记录文件,可以放心全部删除,系统所需文件重启后能自动生成的。 不过重启的时候,时间有点久,就像第一次启动那样,系统启动加载期间,不要有任何操作,要耐心等待......系统启动加载完毕,一切正常。这时候可以看下使用前后手机空间容量对比,会发现手机内存会有大幅度提升(提醒一下,多次使用并没有效果,最好隔一段时间再清理) 第二种方法打开RE管理器,找到/data/local/目录,里面有rights和tmp两个文件夹,如果没有rights文件夹,打开tmp 文件夹,这里面都是大家之前安装失败的软件,然后清空就可以了

如何编写能够在内存中任意地址运行的程序

一般来说,编译连接之后的代码只能在固定的位置(这里的位置是指偏移地址)上执行,如果直接将其拷贝到其他位置(偏移地址跟编译时的地址不同)上运行时会发生不可预料的错误。 这是因为在汇编语言中对静态变量的寻址通常是用直接寻址方式,这种方式直接使用变量的绝对偏移地址,如果被使用的变量也随代码一起被移动到目标地址,那对该变量的访问将会是对一个无效数据的访问。比如下面这段代码: Org 100H Add SI,SI Mov AX,Var1[SI] Ret Var1 DW 0,1,2,3,4,5,6,7,8,9 它的作用是从字数组Var1中取出SI所指的那个节点的数据给AX并返回。这段程序编译后的代码如下: 0F05:0100 03F6 ADD SI,SI 0F05:0102 2E8B840801 MOV AX,CS:[SI+0108] 0F05:0107 C3 RET 0F05:0100 -00 00 01 00 02 00 03 00 ........ 0F05:0110 04 00 05 00 06 00 07 00-08 00 09 00 ............ 注意红色的数字,它就是数组Var1的绝对偏移地址。此时如果我们把子程序GetData拷贝到偏移地址200H处,可以得到如下代码: 0F05:0200 03F6 ADD SI,SI 0F05:0202 2E8B840801 MOV AX,CS:[SI+0108] 0F05:0207 C3 RET 0F05:0200 -00 00 01 00 02 00 03 00 ........ 0F05:0210 04 00 05 00 06 00 07 00-08 00 09 00 ............ 再次注意红色的数字!此时数组Var1已经被移动到偏移地址208H处,而代码中对数组的访问仍然使用的是编译时的偏移地址。如果该处的数据正好被另的模块更改过的话,后果就...... 1

各种内存概念

各种内存概念 这里需要明确的是,我们讨论的不同内存的概念是建立在寻址空间上的。 IBM推出的第一台PC机采用的CPU是8088芯片,它只有20根地址线,也就是说,它的地址空间是1MB。 PC机的设计师将1MB中的低端640KB用作RAM,供DOS及应用程序使用,高端的384KB则保留给ROM、视频适配卡等系统使用。从此,这个界限便被确定了下来并且沿用至今。低端的640KB就被称为常规内存即PC机的基本RAM区。保留内存中的低128KB是显示缓冲区,高64KB是系统BIOS(基本输入/输出系统)空间,其余192KB空间留用。从对应的物理存储器来看,基本内存区只使用了512KB芯片,占用0000至80000这512KB 地址。显示内存区虽有128KB空间,但对单色显示器(MDA卡)只需4KB就足够了,因此只安装4KB的物理存储器芯片,占用了B0000至B10000这4KB的空间,如果使用彩色显示器(CGA卡)需要安装16KB的物理存储器,占用B8000至BC000这16KB的空间,可见实际使用的地址范围都小于允许使用的地址空间。 在当时(1980年末至1981年初)这么“大”容量的内存对PC机使用者来说似乎已经足够了,但是随着程序的不断增大,图象和声音的不断丰富,以及能访问更大内存空间的新型CPU相继出现,最初的PC机和MS-DOS设计的局限性变得越来越明显。 ●1.什么是扩充内存? 到1984年,即286被普遍接受不久,人们越来越认识到640KB的限制已成为大型程序的障碍,这时,Intel和Lotus,这两家硬、软件的杰出代表,联手制定了一个由硬件和软件相结合的方案,此方法使所有PC机存取640KB以上RAM成为可能。而Microsoft刚推出Windows不久,对内存空间的要求也很高,因此它也及时加入了该行列。 在1985年初,Lotus、Intel和Microsoft三家共同定义了LIM-EMS,即扩充内存规范,通常称EMS为扩充内存。当时,EMS需要一个安装在I/O槽口的内存扩充卡和一个称为EMS的扩充内存管理程序方可使用。但是I/O插槽的地址线只有24位(ISA总线),这对于386以上档次的32位机是不能适应的。所以,现在已很少使用内存扩充卡。现在微机中的扩充内存通常是用软件如DOS中的EMM386把扩展内存模拟或扩充内存来使用。所以,扩充内存和扩展内存的区别并不在于其物理存储器的位置,而在于使用什么方法来读写它。下面将作进一步介绍。 前面已经说过扩充存储器也可以由扩展存储器模拟转换而成。EMS的原理和XMS不同,它采用了页帧方式。页帧是在1MB空间中指定一块64KB空间(通常在保留内存区内,但其物理存储器来自扩展存储器),分为4页,每页16KB。EMS存储器也按16KB分页,每次可交换4页内容,以此方式可访问全部EMS存储器。符合EMS的驱动程序很多,常用的有EMM386.EXE、QEMM、TurboEMS、386MAX等。DOS和Windows中都提供了EMM386.EXE。 ●2.什么是扩展内存? 我们知道,286有24位地址线,它可寻址16MB的地址空间,而386有32位地址线,它可寻址高达4GB的地址空间,为了区别起见,我们把1MB以上的地址空间称为扩展内存XMS(eXtend memory)。 在386以上档次的微机中,有两种存储器工作方式,一种称为实地址方式或实方式,

操作系统课设——三种存储管理方式的地址换算

题目三种存储管理方式的地址换算 姓名: 学号: 专业: 学院: 指导教师:姚若龙 2018年11月27日

【目录】 摘要 (01) 引言 (02) 算法设计 (02) 程序分析 (04) 算法分析 (09) 调试结果 (11) 个人总结 (15) 参考文献 (15)

摘要: 操作系统(Operating System,OS)是方便用户、管理和控制计算机软硬件资源的系统软件(或程序集合)。 从用户角度看,操作系统可以看成是对计算机硬件的扩充; 从人机交互方式来看,操作系统是用户与机器的接口;从计算机的系统结构看,操作系统是一种层次、模块结构的程序集合,属于有序分层法,是无序模块的有序层次调用。操作系统在设计方面体现了计算机技术和管理技术的结合。操作系统是系统软件的核心,、它控制程序的执行和提供资源分配、调度、输入/输出控制和数据管理等任务。如DOS、UNIX、OS/2和Windows NT都是得到广泛使用的操作的系统。 三种管理方式中,分页系统能有效地提高内存利用率,分段系统则能很好地满足用户需要,而段页式系统则是把前两种结合起来形成的系统。这种新系统既具有分段系统的便于实现、分段可共享、易于保护、可动态链接等一系列优点,有能像分页系统那样很好地解决内存的外部碎片问题,以及可为各个分段离散地分配内存等问题。 关键字: 分页方式,分段方式,段页式方式,操作系统。

一.引言 分页存储管理是将一个进程的逻辑地址空间分成若干个大小相等的片,称为页面或页。在分段存储管理方式中,作业的地址空间被划分为若干个段,每个段定义了一组逻辑信息。段的长度由相应的逻辑信息组的长度决定,因而个段长度不等。段页式存储管理方式是分段和分页原理的结合,即先将用户程序分成若干个段,再把每个段分成若干个页,并为每一个段赋予一个段名。三种存储管理都有其相应的段表、页表和地址变换机构。 二.三种存储管理方式地址换算描述 (1)分页存储管理方式 在页式存储管理方式中地址结构由两部构成,前一部分是页号,后一部分为页内地址w(位移量),如图 为了实现从进程的逻辑地址到物理地址的变换功能,在系统中设置了页表寄存器,用于存放页表在内存中的始址和页表的长度。当进程要访问某个逻辑地址中的数据时,分页地址变换机构会自动地将有效地址(相对地址)分为页号和页内地址两部分,再以页号为索引去检索页表。查找操作由硬件执行。在执行检索之前,先将页号与页表长度进行比较,如果页号大于或等于页表长度,则表示本次所访问的地址已超越进程的地址空间。于是,这一错误将被系统发现并产生一地址越界中断。若未出现越界错误,则将页表始址与页号和页表项长度的乘积相加,便得到该表项在页表中的位置,于是可从中得到该页的物理块号,将之装入物理地址寄存器中。与此同时,再将有效地址寄存器中的页内地址送入物理地址寄存器的块内地址字段中。这样便完成了从逻辑地址到物理地址的变换。

mips地址空间

就是一个虚拟地址,一个物理地址。一般bootloader会连接到bfc00000,因为在MIPS上运行的程序都使用虚拟地址,而板子上的boot flash一般会被映射到物理地址1fc00000,这样上电时直接取flash的第一条指令,也就是bootloader的第一条指令。 嵌入式u-boot和mips地址空间 1.一个家用路由器的u-boot address space: memstart = 0x80000000, memsize = 0x02000000 flashstart = 0xBF000000, flashsize = 0x00400000 images in flash: u-boot:0xBF000000 ecos: 0xBF050000 linux: 0xBF0C0000 u-boot启动信息: 分析: 1.内存地址范围从0x80000000开始,到0x82000000结束。 2.u-boot被load到内存地址0x81fc0000. 3.启动流程:AP83上电后首先运行flash上面的cpu/mips/start.S这个汇编程序,并没有进入内存。接着,start.S把u-boot的代码段全部copy到内存地址0x81fc0000,并从该地址开始转入内存运行。 2.MIPS的地址空间 1.综述: 一般嵌入式的hardware有两部分存贮器,一个是RAM,另一个是ROM(flash). flash用来存放code,包括操作系统本身,当然也包括bootloader(u-boot). RAM就是相当于PC的内存了,比flash速度快的多,但掉电后会丢失所有数据,所以用作动态内存。 2.MIPS的地址空间: 32位mips的地址空间跟PC一样,是2^32=4G字节。对于嵌入式设备来说,所有的设备的地址都存在于一个地址空间。如下图:flash的地址空间一般放在Kseg1段,而RAM 的地址空间一般则放在kseg0段。

java内存空间详解

硬盘 heap stack Data code 内存 程序 操作系统代码 程序代码 New ,在堆里面为属性分配空间,初始化(String 默认值为null ) 声明的时候非配空间,初始值为null (局部变量,方法参数) 全局变量 存放程序所需要的代码 类变量,全局字符串,常量存放在数据段

Java内存分配与管理是Java的核心技术之一,之前我们曾介绍过Java的内存管理与内存泄露以及Java垃圾回收方面的知识,今天我们再次深入Java核心,详细介绍一下Java 在内存分配方面的知识。一般Java在内存分配时会涉及到以下区域: ◆寄存器:我们在程序中无法控制 ◆栈:存放基本类型的数据和对象的引用,但对象本身不存放在栈中,而是存放在堆中 ◆堆:存放用new产生的数据 ◆静态域:存放在对象中用static定义的静态成员 ◆常量池:存放常量

◆非RAM存储:硬盘等永久存储空间 Java内存分配中的栈 在函数中定义的一些基本类型的变量数据和对象的引用变量都在函数的栈内存中分配。 当在一段代码块定义一个变量时,Java就在栈中为这个变量分配内存空间,当该变量退出该作用域后,Java会自动释放掉为该变量所分配的内存空间,该内存空间可以立即被另作他用。 Java内存分配中的堆 堆内存用来存放由new创建的对象和数组。在堆中分配的内存,由Java虚拟机的自动垃圾回收器来管理。 在堆中产生了一个数组或对象后,还可以在栈中定义一个特殊的变量,让栈中这个变量的取值等于数组或对象在堆内存中的首地址,栈中的这个变量就成了数组或对象的引用变量。引用变量就相当于是为数组或对象起的一个名称,以后就可以在程序中使用栈中的引用变量来访问堆中的数组或对象。引用变量就相当于是为数组或者对象起的一个名称。 引用变量是普通的变量,定义时在栈中分配,引用变量在程序运行到其作用域之外后被释放。而数组和对象本身在堆中分配,即使程序运行到使用new 产生数组或者对象的语句所在的代码块之外,数组和对象本身占据的内存不会被释放,数组和对象在没有引用变量指向它的时候,才变为垃圾,不能在被使用,但仍然占据内存空间不放,在随后的一个不确定的时间被垃圾回收器收走(释放掉)。这也是Java 比较占内存的原因。 实际上,栈中的变量指向堆内存中的变量,这就是Java中的指针! 常量池(constant pool) 常量池指的是在编译期被确定,并被保存在已编译的.class文件中的一些数据。除了包含代码中所定义的各种基本类型(如int、long等等)和对象型(如String及数组)的常量值(final)还包含一些以文本形式出现的符号引用,比如: ◆类和接口的全限定名; ◆字段的名称和描述符; ◆方法和名称和描述符。 虚拟机必须为每个被装载的类型维护一个常量池。常量池就是该类型所用到常量的一个有序集和,包括直接常量(string,integer和floating point常量)和对其他类型,字段和

内存地址的计算方法

内存地址的计算方法 内存是按字节编址的,所以单位是字节哈,1字节可是等于8位的。因为计算的范围一般比较小,所以记住几个常用的就够了: 2的10次方为1024即1KB ; 2的20次方=(2的10次方)的平方,即1MB ;(1024KB) 2的40次方=(2的10次方)的4次方,即1GB 。(1024*1024KB ,或者1024MB) 计算计算内存容量内存容量:DFFFF-A0000 = 3FFFF 一眼看不出来大小滴,或许你要用笔算,不过用这个方法两眼就能看出来: 3FFFF 展开为2进制就是2的18次方,是吧, 即2的10次方乘以2的8次方=1KB*256,即256KB ; 或者,直接2的20次方/2的2次方=2的18次方,一般选就近原则,1MB/4=256KB 32K*8bit=256Kb =(256KB/8bit) 在网上找的另外一道题:计算机SRAM 容量为4K x 8,配置地址首地址为:06800H ,则其末地址是多少 a.38800H B.10800H C.077FFH D.07800H 分析: 公式: =末地址-首地址+1 4K*8bit = 4KB ,即2的平方乘以2的10次方(4*1024),2的12次方(十进制是4096), 方法一:12/4=3(转为16进制(2的4次方)),得出16的3次方,即1000H 方法二:2的12次方(十进制是4096),以此除16取余数,得到1000H 01000H= 末地址 - 6800H + 1H 末地址= 01000H + 6800H -1H 末地址=077FFH 4K*8bit = 4KB ,即2的平方乘以2的10次方(4*1024),2的12次方,内存容量二进制: 0001 0000 0000 0000 即 1000H 末地址=内存容量 + 首地址 - 1 =1000H + 06800H -1 = 07800H – 1 = 077FFH 实例 实例1.若内存按字编址,某存储器的芯片容量为4K*4bit ,用此芯片构成从80000H 到BFFFFH 的内存,要用( 128 )片这样的内存。某RAM 芯片有22条地址线,8条数据线,则该RAM 芯片容量为( 4MB ) 这道题的第二问,只提供了地址线和数据线的个数,如何计算的容量? 2.(2004年5月上午试题47.48)内存地址从4000H 到43FFH ,共有( 1024 )个内存单元。若该内存单元可存储16位二进制数,并用4片存储器芯片构成,则芯片的容量是( 256*16bit )

内存地址映射的认识

内存地址映射的认识(memory map) 内存物理地址为A,即地址A 而物理地址A得地址代码又需要内存来存放,我们设地址A存的地址为地址B 所谓映射就是把存地址A代码的地址B由地址C来来指向地址B,也就是说通过C来间接的指向实际地址A 这就好比一个储藏库为A,地址代码为1111,我把这个地址代码放到B处(B里面放上A的地址代码1111),而B的地址为10000,我在把B的地址10000放到C中(01010),这样C就是对B的映射! 地址映射为了保证CPU执行指令时可正确访问存储单元,需将用户程序中的逻辑地址转换为运行时由机器直接寻址的物理地址,这一过程称为地址映射地址映射原理及实现: 1、地址映射结构 在Tornado\target\h\vmLib.h文件中 typedef struct phys_mem_desc { void *virtualAddr; void *physicalAddr; UINT len; UINT initialStateMask; /* mask parameter to vmStateSet */ UINT initialState; /* state parameter to vmStateSet */ } PHYS_MEM_DESC; virtualAddr:你要映射的虚拟地址 physicalAddr:硬件设计时定义的实际物理地址 len;要进行映射的地址长度 initialStateMask:可以初始化的地址状态: 有如下状态: #define VM_STATE_MASK_VALID 0x03 #define VM_STATE_MASK_WRITABLE 0x0c #define VM_STATE_MASK_CACHEABLE 0x30 #define VM_STATE_MASK_MEM_COHERENCY 0x40 #define VM_STATE_MASK_GUARDED 0x80 不同的CPU芯片类型还有其特殊状态 initialState:实际初始化的地址状态: 有如下状态: #define VM_STATE_VALID 0x01 #define VM_STATE_VALID_NOT 0x00 #define VM_STATE_WRITABLE 0x04 #define VM_STATE_WRITABLE_NOT 0x00 #define VM_STATE_CACHEABLE 0x10 #define VM_STATE_CACHEABLE_NOT 0x00

主板芯片和内存映射

astrotycoon 大道至简,贵在恒久力行

Diagram for modern motherboard. The northbridge and southbridge make up the chipset.

(补充: 北桥芯片用于与CPU、内存和AGP视频接口,这些接口具有很高的传输速率。北桥芯片还起着存储器控制作用,因此Intel把该芯片标号为MCH(Memory Controller Hub)芯片。南桥芯片用来管理低、中速的组件,例如,PCI总线、IDE硬盘接口、USB端口等,因此南桥芯片的名称为ICH(I/O Controller Hub)) As you look at this, the crucial thing to keep in mind is that the CPU doesn’t really know anything about what it’s connected to. It talks to the outside world through its pins bu t it doesn’t care what that outside world is. It might be a motherboard in a computer but it could be a toaster, network router, brain implant, or CPU test bench. There are thre e main ways by which the CPU and the outside communicate: memory address space, I/O address space, and interrupts. We only worry about motherboards and memory for now. 正如你所看到的,其实CPU是完全不知道自己与哪些外部器件相连接的。 CPU仅仅通过自己的引脚与外界沟通,而它并不关心自己是与什么设备在沟通。或许是另一台计算机的主板,或许是烤面包机,网络路由器,脑植入医疗设备,又或许是CPU测试仪。 CPU主要通过三种方式与外界通信:内存地址空间,IO地址空间,和中断。我们目前只关注主板和内存。 In a motherboard the CPU’s gateway to the world is the front-side bus connecting it to the northbridge. Whenever the CPU needs to read or write memory it does so via this b us. It uses some pins to transmit the physical memory address it wants to write or read, while other pins send the value to be written or receive the value being read. An Intel Core 2 QX6600 has 33 pins to transmit the physical memory address (so there are 233 choices of memory locations) and 64 pins to send or receive data (so data is transmitte d in a 64-bit data path, or 8-byte chunks). This allows the CPU to physically address 64 gigabytes of memory (233 locations * 8 bytes) although most chipsets only handle up to 8 gigs of RAM. CPU通过前端总线与北桥芯片连接,作为与外界通信的桥梁。无论何时,CPU都可以通过前端总线来读写内存。 CPU通过一些引脚来传送想要读写物理内存的地址,同时通过另一些引脚来发送将要写入内存的数据或者接收从内存读取到的数据。 Intel Core 2 QX6600 用33个引脚来传送物理内存地址(因此共有233 个内存地址),并且用64个引脚来发送或接收数据(所以数据在64位通道中传输,也就是8字节的数据块)。因此C PU可以访问64G的物理内存(233*8字节),尽管多数芯片组只能处理8G大小的物理内存。 Now comes the rub. We’re used to thinking of memory only in terms of RAM, the stuff programs read from and write to all the time. And indeed most of the memory requests from the processor are routed to RAM modules by the northbridge. But not all of them. Physical memory addresses are also used for communication with assorted devices on t he motherboard (this communication is called memory-mapped I/O). These devices include video cards, most PCI cards (say, a scanner or SCSI card), and also the flash mem ory that stores the BIOS. 那么现在的问题是,通常一提起内存我们仅仅联想到RAM,以为程序一直读写的就只是RAM。的确,绝大多数来自CPU的内存访问请求都被北桥芯片映射到了RAM。但是,注意,不是全部。物理内存同样可以用来与主板上的各种设备通信(这种通信方式被称为I/O内存映射)。这些设备包括显卡,大多数PCI卡(比如,扫描仪,或者是SCSI卡),也包括存储BIOS的flash存储器。 When the northbridge receives a physical memory request it decides where to route it: should it go to RAM? Video card maybe? This routing is decided via the memory addres s map. For each region of physical memory addresses, the memory map knows the device that owns that region. The bulk of the addresses are mapped to RAM, but when the y aren’t the memory map tells the chipset which device should service requests for those addresses. This mapping of memory addresses away from RAM modules causes the c lassic hole in PC memory between 640KB and 1MB. A bigger hole arises when memory addresses are reserved for video cards and PCI devices. This is why 32-bit OSes have pr oblems using 4 gigs of RAM. In Linux the file /proc/iomem neatly lists these address range mappings. The diagram below shows a typical memory map for the first 4 gigs of p hysical memory addresses in an Intel PC:

计算机+计算题公式梳理

计算题公式梳理 1.总线带宽计算:总线带宽(M B/s)=(数据线宽度/8)(B)×总线工作频率(MHz) 2.存储容量= 磁盘面数(磁头数)?磁道数(柱面数)?扇区数?512字节B 3.CPU访问内存空间大小是由 CPU的地址线宽为n决定,那么CPU的寻址大小是2n(B) 平均存取时间T=寻道时间5ms+旋转等待时间+数据传输时间扇区 平均等待时间为盘片旋转一周所需时间的一半 4.内存地址编码 4.1容量=末地址-首地址+1 4.2末地址=容量+首地址-1 5.点阵字存储计算:点阵/8(例:24*24/8,单位B) 6.光驱数据传输速率:倍速*150KB/s 7.进制转换 7.1十转非十:整数(短除求余倒取),小数(乘进制,取整,顺取) 7.2非十转十:按权展开求和(权*基数n-1) 7.32与8关系:一位8进制转为3位2进制,3位2进制转为一位8进制(421法) 7.42与16:一位16进制转为4位2进制,4位2进制转为一位16进制(8421法) 8.二进制算术运算 8.1加法:逢二进一 8.2减法:借一位算二 9.二进制逻辑运算 9.1逻辑或:有1得1,全0得0 逻辑加V 9.2逻辑与:有0得0,全1得1 逻辑乘 9.3异或:相同时为0,不同时为1 10.无符号整数表示:0-[2n-1] 11.有符号整数原码表示:[-2n-1+1,+2n-1-1] 12.有符号整数补码表示:[-2n-1,+2n-1-1] 13.有符号整数二进制原码:该十进制的八位二进制原码,正数最高位置0,负数最高位置1 14.有符号整数二进制补码:该十进制的八位二进制原码后,反码,末尾+1 15.每类IP地址可用主机数量:2主机号二进制位数-2 16.ASCII编码计算:A(65,41H),a(97,61H),两者相差32(20H)

真正彻底释放、手机内存可用空间

手机需 .打开管理器,进入手机目录下,里面全是一些数据文件,不管软件安装在手机或内存卡,都会在这里生成文件,特别是当软件删除后,文件仍然留在此目录下.资料个人收集整理,勿做商业用途 .文件名全部为英文,大家仔细看文件名后看软件是否已经删除,删除了地就可以直接删除文件,每个文件占用空间都比较大,真正彻底释放手机内存可用空间.资料个人收集整理,勿做商业用途 .当然后删除自带地软件里面也是有残留文件地,对准软件名后可以一一删除,如果哪个文件名不知具体是哪个软件,多百度吧.资料个人收集整理,勿做商业用途 .打开管理器,进入手机目录下,里面是一些日志文件,占用地空间也是非常大地,可以全部删除,不过开机后仍然有两三个文件会自动生成,没关系.资料个人收集整理,勿做商业用途 深度清理三星安卓手机各种残留文件,释放手机内存可用空间”教程 、本教程由官方出品,适用所有三星安卓手机:~4.1.2,自己用了久,效果刚刚滴!论坛没人发,我给大家分享一下!资料个人收集整理,勿做商业用途 、深度清理三星安卓手机各种残留文件教程: 、首先,你得要,对于有系统洁癖滴你来说,眼里揉不进沙子呵呵,那是必须装文件浏览器地. 、进入浏览器,然后第二个文件就是了,进入后删除全部即可. 、返回浏览器主页,找到文件夹,进入后往下拉,找到文件夹,进入后删除全部即可,有时候你地手机会因为这样那样滴原因而资料个人收集整理,勿做商业用途 、产生系统错误,就会产生那个高达左右滴文件了. 、接下来,进入刺激滴环节,在浏览器主页面,找到文件夹,往下拉,找到文件夹,进入后你会看到诸多结尾滴文资料个人收集整理,勿做商业用途 、件,有些你通过名字即可判知其所属软件程序.那为啥要清理那些文件呢?因为在你安装软件、游戏后,就好在这个目录下产生文件,资料个人收集整理,勿做商业用途 、而删除软件后,它还存在地而且你可以借助文件浏览器看一下他们滴大小,呵呵,很惊人吧. 、那接下来就是点击最左下角滴虚拟功能键,点击“多选模式”,然后点“全部选择”,点击“删除”即可,接下来要赶紧做地事情就是资料个人收集整理,勿做商业用途 、退出浏览器,迅速关机,否则时间长了就会产生系统错误通知. 、开机后再去看看这些文件,是地,他们又自动生成了! 但是删除软件地那些文件就消失地无影无踪了,这样可以有效清理很多无资料个人收集整理,勿做商业用途 、用地废品,节省空间. 全面清理三星安卓手机各种残留文件教程 首先,你得要,对于有系统洁癖滴你来说,眼里揉不进沙子呵呵,那是必须装文件管理器地. 进入管理器,然后第二个文件就是了,进入后删除全部即可. 返回管理器主页,找到文件夹,进入后往下拉,找到文件夹,进入后删除全部即可,有时候你地手机会因为这样那样滴原因而资料个人收集整理,勿做商业用途 产生系统错误,就会产生那个高达左右滴文件了. 接下来,进入刺激滴环节,在管理器主页面,找到文件夹,往下拉,找到文件夹,进入后你会看到诸多结尾滴文资料个人收集整理,勿做商业用途 件,有些你通过名字即可判知其所属软件程序.那为啥要清理那些文件呢?因为在你安装软件、游戏后,就好在这个目录下产生文件,资料个人收集整理,勿做商业用途

Linux下访问内存物理地址

Linux下访问内存物理地址 by tmsonhsut 2008.4.28 Linux内核里提供的/dev/mem驱动,为我们读写内存物理地址,提供了一个渠道。下面讲述2种利用mem设备文件进行物理地址读写的方法,一种是设备驱动的方法,另一种是系统调用的方法。 首先我们看下mem这个设备文件,/dev/mem是linux下的一个字符设备,源文件是~/drivers/char/mem.c,这个设备文件是专门用来读写物理地址用的。里面的内容是所有物理内存的地址以及内容信息。通常只有root用户对其有读写权限。 1.设备驱动的方法 下面是mem.c文件里定义的file_operations结构,提供了llseek,read,write,mmap以及open等方法。 static structfile_operationsmem_fops = { .llseek = memory_lseek, .read = read_mem, .write = write_mem, .mmap = mmap_mem, .open = open_mem, }; 因此我们可以通过一般驱动的使用方法,将内存完全当作一个设备来对对待。应用程序如下: #include #include int main(void) { intfd; char *rdbuf; char *wrbuf = "butterfly"; int i; fd = open("/dev/mem",O_RDWR); if(fd< 0) { printf("open /dev/mem failed."); } read(fd,rdbuf,10); for(i = 0;i < 10;i++) { printf("old mem[%d]:%c\n",i,*(rdbuf + i)); }

Linux内核空间和用户空间

Linux 操作系统和驱动程序运行在内核空间,应用程序运行在用户空间,两者不能简单地使用指针传递数据,因为Linux使用的虚拟内存机制,用户空间的数据可能被换出,当内核空间使用用户空间指针时,对应的数据可能不在内存中。 Linux内核地址映射模型 x86 CPU采用了段页式地址映射模型。进程代码中的地址为逻辑地址,经过段 页式地址映射后,才真正访问物理内存。 段页式机制如下图。 Linux内核地址空间划分

通常32位Linux内核地址空间划分0~3G为用户空间,3~4G为内核空间。注意这里是32位内核地址空间划分,64位内核地址空间划分是不同的。 Linux内核高端内存的由来 当内核模块代码或线程访问内存时,代码中的内存地址都为逻辑地址,而对应到真正的物理内存地址,需要地址一对一的映射,如逻辑地址0xc0000003对应的物理地址为0×3,0xc0000004对应的物理地址为0×4,… …,逻辑地址与物理地址对应的关系为 物理地址= 逻辑地址– 0xC0000000

么物理地址为0×40000001的内存,内核该怎么去访问呢?代码中必须要有内存逻辑地址的,0xc0000000 ~ 0xffffffff的地址空间已经被用完了,所以无法访问物理地址0×40000000以后的内存。 显然不能将内核地址空间0xc0000000 ~ 0xfffffff全部用来简单的地址映射。因此x86架构中将内核地址空间划分三部分:ZONE_DMA、ZONE_NORMAL和ZONE_HIGHMEM。 ZONE_HIGHMEM即为高端内存,这就是内存高端内存概念的由来。 在x86结构中,三种类型的区域如下: ZONE_DMA 内存开始的16MB ZONE_NORMAL 16MB~896MB ZONE_HIGHMEM896MB ~ 结束 Linux内核高端内存的理解 前面我们解释了高端内存的由来。Linux将内核地址空间划分为三部分ZONE_DMA、 ZONE_NORMAL和ZONE_HIGHMEM,高端内存HIGH_MEM地址空间范围为0xF8000000 ~ 0xFFFFFFFF(896MB~1024MB)。那么如内核是如何借助128MB高端内存地址空间是如何实现访问可以所有物理内存?

相关主题