Linux下如何操作寄存器(用户空间、内核空间方法讲解)

2023-10-27

本期主题:
linux下操作寄存器


往期链接:



1.为什么有这个问题

Linux开发与裸机开发不同,在裸机开发中直接使用指针方式就能访问到对应地址,但是在Linux中,由于内存管理的存在,并不能这么粗暴的直接用指针进行访问。

那么Linux下的内存管理是怎样的呢?linux内存管理相当复杂,本篇文章只能简单介绍一部分:

1.内存空间与I/O空间

  • I/O空间: 在x86处理器中存在着I/O空间的概念,I/O空间是相对于内存空间而言的,通过特定的指令 in、out来访问,端口号标识了外设的寄存器地址;
//intel的in指令格式如下:
IN 累加器, { 端口号 | DX}
  • 内存空间: 大多数的嵌入式微控制器(如ARM、PowerPC等)并不提供I/O空间,仅存在内存空间,可以直接通过地址、指针来进行访问;

下图给出了内存空间和I/O空间的对比:
在这里插入图片描述
从上图可以看出,内存空间是必须的,而I/O空间是可选的。

2.内存管理单元

高性能处理器一般会提供一个内存管理单元MMU,该单元辅助操作系统进行内存管理。
提供虚拟地址和物理地址映射内存访问权限保护cache缓存控制等硬件支持。

3.Linux内存管理

对于包含MMU的处理器,linux提供了复杂的存储管理系统,(以32位处理器为例),进程所能够访问的空间达到4GB。
在Linux系统中,进程的4GB内存空间被分为两个部分——用户空间和内核空间,具体的描述可以看这个链接:操作系统系列(二)——进程

2.用户空间下怎么访问寄存器

用户空间下我们对于寄存器的访问可以使用 mmap接口

1.mmap原理

mmap是一种内存映射文件的方法,即将一个文件或者其它对象映射到进程的地址空间,实现文件磁盘地址和进程虚拟地址空间中一段虚拟地址的一一对映关系。实现这样的映射关系后,进程就可以采用指针的方式读写操作这一段内存,而系统会自动回写脏页面到对应的文件磁盘上,即完成了对文件的操作而不必再调用read,write等系统调用函数。

在这里插入图片描述

2.mmap函数原型

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

参数:

start:映射区的开始地址
length:映射区的长度

prot:期望的内存保护标志,不能与文件的打开模式冲突。是以下的某个值,可以通过or运算合理地组合在一起
PROT_EXEC :页内容可以被执行
PROT_READ :页内容可以被读取
PROT_WRITE :页可以被写入
PROT_NONE :页不可访问

flags:指定映射对象的类型,映射选项和映射页是否可以共享。它的值可以是一个或者多个以下位的组合体
MAP_FIXED //使用指定的映射起始地址,如果由start和len参数指定的内存区重叠于现存的映射空间,重叠部分将会被丢弃。如果指定的起始地址不可用,操作将会失败。并且起始地址必须落在页的边界上。
MAP_SHARED //与其它所有映射这个对象的进程共享映射空间。对共享区的写入,相当于输出到文件。直到msync()或者munmap()被调用,文件实际上不会被更新。
MAP_PRIVATE //建立一个写入时拷贝的私有映射。内存区域的写入不会影响到原文件。这个标志和以上标志是互斥的,只能使用其中一个。
MAP_DENYWRITE //这个标志被忽略。
MAP_EXECUTABLE //同上
MAP_NORESERVE //不要为这个映射保留交换空间。当交换空间被保留,对映射区修改的可能会得到保证。当交换空间不被保留,同时内存不足,对映射区的修改会引起段违例信号。
MAP_LOCKED //锁定映射区的页面,从而防止页面被交换出内存。
MAP_GROWSDOWN //用于堆栈,告诉内核VM系统,映射区可以向下扩展。
MAP_ANONYMOUS //匿名映射,映射区不与任何文件关联。
MAP_ANON //MAP_ANONYMOUS的别称,不再被使用。
MAP_FILE //兼容标志,被忽略。
MAP_32BIT //将映射区放在进程地址空间的低2GB,MAP_FIXED指定时会被忽略。当前这个标志只在x86-64平台上得到支持。
MAP_POPULATE //为文件映射通过预读的方式准备好页表。随后对映射区的访问不会被页违例阻塞。
MAP_NONBLOCK //仅和MAP_POPULATE一起使用时才有意义。不执行预读,只为已存在于内存中的页面建立页表入口。

fd:有效的文件描述词。如果MAP_ANONYMOUS被设定,为了兼容问题,其值应为-1

offset:被映射对象内容的起点

3.mmap使用例子

以操作一个地址为0xA4030000的寄存器为例

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <time.h>
#include <unistd.h>
#include <string.h>

#deinfe REG_BASE 0xA4030000

int main(void)
{
	int fd;
	void *map_reg_base;
    // map to register base and memory
	fd = open("/dev/mem", O_RDWR | O_SYNC);
	if (fd)	{
		DEBUG("Success to open /dev/mem fd=%08x\n", fd);
	} else {
		DEBUG("Fail to open /dev/mem fd=%08x\n", fd);
	}
	//这里的map_reg_base就是被mmap过后的指针,可以直接操作了
	map_reg_base = mmap(0, 0x400, PROT_READ | PROT_WRITE,
			MAP_SHARED, fd, REG_BASE);
    printf("--------start write regs\n");
    *(volatile uint32_t *)map_reg_base = 0x01;

}

测试结果:

$ devmem 0xA4030000 32
0x81
$ ./test
$ devmem 0xA4030000 32
0x01

3.内核空间下怎么访问寄存器

1.ioremap

在内核中访问I/O内存(通常是一些控制器的寄存器)之前,需要使用ioremap()函数将设备所处的物理地址映射到虚拟地址上

函数原型:

void __iomem *ioremap(resource_size_t phys_addr, unsigned long size)
/**
 * ioremap     -   map bus memory into CPU space
 * @phys_addr:    bus address of the memory
 * @size:      size of the resource to map
 *
 * ioremap performs a platform specific sequence of operations to
 * make bus memory CPU accessible via the readb/readw/readl/writeb/
 * writew/writel functions and the other mmio helpers. The returned
 * address is not guaranteed to be usable directly as a virtual
 * address.
 *
 * This version of ioremap ensures that the memory is marked uncachable
 * on the CPU as well as honouring existing caching rules from things like
 * the PCI bus. Note that there are other caches and buffers on many
 * busses. In particular driver authors should read up on PCI writes
 *
 * It's useful if some control registers are in such an area and
 * write combining or read caching is not desirable:
 *
 * Must be freed with iounmap.
 */

2.实际例子

使用ioremap和不使用ioremap进行对比:

#include <linux/init.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <asm/io.h>

#define USE_IOREMAP

#define H3_GPIO_BASE (0x01C20800)

static volatile unsigned long *gpio_regs = NULL;

static int __init ioremap_mod_init(void)
{

    int i = 0;
    printk(KERN_INFO "ioremap_mod init\n");

#ifdef USE_IOREMAP
    gpio_regs = (volatile unsigned long *)ioremap(H3_GPIO_BASE, 1024);
#else
    gpio_regs = (volatile unsigned long *)H3_GPIO_BASE;
#endif

    for (i=0; i<3; i++)
        printk(KERN_INFO "reg[%d] = %lx\n", i, gpio_regs[i]);

    return 0;
}
module_init(ioremap_mod_init);

static void __exit ioremap_mod_exit(void)
{
    printk(KERN_INFO "ioremap_mod exit\n ");

#ifdef USE_IOREMAP
    iounmap(gpio_regs);
#endif 
}

module_exit(ioremap_mod_exit);

MODULE_AUTHOR("es-hacker");
MODULE_LICENSE("GPL v2");

实验结果:
1.使用ioremap

$ insmod ioremap
ioremap_mod init
reg[0] = 71227722
reg[1] = 33322177
reg[2] = 773373

2.不使用ioremap

$ insmod ioremap_mod.ko

Unable to handle kernel paging request at virtual address 01c20800
pgd = c9ece7c0
[01c20800] *pgd=6ddd7003, *pmd=00000000
Internal error: Oops: 206 [#1] SMP ARM
CPU: 1 PID: 1253 Comm: insmod Tainted: G           O    4.14.111 #116
Hardware name: sun8i
task: ef15d140 task.stack: edc50000
PC is at ioremap_mod_init+0x3c/0x1000 [ioremap_mod]
LR is at ioremap_mod_init+0x14/0x1000 [ioremap_mod]
pc : [<bf5d903c>]    lr : [<bf5d9014>]    psr: 600e0013
sp : edc51df8  ip : 00000007  fp : 118fa95c
r10: 00000001  r9 : ee7056c0  r8 : bf5d6048
r7 : bf5d6000  r6 : 00000000  r5 : bf5d6200  r4 : 00000000
r3 : 01c20800  r2 : 01c20800  r1 : 00000000  r0 : bf5d5048
Flags: nZCv  IRQs on  FIQs on  Mode SVC_32  ISA ARM  Segment user
Control: 30c5387d  Table: 49ece7c0  DAC: b106c794
Process insmod (pid: 1253, stack limit = 0xedc50210)

[<bf5d903c>] (ioremap_mod_init [ioremap_mod]) from [<c0201a70>] (do_one_initcall+0x40/0x16c)
[<c0201a70>] (do_one_initcall) from [<c02b20c8>] (do_init_module+0x60/0x1f0)
[<c02b20c8>] (do_init_module) from [<c02b1214>] (load_module+0x1b48/0x2250)
[<c02b1214>] (load_module) from [<c02b1ad8>] (SyS_finit_module+0x8c/0x9c)
[<c02b1ad8>] (SyS_finit_module) from [<c0221f80>] (ret_fast_syscall+0x0/0x4c)
Code: e5953000 e3050048 e1a01004 e34b0f5d (e7932104) 
---[ end trace 928c64a33a054308 ]---
Segmentation fault

例子截图:
在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Linux下如何操作寄存器(用户空间、内核空间方法讲解) 的相关文章

  • GCC 和 ld 找不到导出的符号...但它们在那里

    我有一个 C 库和一个 C 应用程序 尝试使用从该库导出的函数和类 该库构建良好 应用程序可以编译 但无法链接 我得到的错误遵循以下形式 app source file cpp text 0x2fdb 对 lib namespace Get
  • .NET Core 中的跨平台文件名处理

    如何处理文件名System IO以跨平台方式运行类以使其在 Windows 和 Linux 上运行 例如 我编写的代码在 Windows 上完美运行 但它不会在 Ubuntu Linux 上创建文件 var tempFilename Dat
  • 并行运行 make 时出错

    考虑以下制作 all a b a echo a exit 1 b echo b start sleep 1 echo b end 当运行它时make j2我收到以下输出 echo a echo b start a exit 1 b star
  • ansible 重新启动 2.1.1.0 失败

    我一直在尝试创建一个非常简单的 Ansible 剧本 它将重新启动服务器并等待它回来 我过去在 Ansible 1 9 上有一个可以运行的 但我最近升级到 2 1 1 0 并且失败了 我正在重新启动的主机名为 idm IP 为 192 16
  • Locale.getDefault() 始终返回 en

    unix 机器上的服务器始终使用 en 作为默认区域设置 以下是区域设置输出 LANG en US LC CTYPE C LC NUMERIC C LC TIME C LC COLLATE C LC MONETARY C LC MESSAG
  • 为什么我收到的数据包数据大小大于mss?

    我在两台 PC 上使用 ifconfig ethX mtu 300 修改了 MTU 并使用 netperf 测试网络 我用 WireShark 嗅探了 SYN 数据包中的 MSS 260 但我得到了一些大于 260 的数据包 为什么 嗅探器
  • 何时使用 pthread 条件变量?

    线程问题 看来 只有在其他线程调用 pthread cond notify 之前调用 pthread cond wait 时 条件变量才起作用 如果在等待之前发生通知 那么等待将被卡住 我的问题是 什么时候应该使用条件变量 调度程序可以抢占
  • 在 Linux 上更快地分叉大型进程?

    在现代 Linux 上达到与 Linux 相同效果的最快 最好的方法是什么 fork execve combo 从一个大的过程 我的问题是进程分叉大约 500MByte 大 并且一个简单的基准测试只能从进程中实现约 50 个分叉 秒 比较最
  • 是否可以在Linux上将C转换为asm而不链接libc?

    测试平台为Linux 32位 但也欢迎 Windows 32 位上的某些解决方案 这是一个c代码片段 int a 0 printf d n a 如果我使用 gcc 生成汇编代码 gcc S test c 然后我会得到 movl 0 28 e
  • 如何检测并找出程序是否陷入死锁?

    这是一道面试题 如何检测并确定程序是否陷入死锁 是否有一些工具可用于在 Linux Unix 系统上执行此操作 我的想法 如果程序没有任何进展并且其状态为运行 则为死锁 但是 其他原因也可能导致此问题 开源工具有valgrind halgr
  • 应用程序无缘无故地被杀死。怀疑 BSS 高。如何调试呢?

    我已经在CentOs6 6中成功运行我的应用程序 最近 硬件 主板和内存 更新了 我的应用程序现在毫无理由地被杀死 root localhost PktBlaster PktBlaster Killed 文件和 ldd 输出 root lo
  • 如何在 Linux 中编写文本模式 GUI? [关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 当我编写脚本 程序时 我经常想弹出一个简单的文本 gui 来提示输入 我该怎么做 例如 来自 Shel
  • Linux TUN/TAP:无法从 TAP 设备读回数据

    问题是关于如何正确配置想要使用 Tun Tap 模块的 Linux 主机 My Goal 利用现有的路由软件 以下为APP1和APP2 但拦截并修改其发送和接收的所有消息 由Mediator完成 我的场景 Ubuntu 10 04 Mach
  • 无法从 jenkins 作为后台进程运行 nohup 命令

    更新 根据下面的讨论 我编辑了我的答案以获得更准确的描述 我正在尝试从詹金斯运行 nohup 命令 完整的命令是 nohup java jar home jar server process 0 35 jar prod gt gt var
  • Linux 中的动态环境变量?

    Linux 中是否可以通过某种方式拥有动态环境变量 我有一个网络服务器 网站遵循以下布局 site qa production 我想要一个环境变量 例如 APPLICATION ENV 当我在 qa 目录中时设置为 qa 当我在生产目录中时
  • 如何有效截断文件头?

    大家都知道truncate file size 函数 通过截断文件尾部将文件大小更改为给定大小 但是如何做同样的事情 只截断文件的尾部和头部呢 通常 您必须重写整个文件 最简单的方法是跳过前几个字节 将其他所有内容复制到临时文件中 并在完成
  • linux perf:如何解释和查找热点

    我尝试了linux perf https perf wiki kernel org index php Main Page今天很实用 但在解释其结果时遇到了困难 我习惯了 valgrind 的 callgrind 这当然是与基于采样的 pe
  • nslookup 报告“无法解析 '(null)': 名称无法解析”,尽管它成功解析了 DNS 名称

    我在 ubuntu 上 并且正在运行 docker 默认桥接网络 我有 Zookeeper kafka 的容器化版本 以及我编写的与 kafka 对话的应用程序 I do a docker exec it
  • vector 超出范围后不清除内存

    我遇到了以下问题 我不确定我是否错了或者它是一个非常奇怪的错误 我填充了一个巨大的字符串数组 并希望在某个点将其清除 这是一个最小的例子 include
  • 尝试安装 LESS 时出现“请尝试以 root/管理员身份再次运行此命令”错误

    我正在尝试在我的计算机上安装 LESS 并且已经安装了节点 但是 当我输入 node install g less 时 出现以下错误 并且不知道该怎么办 FPaulMAC bin paul npm install g less npm ER

随机推荐

  • springboot中restful风格请求的使用

    springboot中restful风格请求的使用 restful风格 springboot中的使用 1 创建html表单页面 2 在yml配置文件中开启rest表单支持 3 编写controller层及对应映射处理 4 启动服务 逐个访问
  • 猜数字游戏代码

    void Menu printf MENU n printf 1 PLAY n printf 0 EXIT n printf n void Game int randnum rand
  • Highstock中如何获取时间选择器的消息响应

    Highstock中的时间选择器在绘制时间相关的图像的时候很好用 最近有一个需求 获取时间选择器选择的时间范围用于后面的处理 查看了下官方文档 还真有相关事件的定义 afterSetExtremes 参考链接 https www highc
  • C++外观模式:Facade Pattern

    装饰者 不改变接口 但加入责任 适配器 将一个接口转换成另一个接口 外观 让接口更简单 外观模式 将一个或数个类的复杂的一切都隐藏在背后 只显露出一个干净美好的外观 外观模式提供了一个统一的接口 用来访问子系统中的一群接口 外观模式定义了一
  • 区块链技术核心概念与原理理解

    区块链的前世今生 说到区块链 就不得不提及密码朋克 密码朋克萌芽于1970年代 正式发起于1993年 认为保护个人隐私是自由社会的重要基石 反对政府 公司对个人隐私的侵害 政权的基础经常建立在控制数据上 通过此类控制可以害人 压迫人 或让人
  • C++图形开发(2):最基本的图形界面

    文章目录 1 构成 2 内容介绍 2 1 initgraph 2 2 getch 2 3 closegraph 3 总结 今天来简单介绍下最基本的图形界面 1 构成 输入以下内容并编译 这就是一个最基本的图形界面了 include
  • java for循环打印爱心

    心形 import java util Scanner class MyTest public static void main String args for int m 1 m lt 5 m for int n 6 n
  • anaconda虚拟环境搭建(python+opencv)

    一般安装和使用流程 1 安装Anaconda 打开命令行输入conda V检验是否安装及当前conda的版本 以下操作均在Anaconda Prompt命令框下进行 2 conda常用的命令 1 查看安装了哪些包 conda list 2
  • 2019牛客多校训练赛第五场A题 (思维题)

    题目描述 看不清图片可以右击图片 gt 复制图片地址 gt 浏览器新开一个标签页 粘贴此地址就可看大图 也可以右击图片 gt 在新标签页打开图片 题解 题意 给你一个整型x x lt 100 让你输出一个整型y y要满足3个条件 y 能被
  • Ubuntu 20.04无法连接网络(网络图标丢失),重启网络出现Failed to restart network-manager.service

    问题 失去网络图标 这里已经解决 sudo service NetworkManager stop sudo rm var lib NetworkManager NetworkManager state sudo service Netwo
  • 如何按需下载和安装Win10补丁

    如何按需下载和安装Win10补丁 一般我们都是通过系统自带的Windows更新来直接安装补丁 这种方式虽然方便 但是耗时久 而且更新体量也大 会占用很多空间 其实我们完全可以按需下载和安装 下面就给大家介绍方法 工具 原料 Thinkpad
  • Harmony系统更改手机IP

    在当今的互联网环境中 我们经常需要更改手机的IP地址来绕过限制或保护我们的隐私 虽然在一些操作系统上更改IP地址相对较容易 但在Harmony系统上 这可能会有些困难 因此 本文将分享一种在Harmony系统上免费更改手机IP地址的方法 在
  • 【Java SE】继承和多态(保姆级教学)

    点进来你就是我的人了博主主页 戳一戳 欢迎大佬指点 欢迎志同道合的朋友一起加油喔 目录 前言 一 继承 1 什么是继承 2 继承的优缺点 3 对继承的理解 4 方法的重写 5 继承中的构造方法的调用 6 包的声明和使用 7 四种权限修饰符
  • SM3算法设计原理

    SM3密码杂凑算法的描述 SM3密码杂凑算法采用Merkle Damgard结构 消息分组长度为512b 摘要长度256b 压缩函数状态256b 共64步操作步骤 SM3密码杂凑算法的初始值 SM3密码杂凑算法的初始值共256b 由8个32
  • 5G LAN技术专题详解(1)-目录

    相关文章会在公众号同步更新 最近工作忙 更新完公众号后 经常容易忘记再CSDN上再发 公众号上的文章更新的能快一些 各位同学有兴趣可以关注一下 公众号 5G通信大家学 持续更新的相关5G内容都是直接根据3GPP整理 保证更新内容的准确性 避
  • VMware Fusion Pro 12 Mac介绍(支持11.0 Big Sur出来啦)

    VMware Fusion 12 出来啦 完美支持macOS Big Sur系统 Fusion 12 包含几项新的更新和改进 包括 eGPU 兼容性 对使用 Kubernetes 构建的基于容器的应用程序的支持 DirectX 11 和 O
  • 计算机软件毕业设计项目源码大全

    给计算机软件相关专业的同学准备了许多毕设项目源码 大家可以下载 找到跟自己类似的 学习下别人的软件是如何做出来的 gitee下载地址 https gitee com chenshuai777 soft 部分截图如下 太多了我就不一一截出来了
  • 数字化项目建设管理难点分析与对策

    企业数字化发展主要以项目建设为依托 通过分阶段 有计划地实施一系列数字化项目 来不断夯实基础设施建设 持续深化业务系统应用 大力推进研发资源服务 稳步提升安全保密防护措施 日益完善运维管理体系 随着企业改革的不断深入 在加快数字化建设进程过
  • 使用随机森林算法编写评分卡模型

    数据来源于信贷用户 数据量级为2W 首先读取数据 忽略警告 import warnings warnings filterwarnings ignore 导入常用库pandas Numpy matplotlib import pandas
  • Linux下如何操作寄存器(用户空间、内核空间方法讲解)

    本期主题 linux下操作寄存器 往期链接 linux设备驱动中的并发 linux设备驱动中的编译乱序和执行乱序 linux设备驱动之内核模块 linux字符驱动 linux字符驱动之ioctl部分 linux字符驱动之read write