色哟哟视频在线观看-色哟哟视频在线-色哟哟欧美15最新在线-色哟哟免费在线观看-国产l精品国产亚洲区在线观看-国产l精品国产亚洲区久久

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

openharmony源碼靜態分析

姚小熊27 ? 來源:整合自博客園 ? 作者:整合自博客園 ? 2021-06-23 15:24 ? 次閱讀

放原子開源基金會(簡稱“基金會”)于 2020 年 9 月接受華為捐贈的智能終端操作系統基礎能力相關代碼,隨后進行開源,并根據命名規則為該開源項目命名為 OpenAtom OpenHarmony(簡稱“OpenHarmony”)。

OpenHarmony是自主研發、不兼容安卓的全領域下一代開源操作系統。OpenHarmony內核主要包括進程和線程調度、內存管理、IPC機制、timer管理等內核基本功能。

#ifndef __scc

#define __scc(X) ((long) (X)) // 轉為long類型

typedef long syscall_arg_t;

#endif

#define __syscall1(n,a) __syscall1(n,__scc(a))

#define __syscall2(n,a,b) __syscall2(n,__scc(a),__scc(b))

#define __syscall3(n,a,b,c) __syscall3(n,__scc(a),__scc(b),__scc(c)) //

繼續搜索發現有多出匹配,我們關注arch/arm目錄下的文件,因為ARM Cortext A7是Armv7-A指令集的32位CPU(如果是Armv8-A指令集的64位CPU則對應arch/aarch64下的文件):

static inline long __syscall3(long n, long a, long b, long c)

{

register long r7 __ASM____R7__ = n;

register long r0 __asm__(“r0”) = a;

register long r1 __asm__(“r1”) = b;

register long r2 __asm__(“r2”) = c;

__asm_syscall(R7_OPERAND, “0”(r0), “r”(r1), “r”(r2));

}

這段代碼中還有三個宏,__ASM____R7__、__asm_syscall和R7_OPERAND:

#ifdef __thumb__

#define __ASM____R7__

#define __asm_syscall(。。.) do { \

__asm__ __volatile__ ( “mov %1,r7 ; mov r7,%2 ; svc 0 ; mov r7,%1” \

: “=r”(r0), “=&r”((int){0}) : __VA_ARGS__ : “memory”); \

return r0; \

} while (0)

#else // __thumb__

#define __ASM____R7__ __asm__(“r7”)

#define __asm_syscall(。。.) do { \

__asm__ __volatile__ ( “svc 0” \

: “=r”(r0) : __VA_ARGS__ : “memory”); \

return r0; \

} while (0)

#endif // __thumb__

#ifdef __thumb2__

#define R7_OPERAND “rI”(r7)

#else

#define R7_OPERAND “r”(r7)

#endif

它們有兩個實現版,分別對應于編譯器THUMB選項的開啟和關閉。這兩種選項條件下的代碼流程基本一致,以下僅以未開啟THUMB選項為例進行分析。這兩個宏展開后的__syscall3函數內容為:

static inline long __syscall3(long n, long a, long b, long c)

{

register long r7 __asm__(“r7”) = n; // 系統調用號

register long r0 __asm__(“r0”) = a; // 參數0

register long r1 __asm__(“r1”) = b; // 參數1

register long r2 __asm__(“r2”) = c; // 參數2

do { \

__asm__ __volatile__ ( “svc 0” \

: “=r”(r0) : “r”(r7), “0”(r0), “r”(r1), “r”(r2) : “memory”); \

return r0; \

} while (0);

}

這里最后的一個內嵌匯編比較復雜,它符合如下格式(具體細節可以查閱gcc內嵌匯編文檔的擴展匯編說明):

asm asm-qualifiers ( AssemblerTemplate

: OutputOperands

[ : InputOperands

[ : Clobbers ] ])

匯編模板為:“svc 0”, 輸出參數部分為:“=r”(r0),輸出寄存器為r0輸入參數部分為:“r”(r7), “0”(r0), “r”(r1), “r”(r2),輸入寄存器為r7,r0,r1,r2,(“0”的含義是,這個輸入寄存器必須和輸出寄存器第0個位置一樣) Clobber部分為:“memory”

這里我們只需要記住:系統調用號存放在r7寄存器,參數存放在r0,r1,r2,返回值最終會存放在r0中;

SVC指令,ARM Cortex A7手冊 的解釋為:

The SVC instruction causes a Supervisor Call exception. This provides a mechanism for unprivileged software to make a call to the operating system, or other system component that is accessible only at PL1.

翻譯過來就是說

SVC指令會觸發一個“特權調用”異常。這為非特權軟件調用操作系統或其他只能在PL1級別訪問的系統組件提供了一種機制。

詳細的指令說明在

到這里,我們分析了鴻蒙系統上應用程序如何進入內核態,主要分析的是musl libc的實現。

liteos-a內核的系統調用實現分析

既然SVC能夠觸發一個異常,那么我們就要看看liteos-a內核是如何處理這個異常的。

ARM Cortex A7中斷向量表

在ARM架構參考手冊中,可以找到中斷向量表的說明:

f4fa71d9e8dfffc1b1e7c3efcb4001e0.png

可以看到SVC中斷向量的便宜地址是0x08,我們可以在kernel/liteos_a/arch/arm/arm/src/startup目錄的reset_vector_mp.S文件和reset_vector_up.S文件中找到相關匯編代碼:

__exception_handlers:

/*

*Assumption: ROM code has these vectors at the hardware reset address.

*A simple jump removes any address-space dependencies [i.e. safer]

*/

b reset_vector

b _osExceptUndefInstrHdl

b _osExceptSwiHdl

b _osExceptPrefetchAbortHdl

b _osExceptDataAbortHdl

b _osExceptAddrAbortHdl

b OsIrqHandler

b _osExceptFiqHdl

PS:kernel/liteos_a/arch/arm/arm/src/startup目錄有兩個文件reset_vector_mp.S文件和reset_vector_up.S文件分別對應多核和單核編譯選項:

ifeq ($(LOSCFG_KERNEL_SMP), y)

LOCAL_SRCS += src/startup/reset_vector_mp.S

else

LOCAL_SRCS += src/startup/reset_vector_up.S

endif

SVC中斷處理函數

上面的匯編代碼中可以看到,_osExceptSwiHdl函數就是SVC異常處理函數,具體實現在kernel/liteos_a/arch/arm/arm/src/los_hw_exc.S文件中:

@ Description: Software interrupt exception handler

_osExceptSwiHdl:

SUB SP, SP, #(4 * 16) @ 棧增長

STMIA SP, {R0-R12} @ 保存R0-R12寄存器到棧上

MRS R3, SPSR @ 移動SPSR寄存器的值到R3

MOV R4, LR

AND R1, R3, #CPSR_MASK_MODE @ Interrupted mode

CMP R1, #CPSR_USER_MODE @ User mode

BNE OsKernelSVCHandler @ Branch if not user mode

@ we enter from user mode, we need get the values of USER mode r13(sp) and r14(lr)。

@ stmia with ^ will return the user mode registers (provided that r15 is not in the register list)。

MOV R0, SP

STMFD SP!, {R3} @ Save the CPSR

ADD R3, SP, #(4 * 17) @ Offset to pc/cpsr storage

STMFD R3!, {R4} @ Save the CPSR and r15(pc)

STMFD R3, {R13, R14}^ @ Save user mode r13(sp) and r14(lr)

SUB SP, SP, #4

PUSH_FPU_REGS R1

MOV FP, #0 @ Init frame pointer

CPSIE I @ Interrupt Enable

BLX OsArmA32SyscallHandle

CPSID I @ Interrupt Disable

POP_FPU_REGS R1

ADD SP, SP,#4

LDMFD SP!, {R3} @ Fetch the return SPSR

MSR SPSR_cxsf, R3 @ Set the return mode SPSR

@ we are leaving to user mode, we need to restore the values of USER mode r13(sp) and r14(lr)。

@ ldmia with ^ will return the user mode registers (provided that r15 is not in the register list)

LDMFD SP!, {R0-R12}

LDMFD SP, {R13, R14}^ @ Restore user mode R13/R14

ADD SP, SP, #(2 * 4)

LDMFD SP!, {PC}^ @ Return to user

這段代碼的注釋較為清楚,可以看到,內核模式會繼續調用OsKernelSVCHandler,用戶模式會繼續調用OsArmA32SyscallHandle函數;

OsArmA32SyscallHandle函數

我們這里分析的流程是從用戶模式進入的,所以調用的是OsArmA32SyscallHandle,它的實現位于kernel/liteos_a/syscall/los_syscall.c文件:

/* The SYSCALL ID is in R7 on entry. Parameters follow in R0..R6 */

LITE_OS_SEC_TEXT UINT32 *OsArmA32SyscallHandle(UINT32 *regs)

{

UINT32 ret;

UINT8 nArgs;

UINTPTR handle;

UINT32 cmd = regs[REG_R7];

if (cmd 》= SYS_CALL_NUM) {

PRINT_ERR(“Syscall ID: error %d !!!\n”, cmd);

return regs;

}

if (cmd == __NR_sigreturn) {

OsRestorSignalContext(regs);

return regs;

}

handle = g_syscallHandle[cmd]; // 得到實際系統調用處理函數

nArgs = g_syscallNArgs[cmd / NARG_PER_BYTE]; /* 4bit per nargs */

nArgs = (cmd & 1) ? (nArgs 》》 NARG_BITS) : (nArgs & NARG_MASK);

if ((handle == 0) || (nArgs 》 ARG_NUM_7)) {

PRINT_ERR(“Unsupport syscall ID: %d nArgs: %d\n”, cmd, nArgs);

regs[REG_R0] = -ENOSYS;

return regs;

}

switch (nArgs) { // 以下各個case是實際函數調用

case ARG_NUM_0:

case ARG_NUM_1:

ret = (*(SyscallFun1)handle)(regs[REG_R0]);

break;

case ARG_NUM_2:

case ARG_NUM_3:

ret = (*(SyscallFun3)handle)(regs[REG_R0], regs[REG_R1], regs[REG_R2]);

break;

case ARG_NUM_4:

case ARG_NUM_5:

ret = (*(SyscallFun5)handle)(regs[REG_R0], regs[REG_R1], regs[REG_R2], regs[REG_R3],

regs[REG_R4]);

break;

default:

ret = (*(SyscallFun7)handle)(regs[REG_R0], regs[REG_R1], regs[REG_R2], regs[REG_R3],

regs[REG_R4], regs[REG_R5], regs[REG_R6]);

}

regs[REG_R0] = ret; // 返回值填入R0

OsSaveSignalContext(regs);

/* Return the last value of curent_regs. This supports context switches on return from the exception.

* That capability is only used with theSYS_context_switch system call.

*/

return regs;

}

這個函數中用到了個全局數組g_syscallHandle和g_syscallNArgs,它們的定義以及初始化函數也在同一個文件中:

static UINTPTR g_syscallHandle[SYS_CALL_NUM] = {0};

static UINT8 g_syscallNArgs[(SYS_CALL_NUM + 1) / NARG_PER_BYTE] = {0};

void SyscallHandleInit(void)

{

#define SYSCALL_HAND_DEF(id, fun, rType, nArg) \

if ((id) 《 SYS_CALL_NUM) { \

g_syscallHandle[(id)] = (UINTPTR)(fun); \

g_syscallNArgs[(id) / NARG_PER_BYTE] |= \

((id) & 1) ? (nArg) 《《 NARG_BITS : (nArg); \

}

#include “syscall_lookup.h”

#undef SYSCALL_HAND_DEF

}

其中SYSCALL_HAND_DEF宏的對齊格式我做了一點調整。

從g_syscallNArgs成員賦值以及定義的地方,能看出它的每個UINT8成員被用來存放兩個系統調用的參數個數,從而實現更少的內存占用;

syscall_lookup.h文件和los_syscall.c位于同一目錄,它記錄了系統調用函數對照表,我們僅節取一部分:

SYSCALL_HAND_DEF(__NR_read, SysRead, ssize_t, ARG_NUM_3)

SYSCALL_HAND_DEF(__NR_write, SysWrite, ssize_t, ARG_NUM_3) //

看到這里,write系統調用的內核函數終于找到了——SysWrite。

到此,我們已經知道了liteos-a的系統調用機制是如何實現的。

liteos-a內核SysWrite的實現

SysWrite函數的實現位于kernel/liteos_a/syscall/fs_syscall.c文件:

ssize_t SysWrite(int fd, const void *buf, size_t nbytes)

{

int ret;

if (nbytes == 0) {

return 0;

}

if (!LOS_IsUserAddressRange((vaddr_t)(UINTPTR)buf, nbytes)) {

return -EFAULT;

}

/* Process fd convert to system global fd */

fd = GetAssociatedSystemFd(fd);

ret = write(fd, buf, nbytes); //

它又調用了write?但是這一次是內核空間的write,不再是 musl libc,經過一番搜索,我們可以找到另一個文件third_party/NuttX/fs/vfs/fs_write.c中的write:

ssize_t write(int fd, FAR const void *buf, size_t nbytes) {

#if CONFIG_NFILE_DESCRIPTORS 》 0

FAR struct file *filep;

if ((unsigned int)fd 》= CONFIG_NFILE_DESCRIPTORS)

#endif

{ /* Write to a socket descriptor is equivalent to send with flags == 0 */

#if defined(LOSCFG_NET_LWIP_SACK)

FAR const void *bufbak = buf;

ssize_t ret;

if (LOS_IsUserAddress((VADDR_T)(uintptr_t)buf)) {

if (buf != NULL && nbytes 》 0) {

buf = malloc(nbytes);

if (buf == NULL) { /* 省略 錯誤處理 代碼 */ }

if (LOS_ArchCopyFromUser((void*)buf, bufbak, nbytes) != 0) {/* 省略 */}

}

}

ret = send(fd, buf, nbytes, 0); // 這個分支是處理socket fd的

if (buf != bufbak) {

free((void*)buf);

}

return ret;

#else

set_errno(EBADF);

return VFS_ERROR;

#endif

}

#if CONFIG_NFILE_DESCRIPTORS 》 0

/* The descriptor is in the right range to be a file descriptor.。。 write

* to the file.

*/

if (fd 《= STDERR_FILENO && fd 》= STDIN_FILENO) { /* fd : [0,2] */

fd = ConsoleUpdateFd();

if (fd 《 0) {

set_errno(EBADF);

return VFS_ERROR;

}

}

int ret = fs_getfilep(fd, &filep);

if (ret 《 0) {

/* The errno value has already been set */

return VFS_ERROR;

}

if (filep-》f_oflags & O_DIRECTORY) {

set_errno(EBADF);

return VFS_ERROR;

}

if (filep-》f_oflags & O_APPEND) {

if (file_seek64(filep, 0, SEEK_END) == -1) {

return VFS_ERROR;

}

}

/* Perform the write operation using the file descriptor as an index */

return file_write(filep, buf, nbytes);

#endif

}

找到這段代碼,我們知道了:

liteos-a的vfs是在NuttX基礎上實現的,NuttX是一個開源RTOS項目;

liteos-a的TCP/IP協議棧是基于lwip的,lwip也是一個開源項目;

這段代碼中的write分為兩個分支,socket fd調用lwip的send,另一個分支調用file_write;

至于,file_write如何調用到存儲設備驅動程序,則是更底層的實現了,本文不在繼續分析。

補充說明

本文內容均是基于鴻蒙系統開源項目OpenHarmony源碼靜態分析所整理,沒有進行實際的運行環境調試,實際執行過程可能有所差異,希望發現錯誤的讀者及時指正。文中所有路徑均為整個openharmony源碼樹上的相對路徑(而非liteos源碼相對路徑)。

責任編輯:YYX

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 開源
    +關注

    關注

    3

    文章

    3371

    瀏覽量

    42583
  • 鴻蒙系統
    +關注

    關注

    183

    文章

    2636

    瀏覽量

    66470
  • OpenHarmony
    +關注

    關注

    25

    文章

    3729

    瀏覽量

    16408
收藏 人收藏

    評論

    相關推薦

    OpenHarmony程序分析框架論文入選ICSE 2025

      近日,ICSE 2025軟件工程實踐Track放榜,面向OpenAtom OpenHarmony(以下簡稱“OpenHarmony”)的ArkTS程序分析基礎框架--方舟程序分析
    的頭像 發表于 01-02 13:41 ?131次閱讀
    <b class='flag-5'>OpenHarmony</b>程序<b class='flag-5'>分析</b>框架論文入選ICSE 2025

    OpenHarmony源碼編譯后燒錄鏡像教程,RK3566鴻蒙開發板演示

    本文介紹瑞芯微主板/開發板編譯OpenHarmony源碼后燒錄鏡像的教程,觸覺智能Purple Pi OH鴻蒙開發板演示。搭載了瑞芯微RK3566四核處理器,樹莓派卡片電腦設計,支持開源鴻蒙OpenHarmony3.2-5.0系
    的頭像 發表于 12-30 10:08 ?122次閱讀
    <b class='flag-5'>OpenHarmony</b><b class='flag-5'>源碼</b>編譯后燒錄鏡像教程,RK3566鴻蒙開發板演示

    【開源鴻蒙】使用QEMU運行OpenHarmony輕量系統

    本文將會介紹如何從源碼安裝QEMU 6.2.0,以及如何使用QEMU運行OpenHarmony輕量系統。通過本文,你將會對QEMU和OpenHarmony輕量系統又一個初步的認知,并對如何使用QEMU又一個初步的理解和體會。
    的頭像 發表于 09-14 08:51 ?643次閱讀
    【開源鴻蒙】使用QEMU運行<b class='flag-5'>OpenHarmony</b>輕量系統

    鴻蒙OpenHarmony南向/北向快速開發教程-迅為RK3568開發板

    優化開發流程-配置遠程訪問環境 P8_優化開發流程-編譯源碼和燒寫鏡像 P9_OpenHarmony源碼目錄介紹 P10_整體移植方案介紹 P11_編譯目標分析 P12_編譯框架基本概
    發表于 07-23 10:44

    開源鴻蒙 編譯OpenHarmony輕量系統QEMU RISC-V版本

    本文將介紹如何為QEMU RISC-V虛擬平臺構建OpenHarmony輕量系統。得益于QEMU的CPU指令集模擬執行能力,該方法可以在沒有開發板的情況下調試和運行OpenHarmony系統源碼。本文介紹的該方法,可以用于
    的頭像 發表于 07-15 10:36 ?1118次閱讀
    開源鴻蒙 編譯<b class='flag-5'>OpenHarmony</b>輕量系統QEMU RISC-V版本

    OpenHarmony之開機優化

    一丶環境信息 源碼版本:OpenHarmony-4.1-Release 板子型號:dayu200(RK3568) 二丶Bootchart工具 在開機優化時,我們需要借助Bootchart工具,當前
    發表于 07-01 16:39

    如何在OpenHarmony設置靜態IP?

    介紹本文適用于所有RK3566/RK3568/RK3588平臺產品在OpenHarmony系統上設置靜態IP。本文以PurplePiOH開發板為例,在OpenHarmony系統上進行設置。觸覺智能
    的頭像 發表于 05-12 08:32 ?781次閱讀
    如何在<b class='flag-5'>OpenHarmony</b>設置<b class='flag-5'>靜態</b>IP?

    鴻蒙OpenHarmony【標準系統 編譯】(基于RK3568開發板)

    OpenHarmony支持hb和build.sh兩種編譯方式。此處介紹hb方式,build.sh腳本編譯方式請參考[使用build.sh腳本編譯源碼]。
    的頭像 發表于 05-08 17:37 ?1245次閱讀
    鴻蒙<b class='flag-5'>OpenHarmony</b>【標準系統 編譯】(基于RK3568開發板)

    HarmonyOS開發:【基于命令行(獲取源碼)】

    在Ubuntu環境下通過以下步驟獲取OpenHarmony源碼
    的頭像 發表于 04-25 22:08 ?413次閱讀
    HarmonyOS開發:【基于命令行(獲取<b class='flag-5'>源碼</b>)】

    鴻蒙OpenHarmony【創建工程并獲取源碼

    在通過DevEco Device Tool創建OpenHarmony工程時,可自動下載相應版本的OpenHarmony源碼
    的頭像 發表于 04-19 21:40 ?391次閱讀
    鴻蒙<b class='flag-5'>OpenHarmony</b>【創建工程并獲取<b class='flag-5'>源碼</b>】

    鴻蒙OpenHarmony【搭建Ubuntu環境】

    在嵌入式開發中,很多開發者習慣于使用Windows進行代碼的編輯,比如使用Windows的Visual Studio Code進行OpenHarmony代碼的開發。但當前階段,大部分的開發板源碼還不
    的頭像 發表于 04-19 16:53 ?1294次閱讀
    鴻蒙<b class='flag-5'>OpenHarmony</b>【搭建Ubuntu環境】

    鴻蒙OpenHarmony【搭建Windows環境】

    在嵌入式開發中,很多開發者習慣于使用Windows進行代碼的編輯,比如使用Windows的Visual Studio Code進行OpenHarmony代碼的開發。但當前階段,大部分的開發板源碼還不
    的頭像 發表于 04-19 15:42 ?629次閱讀
    鴻蒙<b class='flag-5'>OpenHarmony</b>【搭建Windows環境】

    OpenHarmony開發學習:【源碼下載和編譯】

    本文介紹了如何下載鴻蒙系統源碼,如何一次性配置可以編譯三個目標平臺(`Hi3516`,`Hi3518`和`Hi3861`)的編譯環境,以及如何將源碼編譯為三個目標平臺的二進制文件。
    的頭像 發表于 04-14 09:36 ?978次閱讀
    <b class='flag-5'>OpenHarmony</b>開發學習:【<b class='flag-5'>源碼</b>下載和編譯】

    OpenHarmony內核編程實戰

    編程入門[Hello,OpenHarmony]在正式開始之前,對于剛接觸OpenHarmony的伙伴們,面對大篇幅的源碼可能無從下手,不知道怎么去編碼寫程序,下面用一個簡單的例子帶伙伴們入門。▍任務
    的頭像 發表于 03-27 08:31 ?870次閱讀
    <b class='flag-5'>OpenHarmony</b>內核編程實戰

    鴻蒙開發學習:【OpenHarmony HAR】

    OpenHarmony js/ts三方庫使用的是OpenHarmony靜態共享包,即HAR(Harmony Archive),可以包含js/ts代碼、c++庫、資源和配置文件。通過HAR,可以實現
    的頭像 發表于 03-18 16:27 ?772次閱讀
    主站蜘蛛池模板: 欧美亚洲国产手机在线有码| 国产热久久精| 帝王被大臣们调教高肉| 国模丽丽啪啪一区二区| 嫩草影院在线观看网站成人| 性色欲情网站IWWW| videossexotv极度另类| 精品久久久久久综合网| 我和妽妽在厨房里的激情区二区| 99久久精品免费看国产一区二区三区 | 先锋影音 av| CHINA篮球体育飞机2022网站| 久9视频这里只有精品123| 日韩男明星| 26uuu老色哥| 久久99AV无色码人妻蜜| 四虎永久精品视频在线| 把英语老师强奷到舒服动态图| 久久大胆视频| 亚洲国产精品一区二区久久第| 第一次玩老妇真实经历| 牛牛在线视频| 99久久国产露脸精品麻豆| 久青草国产97香蕉在线视频| 亚洲人成在线播放网站岛国| 国产久久re6免费热在线| 色噜噜视频影院| 本庄优花aⅴ全部在线影片| 欧美美女一区二区三区| 99热这里只有精品| 欧美ZC0O人与善交的最新章节| 91日本在线观看亚洲精品| 两个奶头被吃得又翘又痛| 欲插爽乱浪伦骨| 久久偷拍人| 2021自产拍在线观看视频| 久久亚洲欧美国产综合| 2021国产精品视频一区| 欧美videos人牛交| YY8090福利午夜理论片| 日韩在线av免费视久久|