精华内容
下载资源
问答
  • 内核中操作寄存器的方法

    千次阅读 2016-08-27 19:53:55
    由于Linux开启了MMU,所以我们在访问寄存器时,必须要使用寄存器物理地址对应的虚拟地址来访问

    内核中操作寄存器的方法

    由于Linux开启了MMU,所以我们在访问寄存器时,必须要使用寄存器物理地址对应的虚拟地址来访问。

    1.内核提供的读写接口

    利用内核提供的寄存器读写接口会有较好的可移植性,最重要的是拥有“读写屏障”

    • 何谓“读写屏障”?其有何意义?试看以下代码
    #define XXX_SET   0xe0200240
    #define XXX_EN    0xe0200244
    
    *((volatile unsigned int *)XXX_SET) = 0xffffffff;
    *((volatile unsigned int *)XXX_EN) = 0xffffffff;
    • 现代编译器为了提高效率,采用的乱序编译,同样,现代soc采用的是乱序执行。对于soc和编译器来说,它们判断这两个寄存器设置的先后顺序没有逻辑关系,所以上述两个寄存器的设置顺序是不定的。但是某些外设硬件来说,需要先配置再使能
    • 使用内核提供的读写接口,即可保证读写寄存器的顺序不会改变。其内部的实现机制是使用了ARM指令集中的各种屏障指令
    writel(0xffffffff, XXX_SET);
    writel(0xffffffff, XXX_EN);
    • writel是内核提供的寄存器读写函数之一,writel代表的是读long,4字节(32位),writeb和writew分别代表读byte1个字节和word2个字节。其他读写函数都以此类推,至于具体参数格式都可以去看定义

    2.动态映射操作寄存器

    
    /*需要的一些定义*/
    #define GPJ0_REGBASE   0xe0200240
    static void *p_gpj0_base;
    
    
    /*相关资源的申请*/
    if (!request_mem_region(GPJ0_REGBASE, 8, "gpj0reg")){
            return -EINVAL;
    }
    p_gpj0_base = ioremap(GPJ0_REGBASE, 8);
    
    /*正式操作硬件*/
    writel(0x11111111, p_gpj0_base + 0);
    writel(0xffffff00, p_gpj0_base + 4);
    
    /*相关资源的释放*/
    iounmap(p_gpj0_base);
    release_mem_region(GPJ0_REGBASE, 8);
    
    

    这种方法的本质其实还是连续申请了一长段内存映射,但是没有用结构体的方式而是用了基地址+偏移量来定位地址,然后内核提供的寄存器读写接口通过这个地址来操作寄存器

    • 首先定义需要用到的物理基地址,比如我们要操作GPJ0相关的寄存器,那么定义GPJ0的物理基地址#define GPJ0_REGBASE 0xe0200240。此外,我们还需要定义一个指向虚拟基地址的指针,注意类型最好是void *,具体原因在后面讲述
    • 动态映射涉及到虚拟地址的申请。任何关于资源的申请和释放,顺序必须要符合“倒影式结构”,这里也不例外,操作顺序是 request_mem_region 申请-> ioremap 建立映射-> 寄存器操作 -> iounmap 解除映射-> release_mem_region 释放申请。一般来说,申请和释放操作分别放在open和release函数内比较好
    • 记得申请的时候长度设置为自己需要的寄存器量占的地址大小
    • 最值得注意的是指针的加法,前面说到虚拟基地址指针应该定义为void 。原因是这样就能直接加上地址偏移量了。比如+4就是定位到偏移量为4的地址处。但是如果基地址指针应该定义为unsigned int ,那么偏移量就不能直接加上去了因为unsigned int *类型的指针+1,其实就相当于地址值+4

    3. 结构体动态映射操作寄存器

    /*需要的一些定义*/
    #define GPJ0_REGBASE   0xe0200240
    struct GPJ0_REG{
            volatile unsigned int gpj0con;
            volatile unsigned int gpj0dat;
    };
    struct GPJ0_REG *p_gpj0_str;
    
    /*相关资源的申请*/
    if (!request_mem_region(GPJ0_REGBASE, sizeof(struct GPJ0_REG), "gpj0reg")){
            return -EINVAL;
    }
    p_gpj0_str = ioremap(GPJ0_REGBASE, sizeof(struct GPJ0_REG));
    
    /*正式操作硬件*/
    writel(0x11111111, &(p_gpj0_str->gpj0con));
    writel(0xffffff00, &(p_gpj0_str->gpj0dat));
    
    /*相关资源的释放*/
    iounmap(p_gpj0);
    release_mem_region(GPJ0_REGBASE, sizeof(struct GPJ0_REG));
    
    

    这种以结构体为单位操作的方法,适用于一大块地址连续的寄存器申请动态映射

    • 首先定义需要的物理基地址,比如我们要操作GPJ0相关的寄存器,那么定义GPJ0的物理基地址#define GPJ0_REGBASE 0xe0200240。然后定义一个结构体以及指向它的指针,由于把需要的寄存器按照地址的顺序放进去。比如我们这里gpj0con和gpj0dat两个连续的寄存器,就能封装成一个结构体(大小为2*32bit=8字节)
    • 动态映射涉及到虚拟地址的申请。任何关于资源的申请和释放,顺序必须要符合“倒影式结构”,这里也不例外,操作顺序是 request_mem_region 申请-> ioremap 建立映射-> 寄存器操作 -> iounmap 解除映射-> release_mem_region 释放申请。 一般来说,申请和释放操作分别放在open和release函数内比较好
    • 申请映射的时候,通过把映射地址长度设成结构体的长度,这样就能一步到位,申请到一整片寄存器的映射地址了
    • 值得注意的是,当我们把ioremap返回的指针赋给我们的结构体指针时,我们的结构体的地址与寄存器的地址重合了,也就是说结构体里的元素就相当于是寄存器了。我们直接给元素赋值就相当于给寄存器赋值!!!
    • 这样相当方便,由此一来,似乎也理解了stm32标准库中为什么通过结构体指针访问寄存器。不得不说与这里有异曲同工之妙
    展开全文
  • 内核中访问物理寄存器

    千次阅读 2012-10-17 22:49:50
    有过裸板驱动程序编写经历的都清楚,在编写裸板驱动程序时我们是通过访问物理地址来操作寄存器的。但是在内核中根本不可能使用物理地址,只可以使用4G虚拟地址的高1G。这就需要我们把物理地址映射到虚拟地址。 下面...

    有过裸板驱动程序编写经历的都清楚,在编写裸板驱动程序时我们是通过访问物理地址来操作寄存器的。但是在内核中根本不可能使用物理地址,只可以使用4G虚拟地址的高1G。这就需要我们把物理地址映射到虚拟地址。

    下面是一个例子:

    #include <linux/ioport.h>//io端口头文件

    //GPIO物理基地址和偏移

    #define GPIO+BASE 0x7F008000

    #define GPIO_SIZE 0x28c

    /* 将物理地址转换为虚拟地址(一定在3G以上的内核空间) */
    void __iomem *vir_base;
    vir_base = ioremap(GPIO_BASE, GPIO_SIZE);
    if (!vir_base)
        return -EIO;
    ...
    /* 使用虚拟基地址和寄存器偏移,来访问物理寄存器 */
    ...

    /* 释放虚拟地址的映射 */
    iounmap(vir_base);


    (2)寄存器的访问函数
    内核根据寄存器的宽度,定义了一系列寄存器的访问函数,要求驱动开发人员使用:

    #include <linux/io.h>
    
    /* 8位寄存器 */
    char value;
    value = readb(vir_base + offset);
    writeb(value, (vir_base + offset));
    __raw_readb()/__raw_writeb();
    
    /* 16位寄存器 */
    short value;
    value = readw(vir_base + offset);
    writew(value, (vir_base + offset));
    
    /* 32位寄存器 */
    int value;
    value = readl(vir_base + offset);
    writel(value, (vir_base + offset));
    

     

    展开全文
  • linux 内核中 查看寄存器的值

    千次阅读 2015-05-29 15:49:19
    #include u32 temp; temp=__raw_readl(S5PV210_GPJ0_BASE);; printk(KERN_ALERT "before READ_GPJ0CON=0x%x\n",temp); temp=__raw_readl(S5PV210_GPH1_BASE+0x4);...printk(KERN_ALERT "before READ_GPJ0=0x

    #include <asm/io.h>

    u32 temp;



    temp=__raw_readl(S5PV210_GPJ0_BASE);;
    printk(KERN_ALERT "before READ_GPJ0CON=0x%x\n",temp);
    temp=__raw_readl(S5PV210_GPH1_BASE+0x4);
    printk(KERN_ALERT "before READ_GPJ0=0x%x\n",temp);
    printk("request_irq error,i=%d\n",i);
    展开全文
  • ARM内核寄存器介绍

                                 ARM内核中寄存器的浅见

    源地址:http://blog.csdn.net/dennisgang/article/details/52252386


    • 我们先来看一张图

    这张图是ARM手册中的寄存器状态图,我想大部分人应该首先会想到它吧。正如手册中所讲的,这张图中包含37个32位寄存器,其中有31个通用寄存器6个状态寄存器CPU会根据不同的工作模式,使部分寄存器可见(即可被使用),图中有灰色下标的正是不同模式下可见的寄存器,被称为分组寄存器。未分组的寄存器在不同模式下都是可见的,但是在寄存器使用时,分组寄存器会屏蔽共享寄存器,从而实现特殊用途。

    37个寄存器实际如下图所示:


    转换成我们熟悉的手册中的图,如下图:


    我们需要特殊指出几个寄存器:

    1、R13 ——> SP,为堆栈寄存器,用于C语言类程序之间调用所需的空间指针;

    2、R14 ——> LR,为连接寄存器,在发生程序调用时,一般用户存放程序返回地址;

    3、R15 ——> PC,为程序计数寄存器,存放西一条要执行的程序码地址。

    程序状态寄存器

    CPSR(Current Program Status Register)表示当前程序状态寄存器,SPSR(Saved Program Status Register)用来保存异常程序处理个程序状态,这些寄存器的格式和功能见下图所示。


    寄存器的具体详细描述见数据手册,另外我们在贴一张Thumb指令下的寄存器和对比图



    展开全文
  • 内核驱动改写寄存器

    千次阅读 2016-01-14 18:00:04
    在Kernel Model的驱动程序向给定的寄存器地址、内存地址或IO端口地址等16进制的地址写入指定的值。 主要依靠的是MSDN提供的MmMapIoSpace函数进行的。该函数将一个十六进制的物理地址映射到一个指针,然后针对该...
  • 之前在使用Windbg进行内核调试的时候,想要查看寄存器的值,结果发现打开寄存器窗口之后,不显示数据,但是执行r命令可以正常查看寄存器的值,网上搜索了一下相关资料,记录一下。 环境:Windbg.exe Windows10 x64...
  • 3.CM3内核架构-寄存器

    2017-12-02 16:56:00
    一、寄存器的种类   转载于:https://www.cnblogs.com/nyqm/p/7954762.html
  • jtag访问arm内核寄存器

    千次阅读 2017-03-25 21:35:56
    jtag的原理图 jtag接口访问arm Device ID code register的步骤 jtag接口访问arm Device ID code register的功能验证的testbench ...jtag访问arm内核寄存器的步骤 与DTR相关的协处理器指令介绍 最后通过封装成veril
  • 这时外设IO寄存器应该称为IO端口,访问IO寄存器可以ioport_map()将其映射到虚拟地址空间,但是实际上这只是给开发人员造成一个“假象”,并没有映射到内核虚拟地址,仅仅是为了使用和IO内存一样的接口访问IO寄存器;...
  • 从watchdog驱动提取出来的代码  u16 mattval; mattstart = MX6Q_WDOG1_BASE_ADDR ; matt = ioremap_nocache(mattstart, 0x00004000); mattval = __raw_readw(matt + IMX2_WDT_WCR);  __raw_writew(val, imx
  •  TSS 全称为task state segment,是指在操作系统进程管理的过程,进程切换时的任务现场信息。 X86体系从硬件上支持任务间的切换。为此目的,它增设了一个新段:任务状态段(TSS),它和数据段、代码段一
  • 内核学习之段寄存器

    2014-05-22 16:37:53
    内核学习之段寄存器 关于段寄存器的介绍大部分只是介绍其分类和在寻址的应用,很少提到段寄存器如何去寻址的。这几天一直在纠结着方面的内容,今天算是大体明白了吧! 还是首先提一下段寄存器的作用和分类。在...
  • STM32F429内核寄存器

    千次阅读 2020-02-04 13:45:49
    目录 一、STM32 芯片架构简图 ...三、寄存器映射 1、STM32 的外设地址映射 2、C 语言对寄存器的封装 3、修改寄存器的位操作方法 一、STM32 芯片架构简图 h STM32 有三种启动方式,从 FLASH...
  • 内核提供的读写寄存器接口实现可移植性 arm是IO与内存统一编址,其他平台如x86是IO与内存独立编址访问方式不一样,使用内核提供的寄存器读写接口writel\readl具有可移植性
  • 现在出现的问题就是,按照裸板上的配置步骤,让开发板在Linux内核模块程序配置寄存器,insmod能够成功添加模块,但printk打印来看,某些寄存器(LCD寄存器)能够修改,某些寄存器不能修改,修改的方法是一样的。...
  • 控制寄存器用于控制和确定CPU的操作模式。主要有:CR0\CR1\CR2\CR3\CR4 2.CR0寄存器 PE:启用保护模式标志,1是保护模式,0是实模式,这个位只是开始或关闭段机制,并没有启用分页机制 PG:分页机制开关,在启用...
  • cortex_m3内核寄存器说明,英文版本 cortex_m3内核寄存器说明.
  • Cortex-M3内核寄存器相关知识,不断更新。
  • 这个系列是为了学习操作系统而带着学习M3内核的基本知识。学习的资料是Joseph Yiu编著的宋岩翻译的《M3 权威指南》。 开始。 应该说汇编是在CPU对存储器和寄存器内部...这里贴出M3内核寄存器组。 可以看出前13...
  • 1、前面访问寄存器的方式 通过定义指向寄存器的指针,然后解引用来对寄存器进行操作。 (1)行不行?sure! (2)好不好?不好,因为ARM体系内存和IO统一编址的,但有其他体系(如X86)不是统一编址的,因此不...
  • void __iomem *mmio; mmio = ioremap_nocache(0xFEB00000, 0x4); if (mmio) { printk("[%s] -------------0xFEB00000 = 0x%08x.\n",__FUNCTION__,ioread32(mmio)); iounmap(mmio); ...//iowrite32(addr,valu...
  • 关于linux下访问寄存器

    千次阅读 2011-10-28 09:49:06
    由于linux体系特殊的结构,于是我们在嵌入式linux是不能够直接访问寄存器的。比如,我们在51,想让一个IO口输出高电平,只需要让相应的寄存器置1就可以,但是,linux为了保证其程序的可移植性,以及程序的稳定性...
  • PPC E500内核寄存器

    千次阅读 2011-06-05 21:31:00
    ABI手册规定用户编程是需要注意的:1.r0 存放LR寄存器的值,即函数的返回地址。2.r1 PPC处理器没有在指令级别上支持堆栈,没有专门的堆栈类寄存器,ABI规定使用r1保存栈顶指针。3.r3-r4 存放程序的返回值。4.r3-...
  • ARM内核寄存器的操作函数

    千次阅读 2017-01-11 17:09:00
    在修改嵌入式底层的参数时需要使用一些内核寄存器的操作,在编译器往往都封装了对应的函数。 1.__ASM uint32_t __get_PSP(void):获取进程堆栈指针PSP。 2.__ASM void __set_PSP(uint32_t topOfProcStack):...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 125,011
精华内容 50,004
关键字:

内核中如何访问寄存器