首页 > 其他分享 >记一次有趣的hwclock写RTC的PermissionDenied错误

记一次有趣的hwclock写RTC的PermissionDenied错误

时间:2023-11-19 10:57:50浏览次数:40  
标签:... set rtc err RTC hwclock tm PermissionDenied time

PS:要转载请注明出处,本人版权所有。

PS: 这个只是基于《我自己》的理解,

如果和你的原则及想法相冲突,请谅解,勿喷。

环境说明

  无

前言


  稍微接触过嵌入式板卡的,基本都知道嵌入式板卡里面有个功能叫做RTC。在Linux里面,有几个概念比较重要,它们分别是系统时间和硬件时钟。对于系统时间的话,大家都了解的比较多,我们在各种界面上看到的时间都是系统时间,我们在CLI里面,用date命令操作的时间就是系统时间,我们的系统时间可以通过网络同步或者说RTC同步。

  此外,还有一个硬件时钟功能,这个功能就是RealTimeClock,它主要是用纽扣电池来维护一个硬件时钟,主要是用来同步时钟用的。例如,我们的设备怎么在没有网络的情况下,每次上电开机都能够得到真实时间,就需要靠RTC功能。对于RTC来说,在Linux里面,我们一般使用hwclock命令来对他做相关的操作,例如设置硬件时钟,例如从硬件时钟中得到真实时间,并设置到系统时钟等等。

一个奇怪的错误


  上面我们提到了hwclock,最近,我们常用的一个板卡,其是Android系统,我们在交付给客户的时候,发现了一个奇怪的问题,我们执行hwclock失败了,而且错误还是Permission Deniend,熟悉linux的朋友可能都经常看到这个错误,它就是权限错误。下面是我们执行此命令的环境和错误:

rep_img

  有人立马就会想到是不是我们没有用root用户来执行的原因,从上图可知,并不是这样的,这个错误远远没有想象的那么简单,但是也没有那么复杂。





深入分析相关源码


  首先,在Android里面,hwclock是来至于一个叫做toybox的库,大概在external/toybox/toys/other/hwclock.c,其中关于设置硬件时钟时的核心代码段如下:

if (toys.optflags & FLAG_w) {
    /* The value of tm_isdst is positive if daylight saving time is in effect,
     * zero if it is not and negative if the information is not available.
     * todo: so why isn't this negative...? */
    tm.tm_isdst = 0;
    xioctl(fd, RTC_SET_TIME, &tm);
}

  看到这里,我们明白,必须要到内核源码才能够得到我们想要的答案。

  通过RTC_SET_TIME,在内核代码的drivers/rtc/rtc-dev.c里面,我们找到了第一处可能导致出现Permission Deniend的地方,代码如下:

static long rtc_dev_ioctl(struct file *file,
                unsigned int cmd, unsigned long arg)
{
    int err = 0;
    struct rtc_device *rtc = file->private_data;
    const struct rtc_class_ops *ops = rtc->ops;
    struct rtc_time tm;
    struct rtc_wkalrm alarm;
    void __user *uarg = (void __user *) arg;

    err = mutex_lock_interruptible(&rtc->ops_lock);
    if (err)
            return err;

    /* check that the calling task has appropriate permissions
        * for certain ioctls. doing this check here is useful
        * to avoid duplicate code in each driver.
        */
    switch (cmd) {
    case RTC_EPOCH_SET:
    case RTC_SET_TIME:
            if (!capable(CAP_SYS_TIME))
                    err = -EACCES;
            break;

    case RTC_IRQP_SET:
            if (arg > rtc->max_user_freq && !capable(CAP_SYS_RESOURCE))
                    err = -EACCES;
            break;

    case RTC_PIE_ON:
            if (rtc->irq_freq > rtc->max_user_freq &&
                            !capable(CAP_SYS_RESOURCE))
                    err = -EACCES;
            break;
    }

        //......
}

  这里产生权限拒绝的原因是由于Linux Capability,因此我们首要的是检查我们的hwclock有没有CAP_SYS_TIME能力,我们通过prctl + PR_CAPBSET_READ 来获取hwclock有没有这个能力(当然,这里可以有很多的其他方式来确定,我这里用最简单的方法来确定),在hwclock源码中添加如下代码段:

  int ret = prctl(PR_CAPBSET_READ, CAP_SYS_TIME);
  if (ret < 0)
          perror("sky: prctl PR_CAPBSET_READ");

  printf("has CAP_SYS_TIME %d\n", ret);

  运行结果如下图:

rep_img

  从这里我们可以知道,我们的hwclock程序是具备CAP_SYS_TIME的,因此,报权限拒绝的地方并不在这里。

  我们接着通过RTC_SET_TIME,在内核代码的drivers/rtc/rtc-dev.c里面,有如下片段:

static long rtc_dev_ioctl(struct file *file,
                unsigned int cmd, unsigned long arg)
{
    // ... ...
    case RTC_SET_TIME:
            mutex_unlock(&rtc->ops_lock);

            if (copy_from_user(&tm, uarg, sizeof(tm)))
                    return -EFAULT;

            return rtc_set_time(rtc, &tm);
    
    // ... ...
}

  我们从这里可以看到,通过RTC_SET_TIME,我们执行rtc_set_time此方法,然后得到了返回值,我们有理由怀疑,我们得到的权限拒绝,来自于这个地方。

  在内核代码的drivers/rtc/interface.c里面,有rtc_set_time的定义,函数定义如下:

int rtc_set_time(struct rtc_device *rtc, struct rtc_time *tm)
{
        int err;

        err = rtc_valid_tm(tm);
        if (err != 0)
                return err;

        err = rtc_valid_range(rtc, tm);
        if (err)
                return err;

        rtc_subtract_offset(rtc, tm);

        err = mutex_lock_interruptible(&rtc->ops_lock);
        if (err)
                return err;

        if (!rtc->ops)
                err = -ENODEV;
        else if (rtc->ops->set_time)
                err = rtc->ops->set_time(rtc->dev.parent, tm);
        else if (rtc->ops->set_mmss64) {
                time64_t secs64 = rtc_tm_to_time64(tm);

                err = rtc->ops->set_mmss64(rtc->dev.parent, secs64);
        } else if (rtc->ops->set_mmss) {
                time64_t secs64 = rtc_tm_to_time64(tm);
                err = rtc->ops->set_mmss(rtc->dev.parent, secs64);
        } else
                err = -EINVAL;

        pm_stay_awake(rtc->dev.parent);
        mutex_unlock(&rtc->ops_lock);
        /* A timer might have just expired */
        schedule_work(&rtc->irqwork);

        trace_rtc_set_time(rtc_tm_to_time64(tm), err);
        return err;
}
EXPORT_SYMBOL_GPL(rtc_set_time);

  从这段代码可知,真正的错误还是来自于rtc 具体驱动里面的xxx_set_time 函数里面。在Linux内核里面,有许多的RTC驱动,因此,我们需要了解到我们的当前的RTC硬件是什么,我们通过logcat -b kernel |grep rtc命令得到了如下的信息:

rep_img

  因此,我们当前的rtc驱动就是rtc-pm8xxx,我们去查找相关的驱动源码drivers/rtc/rtc-pm8xxx.c,发现了一点端倪,其set_time源码重点片段如下:

static int pm8xxx_rtc_set_time(struct device *dev, struct rtc_time *tm)
{
    // ... ...
    struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev);
    // ... ...
    
    // ... ...
    if (!rtc_dd->allow_set_time)
            return -EACCES;
    // ... ...
}

  从这里,我们可以知道,这个驱动有一个allow_set_time的参数,如果不允许,就会返回权限拒绝,那到底可不可以呢?我们尝试将这个属性设置一下,或者直接修改当前的源码。我们全局查找一下这个属性,发现其来自于这里:

static int pm8xxx_rtc_probe(struct platform_device *pdev)
{
    // ... ...
    struct pm8xxx_rtc *rtc_dd;

    // ... ...
    rtc_dd = devm_kzalloc(&pdev->dev, sizeof(*rtc_dd), GFP_KERNEL);
    if (rtc_dd == NULL)
            return -ENOMEM;
    // ... ...
    rtc_dd->allow_set_time = of_property_read_bool(pdev->dev.of_node,
                                                "allow-set-time");
    // ... ...
}

  从这里,我们可以知道当前这个rtc_dd->allow_set_time来自于dts里面,一个叫做allow-set-time的属性。

  我们通过pm8150_rtc全局搜索,在某dtsi文件里面发现了此驱动的相关定义,我们修改这个字段,添加allow-set-time属性,示例如下:


pm8150_rtc: qcom,pm8150_rtc {
        // ... ...
        allow-set-time;
};

  然后我们通过重新编译android源码,重新生成dtbo.img镜像,然后刷入我们的系统,然后我们惊奇的发现,我们解决了这个奇怪的permission denied问题。





后记


  虽然,我们解决了permission denied问题,但是后续还是出现了rtc无法正常设置的问题,通过内核日志查看,是pm8150驱动出了问题,最后只能交给上游板卡厂家去适配解决。

参考文献




打赏、订阅、收藏、丢香蕉、硬币,请关注公众号(攻城狮的搬砖之路)
qrc_img

PS: 请尊重原创,不喜勿喷。

PS: 要转载请注明出处,本人版权所有。

PS: 有问题请留言,看到后我会第一时间回复。

标签:...,set,rtc,err,RTC,hwclock,tm,PermissionDenied,time
From: https://www.cnblogs.com/Iflyinsky/p/17841708.html

相关文章

  • 2023-11-17 记录formly+antd+dayjs的shortcuts设置筛选项全部、昨天、今天
    业务中需要用到formly+antd的组件DatePicker日期组件,其中要给该组件添加筛选项(如:全部、昨天、今天),日期的格式化用到了日期插件dayjs(注意不是momentjs)shortcuts=[{text:'全部',onClick:()=>([null,null])},...shortcutsData]如果只是设置昨天或者今天,只需传开始和结束......
  • 硬件开发笔记(十二):RK3568底板电路电源模块和RTC模块原理图分析
    前言  做硬件做系统做驱动,很难从核心板做起,所以我们先依赖核心板,分析底板周围的电路,然后使用AD绘制原理图和设计PCB,打样我司测试底板,完成硬件测试,再继续系统适配,驱动移植,从而一步一步完善成为一个功能完善的底板,且搭载了我们跳完的系统和驱动。  本篇文章,先从底板的电源电......
  • 在ESP32-C3上实现断电后RTC(Real-Time Clock)继续走时
    如果您想在ESP32-C3上实现断电后RTC(Real-TimeClock)继续走时,可以考虑以下几种方法:使用外部RTC芯片:您可以连接一个外部的RTC芯片,例如DS1307或DS3231等,这些芯片通常具有内置的锂电池,可以在断电时保持走时。将外部RTC芯片的VDD引脚连接到ESP32-C3的电池或电源,并将时钟信号线连接到ESP3......
  • WebRTC服务搭建(使用SRS)
    原贴:https://www.psvmc.cn/article/2021-01-21-webrtc-srs.htmlWebRTC服务搭建(使用SRS) 发表于 2021-01-21 |  分类于 liveWebRTC服务搭建(使用SRS)SRS4目前SRS对WebRTC的支持进度如下:SRS4.0.14,支持了RTMP推流,WebRTC播放。SRS4.0.76,支持了WebRTC推流,WebRTC播放。......
  • 通过WebRTC简单实现媒体共享
    通过WebRTC简单实现媒体共享媒体协商在设置本地描述符(offer/answer)前,我们总是需要将媒体添加到连接中,只有这样在描述符中才能包含需要共享的媒体信息,除非你不需要共享媒体。在实际应用中,我们通常没办法让两个客户端直接通信,进行媒体协商。因此我们通常需要一个双方都可以访问......
  • webrtc 低通滤波器
     #include"low_pass_filter.h"  doubleprev_output=0.0;doubleprev_input=0.0;  //去噪 WebRtcNsx_Process(webrtc_nsx,&g_aecmAudio,1,&g_ns); if(WebRtcAgc_Process(webrtc_agc,&g_ns,1,160,&pBuff,in_mic_......
  • mac os 编译webrtc 报错screen_capturer_mac.mm:500:5: error: 'CGDisplayStreamStop'
    ../../modules/desktop_capture/mac/screen_capturer_mac.mm:462:11:error:'CGDisplayStreamUpdateGetRects'isonlyavailableonmacOS13.0ornewer[-Werror,-Wunguarded-availability-new]462|CGDisplayStreamUpdateGetRects(updateRef,kC......
  • vue视频直接播放rtsp流;vue视频延迟问题解决;webRTC占cpu太大卡死问题解决;解决webRTC播
    vue视频直接播放rtsp流;vue视频延迟问题解决;webRTC占cpu太大卡死问题解决;解决webRTC播放卡花屏问题::https://blog.csdn.net/killerdoubie/article/details/133884070......
  • nodejs 基于sharp + smartcrop 实现图片的智能提取排版
    属于一个简单的demo示例,主要是学习下sharp包对于图片的处理,以及基于smartcrop.js实现智能图片抠图结合sharp提供的图片组合能力,实现一个基于模版的图片组合,代码很简单简单任务描述就是有一个图片,我们需要智能的提取核心信息,并生成一个确定大小的图片,然后基于将生成的图片填......
  • docker容器内需要执行sudo hwclock --systohc吗
     在Docker容器内部,你通常不需要(也不应该)执行与硬件时钟相关的操作。这有几个原因:1.**隔离性**:Docker容器设计为与宿主机隔离。容器不会(也不应该)直接与硬件交互,包括硬件时钟。2.**依赖宿主机**:容器通常会从宿主机继承时间。如果宿主机的时间设置正确,那么容器的时间也应该是正确......