控制檯

結構體 Console

enum cons_flags

通用控制檯標誌

常量

CON_PRINTBUFFER

由新註冊的控制檯使用,以避免重複輸出已被引導控制檯顯示或使用者空間透過 syslog() 系統呼叫讀取的訊息。

CON_CONSDEV

指示控制檯驅動程式正在支援 /dev/console。

CON_ENABLED

指示是否允許控制檯列印記錄。 如果為 false,控制檯也不會前進到後面的記錄。

CON_BOOT

將控制檯驅動程式標記為早期控制檯驅動程式,該驅動程式在啟動期間在真實驅動程式可用之前使用。 當註冊真實的控制檯驅動程式時,它將自動登出,除非使用“keep_bootcon”引數。

CON_ANYTIME

一個用詞不當的歷史標誌,它告訴核心程式碼,傳統的 console::write 回撥可以在標記為 OFFLINE 的 CPU 上呼叫。 這是具有誤導性的,因為它表明呼叫回撥沒有上下文限制。 最初的動機是每個 CPU 區域的就緒狀態。

CON_BRL

指示盲文裝置,出於顯而易見的原因,該裝置可以免於接收 printk 垃圾郵件。

CON_EXTENDED

控制檯支援 /dev/kmesg 的擴充套件輸出格式,這需要更大的輸出緩衝區。

CON_SUSPENDED

指示控制檯是否已掛起。 如果為 true,則不得呼叫列印回撥。

CON_NBCON

控制檯可以在傳統的 console_lock 約束之外執行。

struct console

控制檯描述符結構

定義:

struct console {
    char name[16];
    void (*write)(struct console *co, const char *s, unsigned int count);
    int (*read)(struct console *co, char *s, unsigned int count);
    struct tty_driver       *(*device)(struct console *co, int *index);
    void (*unblank)(void);
    int (*setup)(struct console *co, char *options);
    int (*exit)(struct console *co);
    int (*match)(struct console *co, char *name, int idx, char *options);
    short flags;
    short index;
    int cflag;
    uint ispeed;
    uint ospeed;
    u64 seq;
    unsigned long           dropped;
    void *data;
    struct hlist_node       node;
    void (*write_atomic)(struct console *con, struct nbcon_write_context *wctxt);
    void (*write_thread)(struct console *con, struct nbcon_write_context *wctxt);
    void (*device_lock)(struct console *con, unsigned long *flags);
    void (*device_unlock)(struct console *con, unsigned long flags);
    atomic_t __private nbcon_state;
    atomic_long_t __private nbcon_seq;
    struct nbcon_context    __private nbcon_device_ctxt;
    atomic_long_t __private nbcon_prev_seq;
    struct printk_buffers   *pbufs;
    struct task_struct      *kthread;
    struct rcuwait          rcuwait;
    struct irq_work         irq_work;
};

成員

name

控制檯驅動程式的名稱

write

用於輸出訊息的傳統寫入回撥(可選)

read

用於控制檯輸入的讀取回調(可選)

device

底層 TTY 裝置驅動程式(可選)

unblank

用於取消消隱控制檯的回撥(可選)

setup

用於初始化控制檯的回撥(可選)

exit

用於拆卸控制檯的回撥(可選)

match

用於匹配控制檯的回撥(可選)

flags

控制檯標誌。 請參見 enum cons_flags

index

控制檯索引,例如埠號

cflag

TTY 控制模式標誌

ispeed

TTY 輸入速度

ospeed

TTY 輸出速度

seq

要列印的下一個環形緩衝區記錄的序列號

dropped

未報告的丟棄的環形緩衝區記錄數

data

驅動程式私有資料

node

控制檯列表的 hlist 節點

write_atomic

用於在任何上下文中寫出文字的 NBCON 回撥。(可選)

在呼叫此回撥時,控制檯已被獲取。 但是,預設情況下允許更高優先順序的上下文接管它。

回撥必須在任何接管不安全的程式碼周圍呼叫 nbcon_enter_unsafe() 和 nbcon_exit_unsafe(),例如,在操作序列埠暫存器時。

如果在該上下文失去控制檯所有權的同時,nbcon_enter_unsafe() 將失敗。 在這種情況下,不再允許回撥繼續進行。 它必須立即小心地退出。 緩衝區內容也不再可信,因為它不再屬於上下文。

回撥應在安全的情況下允許接管。 這增加了在系統出現問題時檢視訊息的機會。 如果驅動程式必須重新獲取所有權才能最終確定或恢復硬體更改,則可以使用 nbcon_reacquire_nobuf()。 但是,重新獲取後,緩衝區內容不再可用。 重新獲取不能用於恢復列印。

可以從任何上下文(包括 NMI)呼叫回撥。 因此,它必須避免使用任何鎖定,而是依靠控制檯所有權進行同步。

write_thread

用於在任務上下文中寫出文字的 NBCON 回撥。

只能在任務上下文中呼叫此回撥,並且必須使用 NBCON_PRIO_NORMAL 獲取 device_lock() 和 nbcon 控制檯。

控制檯所有權驗證和不安全區域處理的規則與 write_atomic() 相同。

控制檯所有權處理對於與僅透過上下文同步的 write_atomic() 進行同步是必需的。

device_lock() 為裝置上的操作提供主要序列化。 它可以根據需要寬鬆(互斥)[*] 或緊密(停用搶佔和中斷)。 它允許 kthread 在限制最少的模式下執行 [**]。

[*] 啟用了搶佔後,獨立的 nbcon_context_try_acquire() 不安全,請參閱 nbcon_owner_matches()。 但是,當始終在裝置鎖下的搶佔上下文中呼叫它時,它可以是安全的。

the preemption enabled, see nbcon_owner_matches(). But it can be safe when always called in the preemptive context under the device_lock().

[**] device_lock() 確保 nbcon_context_try_acquire()

would never need to spin which is important especially with PREEMPT_RT.

device_lock

用於開始與驅動程式程式碼同步的 NBCON 回撥。

控制檯驅動程式通常必須處理透過使用者輸入/輸出(例如互動式登入 shell)對硬體的訪問,以及透過 printk() 呼叫輸出核心訊息。 每當 printk 子系統需要與驅動程式的硬體訪問同步時,都會呼叫此回撥。 應該實現它以使用驅動程式自身正在使用的任何同步機制(例如,用於 uart 序列控制檯的埠鎖)。

始終從任務上下文中呼叫回撥。 它可以使用驅動程式所需的任何同步方法。

重要提示:回撥必須停用遷移。 控制檯驅動程式

may be using a synchronization mechanism that already takes care of this (such as spinlocks). Otherwise this function must explicitly call migrate_disable().

flags 引數作為驅動程式的便利提供。 它將再次傳遞給 device_unlock()。 如果驅動程式不需要它,則可以忽略它。

device_unlock

用於完成與驅動程式程式碼同步的 NBCON 回撥。

它是 device_lock() 的對應項。

始終從任務上下文中呼叫此回撥。 它必須適當地重新啟用遷移(具體取決於 device_lock() 如何停用遷移)。

flags 引數是傳遞給 device_lock() 的同一變數的值。

nbcon_state

nbcon 控制檯的狀態

nbcon_seq

nbcon 要列印的下一條記錄的序列號

nbcon_device_ctxt

可用於非列印操作的上下文

nbcon_prev_seq

上次 nbcon 所有者被分配列印的序列號

pbufs

指向 nbcon 私有緩衝區的指標

kthread

此控制檯的印表機 kthread

rcuwait

用於 kthread 喚醒的 RCU 安全等待物件

irq_work

kthread 喚醒推遲到 IRQ 工作上下文

內部結構

struct nbcon_state

nbcon 控制檯的控制檯狀態

定義:

struct nbcon_state {
    union {
        unsigned int    atom;
        struct {
            unsigned int prio               :  2;
            unsigned int req_prio           :  2;
            unsigned int unsafe             :  1;
            unsigned int unsafe_takeover    :  1;
            unsigned int cpu                : 24;
        };
    };
};

成員

{unnamed_union}

anonymous

atom

用於原子操作的狀態欄位的複合

{unnamed_struct}

anonymous

prio

當前所有者的優先順序

req_prio

切換請求的優先順序

unsafe

控制檯在一個非接管區域中處於忙碌狀態

unsafe_takeover

過去發生了不安全狀態下的惡意接管。 在重新初始化之前,控制檯無法安全。

cpu

所有者在其上執行的 CPU

描述

用於讀取和準備儲存在 nbcon 狀態變數 console::nbcon_state 中的值。

prioreq_prio 欄位尤其重要,允許旋轉等待超時並放棄,而不會有等待者在放棄後被分配鎖的風險。

enum nbcon_prio

nbcon 控制檯的控制檯所有者優先順序

常量

NBCON_PRIO_NONE

未使用

NBCON_PRIO_NORMAL

正常(非緊急)使用

NBCON_PRIO_EMERGENCY

緊急輸出 (WARN/OOPS...)

NBCON_PRIO_PANIC

Panic 輸出

NBCON_PRIO_MAX

優先順序級別的數量

描述

當控制檯處於安全狀態時,更高優先順序的上下文可以接管控制檯。 在 panic() 中重新整理控制檯的最後一次嘗試甚至可以在不安全狀態下進行(希望和祈禱)。

struct nbcon_context

用於控制檯獲取/釋放的上下文

定義:

struct nbcon_context {
    struct console          *console;
    unsigned int            spinwait_max_us;
    enum nbcon_prio         prio;
    unsigned int            allow_unsafe_takeover   : 1;
    unsigned int            backlog                 : 1;
    struct printk_buffers   *pbufs;
    u64 seq;
};

成員

console

關聯的控制檯

spinwait_max_us

旋轉等待獲取的限制

prio

上下文的優先順序

allow_unsafe_takeover

即使不安全也允許執行接管。 只能與 NBCON_PRIO_PANIC prio 一起使用。 當稍後使用控制檯時,它可能會導致系統凍結。

backlog

環形緩衝區具有待處理的記錄

pbufs

指向此上下文的文字緩衝區的指標

seq

要為此上下文列印的序列號

struct nbcon_write_context

傳遞給 nbcon 寫入回撥的上下文

定義:

struct nbcon_write_context {
    struct nbcon_context    __private ctxt;
    char *outbuf;
    unsigned int            len;
    bool unsafe_takeover;
};

成員

ctxt

核心控制檯上下文

outbuf

指向用於輸出的文字緩衝區的指標

len

要寫入的長度

unsafe_takeover

如果發生了不安全狀態下的惡意接管

結構體 Consw

struct consw

用於控制檯的回撥

定義:

struct consw {
    struct module *owner;
    const char *(*con_startup)(void);
    void (*con_init)(struct vc_data *vc, bool init);
    void (*con_deinit)(struct vc_data *vc);
    void (*con_clear)(struct vc_data *vc, unsigned int y, unsigned int x, unsigned int count);
    void (*con_putc)(struct vc_data *vc, u16 ca, unsigned int y, unsigned int x);
    void (*con_putcs)(struct vc_data *vc, const u16 *s,unsigned int count, unsigned int ypos, unsigned int xpos);
    void (*con_cursor)(struct vc_data *vc, bool enable);
    bool (*con_scroll)(struct vc_data *vc, unsigned int top,unsigned int bottom, enum con_scroll dir, unsigned int lines);
    bool (*con_switch)(struct vc_data *vc);
    bool (*con_blank)(struct vc_data *vc, enum vesa_blank_mode blank, bool mode_switch);
    int (*con_font_set)(struct vc_data *vc,const struct console_font *font, unsigned int vpitch, unsigned int flags);
    int (*con_font_get)(struct vc_data *vc, struct console_font *font, unsigned int vpitch);
    int (*con_font_default)(struct vc_data *vc, struct console_font *font, const char *name);
    int (*con_resize)(struct vc_data *vc, unsigned int width, unsigned int height, bool from_user);
    void (*con_set_palette)(struct vc_data *vc, const unsigned char *table);
    void (*con_scrolldelta)(struct vc_data *vc, int lines);
    bool (*con_set_origin)(struct vc_data *vc);
    void (*con_save_screen)(struct vc_data *vc);
    u8 (*con_build_attr)(struct vc_data *vc, u8 color,enum vc_intensity intensity, bool blink, bool underline, bool reverse, bool italic);
    void (*con_invert_region)(struct vc_data *vc, u16 *p, int count);
    void (*con_debug_enter)(struct vc_data *vc);
    void (*con_debug_leave)(struct vc_data *vc);
};

成員

owner

當使用此控制檯時,要獲取引用的模組

con_startup

設定控制檯並返回其名稱(如 VGA、EGA 等)

con_init

vc 上初始化控制檯。 對於在此 vc 上的第一次呼叫,init 為 true。

con_deinit

vc 中取消初始化控制檯。

con_clear

vc 上的 [x, y] 處擦除 count 個字元。 count >= 1。

con_putc

使用屬性 ca 將一個字元傳送到 vc 上的 [x, y]。 (可選 -- 將呼叫 con_putcs

con_putcs

使用屬性 scount 個字元傳送到 vc 上的 [x, y]。

con_cursor

根據 enable 啟用/停用游標

con_scroll

lines 在方向 dir 中將 topbottom 的行移動。 如果不應進行通用處理,則返回 true。 由 csi_M 呼叫和列印到控制檯。

con_switch

有關控制檯切換的通知器; 如果需要重繪,則應返回 true。

con_blank

消隱/取消消隱控制檯。 目標模式在 blank 中傳遞。 如果從/向文字/圖形更改,則設定 mode_switch。 如果需要重繪,則掛鉤應返回 true。

con_font_set

將控制檯 vc 字型設定為高度為 vpitchfontflags 可以是 KD_FONT_FLAG_DONT_RECALC。(可選)

con_font_get

在高度為 vpitchvc 上獲取當前字型到 font 中。(可選)

con_font_default

vc 上設定預設字型。 name 可以是 NULL 或要搜尋的字型名稱。 可以將 font 填充回。(可選)

con_resize

vc 控制檯調整為 width x height。 當此更改來自使用者空間時,from_user 為 true。

con_set_palette

將控制檯 vc 的調色盤設定為 table(可選)

con_scrolldelta

控制檯的內容應按 lines 滾動。 由使用者呼叫。(可選)

con_set_origin

設定 vc 的原點(請參閱 vc_data::vc_origin)。 如果未提供或返回 false,則原點設定為 vc->vc_screenbuf。(可選)

con_save_screen

將螢幕內容儲存到 vc->vc_screenbuf 中。 例如,在進入圖形時呼叫。(可選)

con_build_attr

基於 colorintensity 和其他引數構建屬性。 結果用於普通字元和擦除字元。(可選)

con_invert_region

反轉 vc 上從 p 開始的長度為 count 的區域。(可選)

con_debug_enter

為偵錯程式準備控制檯。 這包括但不限於,取消消隱控制檯、載入適當的調色盤和允許偵錯程式生成的輸出。(可選)

con_debug_leave

儘可能將控制檯恢復到除錯前的狀態。(可選)

控制檯函式

short console_srcu_read_flags(const struct console *con)

以無鎖方式讀取可能已註冊的控制檯的標誌

引數

const struct console *con

要從中讀取標誌的控制檯的 struct console 指標

描述

以無鎖方式讀取 con->flags 提供了 Read 一致的值,因為最多隻有一個 CPU 正在修改 con->flags,並且該 CPU 僅使用讀取-修改-寫入操作來執行此操作。

需要保持 console_srcu_read_lock,這意味著 con 可能是已註冊的控制檯。 保持 console_srcu_read_lock 的目的是保證控制檯狀態有效 (CON_SUSPENDED/CON_ENABLED),並且如果控制檯當前正在登出,則不會執行任何退出/清理例程。

如果呼叫方保持 console_list_lock,或者 _certain_ con 未註冊且不會變為已註冊,則呼叫方可以直接讀取 con->flags

上下文

任何上下文。

返回

con->flags 欄位的當前值。

void console_srcu_write_flags(struct console *con, short flags)

為已註冊的控制檯寫入標誌

引數

struct console *con

要寫入標誌的控制檯的 struct console 指標

short flags

要寫入的新標誌值

描述

僅使用此函式為已註冊的控制檯寫入標誌。 它需要保持 console_list_lock。

上下文

任何上下文。

for_each_console_srcu

for_each_console_srcu (con)

遍歷已註冊的控制檯

引數

con

用作循環遊標的 struct console 指標

描述

儘管 SRCU 保證控制檯列表將保持一致,但在迭代時,struct console 欄位可能會被其他 CPU 更新。

需要保持 console_srcu_read_lock。 可以從任何上下文中呼叫。

for_each_console

for_each_console (con)

遍歷已註冊的控制檯

引數

con

用作循環遊標的 struct console 指標

描述

控制檯列表和 console.flags 在迭代時是不可變的。

需要保持 console_list_lock。

void clear_selection(void)

刪除當前選擇

引數

void

無引數

描述

從保持選擇的控制檯中刪除當前選擇突出顯示(如果有)。

鎖定:呼叫方必須保持控制檯鎖。

int __vc_resize(struct vc_data *vc, unsigned int cols, unsigned int rows, bool from_user)

調整 VT 的大小

引數

struct vc_data *vc

虛擬控制檯

unsigned int cols

unsigned int rows

bool from_user

由使用者呼叫?

描述

從控制檯的角度來看,調整虛擬控制檯的大小。 我們使用通用的 vc_do_resize() 方法來更新結構。

鎖定:呼叫方必須保持控制檯 sem 以保護控制檯內部結構和 vc->port.tty

int con_is_bound(const struct consw *csw)

檢查驅動程式是否繫結到控制檯

引數

const struct consw *csw

控制檯驅動程式

返回

如果未繫結,則為零; 如果已繫結,則為非零

描述

驅動程式可以呼叫此函式,如果為零,則應釋放 consw.con_startup() 上分配的所有資源

bool con_is_visible(const struct vc_data *vc)

檢查當前控制檯是否可見

引數

const struct vc_data *vc

虛擬控制檯

返回

如果不可見,則為零; 如果可見,則為非零

void con_debug_enter(struct vc_data *vc)

為核心偵錯程式準備控制檯

引數

struct vc_data *vc

虛擬控制檯

描述

當控制檯被核心偵錯程式接管時呼叫,此函式需要儲存當前控制檯狀態,然後將控制檯置於適合核心偵錯程式的狀態。

void con_debug_leave(void)

恢復控制檯狀態

引數

void

無引數

描述

將控制檯狀態恢復到呼叫核心偵錯程式之前的狀態。

int do_unregister_con_driver(const struct consw *csw)

從控制檯層登出控制檯驅動程式

引數

const struct consw *csw

控制檯驅動程式

描述

所有註冊到控制檯層的驅動程式都必須在退出時呼叫此函式,或者如果控制檯驅動程式處於無法處理控制檯服務的狀態,例如沒有載入幀緩衝驅動程式的幀緩衝控制檯。

驅動程式必須先取消繫結,然後才能登出。

內部結構

int sel_loadlut(u32 __user *lut)

載入 LUT 表

引數

u32 __user *lut

使用者表

描述

從使用者空間載入 LUT 表。 建立一個臨時副本,以便部分更新不會造成混亂。

鎖定:已獲取控制檯鎖。

int set_selection_user(const struct tiocl_selection __user *sel, struct tty_struct *tty)

設定當前選擇。

引數

const struct tiocl_selection __user *sel

使用者選擇資訊

struct tty_struct *tty

控制檯 tty

描述

由 vt 層的 ioctl 控制代碼呼叫。

鎖定:整個選擇過程都在 console_lock 下進行管理。 它在鎖定下進行了很多處理,但這幾乎不是效能路徑。

int vc_do_resize(struct tty_struct *tty, struct vc_data *vc, unsigned int cols, unsigned int lines, bool from_user)

tty 的調整大小方法

引數

struct tty_struct *tty

正在調整大小的 tty

struct vc_data *vc

虛擬控制檯私有資料

unsigned int cols

unsigned int lines

行數

bool from_user

由使用者呼叫?

描述

調整虛擬控制檯的大小,根據實際約束進行裁剪。 如果呼叫者傳遞了一個 tty 結構,則更新 termios winsize 資訊並執行任何必要的訊號處理。

鎖定:呼叫者必須持有控制檯訊號量。 如果傳遞了 tty,則獲取 tty 的 termios rwsem 和 ctrl.lock。

int vt_resize(struct tty_struct *tty, struct winsize *ws)

調整 VT 的大小

引數

struct tty_struct *tty

要調整大小的 tty

struct winsize *ws

winsize 屬性

描述

調整虛擬終端的大小。 這是由 tty 層呼叫的,因為我們註冊了自己的調整大小處理程式。 互助助手完成了所有實際工作。

鎖定:獲取控制檯訊號量,然後被呼叫的方法按順序獲取 tty termios_rwsem 和 tty ctrl.lock。

enum vc_ctl_state

vt 的控制字元狀態

常量

ESnormal

初始狀態,未解析控制字元

ESesc

已解析 ESC

ESsquare

已解析 CSI -- 預期修飾符/引數/控制字元

ESgetpars

已解析 CSI -- 預期引數/控制字元

ESfunckey

已解析 CSI [

EShash

已解析 ESC #

ESsetG0

已解析 ESC (

ESsetG1

已解析 ESC )

ESpercent

已解析 ESC %

EScsiignore

已解析 CSI [0x20-0x3f]

ESnonstd

已解析 OSC

ESpalette

已解析 OSC P

ESosc

已解析 OSC [0-9]

ESANSI_first

用於忽略 ansi 控制序列的第一個狀態

ESapc

已解析 ESC _

ESpm

已解析 ESC ^

ESdcs

已解析 ESC P

ESANSI_last

用於忽略 ansi 控制序列的最後一個狀態

int vc_sanitize_unicode(const int c)

將無效的 Unicode 程式碼點替換為 U+FFFD

引數

const int c

收到的程式碼點

int vc_translate_unicode(struct vc_data *vc, int c, bool *rescan)

vc_data.vc_utf_char 中將 UTF-8 組合成 Unicode

引數

struct vc_data *vc

虛擬控制檯

int c

要翻譯的 UTF-8 位元組

bool *rescan

如果 c 未在此處使用並且需要重新處理,則設定為 true

描述

  • vc_data.vc_utf_char 是正在構建的 Unicode 程式碼點。

  • vc_data.vc_utf_count 是仍然期望到達的延續位元組數。

  • vc_data.vc_npar 是到目前為止到達的延續位元組數。

返回

  • -1 - 到目前為止輸入正常,c 已使用,預期有更多位元組。

  • 0xFFFD - 可能性 1:輸入無效,可能已使用 c(請參閱

    rescan 的描述)。 可能性 2:輸入正常,已使用 cU+FFFD 是生成的程式碼點。 U+FFFD 有效,REPLACEMENT CHARACTER

  • 否則 - 輸入正常,已使用 c,返回生成的程式碼點。

int vt_kmsg_redirect(int new)

設定/獲取核心訊息控制檯

引數

int new

新的虛擬終端編號,如果控制檯應保持不變,則為 -1

描述

預設情況下,核心訊息始終列印在當前的虛擬控制檯上。 但是,使用者可以使用 TIOCL_SETKMSGREDIRECT ioctl 呼叫修改該預設值。

此函式將核心訊息控制檯設定為 new。 它返回舊的虛擬控制檯編號。 虛擬終端編號 0(作為引數和返回值)表示沒有重定向(即始終列印在當前活動的控制檯上)。

引數 -1 表示僅返回當前控制檯,但不修改該值。 在這種情況下,可以使用宏 vt_get_kmsg_redirect() 來使程式碼更易於理解。

如果核心在沒有 CONFIG_VT_CONSOLE 的情況下編譯,則此函式會忽略該引數並始終返回 0