当前位置:  编程技术>软件工程/软件设计
本页文章导读:
    ▪第七学 linux内核——内存寻址——段机制(1)              x86的段机制是实现程序的逻辑地址到线性地址的映射的一种机制。        我们先介绍实现这个机制的几个组成部件,它包括一些软件.........
    ▪第八学 linux内核——内存寻址——段机制(2)              这节我们讨论linux是如何利用x86结构中的段机制的,更确切的说是如何绕过linux的段机制的。         我们决定从linux的可移植性开始讨.........
    ▪mini2440烧写裸机程序(linux+JLink)      一、编写源代码 源代码: /*******************************led_off.S**************************/ .text .global _start _start:             LDR     R0,=0x56000010  &nb.........

[1]第七学 linux内核——内存寻址——段机制(1)
    来源: 互联网  发布时间: 2013-11-19

        x86的段机制是实现程序的逻辑地址到线性地址的映射的一种机制。

       我们先介绍实现这个机制的几个组成部件,它包括一些软件的东西和一些硬件的东西:硬件的东西有:段寄存器、分段部件、段描述符高速缓冲器;软件的东西有(即几个数据结构):段描述符表、段描述符;另外得知道的两个概念前面已经介绍过了:逻辑地址和线性地址。

       下面我们看段机制是怎么用这些概念实现的。

       由于段寄存器是16位的,所以它不能存储32位的基地址,但是这32位基地址又必须得存,于是我们把这32位基址存储到一块内存中,而把这个地址的索引放段寄存器里边,从而得到段基址,这是大体思路。但x86做得更好。

       我们知道程序都有模块性,一个复杂的大程序总可以分解成多个在逻辑上相对独立的模块或者线程。每个模块都是一个单独的段,都以该段的起点为0相对编址。也就是说,我们得用一个数据结构描述各个段的相关信息,比如该段装进内存的基址(段基址),该段的长度,以及该段是否存在内存中等信息,这个数据结构就是段描述符。言下之意,我们每个模块都有一个段描述符,用来描述该段的属性,而段描述符表其实就是用来盛载这些段描述符的一个表格,一个段描述表可能长这样:

        其中的表项就是段描述符,段描述要存储三个信息:基地址、段长度和段属性。我们用8个字节来存储这三个信息,首先我们说段基址是32位,所以基址占四个字节32位,然后我们用20位来描述段长度。那么这8个字节64位还剩下12位,就用来存储段的属性信息了。

        G:一位,G=0:表示以字节为单位表示段的长度,刚才我们说了我们用20位存储段的长度,那么这样我们段的最大长度就是2^20次方,即1M大小,即我们给程序分段的时候,一个段最大是1M。G=1:表示以4KB表示段的长度,这样我们一个段的最大长度就是2^20次方乘以4KB,即4GB。后边我们会知道linux内核就让这个G等于1,从而直接越过x86的段机制,使逻辑地址没映射线性地址,再映射到物理地址,而是直接映射到物理地址(分页机制)。

        D:一位,表示操作数的位数,D=1表示32位操作数,D=0表示16位操作数,这显然是为向下兼容而设计的。

        接下来两位暂时没用,可留作扩展。

        P:一位,表示这个段是否在内存中,如果我们要把这个段加载进内存,那么在加载进去的时候把这个值修改为1,否则让它等于0。

       DPL:两位,表示段描述符的特权级。

        S:一位,表示这个段是系统段还是用户段。S=0,则为系统段,即内核专门使用的段,S=1,表示用户段,即为程序的代码段、数据段或堆栈段。

       类型占三位:依次是E、D、W。E=0,为数据段描述符,这时D位表示数据的扩展方向,D=0,表示向地址增大的方向扩展,反之,向地址减小的方向扩展。E=1时,直接表示的是数据段,此时W=0时表示数据段不能写(我们就可以想到C++中定义const变量的时候,最后肯定是修改了这个值的),W=1,数据段可写。

        保护模式下,有三种类型的描述符表,分别是全局描述符表(GDT),中段描述符表(IDT),局部描述符表(LDT)。为了加快对这些表的访问,Inter设计了三个专门的寄存器,GDTR、IDTR、LDTT,以存放这些表的基地址和表的长度界限。

      下来我们看段寄存器。我们说过段寄存器存放的就是段描述符在段描述符表中的索引,其实段寄存器还存了另外两个信息,这意味着,我们不能用着16位全部来存储索引值。其实Inter只用了13位来存储段描述符的索引,另外还用1位标志我们是从全局描述符表(GDT)中选择段描述符还是从局部描述符表(LDT)中选择段描述符。剩下两位表示请求者的特权级。

        保护模式提供了4个特权级,用0-3表示。0表示最高特权级,对应内核态,此时它可以访问内核代码,也可以访问用户代码;3表示最低特权级,对应用户态,此时它只能访问用户态代码。

        下面是段机制的硬件构成:

        这样就完成了逻辑地址到线性地址的映射。

作者:bcs_01 发表于2013-5-10 15:35:18 原文链接
阅读:59 评论:0 查看评论

    
[2]第八学 linux内核——内存寻址——段机制(2)
    来源: 互联网  发布时间: 2013-11-19

        这节我们讨论linux是如何利用x86结构中的段机制的,更确切的说是如何绕过linux的段机制的。

        我们决定从linux的可移植性开始讨论。我们说linux是一个广泛移植的操作移动,它支持x86,Alpha,arm等多种体系结构。但是很多的结构其实都是不支持段机制的,比如arm,Alpha等,但是他们都支持分页机制。linux为了能移植到x86上,做了不少工作。

        首先我们说,x86是肯定有段机制的,那么我们要在x86上运行程序,那不可避免要用到段机制。于是我们想到我们先前所想到的段描述符中有一个表示以字节为单位还是以页为单位表示一个段长度的属性位。我们当时说,当G=1时表示以页(4KB)为单位,那么一个段最大长度能到4GB。根据这一点,我们把一个段的段基址固定设置为0,然后让G=1,于是我们一个段的最大长度就是4GB了,呐,这个很显然就能和我们4GB的线性地址空间一一映射了。通过这样的处理,我们说现在x86的段机制已经形同虚设了,逻辑地址和线性地址可以混为一谈了。

        但是x86还规定说,必须为代码段和数据段创建不同的段,所以linux为代码段和数据段分别创建了一个基地址为0,段长度为4GB的段描述符。不仅如此,由于linux内核运行在特权级0,用户程序运行在特权级3,x86规定说特权级为3的用户程序是不能访问特权级为0的内核代码的,所以linux又分别为内核和用户程序分别创建代码段和数据段。

        于是在arch/x86/include/asm/segment.h中这样定义四个段(即在机器启动过程中段寄存器中放的值):

#define __KERNEL_CS     (GDT_ENTRY_KERNEL_CS*8)
#define __KERNEL_DS     (GDT_ENTRY_KERNEL_DS*8)
#define __USER_DS       (GDT_ENTRY_DEFAULT_USER_DS*8+3)
#define __USER_CS       (GDT_ENTRY_DEFAULT_USER_CS*8+3)

        其中:

#define GDT_ENTRY_DEFAULT_USER_CS       14
#define GDT_ENTRY_DEFAULT_USER_DS       15
#define GDT_ENTRY_KERNEL_BASE           (12)
#define GDT_ENTRY_KERNEL_CS             (GDT_ENTRY_KERNEL_BASE+0)
#define GDT_ENTRY_KERNEL_DS             (GDT_ENTRY_KERNEL_BASE+1)

 

        于是上边的定义的结果是下边这样:

#define __KERNEL_CS     0x00C0      /*内核代码段,index=12,TI=0,RPL=0*/
#define __KERNEL_DS     0x00D0      /*内核代码段,index=13,TI=0,RPL=0*/
#define __USER_DS       0x00E3      /*用户代码段,index=14,TI=0,RPL=3*/
#define __USER_CS       0x00F3      /*用户代码段,index=15,TI=0,RPL=3*/

 

        于是我们可以用12,13,14,15四个索引来找到我们四个段所对应的段描述符,并且我们把内核代码段的特权声明为0,用户代码段的特权为3,TI为0表示我们总是访问全局描述符表。

        在我们对应的段描述符中我们把G设置为1,段上限规定为0xfffff,就巧妙的绕过了x86的段机制。

        但在这里我不能忽略的一个问题就是,我们把四个段的上限全部设置为4G,那就完全破坏了段的保护,就是说,我们有可能随随便便就修改了我们的其他段的数据。所幸,我们现在还是个线性地址,所幸此时我们还没把数据装载进内存,因此,我们就有处理这个问题的办法,这就是下面要讲的分页机制了。



 

       

作者:bcs_01 发表于2013-5-10 18:02:10 原文链接
阅读:64 评论:0 查看评论

    
[3]mini2440烧写裸机程序(linux+JLink)
    来源: 互联网  发布时间: 2013-11-19

一、编写源代码

源代码:

/*******************************led_off.S**************************/

.text
.global _start
_start:
            LDR     R0,=0x56000010
            MOV     R1,#0x00015400
            STR     R1,[R0]

            LDR     R0,=0x56000014
            MOV     R1,#0x0df
            STR     R1,[R0]

MAIN_LOOP:
            B       MAIN_LOOP

/*******************************Makefile****************************/

*指定链接文件地址

*指定链接文件顺序

*********************************************************************/

 

led_off.bin : led_off.S
        arm-linux-gcc -g -c -o led_off.o led_off.S
        arm-linux-ld -Ttext 0x0000000 -g led_off.o -o led_off_elf
        arm-linux-objcopy -O binary -S led_off_elf led_off.bin
clean:
        rm -f   led_off.bin led_off_elf *.o

/*******************************************************************/

二、使用Jlink下载led_off.bin到nand flash(参考烧写Uboot方法)

5.1 打开 J-Link Commander,输入-r
5.2 speed 12000
5.3  J-Link Commonder 输入loadbin f:\init.bin 0
5.4  setpc 0
5.5  g
5.5  h
5.6  J-Link Commonder 输入loadbin f:\u-boot.bin_openjtag 0x33f80000
5.7  setpc 0x33f80000
5.8  g
5.9  h
5.10 J-Link Commonder 输入loadbin f:\u-boot.bin  0x30000000
******************************************************************************************
J-Link Commonder 输入loadbin f:\led_off.bin  0x30000000,即可以烧写汇编程序
******************************************************************************************
5.11 g
5.12 h
5.13 在secretcat 中输入nand scrub
5.14 y
5.15 在secretcat 中输入nand erase 0 0x40000
5.16 在secretcat 中输入nand write.jffs2 30000000 0 0x40000
5.17 重新启动进入nand flash

三、开发板重启即可。

 


 

 

作者:z251941074 发表于2013-5-10 18:09:55 原文链接
阅读:86 评论:0 查看评论

    
最新技术文章:
▪主-主数据库系统架构    ▪java.lang.UnsupportedClassVersionError: Bad version number i...    ▪eclipse项目出现红色叉叉解决方案
mysql iis7站长之家
▪第三章 AOP 基于@AspectJ的AOP    ▪基于插件的服务集成方式    ▪Online Coding开发模式 (通过在线配置实现一个表...
▪观察者模式(Observer)    ▪工厂模式 - 程序实现(java)    ▪几种web并行化编程实现
▪机器学习理论与实战(二)决策树    ▪Hibernate(四)——全面解析一对多关联映射    ▪我所理解的设计模式(C++实现)——解释器模...
▪利用规则引擎打造轻量级的面向服务编程模式...    ▪google blink的设计计划: Out-of-Progress iframes    ▪FS SIP呼叫的消息线程和状态机线程
▪XML FREESWITCH APPLICATION 实现    ▪Drupal 实战    ▪Blink: Chromium的新渲染引擎
▪(十四)桥接模式详解(都市异能版)    ▪你不知道的Eclipse用法:使用Allocation tracker跟...    ▪Linux内核-进程
▪你不知道的Eclipse用法:使用Metrics 测量复杂度    ▪IT行业为什么没有进度    ▪Exchange Server 2010/2013三种不同的故障转移
▪第二章 IoC Spring自动扫描和管理Bean    ▪CMMI简介    ▪目标检测(Object Detection)原理与实现(六)
▪值班总结(1)——探讨sql语句的执行机制    ▪第二章 IoC Annotation注入    ▪CentOS 6.4下安装Vagrant
▪Java NIO框架Netty1简单发送接受    ▪漫画研发之八:会吃的孩子有奶吃    ▪比较ASP和ASP.NET
▪SPRING中的CONTEXTLOADERLISTENER    ▪在Nginx下对网站进行密码保护    ▪Hibernate从入门到精通(五)一对一单向关联映...
▪.NET领域驱动设计—初尝(三:穿过迷雾走向光...    ▪linux下的块设备驱动(一)    ▪Modem项目工作总结
▪工作流--JBPM简介及开发环境搭建    ▪工作流--JBPM核心服务及表结构    ▪Eclipse:使用JDepend 进行依赖项检查
▪windows下用putty上传文件到远程Linux方法    ▪iBatis和Hibernate的5点区别    ▪基于学习的Indexing算法
▪设计模式11---设计模式之中介者模式(Mediator...    ▪带你走进EJB--JMS编程模型    ▪从抽象谈起(二):观察者模式与回调
▪设计模式09---设计模式之生成器模式(Builder)也...    ▪svn_resin_持续优化中    ▪Bitmap recycle方法与制作Bitmap的内存缓存
▪Hibernate从入门到精通(四)基本映射    ▪设计模式10---设计模式之原型模式(Prototype)    ▪Dreamer 3.0 支持json、xml、文件上传
▪Eclipse:使用PMD预先检测错误    ▪Jspx.net Framework 5.1 发布    ▪从抽象谈起(一):工厂模式与策略模式
▪Eclipse:使用CheckStyle实施编码标准    ▪【论文阅读】《Chain Replication for Supporting High T...    ▪Struts2 Path_路径问题
▪spring 配置文件详解    ▪Struts2第一个工程helloStruts极其基本配置    ▪Python学习入门基础教程(learning Python)--2 Python简...
▪maven springmvc环境配置    ▪基于SCRUM的金融软件开发项目    ▪software quality assurance 常见问题收录
▪Redis集群明细文档    ▪Dreamer 框架 比Struts2 更加灵活    ▪Maven POM入门
▪git 分支篇-----不断更新中    ▪Oracle非主键自增长    ▪php设计模式——UML类图
▪Matlab,Visio等生成的图片的字体嵌入问题解决...    ▪用Darwin和live555实现的直播框架    ▪学习ORM框架—hibernate(二):由hibernate接口谈...
▪(十)装饰器模式详解(与IO不解的情缘)    ▪无锁编程:最简单例子    ▪【虚拟化实战】网络设计之四Teaming
▪OSGi:生命周期层    ▪Javascript/Jquery——简单定时器    ▪java代码 发送GET、POST请求
▪Entity Framework底层操作封装(3)    ▪HttpClient 发送GET、POST请求    ▪使用spring框架,应用启动时,加载数据
▪Linux下Apache网站目录读写权限的设置    ▪单键模式的C++描述    ▪学习ORM框架—hibernate(一):初识hibernate
 


站内导航:


特别声明:169IT网站部分信息来自互联网,如果侵犯您的权利,请及时告知,本站将立即删除!

©2012-2021,,E-mail:www_#163.com(请将#改为@)

浙ICP备11055608号-3