riscv架構下linux4.15實現early打印

在高版本linux6.12.7源碼中,early console介紹,可參考《riscv架構下linux6.12.7實現early打印》文章。

1 什么是early打印

適配內核到新的平臺,基本環境搭建好之后,首要的就是要調通串口,方便后面的信息打印。
正常流程 init/main.c 中 start_kernel 入口,要到 console_init 之后才能真正打印,前面的打印,都是緩存在 printk 的 ringbuffer 中的。
如果在 console_init 前就異常了,此時就看不到打印信息,為了調試 console_init 前的狀態,需要能更早的打印,內核提供了一種 early 打印的方式,尤其是 riscv 平臺我們可以直接 ecall 調用 opensbi 的打印,這樣 opensbi 適配好之后,這里就可以直接使用。

earlyprintk 的實現依賴于特定的硬件平臺,并且通常與特定固件配合使用。
earlyprintk 是一個高級功能,主要用于內核開發和調試。在生產環境中,通常不需要啟用此功能,因為它可能會干擾系統的正常啟動過程,或暴露潛在的敏感信息。

從 earlyprintk 到串行控制臺的轉換,通常發生在內核初始化過程中,特別是在 register_console 函數被調用之后。這個函數負責注冊串行控制臺,并使其成為內核默認的打印信息輸出設備。一旦串行控制臺被注冊,內核就會開始使用它來輸出打印信息,而 earlyprintk 則不再被需要。

2 printk函數實現

printk函數代碼實現,如下所示:

// 1.riscv-linux-4.15/include/linux/printk.h:
#define pr_info(fmt, ...) \printk(KERN_INFO pr_fmt(fmt), ##__VA_ARGS__)  調用==>// 2.riscv-linux-4.15/kernel/printk/printk.c:
asmlinkage __visible int printk(const char *fmt, ...)
{va_list args;int r;va_start(args, fmt);r = vprintk_func(fmt, args);   調用==>va_end(args);return r;
}// 3.riscv-linux-4.15/kernel/printk/printk_safe.c:
__printf(1, 0) int vprintk_func(const char *fmt, va_list args)
{...return vprintk_default(fmt, args);    調用==>
}// 4.riscv-linux-4.15/kernel/printk/printk.c:
int vprintk_default(const char *fmt, va_list args)
{...r = vprintk_emit(0, LOGLEVEL_DEFAULT, NULL, 0, fmt, args);    調用==>return r;
}// 5.riscv-linux-4.15/kernel/printk/printk.c:
asmlinkage int vprintk_emit(int facility, int level,const char *dict, size_t dictlen,const char *fmt, va_list args)
{...printed_len = log_output(facility, level, lflags, dict, dictlen, text, text_len);...console_unlock();    調用==>...
}// 6.riscv-linux-4.15/kernel/printk/printk.c:
void console_unlock(void)
{...call_console_drivers(ext_text, ext_len, text, len);    調用==>...
}// 7.riscv-linux-4.15/kernel/printk/printk.c:
static void call_console_drivers(const char *ext_text, size_t ext_len,const char *text, size_t len)
{struct console *con;trace_console_rcuidle(text, len); if (!console_drivers)return;for_each_console(con) {  // 遍歷console_drivers中每個consoleif (exclusive_console && con != exclusive_console)continue;if (!(con->flags & CON_ENABLED))continue;if (!con->write)continue;if (!cpu_online(smp_processor_id()) &&!(con->flags & CON_ANYTIME))continue;if (con->flags & CON_EXTENDED)con->write(con, ext_text, ext_len);elsecon->write(con, text, len); // 通過console的write函數打印內容}
}

在代碼中,從printk開始,層層分析,最后在call_console_drivers函數中,會遍歷console_drivers中每個console,并調用console的write函數來完成內容打印。

pr_info ==>
printk ==>
vprintk_func ==>
vprintk_default ==>
vprintk_emit ==>
console_unlock ==>
call_console_drivers ==>
con->write

3 console注冊

console結構體定義:

// riscv-linux-4.15/include/linux/console.h:
struct console {char	name[16];void	(*write)(struct console *, const char *, unsigned);int	(*read)(struct console *, char *, unsigned);struct tty_driver *(*device)(struct console *, int *);void	(*unblank)(void);int	(*setup)(struct console *, char *);int	(*match)(struct console *, char *name, int idx, char *options);short	flags;short	index;int	cflag;void	*data;struct	 console *next;
};

通過register_console函數,可以將一個console進行注冊,放入console_drivers鏈表中,如下:

// riscv-linux-4.15/arch/riscv/kernel/setup.c:
void __init setup_arch(char **cmdline_p)
{
#if defined(CONFIG_EARLY_PRINTK)if (likely(early_console == NULL)) {early_console = &riscv_sbi_early_console_dev;register_console(early_console); // 注冊early console}
#endif*cmdline_p = boot_command_line;...
}// early console定義
struct console riscv_sbi_early_console_dev __initdata = {.name	= "early",.write	= sbi_console_write,.flags	= CON_PRINTBUFFER | CON_BOOT | CON_ANYTIME,.index	= -1
};// early console的write函數
static void sbi_console_write(struct console *co, const char *buf,unsigned int n)
{int i;for (i = 0; i < n; ++i) {if (buf[i] == '\n')sbi_console_putchar('\r');sbi_console_putchar(buf[i]);}
}// riscv-linux-4.15/arch/riscv/include/asm/sbi.h:
#define SBI_CALL(which, arg0, arg1, arg2) ({			\register uintptr_t a0 asm ("a0") = (uintptr_t)(arg0);	\register uintptr_t a1 asm ("a1") = (uintptr_t)(arg1);	\register uintptr_t a2 asm ("a2") = (uintptr_t)(arg2);	\register uintptr_t a7 asm ("a7") = (uintptr_t)(which);	\asm volatile ("ecall"					\: "+r" (a0)				\: "r" (a1), "r" (a2), "r" (a7)		\: "memory");				\a0;							\
})/* Lazy implementations until SBI is finalized */
#define SBI_CALL_0(which) SBI_CALL(which, 0, 0, 0)
#define SBI_CALL_1(which, arg0) SBI_CALL(which, arg0, 0, 0)
#define SBI_CALL_2(which, arg0, arg1) SBI_CALL(which, arg0, arg1, 0)static inline void sbi_console_putchar(int ch)
{SBI_CALL_1(SBI_CONSOLE_PUTCHAR, ch);
}static inline int sbi_console_getchar(void)
{return SBI_CALL_0(SBI_CONSOLE_GETCHAR);
}

4 SBI_CALL

console的write函數:先調用sbi_console_putchar,再調SBI_CALL。
SBI_CALL實現的功能,可大致理解為:

SBI_CALL(which, arg0, arg1, arg2) 
{			a0寄存器 = (uintptr_t)(arg0);	a1寄存器 = (uintptr_t)(arg1);	a2寄存器 = (uintptr_t)(arg2);	a7寄存器 = (uintptr_t)(which);	執行ecall指令;					
}

SBI_CALL宏,通過在RISC-V處理器上,執行ecall指令來調用一個服務:

  • 它通過將參數,放入特定的寄存器(a0、a1、a2);
  • 并將服務標識符(調用號),放入a7寄存器;
  • 然后,它執行ecall指令,并返回a0寄存器的值作為結果。

ecall系統調用,會觸發異常(mcause寄存器定義的異常8或9)。只不過這種異常,是由U或S模式下,程序通過ecall指令,軟件觸發的異常,主要用于系統調用,實現一些底層調用,例如輸出打印信息到串口等。

可以看到,這里定義了很多調用號Timer、Console、IPI、Shutdown等,如下:

// riscv-linux-4.15/arch/riscv/include/asm/sbi.h:
#define SBI_SET_TIMER 0
#define SBI_CONSOLE_PUTCHAR 1
#define SBI_CONSOLE_GETCHAR 2
#define SBI_CLEAR_IPI 3
#define SBI_SEND_IPI 4
#define SBI_REMOTE_FENCE_I 5
#define SBI_REMOTE_SFENCE_VMA 6
#define SBI_REMOTE_SFENCE_VMA_ASID 7
#define SBI_SHUTDOWN 8

在這里,就是:

  • 將調用號1放入a7寄存器,將欲打印字符ch放入a0寄存器,然后CPU執行ecall指令,就會觸發一個異常;
  • 然后CPU會處理該異常,由于當前kernel運行在S模式,因此CPU會進入M模式,并跳轉到M模式異常處理入口(Open SBI),在固件OpenSBI的處理代碼中,會判斷當調用號為1時,將字符ch打印出來(打印的方式,可以通過Uart或HTIF)。
    在這里插入圖片描述
    在riscv-pk開源項目中,也支持通過ecall指令,來使用Uart或HTIF輸出打印信息。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/66008.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/66008.shtml
英文地址,請注明出處:http://en.pswp.cn/web/66008.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

improve-gantt-elastic(vue2中甘特圖實現與引入)

1.前言 項目開發中需要使用甘特圖展示項目實施進度&#xff0c;左側為表格計劃&#xff0c;右側為圖表進度展示。wl-gantt-mater&#xff0c;dhtmlx嘗試使用過可拓展性受到限制。gantt-elastic相對簡單&#xff0c;可操作性強&#xff0c;基礎版本免費。 甘特圖&#xff08;Gan…

力扣 全排列

回溯經典例題。 題目 通過回溯生成所有可能的排列。每次遞歸時&#xff0c;選擇一個數字&#xff0c;直到選滿所有數字&#xff0c;然后記錄當前排列&#xff0c;回到上層時移除最后選的數字并繼續選擇其他未選的數字。每次遞歸時&#xff0c;在 path 中添加一個新的數字&…

1/13+2

運算符重載 myString.h #ifndef MYSTRING_H #define MYSTRING_H #include <cstring> #include <iostream> using namespace std; class myString {private:char *str; //記錄c風格的字符串int size; //記錄字符串的實際長度int capacity; …

04.計算機體系三層結構與優化(操作系統、計算機網絡、)

3.計算機體系三層結構與優化&#xff08;day04&#xff09; 3.1 操作系統 內容概要&#xff1a; 操作系統的發展史&#xff1a;批處理系統》分時操作系統》unix>linux多道技術》&#xff08;進程、線程&#xff09;并發進程與線程相關概念任務運行的三種狀態&#xff1a;…

【HM-React】08. Layout模塊

基本結構和樣式reset 結構創建 實現步驟 打開 antd/Layout 布局組件文檔&#xff0c;找到示例&#xff1a;頂部-側邊布局-通欄拷貝示例代碼到我們的 Layout 頁面中分析并調整頁面布局 代碼實現 pages/Layout/index.js import { Layout, Menu, Popconfirm } from antd impor…

計算機視覺算法實戰——實時車輛檢測和分類(主頁有相關源碼)

?個人主頁歡迎您的訪問 ?期待您的三連 ? ?個人主頁歡迎您的訪問 ?期待您的三連 ? ?個人主頁歡迎您的訪問 ?期待您的三連? ? ?????????????????? 1. 領域介紹?? 實時車輛檢測和分類是計算機視覺中的一個重要應用領域&#xff0c;旨在從視頻流或…

使用 selenium-webdriver 開發 Web 自動 UI 測試程序

優缺點 優點 有時候有可能一個改動導致其他的地方的功能失去效果&#xff0c;這樣使用 Web 自動 UI 測試程序可以快速的檢查并定位問題&#xff0c;節省大量的人工驗證時間 缺點 增加了維護成本&#xff0c;如果功能更新過快或者技術更新過快&#xff0c;維護成本也會隨之提高…

性能測試工具Jmeter分布式運行

性能測試工具JMeter的分布式執行是一種用于增強壓力測試能力的技術方案&#xff0c;它允許用戶通過多臺機器來共同完成同一個測試計劃的執行。這種方式特別適用于需要模擬成百上千甚至上萬用戶并發訪問的情況&#xff0c;當單臺機器由于硬件資源&#xff08;如CPU、內存、網絡I…

彌散張量分析開源軟件 DSI Studio 簡體中文漢化版可以下載了

網址&#xff1a; (63條消息) DSIStudio簡體中文漢化版(2022年7月)-算法與數據結構文檔類資源-CSDN文庫

移動云自研云原生數據庫入圍國采!

近日&#xff0c;中央國家機關2024年度事務型數據庫軟件框架協議聯合征集采購項目產品名單正式公布&#xff0c;移動云自主研發的云原生數據庫產品順利入圍。這一成就不僅彰顯了移動云在數據庫領域深耕多年造就的領先技術優勢&#xff0c;更標志著國家權威評審機構對移動云在數…

在vscode中使用R-1

參考我的上一篇博客&#xff1a; https://blog.csdn.net/weixin_62528784/article/details/145092632?spm1001.2014.3001.5501 這篇內容實際上就是上一篇博客的后續承接&#xff0c;既然都在vscode的jupyter中使用R了&#xff0c;實際上其實也能夠直接在vscode中原生使用R的編…

【Block總結】掩碼窗口自注意力 (M-WSA)

摘要 論文鏈接&#xff1a;https://arxiv.org/pdf/2404.07846 論文標題&#xff1a;Transformer-Based Blind-Spot Network for Self-Supervised Image Denoising Masked Window-Based Self-Attention (M-WSA) 是一種新穎的自注意力機制&#xff0c;旨在解決傳統自注意力方法在…

【Linux】統信UOS服務器安裝MySQL8.0(RPM)

目錄 一、下載安裝包 二、安裝MySQL 2.1hive適配 2.2ranger適配 3.2DolphinScheduler適配 一、下載安裝包 官網下載安裝包&#xff1a;MySQL :: MySQL Downloads 選擇社區版本下載 點擊MySQL Community Server 選擇對應系統的MySQL版本號 統信1060a 操作系統對應 redhat8…

小白:react antd 搭建框架關于 RangePicker DatePicker 時間組件使用記錄 2

文章目錄 一、 關于 RangePicker 組件返回的moment 方法示例 一、 關于 RangePicker 組件返回的moment 方法示例 moment方法中日后開發有用的方法如下&#xff1a; form.getFieldsValue().date[0].weeksInWeekYear(),form.getFieldsValue().date[0].zoneName(), form.getFiel…

Jenkins簡單的安裝運行

一、下載 官網下載&#xff1a;https://www.jenkins.io/download/ 清華大學開源軟件鏡像站&#xff1a;https://mirrors.tuna.tsinghua.edu.cn/jenkins/ 官網資料豐富&#xff0c;介紹了各種平臺安裝以及下載。安裝簡單&#xff0c;按照說明來就行。下面我介紹一個非常簡單的…

【CSS】HTML頁面定位CSS - position 屬性 relative 、absolute、fixed 、sticky

目錄 relative 相對定位 absolute 絕對定位 fixed 固定定位 sticky 粘性定位 position&#xff1a;relative 、absolute、fixed 、sticky &#xff08;四選一&#xff09; top&#xff1a;距離上面的像素 bottom&#xff1a;距離底部的像素 left&#xff1a;距離左邊的像素…

網絡安全 | WAF防護開通流程與技術原理詳解

關注&#xff1a;CodingTechWork 引言 隨著互聯網安全形勢的日益嚴峻&#xff0c;Web應用防火墻&#xff08;WAF, Web Application Firewall&#xff09;逐漸成為網站和應用的標準防護措施。WAF能夠有效識別和防止如SQL注入、跨站腳本攻擊&#xff08;XSS&#xff09;、惡意流…

小結:路由器和交換機的指令對比

路由器和交換機的指令有一定的相似性&#xff0c;但也有明顯的區別。以下是兩者指令的對比和主要差異&#xff1a; 相似之處 基本操作 兩者都支持類似的基本管理命令&#xff0c;比如&#xff1a; 進入系統視圖&#xff1a;system-view查看當前配置&#xff1a;display current…

Ubuntu中雙擊自動運行shell腳本

方法1: 修改文件雙擊反應 參考: https://blog.csdn.net/miffywm/article/details/103382405 chmod x test.sh鼠標選中待執行文件&#xff0c;在窗口左上角edit菜單中選擇preference設計雙擊執行快捷鍵&#xff0c;如下圖&#xff1a; 方法2: 設置一個應用 參考: https://blo…

從0開始學習搭網站的第一天

前言&#xff0c;以下內容學習自mdn社區&#xff0c;感興趣的朋友可以直接去看原文章web技術 目錄 web機制互聯網是怎么運作的網站服務器是什么什么是URL&#xff1f;什么是web服務器&#xff1f;什么是域名什么是超鏈接什么是網頁DOMgoole瀏覽器開發者工具 web機制 互聯網是怎…