摘要:本文介紹在OpenHarmony社群LiteOS-M專案中新增C-SKY指令集的開發流程,以及適配相應qemu工程的方法和步驟,供LiteOS核心相關開發者學習交流。
本文分享自華為雲社群《OpenHarmony LiteOS指令集移植指南(C-SKY)》,作者: Lionlace。
C-SKY指令集體系結構(ISA)是指第二代獨立的指令集體系結構CK-Core系列智慧財產權指令集體系結構。CSKY ISA具有高效能、高程式碼密度、低功耗和可擴充套件性等特點。
SmartL_E802採用C-SKY V2自主指令架構的E802處理器,是平頭哥半導體有限公司自主研發的低功耗、低成本嵌入式CPU核。其中,SmartL平臺是用於E801/E802/E803S/E804/E805/E902/E906/E907整合和除錯模擬的綜合演示平臺。
本文介紹在OpenHarmony社群LiteOS-M專案中新增C-SKY指令集的開發流程,以及適配相應qemu工程的方法和步驟,供LiteOS核心相關開發者學習交流。
環境搭建
SmartL_E802需要使用官方提供的csky編譯器和qemu工程,以下介紹安裝步驟。
編譯工具鏈安裝
• 獲取csky-elfabiv2編譯器
$ mkdir csky_toolchain && cd csky_toolchain $ wget https://occ-oss-prod.oss-cn-hangzhou.aliyuncs.com/resource/1356021/1619529111421/csky-elfabiv2-tools-x86_64-minilibc-20210423.tar.gz $ tar -xf csky-elfabiv2-tools-x86_64-minilibc-20210423.tar.gz
• 將編譯工具鏈新增到環境變數
開啟~/.bashrc檔案
$ vim ~/.bashrc
在末尾加入如下命令列並儲存
export PATH=$PATH:使用者自定義路徑/csky_toolchain/bin
使環境變數生效
$ source ~/.bashrc
qemu安裝
• 獲取qemu軟體
$ mkdir csky_qemu && cd csky_qemu $ wget https://occ-oss-prod.oss-cn-hangzhou.aliyuncs.com/resource/1356021/1612269502091/csky-qemu-x86_64-Ubuntu-16.04-20210202-1445.tar.gz $ tar -xf csky-qemu-x86_64-Ubuntu-16.04-20210202-1445.tar.gz
• 將qemu加入環境變數(user_qemu_xxx_path修改為自己的安裝路徑)
開啟~/.bashrc檔案
$ vim ~/.bashrc
在末尾加入如下命令列並儲存
e export PATH=$PATH:使用者自定義路徑/csky-qemu/bin
使環境變數生效
$ source ~/.bashrc
• 安裝依賴
使用ldd指令檢視缺少的依賴庫檔案並下載。
$ ldd qemu_installation_path/bin/qemu-system-cskyv2
注:更詳細的安裝指導,請參考官方指南:https://occ.thead.cn/community/download?id=636946310057951232
碼源獲取
原始碼獲取教程請參考:https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/get-code/sourcecode-acquire.md
移植
移植過程按照已實現的riscv的qemu開發板目錄結構新增csky的qemu的目錄結構,並在kernel、device和vendor中實現csky指令集及開發板相關程式碼。
新增目錄結構
分別在device、vendor和kernel建立SmartL_E802開發板所需檔案。
• 在device/qemu目錄下建立SmartL_E802資料夾,並在該資料夾中新增如下內容:
表1 SmartL_E802資料夾目錄
• 在vendor/ohemu目錄下建立qemu_csky_mini_system_demo資料夾,並在該資料夾中新增如下內容:
表2 開發板資料夾目錄
• 在kernel/liteos_m/kernel/arch目錄下建立csky資料夾,並在該資料夾中新增如下內容:
表3 csky資料夾目錄
修改kernel程式碼
在kernel/liteos_m/kernel/arch下建立csky資料夾,並完成以下步驟。
• 新增csky架構的選項
在kernel/BUILD.gn下新增對csky架構的選擇:
else if ("$board_cpu" == "e802") { deps = [ "arch/csky/v2/gcc:arch" ] }
• 編寫架構程式碼
在kernel/liteos_m/kernel/arch中編寫架構程式碼。
a.編寫異常檔案-los_exc.S
將前32位異常統一入口為HandleEntry,在HandleEntry函式中儲存當前棧 和異常地址並傳參給HalExcHandleEntry函式。該函式將會通過中斷號、g_newTask的值和入參判斷異常發生時所處位置型別(初始化、任務、中斷),並呼叫OsExcInfoDisplay函式輸出記憶體檢測結果、函式呼叫棧回溯結果、任務描述塊資訊、異常型別及原因和異常時暫存器狀態。
表4 異常向量分配(圖片來源:平頭哥玄鐵E802使用者手冊)
b.編寫排程程式碼-los_dispatch.S
在los_dispatch.S中編寫HalStartToRun函式和HalTaskContextSwitch函式,通過儲存及恢復R0~R15、epc、epsr和psr幾個暫存器,實現任務的上下文切換。在los_context.c中適配系統邏輯,編寫任務棧初始化函式並在該檔案中呼叫排程函式。
表5 通用暫存器(圖片來源:平頭哥玄鐵E802使用者手冊)
c.編寫系統中斷檔案-los_interrupt.c
將VIC中斷地址VIC_REG_BASE並轉換成結構體,按手冊描述編寫中斷的優先順序,遮蔽、使能和清除功能。使用相關中斷彙編指令實現中斷開關,讀取中斷號等功能。
表6 緊耦合IP的記憶體地址分配(圖片來源:平頭哥玄鐵E802使用者手冊)
d.編寫定時器檔案-los_timer.c
取定時器地址CORE_TIM_BASE並轉換成對應的地址結構體,按手冊編寫控制和過載等功能。適配系統獲取cycle等介面。
表7 系統計時器暫存器定義(圖片來源:平頭哥玄鐵E802使用者手冊)
e.在kernel/arch/csky/v2/gcc/BUILD.gn中新增所編寫的檔案
static_library("arch") { …(加入需要編譯連結的檔案) }
• 編寫csky架構的backtrace
a.在components/backtrace中增加csky架構的backtrace的相關程式碼。通過棧回溯找到函式呼叫過程中的lr地址並儲存,最後在OsExcInfoDisplay中輸出,為使用者分析異常原因提供參考。
b.在kernel/include/los_config.h的LOSCFG_BACKTRACE_TYPE上增加csky架構backtrace的描述。
5: Call stack analysis for c-sky by scanning the stack.
注:架構相關內容詳情請檢視平頭哥玄鐵E802使用者手冊。
修改device程式碼
在device/qemu下新增SmartL_E802資料夾,並完成以下步驟。
• 移植SDK中程式碼到device目錄下
a.將SmartL_E802 SDK驅動程式碼整理拷貝到driver目錄內,並編寫BUILD.gn檔案編譯驅動程式碼。
b.參考SDK中的gcc_csky.ld中暫存器配置修改liteos.ld檔案,分配程式碼到指定區間。
{ I-SRAM : ORIGIN = 0x0 , LENGTH = 0x20000 /* I-SRAM 128KB */ D-SRAM : ORIGIN = 0x20000000 , LENGTH = 0x20000 /* D-SRAM 128KB */ O-SRAM : ORIGIN = 0x50000000 , LENGTH = 0x800000 /* off-chip SRAM 8MB */ SRAM : ORIGIN = 0x60000000 , LENGTH = 0x20000 /* on-chip SRAM 128KB */ } …
c.參考SDK中的startup.S檔案,刪除vector定義並編寫中斷總入口
.text .align 2 .global IrqE IrqEntry: psrset ee subi sp, 72 stm r0-r15, (sp) mfcr r0, epsr stw r0, (sp, 64) mfcr r0, epc stw r0, (sp, 68) jbsr HalInterrupt ldw r0, (sp, 68) mtcr r0, epc ldw r0, (sp, 64) bseti r0, r0, 6 mtcr r0, epsr ldm r0-r15, (sp) addi sp, 72 rte
• 編寫串列埠驅動
參考SDK中串列埠demo和printf實現邏輯,編寫dprintf.c/.h並在main.c中呼叫串列埠初始化。
• 適配檔案系統
參考LiteOS程式碼,將fs適配層檔案移植到SmartL_E802中。
• 編寫config.gni檔案
參考device/qemu/riscv32_virt中config.gni 的格式,再參考SDK中的編譯選項和需要對外呼叫的介面,在liteos_m資料夾下編寫config.gni檔案。
• 編寫test測試程式碼
參考device/qemu/riscv32_virt編寫測試程式碼。
• 編寫BUILD.gn檔案
編寫BUILD.gn檔案,將fs適配層,driver開發板驅動程式碼等編譯出來的靜態庫合成liteos可執行檔案。
• 編寫README.md
在SmartL_E802資料夾下編寫中英文使用者指南:README_zh.md及README.md,並修改device/qemu目錄下的中英文文件,新增對csky開發板的介紹。
修改vendor程式碼
在vendor/ohemu下建立qemu_csky_mini_system_demo資料夾,並完成以下步驟。
• 拷貝hals/utils資料夾
參考vendor/ohemu/qemu_riscv32_mini_system_demo,在qemu_csky_mini_system_demo資料夾下新增hals/utils資料夾。
• 編寫BUILD.gn檔案
參考vendor/ohemu/qemu_riscv32_mini_system_demo,編寫BUILD.gn檔案並增加./qemu-run指令碼的使用。
• 修改config.json檔案
參考vendor/ohemu/qemu_riscv32_mini_system_demo,將其中riscv內容修改為csky相關內容。
• 編寫qemu_run.sh指令碼
使用./qemu-run對應的架構指令碼,參考vendor/ohemu/qemu_riscv32_mini_system_demo和平頭哥官方提供的qemu使用手冊(https://occ.t-head.cn/community/download?id=636946310057951232)編寫該指令碼。
編譯執行
編譯
• 執行hb set命令並選擇專案qemu_csky_mini_system_demo;
• 執行hb clean && hb build命令構建產生 liteos 可執行檔案。
$ hb set $ hb clean && hb build
在Qemu中執行映象
• 啟動qemu(不配合GDB)
$ ./qemu-run
• 啟動qemu(配合GDB)
a.啟動GDB伺服器,等待連線
$ ./qemu-run -g
b.新建終端並使用GDB連線qemu
$ csky-abiv2-elf-gdb out/SmartL_E802/qemu_csky_mini_system_demo/unstripped/bin/liteos -ex "target remote localhost:1234"
注:
1.預設使用帶符號表的elf檔案;
2.qemu退出方式為:按下ctrl加a鍵,然後鬆開再按下x鍵。
qemu執行結果關鍵日誌如下:
entering kernel init... Entering scheduler Register littlefs done. ../../../third_party/littlefs/lfs.c:1072:error: Corrupted dir pair at {0x0, 0x1} Littlefs mount at /littlefs/ done. Littlefs inited. TaskSampleEntry1 running... TaskSampleEntry2 running...
本次移植適配的相關原始碼路徑為:
kernel : https://gitee.com/openharmony/kernel_liteos_m/tree/master/kernel/arch/csky/v2/gcc
qemu : https://gitee.com/openharmony/device_qemu/tree/master/SmartL_E802
vendor : https://gitee.com/openharmony/vendor_ohemu/tree/master/qemu_csky_mini_system_demo