天天看點

OpenHarmony喂狗源碼解讀之核心态源碼

春節不停更,此文正在參加「星光計劃-春節更帖活動」https://harmonyos.51cto.com/posts/9923

(OpenHarmony3.1Beta喂狗核心源碼解讀

一、喂狗的晶片手冊資料

1.概述

看門狗 WatchDog 用于系統異常情況下,一定時間内發出複位信号,以複位整個系統。系統提供 2 個 WatchDog 子產品。

2.特點

WatchDog 具備以下特點:

内部具有一個 32bit 減法計數器。

支援逾時時間間隔(即計數初值)可配置。

支援寄存器鎖定,防止寄存器被誤改。

支援逾時中斷産生。

支援複位信号産生。

支援調試模式

3.DG 寄存器概覽

OpenHarmony喂狗源碼解讀之核心态源碼

具體詳細的核心請檢視附件晶片手冊

二、核心态代碼分析

1.定義喂狗IO位址

  • 代碼位置
device\hisilicon\hispark_taurus\sdk_linux\soc\src\interdrv\common\wtdg\arch\hi3516cv500\hi_wtdg_hal.h
#define HIWDT_BASE      0x12051000    /* define watchdog IO */
           

2.代碼函數接口分析

  • 設定逾時函數代碼

static void hidog_set_timeout(unsigned int nr)
{
    unsigned int cnt_0 = ~0x0;
    unsigned int cnt = cnt_0 / g_rate;  /* max cnt */
    unsigned long flags;

    osal_spin_lock_irqsave(&g_hidog_lock, &flags);

    if ((nr == 0) || (nr > cnt)) {
        cnt = ~0x0;
    } else {
        cnt = nr * g_rate;
    }
    /* unlock watchdog registers */
    hiwdt_writel(HIWDT_UNLOCK_VAL, HIWDT_LOCK);
    hiwdt_writel(cnt, HIWDT_LOAD);
    hiwdt_writel(cnt, HIWDT_VALUE);
    /* lock watchdog registers */
    hiwdt_writel(0, HIWDT_LOCK);
    osal_spin_unlock_irqrestore(&g_hidog_lock, &flags);
}
           
  • 喂狗函數代碼:

static void hidog_feed(void)
{
    unsigned long flags;

    /* read the RIS state of current wdg */
    unsigned int v = (unsigned int)hiwdt_readl(HIWDT_RIS);
    v &= 0x1; /* 0x1: get INT bit [1] */
    if (v == 0) { /* no INT on current wdg */
        return;
    }

    osal_spin_lock_irqsave(&g_hidog_lock, &flags);
    /* unlock watchdog registers */
    hiwdt_writel(HIWDT_UNLOCK_VAL, HIWDT_LOCK);
    /* clear watchdog */
    hiwdt_writel(0x00, HIWDT_INTCLR);
    /* lock watchdog registers */
    hiwdt_writel(0, HIWDT_LOCK);
    osal_spin_unlock_irqrestore(&g_hidog_lock, &flags);
}
           
  • 喂狗開始函數

static void hidog_start(void)
{
    unsigned long flags;

    osal_spin_lock_irqsave(&g_hidog_lock, &flags);
    /* unlock watchdog registers */
    hiwdt_writel(HIWDT_UNLOCK_VAL, HIWDT_LOCK);
    hiwdt_writel(0x00, HIWDT_CTRL);     /* 0x00: disable watch dog reset signal and interrupt */
    hiwdt_writel(0x00, HIWDT_INTCLR);   /* 0x00: clear interrupt */
    hiwdt_writel(0x03, HIWDT_CTRL);     /* 0x03: enable watch dog reset signal and interrupt */
    /* lock watchdog registers */
    hiwdt_writel(0, HIWDT_LOCK);
    osal_spin_unlock_irqrestore(&g_hidog_lock, &flags);

    g_options = WDIOS_ENABLECARD;
}
           
  • 核心接口函數

/* Kernel Interfaces */
static struct osal_fileops g_hidog_fops = {
    .unlocked_ioctl = hidog_ioctl,
    .open           = hidog_open,
    .release        = hidog_release,
};
           

hidog_open 是使用者态句柄代碼開始喂狗

hidog_release是使用者态停止喂狗,設定喂狗逾時時間,并喂一次狗;

hidog_ioctl是設定喂狗參數,擷取喂狗參數或者喂狗的函數接口;

  • 寄存器的讀寫

g_wtdg_reg_base = (volatile void *)osal_ioremap(HIWDT_BASE, 0x1000); /* 0x1000: watch dog reg length */
#define hiwdt_io_address(x) ((uintptr_t)g_wtdg_reg_base + (x) - HIWDT_BASE)

#define hiwdt_readl(x)       osal_readl(hiwdt_io_address(hiwdt_reg(x)))
#define hiwdt_writel(v, x)   osal_writel(v, hiwdt_io_address(hiwdt_reg(x)))
           

寄存器的讀寫是寄存器的實體位址通過ioremap轉換成虛拟記憶體位址再進行讀寫的,程式退出需要對ioremap的位址進行iounmap。

  • watchdog_init函數中建立字元裝置接口和接口函數進行注冊

g_hidog_miscdev = osal_createdev("watchdog");
g_hidog_miscdev->minor = WATCHDOG_MINOR;
    g_hidog_miscdev->fops = &g_hidog_fops;
    if (osal_registerdevice(g_hidog_miscdev) != 0) {
           
  • 核心線程喂狗

dog = osal_kthread_create(hidog_deamon, NULL, "hidog");
           
OpenHarmony喂狗源碼解讀之核心态源碼

喂狗子產品watchdog_init初始化之後開始喂狗,先有核心喂狗,核心是慢喂狗 30.01s喂一次狗;而使用者态(watchdog_service 10 2)接管喂狗是重新設定的了逾時時間12s,快于核心的喂狗時間,隻要使用者态設定的時間超過30s那麼使用者态停止喂狗,将繼續有核心态喂狗。

想了解更多關于鴻蒙的内容,請通路:

51CTO和華為官方合作共建的鴻蒙技術社群

https://harmonyos.51cto.com/#bkwz