c - u-boot:如何从linux用户空间访问 'bootcount'?

标签 c beagleboneblack u-boot

我正在尝试使用 u-boot's "bootcount" feature在 TI am335x 器件(例如 beaglebone black)上检测多次失败的启动尝试。在 TI/Davinci 平台上,启动计数值存储在 RTC_SCRATCH2 寄存器 ( source ) 中。然而,在 Linux 方面,我找不到任何将 bootcount 公开为 sysfs 节点或设备的驱动程序,作为读取和重置该值的方法。所以看来(主线)内核不支持这一点,但我想知道用户空间是否可以?

引用:

编辑:一个有效的实现

这是一个可行的解决方案的核心内容,但是我有一个问题(见下文......)

int fd = open("/dev/mem", O_SYNC | O_RDWR);
unsigned char *mem = mmap(NULL, page_offset + len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, page_base);
if (mem == MAP_FAILED) {
    perror("Can't map memory");
    return -1;
}

unsigned char *scratch2 = mem + page_offset;

// Read value from SCRATCH2, verify magic number
uint32_t val = *(uint32_t *)scratch2;
//printf("%08" PRIx32 "\n", val);

// low two bytes are the value, high two bytes are magic
if ((val & 0xffff0000) != (BOOTCOUNT_MAGIC & 0xffff0000)) {
  fprintf(stderr, "Error: BOOTCOUNT_MAGIC does not match\n");
  return -1;
}

printf("%d\n", (uint16_t)(val & 0x0000ffff));

现在,如果我将 mmap 的内存转换为 uint32_t * (如下所示)以避免以后的类型转换,则我读回的值是不正确的(BOOTCOUNT_MAGIC 不匹配):

uint32_t *mem = mmap(NULL, page_offset + len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, page_base);

uint32_t *scratch2 = mem + page_offset;

// Read value from SCRATCH2, verify magic number
uint32_t val = *scratch2;
//printf("%08" PRIx32 "\n", val);

// low two bytes are the value, high two bytes are magic
if ((val & 0xffff0000) != (BOOTCOUNT_MAGIC & 0xffff0000)) {
    fprintf(stderr, "Error: BOOTCOUNT_MAGIC does not match\n");
    return -1;
}

printf("%d\n", (uint16_t)(val & 0x0000ffff));

当我使用 uint32_t *mem 时,val 不应该仍然保持相同的值吗?

完整来源可以是found on Github .

最佳答案

Shouldn't val still hold the same value when I use uint32_t *mem?

如果您使用了正确的指针算术(但您没有),那么您将得到正确的结果。

<pointer> + <scaler> 的 C 表达式中,<scaler>用于表示与指针类型大小相同的数量(例如 sizeof(struct foo) )。
只有当指针是字节指针时,<scaler>才会出现。表示字节数。

如果我们有一个数组 x由 100 个结构元素组成,例如

struct foo x[100];

数组的名称可以用作指针。
因此数组第十个元素的地址可以被引用为 &x[9](x + 9)


所以在你的第一个代码示例中

unsigned char *mem ...

mem被声明为字节指针。
所以

中的指针计算
unsigned char *scratch2 = mem + page_offset;

产生您期望的结果,因为 sizeof(unsigned char)是 1(字节),并且 page_offset以字节数表示。


但是在你的第二个代码示例中

uint32_t *mem  ...

mem被声明为指向 4 字节字的指针。
所以同样的指针计算在

unsigned char *scratch2 = mem + page_offset;

实际上相当于

unsigned char *scratch2 = (unsigned char *)mem + (sizeof(uint32_t) * page_offset);

哪里sizeof(uint32_t)是 4(字节),并且应用的偏移量是您预期的四倍。
那是因为page_offset仍然是字节数,但在原始表达式中被视为指针类型的定标器计数,这是一个 4 字节的字。
您不能简单地更改指针类型(即从 charint ),并期望指针算术不受影响。
当你改变 mem输入uint32_t * ,指针计算需要重新编码,将字节偏移量转换为四字节偏移量:

unsigned char *scratch2 = mem + (page_offset / sizeof(uint32_t));

您可以通过使用 printf() 报告 mem 的值来确认这些语句(或调试您的代码)。 , scratch2 ,以及其他指针计算。

关于c - u-boot:如何从linux用户空间访问 'bootcount'?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51372832/

相关文章:

c - C 中的 Malloc 复制先前分配的字符串?

c - C (C89) 中十进制数的有效磁盘存储

c++ - 正则表达式。查找所有非拉丁字符的单词

c - 以编程方式确定有符号整数类型的最大值

embedded-linux - 从美元卡启动时出错 - 没有文件系统可以挂载根目录,尝试了 :Ext4

linux-kernel - 扁平化设备树有什么用 - Linux Kernel

linux - BBB - WLAN USB 适配器配置问题

ubuntu - 在 Ubuntu 上难以与蓝牙 OBDII 设备配对

arm - 如何读取AM335X上的特定寄存器值

linux - uboot 中超出 ARP 重试次数