精华内容
下载资源
问答
  • linux下x86和arm架构区别

    万次阅读 2018-12-24 16:26:04
    1、x86和arm架构定位不同,arm基于精简指令(RISC),本身定位于嵌入式平台,简化了硬件逻辑的设计,减少了晶体管,从而降低功耗,流水线等控制并不复杂,进一步降低了晶体管数量,主要是面对轻量级的、目标明确单一的...

    x86和arm的比较

    问题:两款主频差不多的芯片的移动端平板设备,一个是x86的因特尔i5,一个arm,x86耗电量会大,发热也严重

    分析:

    1、x86和arm架构定位不同,arm基于精简指令(RISC),本身定位于嵌入式平台,简化了硬件逻辑的设计,减少了晶体管,从而降低功耗,流水线等控制并不复杂,进一步降低了晶体管数量,主要是面对轻量级的、目标明确单一的程序,所以主要都是移动端使用;而x86基于复杂指令集CISC,有很多机器指令,只为完成某项专门任务,所以使得硬件逻辑很复杂,加上其他流水线指令集并行、超线程、虚拟化等,复杂度很高,晶体管数量庞大,主要定位计算密集场景,例如多媒体编辑、科研计算等,所以将x86和arm在移动端环境比较并不准确

    2、arm是为了低功耗,x86是为了高性能

     

    CISC和RISC的比较

    (一)CISC

    1. CISC体系的指令特征

    1) 使用微代码。指令集可以直接在微代码存储器(比主存储器的速度快很多)里执行,新设计的处理器,只需增加较少的电晶体就可以执行同样的指令集,也可以很快地编写新的指令集程序。

    2) 庞大的指令集。可以减少编程所需要的代码行数,减轻程序员的负担。高级语言对应的指令集:包括双运算元格式、寄存器到寄存器、寄存器到存储器以及存储器到寄存器的指令。

    2. CISC体系的优缺点

    1) 优点:能够有效缩短新指令的微代码设计时间,允许设计师实现 CISC 体系机器的向上兼容。新的系统可以使用一个包含早期系统的指令超集合,也就可以使用较早电脑上使用的相同软件。另外微程序指令的格式与高级语言相匹配,因而编译器并不一定要重新编写。

    2) 缺点:指令集以及芯片的设计比上一代产品更复杂,不同的指令,需要不同的时钟周期来完成,执行较慢的指令,将影响整台机器的执行效率。

    (二)RISC

    1. RISC体系的指令特征

    1) 精简指令集:包含了简单、基本的指令,通过这些简单、基本的指令,就可以组合成复杂指令。

    2) 同样长度的指令:每条指令的长度都是相同的,可以在一个单独操作里完成。

    3) 单机器周期指令:大多数的指令都可以在一个机器周期里完成,并且允许处理器在同一时间内执行一系列的指令。

    2. RISC体系的优缺点

    1) 优点:在使用相同的芯片技术和相同运行时钟下,RISC 系统的运行速度将是 CISC 的2~4倍。由于RISC处理器的指令集是精简的,它的内存管理单元、浮点单元等都能设计在同一块芯片上。RISC 处理器比相对应的 CISC 处理器设计更简单,所需要的时间将变得更短,并可以比CISC处理器应用更多先进的技术,开发更快的下一代处理器。

    2) 缺点:多指令的操作使得程序开发者必须小心地选用合适的编译器,而且编写的代码量会变得非常大。另外就是RISC体系的处理器需要更快的存储器,这通常都集成于处理器内部,就是L1 Cache(一级缓存)。

    综合上面所述,若要再进一步比较CISC与RISC之差异,可以由以下几点来进行分析:

    1. 指令的形成:CISC 因指令复杂,故采用微指令码控制单元的设计,而RISC的指令90%是由硬件直接完成,只有10%的指令是由软件以组合的方式完成,因此指令执行时间上RISC较短,但RISC所须ROM空间相对的比较大,至于RAM使用大小应该与程序的应用比较有关系。

    2. 寻址模式:CISC的需要较多的寻址模式,而RISC只有少数的寻址模式,因此CPU在计算存储器有效位址时,CISC占用的汇流排周期较多。

    3. 指令的执行:CISC指令的格式长短不一,执行时的周期次数也不统一,而RISC结构刚好相反,故适合采用流水线处理架构的设计,进而可以达到平均一周期完成一指令的方向努力。显然的,在设计上RISC较CISC简单,同时因为CISC的执行步骤过多,闲置的单元电路等待时间增长,不利于平行处理的设计,所以就效能而言RISC较CISC还是占了上风,但RISC因指令精简化后造成应用程式码变大,需要较大的存储器空间,且存在指令种类较多等等的缺点。

    展开全文
  •  面向A R M 微处理器构架的嵌入式操作系统的使用量将在今后五年持续增长,在各种嵌入式操作系统中,Linux是获得支持最多的第三大力量。  目前,ARM Linux 支持包括A R M 6 1 0 、A R M 7 1 0、A R M 7 2 0 ...
    一. 前言
          面向A R M 微处理器构架的嵌入式操作系统的使用量将在今后五年持续增长,在各种嵌入式操作系统中,Linux是获得支持最多的第三大力量。

          目前,ARM Linux 支持包括A R M 6 1 0 、A R M 7 1 0、A R M 7 2 0 Tcores、ARM920T cores、StrongARM110、StrongARM 1100、XScale 等系列的 ARM 处理器。这些处理器都具有M M U 单元,与之相对应是NO MMU 的uClinux,主要是支持ARM7TDMI 系列的微处理器。在ARM Linux 的基础上,很多开发者将其移植到了自己的硬件平台上,并提交相应的 Machine Type。

    本文以实例分析完整地介绍了移植的过程,对于准备在 ARM Linux 上做应用开发的技术人员有一定的借鉴作用。

    二. ARM Linux 的移植过程

    将ARM Linux 移植到特定的硬件平台上,大致需要分成四个步骤:
                        1)首先是准备工作,包括下载源码、建立交叉编译环境等;
                        2)然后是配置和编译内核,必要时还要对源码做一定的修改;
                        3)第三步就是需要制作 RAM disk 来挂接根文件系统;
                        4)最后是下载、调试内核并在 RAM disk中添加自己的应用程序

    本文以StrongARM 为例,说明如何将 ARM Linux 移植到 SA1110 微处理器上。
    下面分四个部分介绍移植工作:

    1.内核源码及交叉编译环境的准备
    2.ARM Linux 的内核配置与编译
    3.制作RAM Disk
    4.内核下载和运行

    1.内核源码交叉编译环境和准备

    1.1 内核源码下载

         标准Linux 的内核源码可以从ftp://ftp.kernel.org 下载,在很多的镜像ftp 站点上也可以方便地获得,建议使用 2.4 版本的内核。ARM Linux 是基于标准Linux、内核为ARM 做的补丁,在ftp://ftp.arm.linux.org.uk上可以下载。当然也可以直接下载已经针对标准内核打好补丁的ARM Linux源码包,例如 SkyEye 上提供的 linux-2.4.18-rmk7.tar.bz2,就是基于 2.4.18内核和 rmk7 补丁,可以直接解压之后进行编译。

    1.2 交叉编译环境的建立

         移植前需要在宿主机上建立ARM 的交叉编译环境,主要用到的开发工具包括三个部分:binutils、gcc、glibc。其中,binutils 是二进制文件的处理工具;gcc 是编译工具;glibc 是链接和运行库。所有需要用到的工具既可以下载源码自行编译,也可以直接下载已经编译好的二进制工具。

    1.2.1. binutils 的安装

         binutils主要包含了一些辅助开发工具,例如objdump显示反汇编码、nm列出符号表、readelf显示elf文件信息及段信息、strip将不必要的代码去掉以减少可执行文件大小等。这些工具在嵌入式开发初期,尤其是移植调试操作系统时非常有用。

    安装的步骤:
    1) 下载安装包文件: binutils-2.11.2.tar.gz;

    2) 解开安装包到当前目录下:
          tar  zxf  binutils-2.11.2.tar.gz,此时在当前目录下生成一个 binutils-2.11.2目录。

    3) 配置安装包:./configure --target=arm-linux --prefix=/usr/local
         target 选项表示选定的目标代码格式,一般是 arm-linux,prefix 表示在执行 make install 时的安装根路径。

    4) 编译和安装:make、make install
        注意安装时可能需要 root 权限,在prefix目录下当前用户有写权限,安装成功后,binutils工具将安装在/usr/local/arm-linux 目录下。


    1.2.2. gcc 交叉编译器

         gcc 是用来编译内核代码的工具,使用它可以编译汇编语言和C语言的程序,生成ARM的代码。建议使用gcc 2.95以上的版本来创建ARM开发环境,本文使用2.95.3版本。
    安装的步骤:

    1) 下载安装包文件和补丁程序:gcc-2.95.3.tar.gz;gcc-2.95.3.diff.bz2

    2) 解开安装包到当前目录下:
        tar zxf gcc-2.95.3.tar.gz,此时在当前目录下生成一个 gcc-2.95.3 目录,进入该目录。

    3) 对当前的安装包打补丁:
        bzcat ../gcc-2.95.3.diff.bz2 | patch -p1。

    4) 修改 gcc/config/arm/t-linux 文件,在文件最后加上如下条件编译选项:
        T_CFLAGS = -Dinhibit_libc  -D__gthr_posix_h。

    5) 配置安装包:./configure --target=arm-linux --prefix=/usr/local  --with-headers=arm linux源码目录下的include目录。
        这里前两个选项和上面binutils的安装类似,--withheaders是用来指定内核头文件的目录,一般就可以使用上面ARM linux的include目录。需要注意的是这里的路径需要用全路径名,而不能使用相对路径。

    6 ) 编译源码:make LANGUAGE=“C ”
        这里因为还没有一个ARM可用的glibc,所以只能编译C 语言的交叉编译工具。如果在编译好 glibc 之后,就可以回来重新编译gcc,以支持其他语言。

    7) 安装编译好的工具:make install LANGUAGE=“C”
        安装成功以后,arm-elf-gcc将安装在/usr/local/arm-linux目录下。有了安装好的binutils和gcc工具,就可以用来编译ARM Linux内核了。如果需要在ARM Linux 做应用程序的开发,就还需要一个glibc库的支持。

    1.2.3. glibc 库

           glibc 的编译需要为刚才做好的ARM 交叉编译器指定编译器;否则编译出的glibc代码将会是同时有ARM和 x86代码的混和体。

    2.ARM Linux 的内核配置与编译
    1) 解开安装包:tar zxf glibc-2.2.3.tar.gz。
        此时在当前目录下生成一个 glibc-2.2.3 目录,进入该目录。

    2) 解开glibc-linuxthreads安装包: tar  zxvf  ../glibc-linuxthreads-2.2.3.tar.gz

    3) 设置编译器: CC=arm-linuxgcc

    4) 配置安装包: ./configure arm-linux --build=i586-linux --prefix=/usr/local/arm-linux -enable-add-ons
          arm-linux 表示选 ELF 格式的可执行格式,--build=i586-linux 表示用来制作交叉开发环境的宿主机的机器类型,--prefix=/usr/local/armlinux表示安装的路径,这里不能指定为/usr/local,否则会把 /usr/local下的库覆盖掉,需要非常留意。

    5) 编译和安装: make; make install
         安装成功后,glibc 库将安装在/usr/local/arm-linux 目录下。

    3. 制作RAM disk(RamDisk也就是内存盘的意思)
         所谓的RAM disk,实际上是把系统内存划出一部分当作硬盘使用。对于操作系统来讲内存的存取速度远远大于机械磁盘,所以RAM驱动器肯定要比机械的硬盘快得多。你可以把整个应用程序都安装在RamDisk的驱动器中,然后用内存的速度运行它.

        ARM Linux采用RAM disk的方式来装载根文件系统,所有在运行内核之前,需要先制作RAM disk,将必须的文件和设备加入到RAM disk中,当内核启动后,会从指定地址去读取根文件系统,这里我们使用RAM disk,在内存中虚拟一个磁盘,具体方法如下:

    1)首先创建一个512k的虚拟磁盘,文件名为initrd.img:
        dd if=/dev/zero of=initrd.img bs=1k count=512

    2)将虚拟磁盘文件格式化成ext2文件系统格式:
         mkfs.ext2 -c initrd.img
       这就生成了一个支持ext2文件系统的ramdisk

    3)添加文件和设备
        mount这个文件系统到/tmp下,mount -o loop -t ext2 initrd.img /tmp

    4)向/tmp中添加linux启动必须的文件和设备
        /bin/sh 
        /bin/init
        /dev/console 
        /etc/rc 
        /etc/motd
    以上这几个程序和设备是启动Linux必须的,这样得到的ram disk大约是400k。


    代码:针对这几个目录的解释(感谢david的搜集整理)
    .
    /bin/sh (/bin/sh是一个SHELL,用来启动系统时执行很多脚本程序的)
    /bin/init init进程的启动程序,在核内引导完成后,LINUX KERNEL都会执行/sbin/init,/etc/init or /bin/init
    /dev/console 是系统控制终端,可以理解为console指向激活的那个tty(准确地说是激活的那个tty才将输出显示到console) 
    /etc/rc 当改变服务的运行级别时,此文件负责启动/停止服务
    /etc/motd  在管理员希望向 Linux 服务器的所有用户传达某个消息时使用,比如登陆时会打印出来 这里面的内容

    4.内核的下载和执行
    4.1.内核下载
         内核的下载一般通过bootloader来完成的,当然也可以通过修改arch/arm/Makefile文件来设置自己的TEXTADDR;TEXTADDR的值在make时传递给arch/arm/vmlinux.lds,在链接时,arm-linux-ld将使用vmlinux.lds来定位内核的起始地址。

    如果是压缩的内核,则可以在make menuconfig时,选择General setup->
             Compressed boot loader in ROM/flash
            (0) Compressed ROM boot loader base address
            (c0000000) Compressed ROM boot loader BSS address

    这里缺省的Compressed ROM boot loader base address是0。

    4.2. RAM disk下载

         RAM disk的下载也是通过bootloader来完成的,它的下载底子好是在内核源码文件arch/arm/machsa1100/assaber.c中定义的,在fixup_addabet()函数中设置了:
         t->u.initrd.start = 0xc0800000;
           t->u.initrd.size = 3 * 1024 * 1024;

    我们制作的ram disk只有512k,所以需要修改t->u.initrd.size = 512 * 1024;下载地址为0xc0800000

    4.3 内核运行
       根据硬件情况修改源码编译之后,就可以通过bootloader下载执行了,内核运行时会通过串口向主机上的超级终端输出启动信息;当ARM linux启动并进入shell之后,就可以运行用户编写的应用程序了,添加自己的应用一般分为两个步骤:
        1)交叉编译得到应用程序的可执行文件(elf格式)
        2)将该可执行文件添加到ram disk中
        
       【全文完】

    原文地址:http://bbs.21ic.com/icview-303600-1-1.html

    展开全文
  • 由于鲲鹏的流行趋势,尝试基于arm的mysql安装 网上很多教程缺斤少两,总是差点意思,亲测后总结一下内容 此教程仅适用于mysql5版本,大于mysql5版本不确保正确 下载地址为:...

    由于鲲鹏的流行趋势,尝试基于arm的mysql安装

    网上很多教程缺斤少两,总是差点意思,亲测后总结一下内容

    此教程仅适用于mysql5版本,大于mysql5版本不确保正确

    下载地址为:https://obs.cn-north-4.myhuaweicloud.com/obs-mirror-ftp4/database/mysql-5.7.27-aarch64.tar.gz
    1. 添加mysql用户组和mysql用户,用于隔离mysql进程
    [root@arm ~]# groupadd -r mysql && useradd -r -g mysql -s /sbin/nologin -M mysql
    2.安装依赖库
    [root@arm ~]# yum install -y libaio*
    3. 下载解压Mysql
    [root@arm ~]# wget https://obs.cn-north-4.myhuaweicloud.com/obs-mirror-ftp4/database/mysql-5.7.27-aarch64.tar.gz
    [root@arm ~]# tar xvf mysql-5.7.27-aarch64.tar.gz -C /usr/local/
    4.配置Mysql
    [root@arm ~]# mv /usr/local/mysql-5.7.27-aarch64 /usr/local/mysql
    [root@arm ~]# mkdir -p /usr/local/mysql/logs
    [root@arm ~]# chown -R mysql:mysql /usr/local/mysql
    [root@arm ~]# ln -sf /usr/local/mysql/my.cnf /etc/my.cnf
    [root@arm ~]# cp -rf /usr/local/mysql/extra/lib* /usr/lib64/
    [root@arm ~]# mv /usr/lib64/libstdc++.so.6 /usr/lib64/libstdc++.so.6.old
    [root@arm ~]# ln -s /usr/lib64/libstdc++.so.6.0.24 /usr/lib64/libstdc++.so.6

    # 设置开机启动
    [root@arm ~]# cp -rf /usr/local/mysql/support-files/mysql.server /etc/init.d/mysqld
    [root@arm ~]# chmod +x /etc/init.d/mysqld
    [root@arm ~]# systemctl enable mysqld
    5. 添加环境变量
    [root@ecs-arm ~]# vi /etc/profile
    export MYSQL_HOME=/usr/local/mysql
    export PATH=$PATH:$MYSQL_HOME/bin

    [root@ecs-arm ~]# source /etc/profile

    随机密码初始化登录
    # "–initialize"生成随机密码,在这里存储在/usr/local/mysql/logs/mysql-error.log
    [root@ecs-arm ~]# mysqld --initialize --user=mysql --basedir=/usr/local/mysql --datadir=/usr/local/mysql/data
    [root@ecs-arm ~]# systemctl start mysqld
    [root@ecs-arm ~]# systemctl status mysqld
    # 查看随机密码
    [root@ecs-arm ~]# cat /usr/local/mysql/logs/mysql-error.log | grep password

    6.登录mysql修改密码(需要输入随机密码)

    [root@localhost /]#  mysql -u root -p
    Enter password:
    mysql>set password for root@localhost = password('NiDeMiMaPassWord'); ----注意最结束符分号一定要写

    7.开放远程连接

    mysql>use mysql;
    msyql>update user set user.Host='%' where user.User='root';
    mysql>flush privileges;

    展开全文
  • linux系统arm架构的CPU与Cache

    千次阅读 2017-04-22 08:06:21
    【摘要】【写作原因】【问题构造】【分析一】总体流程【分析二】get_free_pages与mmap...无论是arm还是powerpc、mips、x86等,提高memory的访问速度都是cpu提高自身性能的重要手段,cache由此而来;无论是Linux还...

    【摘要】

    【写作原因】

    【问题构造】

    【分析一】总体流程

    【分析二】get_free_pages与mmap

    【分析三】CPU与TLB

    【分析四】cpu与L1cache

    【分析五】cpu与L2cache

    【总结】


    注意:请使用谷歌浏览器阅读(IE浏览器排版混乱)


    【摘要】

    无论是arm还是powerpcmipsx86等,提高memory的访问速度都是cpu提高自身性能的重要手段,cache由此而来;无论是Linux还是windows操作系统,充分利用cpu特性,提高系统性能都是不错选择,就像进程上下文切换中页表的切换是linuxMMU的完美利用。性能是软件永恒的主题,了解MMU对软件开发者来说,显得至关重要。那么memorycache是如何工作的?什么是cpu的一级缓存、二级缓存?全相连cache,组相连cache有什么优缺点,如何加以利用?本文将以一个常见的cache问题,剖析一下linux系统对arm架构MMU机制的支持。

    【写作原因】
    1  为了方便自己日后回顾知识点,同时也希望对想了解cache的朋友提供一点参考。
    2  cache问题较为常见,而且合理利用cache能提高软件性能,了解cpu与cache的关系很重要。

    【问题构造】

    首先,我们构造一个常见的cache问题:
    第一步:内核态申请一段内存:
    virt_svc=__get_free_pages(GFP_KERNEL | GFP_DMA,order);
    说明:
    1)也可以使用kmalloc/alloc_pages等接口申请;
    2)此时申请到的virt_svc是内核态的线性地址。 
    第二步: 内核态将第一步中申请到的virt_svc转换为物理地址:phy_addr=virt_to_phys(virt_svc);
    第三步:用户态进程通过mmap,将第二步申请到的物理地址,映射到进程用户态地址空间中。
    fd= open("/dev/mem", O_RDWR|O_DSYNC,0);
    virt_user = mmap(NULL,len,PROT_READ|PROT_WRITE,MAP_SHARED,fd,phy_addr);
    mmap将第二步申请到的物理内存phy_addr映射到了用户态进程地址空间virt_user,映射区间长度为len
    注意:
    1) virt_user地址是uncached.
    原因: open("/dev/mem", O_RDWR|O_DSYNC,0)时,指定了O_DSYNC标记,进而字符驱动mem在为virt_user创建页表时会将页表项的C位置0.此处可以参考内核代码:drivers/char/mem.c,在此不再赘述。
    第四步:将第一步申请到的virt_svc赋值0x12121212;再将第三步的user_virt赋值为
    0x34343434;跟踪user_virt这段内存,很可能被修改。
    以上构造了一个非常典型的cache问题,问题原因也简单,在此不过是想通过该问题引出本文的主题,接下来我们同样以分析问题的形式逐步介绍下arm架构中的CPU与缓存。

    【分析一】总体流程

    要想知道内存上的数据是如何改变的,首先要知道cpu是如何访问内存上数据的。本文讨论armv6架构,下图很好诠释了cpu访问memory的过程,所做的实验也都是基于该图:

             
    说明:

    1.cpu发出virtual address请求时,首先进行的是addresstranslation这一步实际上就是我们常说的TLBtranslation lookaside buffer)。TLB其实也是一块缓存,但它不同于l1l2cache,它是MMU用于缓存页表项的一块区域。此处默认读者对分页机制有所了解,在此不做赘述。关于分页机制可以参考博文:linux内核是如何实现分页机制的 。

    其实,如果不了解这一过程也不妨碍本文的理解。可以简单认为,cpu通过这一过程获取了页表项,知道了VA对应的物理内存基地址和C/B位,后文也会有介绍。C/B bit很重要直接关系到了l1l2cache的访问方式。

    2.cpu是否访问l1l2 cache由上文提到的C/B bit决定。这很关键,后续分析中也会有所涉及。先假设cpu需要访问cache,是如何访问的,后文会有详细解读。总之,cpucache中获取了数据。

    3.如果C/B位中配置页表项为非cache的,或者cache访问时没有命中,则cpu直接发出物理内存访问请求。

    下面就以分析问题的形式,介绍一下linux内核中cache的相关软件实现。
    【分析二】get_free_pages与mmap
    1 __get_free_pages(GFP_KERNEL | GFP_DMA,order)
    .首先要说清楚软件中使用的内存从何而来,这对分析问题至关重要。_get_free_pages是linux系统中常见的申请内存的方式。大家是否清楚它申请的内存从何而来,又具备怎样的特征?
    观察这两个标记GFP_KERNEL | GFP_DMA。在linux中,通常包括ZONE_DMA/ZONE_NORMAL/ZONE_HIGHMEM 等zone_type:
    1)ZONE_DMA:主要用于兼容早期只能在0-16M做DMA映射的device。很多平台上没有使用。
    2)ZONE_HIGHMEM一般是32位系统上使用超过896MB内存,内核线性地址区间不足以映射所有地址。S2平台也没有使用
    3)ZONE_NORMAL:正常的低端地址,很多平台使用,该函数实际上是从ZONE_NORMAL中申请的页框。ZONE_NORMAL对应linux内核中的低端内存区。
    二 Linux系统启动过程中,配置低端内存页表项的方法可以参考博文linux内核是如何实现分页机制的
    总之linux内核在mem_types中定义了初始页表项属性:
    prot_pte  = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY。
    其实在内核启动过程中build_mem_type_table(),还会根据不同arm版本做调整,s2中将低端内存cache配置为写回模式。
    #define L_PTE_MT_WRITEALLOC (_AT(pteval_t, 0x07) << 2);
    三 由以上两点分析出结论如下:
    1)__get_free_pages申请到的内存,在内核态线性地址空间中对应的页表项具有回写属性。
    实验:在内核态下,尝试把__get_free_pages申请到的内存的页表项属性修改为 uncached(在ioremap_page_range中实现):
    实验结论:理论上该实验是可以解决问题的,但实验结果仍然失败了,为什么?因为linux kernel不允许对已经建立页表的低端内存进行再次映射。
    不过 ,也不是没有其他方法进行该实验,可以参照linux的经典做法,把低端内存,映射到高端内存区即vmalloc区,在此过程中修改页表项属性。具体实现可以参照内核接口: __dma_alloc_remap()–>ioremap_page_range() 因为最后定位了问题,所以该实验没有继续做。
    2)ioremap函数
    #define ioremap(cookie,size) __arm_ioremap((cookie), (size), MT_DEVICE)
    #define ioremap_nocache(cookie,size)__arm_ioremap((cookie), (size), MT_DEVICE)
    #define ioremap_cached(cookie,size) __arm_ioremap((cookie), (size), MT_DEVICE_CACHED)
    观察上面ioremap函数mtype,都为MT_DEVICE,这是驱动专用的设备物理内存范围,也是cpu地址线的范围,并不对应真正的dram内存,。此处讨论低端内存为mtype=MT_MEMORY.
    2 mmap系统调用。
    用户进程通过mmap把__get_free_pages申请到的内存映射到用户空间进行使用,本文提到的核心问题就是用户映射后,内存上的数据被篡改。对于linux标准的/dev/mem来说,mmap->mmap_mem:
    其中,打开设备时,open("/dev/mem", O_RDWR|O_DSYNC,0); O_DSYNC 标记会把vm_page_prot指定为uncached/unbufferd.
    尽管我们实现过程中没有使用标准的/dev/mem,而是自己实现了一个驱动。但设计思想没有改变。都是通过remap_pfn_range为物理地址在用户空间创建页表。
    实验:在mmap前后进行cache无效,cache关闭等实验,目的就是验证remap_pfn_range是否创建出nocachede页表项。具体见下面代码截图。
    结论:mmap过程没有问题。
    经过上述实验,有两点怀疑
    1) 用户的remap过程有问题。
    2) 实验方法有问题,即对cache的操作有问题。所以继续探究下cpu与l1-cache、l2-cache的关系。分析之前,简单介绍一下TLB过程。
    【分析三】CPU与TLB
    1 TLB虽然不是所讨论问题的直接原因,但它是MMU过程的重要一环,同时在做了几个cache相关实验,仍不能定位问题所在时,曾经怀疑到了TLB机制,也做了简单的实验排除疑惑。因此,简单介绍下实验过程,以作记录。
    分析过程:几个cache相关实验后(具体见下文),开始怀疑并非cache问题。是否因为:
    1)不同进程虽然各自都为 同一段物理内存做分页映射,但进程的虚拟地址空间是一样的。同一virtual address对应多个页表项,而TLB却没有更新导致TLB查找到的页表项不是当前进程的映射的。
    即相同的虚拟地址对应不同的物理地址,造成TLB出错。
    linux内核启动之初,就已经为内核态线性地址指定了页全局目录的基地址,即TTB。而且进程上下文切换时使用各自不同的ttb。ttb定义如下:
    /*
     * swapper_pg_dir is the virtual address of the initial page table.
     * We place the page tables 16K below KERNEL_RAM_VADDR.  Therefore, we must
     * make sure that KERNEL_RAM_VADDR is correctly set.  Currently, we expect
     * the least significant 16 bits to be 0x8000, but we could probably
     * relax this restriction to KERNEL_RAM_VADDR >= PAGE_OFFSET + 0x4000.
     */
    
    /* 形如0x80008000或0xc0008000 */
    #define KERNEL_RAM_VADDR (PAGE_OFFSET + TEXT_OFFSET)
    #define PG_DIR_SIZE 0x4000
    #define PMD_ORDER 2
    
    
      /* 
    
       1)内核中页全局目录的基地址swapper_pg_dir为形如0x80004000或0xc0004000 
    
       2)每个进程的页全局目录地址(task_struct->pgd)上的内容,内核态的部分都是从swapper_pg_dir地址上拷贝的。
    
      */
    
     .globl swapper_pg_dir
    
     .equ swapper_pg_dir, KERNEL_RAM_VADDR - PG_DIR_SIZE
    其实,分析至此,笔者否定了自己的推论,因为清楚MMU的一个重要功能就是处理以上所怀疑的问题。即便如此,还是做了如下实验,进程remap_pfn_range物理地址的过程中刷一次TLB:
    int remap_pfn_range(struct vm_area_struct *vma, unsigned long addr,
          unsigned long pfn, unsigned long size, pgprot_t prot)
    {
     pgd_t *pgd;
     unsigned long next;
     unsigned long end = addr + PAGE_ALIGN(size);
     struct mm_struct *mm = vma->vm_mm;
     int err;
    
    
     do {
      next = pgd_addr_end(addr, end);
      err = remap_pud_range(mm, pgd, addr, next,
        pfn + (addr >> PAGE_SHIFT), prot);
      if (err)
       break;
     } while (pgd++, addr = next, addr != end);
    
     /*在此添加flush tlb操作*/
    
     flush_tlb_all();
    
     return err;
    }
    与预期的结果一致,没有找到问题原因。不过还是作为一次实验记录下来。
    2 MMU的TLB过程简介:
        
    ps:
    1 tlb过程以上文的ttb为基地址,以我们操作的虚拟地址的最高几个bit(比如12位)为索引,找到指定虚拟地址对应的页一级目录描述符的物理地址:
    2 页一级目录描述符地址上保存了页二级目录描述符基地址,再根据虚拟地址的索引页找到指定地址的页二级目录描述符的物理地址;以此类推,最后找到指定虚拟地址对应的物理地址。
    在此只是简单介绍下,有兴趣可以参考arm手册。
    【分析四】cpu与L1cache
    一.L1-cache又称内部cache,有32k指令cache和32k数据cache组成,通过CP15进行控制。下面以s2平台为例,介绍下cache访问过程。
    为了更好的理解,重新明确一下cache的几个概念:
    写通cache(write-through):
    cpu发出写信号时,也写入主存,保证主存能同步更新。优点是操作简单,但由于访问主存速度慢,降低了系统系能。
    回写式(write-back):
    Cpu发出写信号时,数据一般写到cache上,当 cache中dirty标志位设置时,才回写到内存。
    轮转策略与随机策略:
    当一个cache访问失效时,cache控制器会从当前有效行中取出一个cache行存储从主存获取的信息,被选中替换的cache行,如果drity位为1,则回写到主存,而替换策略决定了哪个cache line会被替换。轮转策略就是取当前cache 行的下一行替换;随机策略是控制器随机选择。
    Cache类型
    1 PIPT 一般用于D cache即数据cache与指令cache相对。
    这种类型避免上下文切换时要flush cache,但是由于皆采用物理地址,每次判断命中都必须进行地址转换,速度较慢。
    2 VIVT 老式缓存
    避免cache命中后地址转换,但上下文切换后地址映射改变,必须flush cache,效率不高。
    3 VIPT 新式cache
    Cache通过index查询到正确set时,TLB可以完成虚拟地址到物理地址转换,在cache比较tag时,物理地址已经准备就绪,也就是说physical tag 可以和cache并行工作,虽然延迟不然VIVT但是不需要上下文切换时flush cache.
    为了验证问题,尝试mmap后把cache disable掉,注意不是invalid cache即无效cache,因为invalid只是清除当前cache line的有效位,并未真正的关掉cache。

    二:关闭l1cache

    1)参考代码如下,主要实现关闭l1cache

    void disabel_l1_cache()
    {
    	u32 value=0;
    	flush_cache_all();
    	asm("mrc p15,0,%0,c0,c0,1 @get CR":"=r"(value)::"cc");
    	/*
    	获取cache type  (0x83338003)
    	*/
    	__asm__ __volatile__(
    		"mrc p15,0,%0,c1,c0,0":"=r"(value):);   
    	/*
    	实验:关闭 l1cache的icache和dcache;
    	bit12:icache enable/disable = 1/0;
    	bit2dcache enable/disable=1/0
    	*/
    	value &=(~0x1004);
    	__asm__ __volatile__(
    		"mcr p15,0,%0,c1,c0,0":"=r"(value):);   
    	flush_cache_all();
    	isb();
    	/* 判断上面mcr是否成功 */
    	__asm__ __volatile__(
    		"mrc p15,0,%0,c1,c0,0":"=r"(value):);   
    }
    注意,根据cp15 register1 进行上述实验。

    结论:cache不能完全关闭,Dcache一旦关闭,系统会卡死。

    2)cp15 register1描述,笔者是通过这个寄存器关闭的l1cache.

    参考disable_l1_cache,实际上是控制bit2和bit13 实现的l1 cache关闭。

    3)Cp15-register0: cache type描述。

    本节主要介绍cache type寄存器的格式,可以通过该寄存器获取cache类型,大小,cache line长度等信息。本部分非常简单,都是直接从arm手册中找到的信息,贴到此处供大家参考。
    一 disable_l1_cache中读出的关键字段定义(0x83338003):

    二 cache type寄存器格式:

    易见,bit25-28为cache类型,文字ctype字段为0b0001即l1cache是write-back类型;
    三 同时我们还可以获取cache的大小和相联属性。cache type寄存器中bit0—11和12-23是icache和dcache的相关属性.
    Cache相联属性bit3-5:
    Cache相联属性bit6-9:
    Cacheline长度bit0-1:
    cpu根据cache大小、cacheline长度、cache相联性进行cache匹配。
    匹配的方法可以参见l2-cache中介绍。
    【分析五】cpu与L2cache
    1)L2-cache又称外部cache,通过AXI bus进行控制。下例中介绍下cache访问过程。
    /* 获取l2-cache信息 */
    void l2x0_init(void __iomem *base, u32 aux_val, u32 aux_mask)
    /* l2-cache register访问 */
    readl_relaxed(l2x0_base + L2X0_AUX_CTRL);
    /* l2-cache信息  */
    以Auxiliary control register 为例:
    * L310 cache controller enabled
    * l2x0: 16 ways, CACHE_ID 0x410000c8, AUX_CTRL 0x02050000,
    * Cache size: 512k  ;
    2)AUX_CTRL=0x02050000,二进制如下:
    3)对比寄存器 cache way大小
    bit[19:17]=010表示每个cache way大小为32k;
    4) 对比寄存器,cache相联性如下
    bit16=1:表示16路主相联cache。
    5)其中相联性定义:
    全相联cache:的特点是任何一个VA都可以缓存到任何一条cacheline 。查找cache,要检查所有cache line。
    直接映射cache:的特点是VA只允许缓存到某一条cacheline,查找过程块,检查一下应该缓存的VA对应的TAG是否与cacheline中的TAG一致,如果一致就cache hit否则cache miss。
    组相联cache:全相联cache和直接映射cache各有优缺点,全相联cache查找慢,但没有抖动问题,直接映射cache,正好相反。实际cpu的cache设计取两者的折衷,把所有cache line分成若干组,每一组n条cache line,称为 n路组相联cache。
    6)分析一下上例中cache命中过程:
    首先为便于理解cache set,cache way和cache line关系,从网上找来一个比较形象的图如下:
           
    参考上图,分析实例:
    本例中获取的l2cache信息:cache way:16ways;way-size=32k;cache line长度32byte;l2 cache大小为512k.
    16way/32B/512k   <->  Index=1024;cacheline=32B
    31                             14        11       5  4       0
    |         TAG                |        index      |  |cacheline|
    其中:
    1)way=16,每个way中有512k/16/32=1024个cache line,每个way都是直接映射的。
    2)way=16表示16路组相连,每个组中有16个cache line,且每个组都是全相联的,每个组称为一个cache set。
    3)以VA=0x76bb9610为例:index=0xb0 找到对应的 cache set;
    同时MMU根据该VA 通过TLB找到PA,并计算出TAG,再与cache set中的16个cacheline进行逐一对比。
    【总结】
    我们知道在进程上下文切换时,会使用各自不同的的页全局目录,进程切换时,pgd的地址会设置给cpu,如此,cpu就能根据不同的pgd地址,实现不同进程地址空间的管理。
    每个用户态进程,在创建过程中都从内核态下的init_mm拷贝页全局目录到各自的pgd里。也就是每个进程都保存了一份页内核态的全局目录。以amba为例,用户态进程的pgd里保存了线性地址0x80008000 之上的页表。
    所以每个用户态进程,切换到内核态下都能正常访问内存。但作为用户态进程,在用户态运行时,需要为用户态地址空间创建页表,例子:0-0x80000000的地址空间创建页表。如malloc或者mmap的过程都是为用户态虚拟地址创建页表的过程。
    大体过程如下:1)首先每个进程管理一个虚拟内存区 的结构体vm_area_struct,他实际保存的是,虚拟地址的使用范围,用户申请内存时会根据vma找到一个未使用的虚拟地址空间(这个空间时用户态地址空间0x80000000以下),然后再把要使用的物理地址映射到该空间上,即创建页表。
    如果不知道物理地址,如malloc.则一般不马上申请物理地址,而只是返回给用户一个地址范围,当用户真正访问时,内核态通过缺页异常申请地址页,再转换为物理地址,并映射到返回给用户的那个地址范围上。
    此时MMU中tlb查到了对应用户态虚拟地址的页表项(mmap时创建remap_pfn_page),同时cache根据该虚拟地址计算出index,并根据该index查询到组相连cache中的一组,一般来讲,armv7的cache是组相连的,组与组之间是直接映射的(不同index代表不同组),而组内的cacheline是全映射的,组内地址可以映射到任意cacheline里面,然后再根据tag进行cache查询。
    如上,不同用户态进程都有各自不同的页表,但内核态只有一组页表,因此在访问内核态线性地址空间时,cache都是根据内核创建的页表项进行访问的,我们使用VIPT的cache,
    对应512K-16way-32byte 的cache来说,virtual index 是5到14位,每隔32K的virtual index在cache的一组里面(一组有16个cacheline),因此同一个物理地址,有可能内核态和用户态,对应的cacheline不一样。
    具体到构造的问题进行分析
    1)虽然用户使用mmap映射物理内存时,页表属性是关闭cache的。
    2)但是这段物理内存映射在内核态的线性地址空间时,页表项属性中开了cache(低端内存都是打开cache的)
    3)归根结底是因为同一段物理内存映射了两次,内核态一次且开了cache,用户进程中一次且关闭cache。
    因为对应同一物理地址,所以内核态刷cache时改变了用户态虚拟地址的值。
    其实构造的问题很简单,本文重点是想对cpu与cache的关系做一个简单总结,方便以后回顾这一块的知识。如果能给读者带来帮助,更是意外之喜。

    【其他】
    这一部分可以忽略不看,是作者的笔记,方便回忆之用。
    struct mm_struct init_mm = {
     .mm_rb  = RB_ROOT,
     .pgd  = swapper_pg_dir,//每个进程都从这里拷贝页全局目录到各自的pgd里
     .mm_users = ATOMIC_INIT(2),
     .mm_count = ATOMIC_INIT(1),
     .mmap_sem = __RWSEM_INITIALIZER(init_mm.mmap_sem),
     .page_table_lock =  __SPIN_LOCK_UNLOCKED(init_mm.page_table_lock),
     .mmlist  = LIST_HEAD_INIT(init_mm.mmlist),
     INIT_MM_CONTEXT(init_mm)
    };
    进程切换时,会重新设置ttb的值为mm->pgd,mm->pgd中保存的内容是内核态虚拟地址的页表。对于amba平台即0x80000000开始的虚拟地址的页表。
    可见不同进程,都保存了内核态虚拟地址的所有页表项。
    用户空间再申请地址时(amba:用户态虚拟地址空间0-0x80000000)
    需要再次映射,此时产生新的页表,这与内核态页表是不同的。
    同时,即使同一物理内存对应的用户态和内核态虚拟地址也可能不在同一个cacheline。
    cpu_switch_mm(mm->pgd, mm);
    #define cpu_switch_mm(pgd,mm) cpu_do_switch_mm(virt_to_phys(pgd),mm)
    ENTRY(cpu_v7_switch_mm)
    #ifdef CONFIG_MMU
     mmid r1, r1    @ get mm->context.id
     asid r3, r1
     mov r3, r3, lsl #(48 - 32)  @ ASID
     mcrr p15, 0, r0, r3, c2  @ set TTB 0
     isb
    #endif
     mov pc, lr
    ENDPROC(cpu_v7_switch_mm)


    
    展开全文
  • Linux-ARM架构

    千次阅读 2018-09-29 16:21:26
    ARM架构  看一款芯片的思路:公司名-芯片型号-ARM内核-ARM架构  ARM内核:  数字递增划分:  ARM1/2/3/6/7/8/9/10/10  ARMv6引入后按功能划分:  Cortex-M Microcontroller 如Cortex-M  Cortex-R Real...
  • 嵌入式Linux--ARM架构

    2020-11-04 23:17:45
    架构 内核位宽 Cortex profile ARMv1 32 ARM1 ARMv2 32 ARM2,ARM250,ARM3 ARMv3 32 ARM6,ARM7 ARMv4 32 ARM11 ARMv4T 32 ARM7TDMI,ARM9TDMI,SecurCore SC100 ARMv5TE 32 ARM7EJ,ARM9E,ARM...
  • x86架构和arm架构处理器分析

    千次阅读 2015-08-09 13:45:48
    x86架构和arm架构处理器分析 目录: 1.两种cpu架构:冯洛伊曼和哈佛 2.x86架构和arm架构分析 3.x86架构和arm架构功耗探究 一.两种cpu架构:  目前主流的cpu处理器都采用了冯洛伊曼架构或者哈佛架构,那么这和x86\...
  • 一文看懂arm架构和x86架构有什么区别

    万次阅读 多人点赞 2019-05-11 20:28:30
    本文主要介绍的是arm架构和x86架构的区别,首先介绍了ARM架构图,其次介绍了x86架构图,最后从性能、扩展能力、操作系统的兼容性、软件开发的方便性及可使用工具的多样性及功耗这五个方面详细的对比了arm架构和x86...
  • Linux操作系统基础(完结)

    万次阅读 多人点赞 2016-03-09 21:00:45
    一、Linux操作系统概述 二、Linux操作系统安装 三、Linux文件系统及文件基础 四、Linux操作系统命令使用基础 五、Linux应用程序的安装与卸载基础 五、用户及进程 六、相关信息查询 七、网络配置 八、Linux...
  • 一般情况华为腾讯的云服务器都是基于X86架构的,而华为云学生版的centos系统只有ARM架构,所以在安装jdk时需要注意jdk版本。 jdk8下载地址 查看linux是ARM还是X86架构命令:uname -a 这是ARM架构64位 这是X86...
  • Linux系统的服务器上使用Memtester进行内存压力测试 Memtester主要用于捕获内存错误,其测试的主要项目有随机值、异或比较、减法、乘法、除法、与或运算等,通过给定测试内存的大小次数,可以对系统现有的内存...
  • ARM架构和x86架构

    千次阅读 2019-06-10 11:25:00
    arm架构 ARM,进阶精简指令集机器(AdvancedRISCMachine,更早称作:AcornRISCMachine),是一个32位精简指令集(RISC)处理器架构,其广泛地使用在许多嵌入式系统设计。 在今日,ARM家族占了所有32位嵌入式处理器7....
  • 编译安装实时库libcobalta) 编译构建xenomai库debian安装包b) 分步编译安装xenomai库9.xenomai实时性测试10.arm架构安装xenomai参考链接: 最近接触实时系统Xenomai,该文章整理记录X86环境下xenomai
  • ARM架构和X86架构的对比

    千次阅读 2018-04-20 10:13:34
    GOOGLE的Android系统和苹果的IPAD、IPHONE推出后,ARM架构的电脑系统(特别是在终端方面应用)受到用户的广泛支持追捧,ARM+Android成为IT、通信领域最热门的话题,众多芯片厂商纷纷推出具有各种独特应用功能基于ARM...
  • ARM架构

    千次阅读 2019-01-23 14:25:37
    ARM架构之所以更复杂,当然是为了跑更快以及更好地支持片上系统,所以在某种程度上来说对片上系统不是很了解的话那对于ARM架构的理解也不会那么深。  本文首先介绍了ARM的架构图及各个模式,其次介绍了通用寄存器...
  • arm架构和x86架构的区别详解

    千次阅读 2020-08-11 21:10:35
    ARM架构过去称作进阶精简指令集机器(AdvancedRISCMachine,更早称作:AcornRISCMachine),是一个32位精简指令集(RISC)处理器架构,其广泛地使用在许多嵌入式系统设计。由于节能的特点,ARM处理器非常适用于移动...
  • arm架构和x86架构介绍

    千次阅读 2018-08-08 10:57:01
     ARM架构过去称作进阶精简指令集机器(AdvancedRISCMachine,更早称作:AcornRISCMachine),是一个32位精简指令集(RISC)处理器架构,其广泛地使用在许多嵌入式系统设计。由于节能的特点,ARM处理器非常适用于...
  • 遇到一个项目是华为鲲鹏arm架构linux服务器(CentOS 7.5 with ARM),刚开始一直按照X86的教程在执行,后来mysql的本地编译命令出现了二进制的错误,于是想到了这个是鲲鹏arm架构的服务器,所以在网上看了很多博客,...
  • ARM架构和ARM核区别和联系

    千次阅读 2017-10-28 21:09:30
    一、架构和核  到目前为止,随着ARM公司64位处理器如Cortex A15的出现,ARM家族的架构或指令集已经发展到V8版本,下面简要列出了 ARMV1到ARMV8的发展以及处理器的典型代表。图中Architecture就是ARM架构,而Cores...
  • 1、硬件系统:Zynq开发板,ARM架构运行arm-linaro-ubuntu操作系统(32-bit) 2、软件:自己利用PythonPyQt写的一个简单的软件,最后利用Pyinstaller进行打包,在我做开发的电脑(也是32-bit,也是ubuntu系统)...
  • 基于PXA255的ARM Linux操作系统移植

    千次阅读 2007-09-18 14:44:00
    Linux操作系统近年来Linux移植/ARM在嵌入式领域中发展很快,由于其强大的性能开源免费的特点,越来越受到嵌入式系统开发商的青睐,信息家电、网络设备、手持终端等都是嵌入式Linux应用的广大市场。 在Linux移植/...
  • 操作系统:ubuntu 10.10 (redhat 等其他的系统,据说用起来很不方便,这是老师推荐的linux操作系统) 虚拟机: vmware 7.0 (目前有更高的版本吧) 软件界面:QTE(qt-embeded) 交叉编译工具: arm-...
  • 两种cpu架构:冯洛伊曼和哈佛2.x86架构和arm架构分析3.x86架构和arm架构功耗探究 一.两种cpu架构: 目前主流的cpu处理器都采用了冯洛伊曼架构或者哈佛架构,那么这和x86\arm架构的关系是什么呢, 冯洛伊曼和哈佛这两个...
  • ARM架构和X86架构对比

    千次阅读 2013-05-08 10:11:44
    我们就ARM架构系统与X86架构系统的特性进行一个系统分析,方便用户在选择系统时进行理性、合理的比价分析。  一、性能:  X86结构的电脑无论如何都比ARM结构的系统在性能方面要快得多、强得多。X86的CPU...
  • vmware虚拟机上ubuntu操作系统安装arm-linux-gcc交叉编译环境
  • 1.eclipse rcp 开发工具准备详见 ... 2. 安装openjdk7,eclipse3.7 只支持JDK7,而oracle的jdk下sflt hflt无法在银河麒麟下运行 openjdk7 arm64版本下载地址 http://archive.kylinos.cn/k...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 32,316
精华内容 12,926
热门标签
关键字:

linux操作系统和arm架构

linux 订阅