內(nèi)核構(gòu)建、RedBoot 引導與 JFFS2 實戰(zhàn)指南)
Intel AssabetSA-1110 評估板內(nèi)核構(gòu)建、RedBoot 引導與 JFFS2 實戰(zhàn)指南【免費下載鏈接】linuxLinux kernel source tree項目地址: https://gitcode.com/GitHub_Trending/li/linux本文以 Linux 內(nèi)核官方文檔 Documentation/arch/arm/sa1100/assabet.rst 為主線系統(tǒng)講解 Intel StrongARM SA-1110 微處理器評估板 Assabet 的完整使用流程從內(nèi)核編譯、引導加載程序Bootloader選擇與安裝到 RedBoot 下燒寫內(nèi)核鏡像、掛載 JFFS2 根文件系統(tǒng)、編寫自動化引導腳本最后結(jié)合當前倉庫源碼arch/arm/mach-sa1100/assabet.c、arch/arm/configs/assabet_defconfig、drivers/mtd/parsers/redboot.c 等深入剖析其底層實現(xiàn)。讀完本文你將能夠獨立完成 Assabet 平臺的交叉編譯、RedBoot 環(huán)境初始化和從 Flash 啟動 Linux 的全過程。Assabet 平臺與文檔背景Assabet 是 Intel 官方推出的 StrongARM SA-1110 微處理器開發(fā)板評估板在 Linux ARM 生態(tài)早期扮演了重要的參考平臺角色。SA-1110 集成了一顆 StrongARM 處理器核心片上集成了 LCD 控制器、串口、USB、PCMCIA 等外設(shè)配合 NeponsetSA-1111擴展板可進一步擴展 I/O 能力。在內(nèi)核源碼樹中Assabet 的平臺支持代碼集中在 arch/arm/mach-sa1100/assabet.c其機器類型描述如下見 assabet.cMACHINE_START(ASSABET, Intel-Assabet) .atag_offset 0x100, .fixup fixup_assabet, .map_io assabet_map_io, .nr_irqs SA1100_NR_IRQS, .init_irq assabet_init_irq, .init_time sa1100_timer_init, .init_machine assabet_init, .init_late sa11x0_init_late, .restart sa11x0_restart, MACHINE_END從 arch/arm/mach-sa1100/Kconfig 可以看到SA11x0 平臺目前已被標記為DEPRECATED已廢棄且明確提示“Support for these machines will go away in 2027, unless there are any remaining users that speak up”若無現(xiàn)存用戶發(fā)聲該平臺支持將于 2027 年移除。因此本文內(nèi)容對 ARM 早期平臺移植和嵌入式 Linux 引導流程的研究、教學與歷史梳理具有重要價值。需要說明的是本文以當前倉庫即 Linux 內(nèi)核源碼樹的實際代碼和文檔為準涉及的命令行、配置與工具鏈描述適用于 Assabet 平臺及其對應(yīng)的內(nèi)核版本。編譯 Assabet 內(nèi)核鏡像三步構(gòu)建流程根據(jù)官方文檔使用默認配置構(gòu)建 Assabet 內(nèi)核只需三條命令make assabet_defconfig make oldconfig make zImagemake assabet_defconfig加載 Assabet 的默認內(nèi)核配置。該配置文件位于 arch/arm/configs/assabet_defconfig是本文檔所述流程的直接依據(jù)。make oldconfig基于現(xiàn)有.config交互式確認新增/變更的配置項確保配置與當前內(nèi)核版本一致。make zImage編譯生成壓縮內(nèi)核鏡像。構(gòu)建完成后內(nèi)核鏡像位于linux/arch/arm/boot/zImage。默認配置的關(guān)鍵選項arch/arm/configs/assabet_defconfig 中的核心配置與本文檔的引導流程一一對應(yīng)值得逐項解讀配置項值含義與引導流程關(guān)聯(lián)CONFIG_ARCH_SA1100y啟用 SA11x0 平臺支持CONFIG_SA1100_ASSABETy啟用 Assabet 板級支持CONFIG_ATAGSy使用 ATAGS 向內(nèi)核傳遞啟動參數(shù)CONFIG_CMDLINEmem32M consolettySA0,38400n8 initrd0xc0800000,3M root/dev/ram默認內(nèi)核命令行32M 內(nèi)存、串口控制臺38400 波特率8 數(shù)據(jù)位無校驗、initrd 起始地址與大小、根文件系統(tǒng)為 ramdiskCONFIG_BLK_DEV_INITRDy支持 initrd/ramdisk 啟動對應(yīng)文檔中“加載 ramdisk 鏡像”一節(jié)CONFIG_MTDy啟用 MTDMemory Technology Device層是 JFFS2 的基礎(chǔ)CONFIG_MTD_REDBOOT_PARTSy啟用 RedBoot FIS 分區(qū)表解析對應(yīng)文檔中 Linux 顯示 “Using RedBoot partition definition” 的輸出CONFIG_MTD_BLOCKy提供/dev/mtdblockN塊設(shè)備接口對應(yīng)文檔中root/dev/mtdblock2的使用CONFIG_MTD_CFIy啟用 CFICommon Flash Interface探測對應(yīng) “SA1100 flash: probing 32-bit flash bus”CONFIG_MTD_SA1100ySA1100 平臺 Flash 映射驅(qū)動CONFIG_JFFS2_FSy啟用 JFFS2 日志型閃存文件系統(tǒng)CONFIG_SERIAL_SA1100_CONSOLEySA1100 串口作為內(nèi)核控制臺CONFIG_FB_SA1100ySA1100 LCD 幀緩沖驅(qū)動CONFIG_PCMCIA_SA1100、CONFIG_PCMCIA_PCNETyPCMCIA 及 PCnet 網(wǎng)卡支持配合文檔中“使用 CF 網(wǎng)卡進行 TFTP 傳輸”CONFIG_NFS_FSyNFS 根文件系統(tǒng)支持對應(yīng)文檔中“通過 NFS 啟動根文件系統(tǒng)”值得關(guān)注的是配置中的CONFIG_MTD_REDBOOT_PARTS直接對應(yīng) Linux 內(nèi)核啟動時讀取 RedBoot 維護的 FISFlash Image System目錄并自動生成 MTD 分區(qū)表的行為這與文檔第五節(jié)中 Linux 輸出 5 個 MTD 分區(qū)的現(xiàn)象完全吻合。引導加載程序Bootloader的選擇Assabet 上可用的 Linux 引導加載程序有三類各有特點Bootloader來源/背景特點BLOBLART 項目的引導程序社區(qū)貢獻補丁加入 Assabet 支持輕量、簡單但無網(wǎng)絡(luò)功能Compaq BootldrCompaq 為 iPAQ Pocket PC 開發(fā)的引導程序John Dorsey 提供 Assabet 與 JFFS 支持補丁面向 PDA帶 JFFS 文件系統(tǒng)支持RedBootRed Hat 基于 eCos RTOS HAL 開發(fā)的引導程序支持眾多硬件平臺唯一具備網(wǎng)絡(luò)支持維護最活躍是當時推薦選擇官方文檔明確指出RedBoot is currently the recommended choice since its the only one to have networking support, and is the most actively maintained.由于 RedBoot 是文檔推薦方案且具備網(wǎng)絡(luò)TFTP能力以下引導與燒寫流程均以 RedBoot 為主線展開。RedBoot 固件安裝在開始使用之前需要先將預編譯好的 RedBoot 二進制寫入 Assabet 的 Flash。文檔給出的預編譯 RedBoot 二進制文件名形如redboot-assabet*.tgz并附有安裝說明redboot-assabet*.txt存放于如下 FTP 站點ftp://ftp.netwinder.org/users/n/nico/ftp://ftp.arm.linux.org.uk/pub/linux/arm/people/nico/ftp://ftp.handhelds.org/pub/linux/arm/sa-1100-patches/硬件注意事項若使用 CF 網(wǎng)卡文檔作者 Assabet 套件附帶 Socket Communications 的 CF LP-E 網(wǎng)卡進行 TFTP 文件傳輸必須在 RedBoot 運行之前插入因為 RedBoot 無法動態(tài)檢測 CF 網(wǎng)卡。RedBoot 初始化配置RedBoot 提供兩類持久化配置初始化 Flash 目錄fis init -f該命令用于初始化 Flash Image SystemFIS目錄-f表示強制操作會清除現(xiàn)有的 FIS 目錄區(qū)域。FIS 是 RedBoot 維護的一張 Flash 鏡像目錄表內(nèi)核側(cè)的 drivers/mtd/parsers/redboot.c 正是解析這張表來生成 MTD 分區(qū)的。初始化非易失性網(wǎng)絡(luò)配置fconfig -ifconfig -i進入交互式配置模式用于設(shè)置 BOOTP 動態(tài)獲取 IP 還是靜態(tài) IP 等網(wǎng)絡(luò)參數(shù)以及腳本超時等選項。這些非易失性設(shè)置保存在 Flash 的 “RedBoot config” 區(qū)域中后續(xù)fis list輸出中可見。RedBoot 分區(qū)結(jié)構(gòu)源碼視角從內(nèi)核側(cè)看RedBoot FIS 目錄中的鏡像描述符結(jié)構(gòu)定義于 drivers/mtd/parsers/redboot.cstruct fis_image_desc { unsigned char name[16]; // Null terminated name u32 flash_base; // Address within FLASH of image u32 mem_base; // Address in memory where it executes u32 size; // Length of image u32 entry_point; // Execution entry point u32 data_length; // Length of actual data unsigned char _pad[256 - (16 7 * sizeof(u32))]; u32 desc_cksum; // Checksum over image descriptor u32 file_cksum; // Checksum over image data };每個字段鏡像名、Flash 基址、內(nèi)存加載地址、長度、入口點、數(shù)據(jù)長度、校驗和與fis list輸出的各列一一對應(yīng)。解析器通過CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK確定的目錄塊位置讀取整塊擦除塊并逐個檢查鏡像描述符的校驗和來構(gòu)建分區(qū)表見 redboot.c。將內(nèi)核鏡像寫入 Flash第一步將 zImage 加載到 RAM內(nèi)核鏡像必須先加載到內(nèi)存中才能燒寫。兩種方式方式一TFTP 網(wǎng)絡(luò)加載前提是 RedBoot 配置好了網(wǎng)絡(luò)且 CF 網(wǎng)卡已插入load zImage -r -b 0x100000方式二串口 Y-Modem 上傳load -m ymodem -r -b 0x100000參數(shù)說明-r將鏡像加載到 RAMraw load。-b 0x100000指定加載到 RAM 的物理地址0x1000001MB 處。第二步寫入 Flashfis create Linux kernel -b 0x100000 -l 0xc0000fis create將 RAM 中0x100000處、長度0xc0000768KB的數(shù)據(jù)寫入 Flash并登記為名為 “Linux kernel” 的 FIS 鏡像。啟動內(nèi)核與加載文件系統(tǒng)加載 ramdisk內(nèi)核本身還需要一個文件系統(tǒng)才能完成啟動。使用 TFTP 加載 ramdisk 鏡像load ramdisk_image.gz -r -b 0x800000若改用串口 Y-Modem 上傳將文件名替換為-y ymodemload -y ymodem -r -b 0x800000從 Flash 取出內(nèi)核并執(zhí)行fis load Linux kernel exec -b 0x100000 -l 0xc0000fis load將 Flash 中名為 “Linux kernel” 的鏡像讀回 RAM默認加載地址即創(chuàng)建時記錄的內(nèi)存地址。exec -b 0x100000 -l 0xc0000從地址0x100000處、長度0xc0000執(zhí)行即跳轉(zhuǎn)啟動內(nèi)核。文檔特別指出ramdisk 也可以燒入 Flash但針對“在 Flash 上存放可寫文件系統(tǒng)”這一需求JFFS2 是更優(yōu)解詳見下一節(jié)。使用 JFFS2 構(gòu)建可寫的 Flash 根文件系統(tǒng)JFFS2 與 MTD 的關(guān)系JFFS2The Second Journalling Flash File System第二代日志型閃存文件系統(tǒng)是當時在 Flash 上存放可寫文件系統(tǒng)最便捷的方案。它必須與 MTDMemory Technology Device層配合使用——MTD 負責底層的 Flash 管理探測、擦除、讀寫、壞塊處理等JFFS2 則在其上提供日志型文件系統(tǒng)語義。從配置看arch/arm/configs/assabet_defconfig 同時啟用了CONFIG_MTD、CONFIG_MTD_SA1100、CONFIG_MTD_CFI、CONFIG_MTD_BLOCK與CONFIG_JFFS2_FS正是 JFFS2 方案所需的完整依賴鏈。加載示例 JFFS2 鏡像示例 JFFS2 鏡像sample_img.jffs2可從與預編譯 RedBoot 相同的 FTP 站點獲取。加載到 RAMload sample_img.jffs2 -r -b 0x100000預期輸出文件實際加載的大小隨鏡像不同而變化RedBoot load sample_img.jffs2 -r -b 0x100000 Raw file loaded 0x00100000-0x00377424即鏡像從0x00100000加載到0x00377424。查詢可用 Flash 空間fis free示例輸出RedBoot fis free 0x500E0000 .. 0x503C0000注意上述地址可能因文件系統(tǒng)大小和 Flash 類型不同而變化以下計算僅作為示例實際使用務(wù)必替換為自己的數(shù)值。計算燒寫參數(shù)size of unallocated flash: 0x503c0000 - 0x500e0000 0x2e0000 size of the filesystem image: 0x00377424 - 0x00100000 0x277424未分配 Flash 區(qū)域大小0x2e0000約 2.875MB文件系統(tǒng)鏡像實際大小0x277424約 2.48MB設(shè)計目標鏡像必須能放進去同時將剩余全部Flash 空間都劃給該文件系統(tǒng)分區(qū)。解鎖、擦除、寫入并創(chuàng)建 FIS 條目fis unlock -f 0x500E0000 -l 0x2e0000 fis erase -f 0x500E0000 -l 0x2e0000 fis write -b 0x100000 -l 0x277424 -f 0x500E0000 fis create JFFS2 -n -f 0x500E0000 -l 0x2e0000逐步解析fis unlock -f解鎖目標 Flash 區(qū)域Flash 寫入前通常需解鎖。fis erase -f擦除整個目標區(qū)域擦除是 Flash 寫入的強制前置步驟。fis write將 RAM 地址0x100000處、長度0x277424的數(shù)據(jù)寫入 Flash 地址0x500E0000。fis create JFFS2 -n-n表示不復制數(shù)據(jù)僅為該區(qū)域在 FIS 目錄中登記名為 “JFFS2” 的鏡像條目數(shù)據(jù)已由上一步寫入。驗證fis list 與 Linux 側(cè) MTD 分區(qū)燒寫完成后fis list顯示完整的 Flash 布局RedBoot fis list Name FLASH addr Mem addr Length Entry point RedBoot 0x50000000 0x50000000 0x00020000 0x00000000 RedBoot config 0x503C0000 0x503C0000 0x00020000 0x00000000 FIS directory 0x503E0000 0x503E0000 0x00020000 0x00000000 Linux kernel 0x50020000 0x00100000 0x000C0000 0x00000000 JFFS2 0x500E0000 0x500E0000 0x002E0000 0x00000000而在 Linux 側(cè)得益于CONFIG_MTD_REDBOOT_PARTS啟動時內(nèi)核解析同一份 FIS 目錄并打印SA1100 flash: probing 32-bit flash bus SA1100 flash: Found 2 x16 devices at 0x0 in 32-bit mode Using RedBoot partition definition Creating 5 MTD partitions on SA1100 flash: 0x00000000-0x00020000 : RedBoot 0x00020000-0x000e0000 : Linux kernel 0x000e0000-0x003c0000 : JFFS2 0x003c0000-0x003e0000 : RedBoot config 0x003e0000-0x00400000 : FIS directory這條輸出的前兩行與 Assabet 板級 Flash 驅(qū)動直接對應(yīng)。從源碼看arch/arm/mach-sa1100/assabet.c 中定義了兩種 Flash 硬件布局Phase 4 AssabetBank 0 中兩塊 Intel 28F160B3 Flash每塊 2MB 級引導區(qū)為0x00020000Phase 5 AssabetBank 0 中兩塊 Intel 28F128J3A Flash每塊 16MB 級引導區(qū)為0x00040000。同時assabet.c 使用cfi_probe作為映射名并將兩塊 Flash 內(nèi)存資源SA1100_CS0_PHYS與SA1100_CS1_PHYS各 32MB注冊給 MTD 層——這解釋了啟動日志中 “probing 32-bit flash bus / Found 2 x16 devices” 的探測行為。從 Flash 直接啟動 JFFS2 根文件系統(tǒng)重要的是理解分區(qū)的順序Linux 側(cè)第三個分區(qū)才是 “JFFS2”它對應(yīng)塊設(shè)備/dev/mtdblock2。因此從 Flash 啟動內(nèi)核 JFFS2 根文件系統(tǒng)的完整命令為fis load Linux kernel exec -b 0x100000 -l 0xc0000 -c root/dev/mtdblock2-c參數(shù)將內(nèi)核命令行設(shè)置為root/dev/mtdblock2指示內(nèi)核將第三個 MTD 塊設(shè)備作為根文件系統(tǒng)。其他文件系統(tǒng)方案文檔也指出除 JFFS 外還可選用其他文件系統(tǒng)cramfs只讀壓縮文件系統(tǒng)適合存放不可變數(shù)據(jù)NFS 根文件系統(tǒng)通過root/dev/nfs配合網(wǎng)絡(luò)啟動直接在 Linux 內(nèi)燒寫 Flash在 ramdisk 或 NFS 引導的系統(tǒng)下使用 Linux MTD 工具如flash_erase、mkfs.jffs2、mount直接對剛擦除的分區(qū)掛載 JFFS2 并拷貝文件——這種方法有時更為便捷。RedBoot 腳本化自動引導每次重啟都手動輸入上述命令顯然不現(xiàn)實RedBoot 的腳本能力可完全自動化引導過程。以下示例腳本實現(xiàn)從網(wǎng)絡(luò) TFTP 服務(wù)器加載內(nèi)核與 ramdisk 后自動啟動RedBoot fconfig Run script at boot: false true Boot script: Enter script, terminate with empty line load zImage -r -b 0x100000 load ramdisk_ks.gz -r -b 0x800000 exec -b 0x100000 -l 0xc0000 Boot script timeout (1000ms resolution): 3 Use BOOTP for network configuration: true GDB connection port: 9000 Network debug at boot time: false Update RedBoot non-volatile configuration - are you sure (y/n)? y配置項逐一說明配置項值含義Run script at bootfalse true改為true啟用開機自動執(zhí)行腳本Boot script3 條命令依次加載內(nèi)核、加載 ramdisk、執(zhí)行內(nèi)核空行結(jié)束輸入Boot script timeout3腳本執(zhí)行前的倒計時單位 1000ms即 3 秒期間可按任意鍵中斷進入交互模式Use BOOTP for network configurationtrue使用 BOOTP 自動獲取網(wǎng)絡(luò)配置GDB connection port9000RedBoot GDB 調(diào)試連接端口Network debug at boot timefalse開機時不進入網(wǎng)絡(luò)調(diào)試模式保存配置后重啟 Assabet 只需等待登錄提示符出現(xiàn)即可——整個引導過程完全自動化。外設(shè)支持狀態(tài)與硬件細節(jié)文檔附錄記錄了截至 2001 年 10 月-rmk內(nèi)核樹中 Assabet 及 Neponset 外設(shè)的支持狀態(tài)可作為評估該平臺能力的權(quán)威參考Assabet 本體串口Serial ports端口狀態(tài)RadioTX、RX、CTS、DSR、DCD、RI 可用PM 未測試COMTX、RX、CTS、DSR、DCD、RTS、DTR、PM 可用PM 未測試I2C已實現(xiàn)未完全測試L3完全測試通過passPM未測試視頻Video項狀態(tài)LCD完全測試通過注意連接 Neponset 時 LCD 不喜歡被 blanked 熄滅Video out未完全測試音頻AudioUDA1341播放完全測試通過錄音已實現(xiàn)未測試PM 未測試。UCB1200音頻播放/錄音、電信音頻播放/錄音均已實現(xiàn)但未重度測試POTS 控制不支持觸摸屏支持PM 未測試。從源碼可以印證 UCB1200 的接入方式assabet.c 注冊了 UCB1x00 平臺數(shù)據(jù)含復位回調(diào)與喚醒支持并通過 MCPMultimedia Communications Portsa11x0_register_mcp以11981000Hz 的 SCLK 時鐘連接 codecassabet.c 中的assabet_codec_reset展示了 UCB1x00 與 UDA1341 共享復位信號的細節(jié)——該復位線同時接到三個器件UCB1x00、UDA1341、ADV7171復位任一器件都會影響其余兩者且會使 ADV7171 消耗約 100mA 電流超過 MAX846 鋰電充電器的預算若未接鋰電池會導致 Assabet 崩潰——這正是注釋中保留的硬件設(shè)計約束。其他Other項狀態(tài)PCMCIALPE完全測試通過USB不支持IRDASIR / FIR均完全測試通過PM 未測試Neponset 擴展板項狀態(tài)串口 COM1、COM2TX、RX、CTS、DSR、DCD、RTS、DTR 可用PM 未測試USB已實現(xiàn)未重度測試PCMCIA已實現(xiàn)未重度測試CF已實現(xiàn)未重度測試Neponset 的板級支持代碼位于 arch/arm/mach-sa1100/neponset.c且在內(nèi)核配置中由CONFIG_ASSABET_NEPONSET見 arch/arm/mach-sa1100/Kconfig控制該選項依賴SA1100_ASSABET并自動選擇SA1111。啟動時探測 NeponsetAssabet 的一大特殊之處在于必須在paging_init()之前探測 Neponset 是否存在以正確確定可用 RAM 數(shù)量。因此 assabet.c 在fixup_assabet階段先手動映射 GPIO 寄存器再通過get_assabet_scr()讀取系統(tǒng)配置字節(jié)static void __init get_assabet_scr(void) { unsigned long scr, i; GPDR | 0x3fc; /* Configure GPIO 9:2 as outputs */ GPSR 0x3fc; /* Write 0xFF to GPIO 9:2 */ GPDR ~(0x3fc); /* Configure GPIO 9:2 as inputs */ for(i 100; i--; ) /* Read GPIO 9:2 */ scr GPLR; GPDR | 0x3fc; /* restore correct pin direction */ scr 0x3fc; /* save as system configuration byte. */ SCR_value scr; }該方法通過 GPIO 9:2 的上下拉采樣得到系統(tǒng)配置字節(jié)SCR若檢測到 Neponset 則打印 “Neponset expansion board detected”。同一掃描邏輯也用于 zImage 解壓階段設(shè)置串口輸出狀態(tài)消息見注釋中引用的arch/arm/boot/compressed/head-sa1100.S。此外assabet.c 中的ASSABET_BCR_DB1110/ASSABET_BCR_DB1111分別定義了未接/接入 Neponset 時板控寄存器BCR的默認值并在assabet_init_irq中按探測結(jié)果初始化見 assabet.c。總結(jié)通過本文你可以完整掌握 AssabetIntel SA-1110 評估板從零構(gòu)建內(nèi)核到 Flash 引導的完整鏈路構(gòu)建make assabet_defconfig make oldconfig make zImage產(chǎn)出arch/arm/boot/zImage默認配置 arch/arm/configs/assabet_defconfig 中CONFIG_MTD_REDBOOT_PARTS、CONFIG_MTD_BLOCK、CONFIG_JFFS2_FS等選項與引導流程深度耦合。引導程序RedBoot 是具備網(wǎng)絡(luò)支持、維護最活躍的推薦選擇。燒寫通過fis init -f、fconfig -i初始化環(huán)境用 TFTP/Y-Modem 加載鏡像用fis create寫入 Flash。文件系統(tǒng)JFFS2 MTD 是 Flash 可寫文件系統(tǒng)的最便捷方案fis listRedBoot 側(cè)與 MTD 分區(qū)Linux 側(cè)一一對應(yīng)root/dev/mtdblock2完成從 Flash 直接啟動。自動化RedBootfconfig腳本可實現(xiàn)開機自動從 TFTP 引導配合 BOOTP 實現(xiàn)無人值守啟動。當前倉庫中板級代碼 arch/arm/mach-sa1100/assabet.c、平臺配置 arch/arm/mach-sa1100/Kconfig 以及 MTD 解析器 drivers/mtd/parsers/redboot.c 為上述全部流程提供了源碼級支撐是深入研究 ARM 早期平臺移植、RedBoot 引導機制與 MTD/JFFS2 分區(qū)的絕佳參考。需要注意的是該平臺支持已進入廢棄倒計時預計 2027 年移除本文內(nèi)容更適合作為嵌入式 Linux 引導技術(shù)的歷史檔案與學習素材。【免費下載鏈接】linuxLinux kernel source tree項目地址: https://gitcode.com/GitHub_Trending/li/linux創(chuàng)作聲明:本文部分內(nèi)容由AI輔助生成(AIGC),僅供參考