Linux設備樹詳解

Linux 設備樹詳解

Linux 操作系統早期是針對個人電腦設備而開發的操作系統,而個人電腦處理器產商較為單一(例如只有 Intel,AMD)同時個人電腦產商均使用 Intel 或 AMD 制造的處理器,業界形成了統一的總線/硬件接口標準,所以 Linux 系統只要遵循這些標準即可。

然而隨著 ARM 處理器在嵌入式微型設備上的廣泛應用,Linux 也支持了 ARM 處理器。但是由于 ARM 架構的授權機制使得任何產商都可以制造 ARM 處理器,各產商沒有統一標準,制造出的 ARM 處理器各不相同。

所以 Linux 系統源碼中添加了各產商 ARM 芯片描述代碼,才能支持各產商的芯片,這也導致 Linux 源碼包含了大量的 ARM 芯片描述代碼。

1. 前言

在 Linux 沒有設備樹之前 ARM 架構的板級芯片硬件細節通過 C 源碼的形式編寫在 “arch/arm/plat-xxx” 和 “arch/arm/mach-xxx” 形式命名的文件中,不同的硬件對應不同的文件,這些不可復用的文件參雜在 Linux 內核源碼目錄中。

為了從 Linux 內核源碼中去除芯片描述代碼就引入了設備樹,設備樹的本質是不再使用 C 源碼去描述芯片,而是使用設備樹DTS結構化腳本語法去描述各種芯片。

引入設備樹后不同的芯片還是需要對應不同的設備樹文件,所以設備樹文件也很多,那引入設備樹的意義在哪?在于(使用一種專屬文件去描述)可以做到芯片描述與內核源碼的分離,同時設備樹描述的硬件信息更結構化,更清晰易懂。

需要知道的是設備樹是集成在 OpenFrame 中的開源項目,并不是 Linux 的原創,現在知道 Linux 設備樹中 OF 操作函數命名的由來了吧。

2. 設備樹

設備樹 Device Tree,故名思意就是由各類設備組成的樹,設備樹文件叫做 DTS 即DeviceTree Source。DTS 文件采用樹形結構語法描述板級設備信息,比如芯片上 CPU 數量,DDR 內存基地址,SPI/I2C 接口連接的設備。

請添加圖片描述

設備樹用于描述硬件設備,本質就是用于描述芯片外設的寄存器地址,而芯片外設寄存器都是連接在系統總線上的,所以設備樹樹的主干就是系統總線,如上圖。

3. 設備樹工具

現在把芯片的描述內容從 Linux 內核源碼中分離出來了,并且使用了 .dts 設備樹文件格式,所以芯片描述部分代碼不能再和 Linux 內核源碼一起編譯了,或是說不能再用 GCC 去編譯了。此時需要一個專門編譯器將設備樹文件編譯成二進制文件,這個編譯器叫做 DTC,編譯后的二進制文件為 .dtb 格式。

總結:設備樹源碼文件 DTS,設備樹編譯器 DTC,DTS編譯后的二進制文件DTB。

3.1 DTC 編譯器

DTC 編譯器和 GCC 一樣由 C 語言編寫而成,其源碼位于內核的 “scripts/dtc” 目錄下,該目錄下默認是沒有 DTC 的可執行文件的,而是編譯 Linux 時再編譯出可執行文件,所以在 “scripts/dtc” 目錄下除了源碼還有一個 Makefile 文件,這個用于構建 DTC 源碼生成可執行文件。

請添加圖片描述

從 Makefile 文件可以看出 DTC 編譯器源碼有 dtc.c,flattree.c,fstree.c,util.c ,ftdput.c 等文件。

3.2 DTC 使用

如果要使用 DTC 編譯 DTS 文件的話只需要進入到 Linux 源碼根目錄下,執行命令 make dtbsmake all 即可。執行后 Linux 根目錄下的主 Makefile 文件就會調用 “scripts/dtc” 目錄下的 DTC 可執行文件去編譯設備樹目錄下指定的 .dts 文件并生成 .dtb 文件。

如果只是編譯設備樹的話建議使用 make dtbs 命令,make dtbs 會編譯選中的所有設備樹文件。如果只要編譯指定的某個設備樹,比如全志 F1C200S 的,那可以執行 make suniv-f1c200s-lctech-pi.dtb 命令。

$ make suniv-f1c200s-lctech-pi.dtb
DTC arch/arm/boot/dts/suniv-f1c200s-lctech-pi.dtb

3.3 添加 DTS

打開設備樹文件所在的 “arch/arm/boot/dts/” 目錄,打開該目錄下的 Makefile 文件,可以看到全志 SUNIV 系列芯片相關的設備樹文件。

dtb-$(CONFIG_MACH_SUNIV) += \suniv-f1c100s-licheepi-nano.dtb \suniv-f1c200s-lctech-pi.dtb \suniv-f1c200s-popstick-v1.1.dtb

可知只要配置 CONFIG_MACH_SUNIV 選項為 y 后,使用全志 SUNIV 系列芯片的板子對應的 .dts 文件都會被編譯為 .dtb 文件。

比如要添加一個新的 SUNIV 系列芯片相關的設備樹文件, 只需要新建一個對應的 .dts 文件,再把對應的 .dtb 文件名添加到 dtb-$(CONFIG_MACH_SUNIV) 分支下即可,這樣編譯設備樹的時候就會將對應的 .dts 文件編譯為 .dtb 文件。

4. DTS 語法

設備樹文件和編程語言一樣有一套特定的編寫語法規則,編寫設備樹文件就要遵循這套規則,不建議自己編寫完整的設備樹,而是復制半導體產商提供的設備樹文件再修改定制即可。

4.1 頭文件 dtsi

和 C/C++ 一樣,DTS 設備樹也支持頭文件引用,設備樹頭文件后綴名為 .dtsi,引用頭文件使用 #include 語句。

設備樹 .dts 可以引用 .dtsi.dts,甚至 C 語言的頭文件 .h,語法如下所示。

#include "suniv.dtsi"
#include "suniv.dts"
#include "suniv.h"

dtsi 的主要作用

實際應用中 .dtsi 文件用于描述芯片的核心信息(比如 CPU 架構,主頻)以及外設信息(比如 UART,USB,GPIO寄存器地址范圍)。芯片產商會把同一個系列芯片共有的外設信息提煉到一個 .dtsi 文件里,差異化部分的內容分布到具體芯片的 .dts 文件,這樣可減少代碼的冗余。

例如同一系列的芯片他們的 CPU 架構和 CPU 主頻肯定是相同的,那這部分信息就可以提煉到一個全系列芯片共有的 .dtsi 文件。

4.2 設備節點

普通的樹木由主干,枝條和葉子組成,而設備樹由根節點(主干),子節點(枝條),節點屬性(葉子)構成,每個節點屬性記錄著各類設備信息,并按所屬關系依層次排列,就像一棵樹木一樣。

根節點

設備樹根節點名稱固定使用 / 表示,節點范圍用 {} 括號標明,屬于根節點的屬性或子節點就放置在 {} 內部,如下所示。

/ {............
}

每個設備樹文件只有一個根節點,如果引用了別的包含根節點的設備樹文件,那這些根節點會合并為一個根節點,內容也會疊加合并為一份。

子節點

設備樹子節點名稱命名規則為 node-name@unit-address,子節點范圍用 {} 括號標明,屬于子節點的屬性或子節點就放置在 {} 內部,如下所示。

/ {node-name@unit-address {............};
}

其中 node-name 是節點名字,為 ASCII 字符串,可以任意意命名,但是最好能夠體現節點的功能,比如 serial@1c25000 就表示這個節點是串口外設。

unit-address 是節點所代表設備的地址或寄存器首地址,如果某個節點沒有地址或者寄存器的話 unit-address 可忽略,比如 cpus,soc,cpu@0。

雖然 node-name 代表節點名字,但是完整的節點名字為 node-name@unit-address如果要訪問節點要使用完整節點名字,或標簽。

子節點標簽

還可以給子節點命名標簽,規則為 label: node-name@unit-address,其中 label 是節點的標簽,而 : 后面的是節點名字 node-name,例如 uart0:serial@1c25000 其中 uart0 就是節點標簽。

引入 label 的目的是為了方便訪問節點,有了標簽可以通過 &label 來訪問節點,比如通過 &uart0 就可以訪問 serial@1c25000 這個節點,而不用輸入完整的節點名字。再比如節點 sram:sram@10000000,節點 label 是 sram,而節點名字就很長了,為 sram@10000000。所以通過 &sram 來訪問 sram@10000000 節點要方便得多。

設備樹實例

主要觀察實例中根節點以及子節點部分的命名以及規則,節點內部涉及到節點的屬性相關內容再下一小節講解。

/ {#address-cells = <1>;#size-cells = <1>;interrupt-parent = <&intc>;clocks {osc24M: clk-24M {#clock-cells = <0>;compatible = "fixed-clock";clock-frequency = <24000000>;clock-output-names = "osc24M";};};cpus {#address-cells = <1>;#size-cells = <0>;cpu@0 {compatible = "arm,arm926ej-s";device_type = "cpu";reg = <0x0>;};};soc {compatible = "simple-bus";#address-cells = <1>;#size-cells = <1>;ranges;sram-controller@1c00000 {compatible = "allwinner,suniv-f1c100s-system-control","allwinner,sun4i-a10-system-control";reg = <0x01c00000 0x30>;#address-cells = <1>;#size-cells = <1>;ranges;};}
}

節點屬性

節點屬性可以理解為編程語言的變量,可以存儲數據。賦值采用 key=value 對的形式,鍵值對的值可以為空或任意的字節流。

/ {node-name@unit-address {key=value};
}

節點屬性支持幾種常用的數據類型具體下:

(1) 字符串類型,例如 compatible = “arm,arm926ej-s” 設置 compatible 屬性的值為字符串 “arm,arm926ej-s”。

(2) 32 位無符號整數類型,例如 reg = <0x0> 設置 reg 屬性的值為整數 0。

(3) 字符串列表類型,例如 compatible = “licheepi,licheepi-nano”, “allwinner,suniv-f1c100s” 設置屬性 compatible 的值為 “licheepi,licheepi-nano” 字符串和 “allwinner,suniv-f1c100s” 字符串。

4.3 標準屬性

節點是由屬性組成,一個節點代表一個設備,不同的設備需要的屬性不同,我們可以自定義屬性,也可以使用 Linux 支持的標準屬性。

compatible 屬性

compatible 屬性叫 “兼容性” 屬性,兼容屬性對驅動至關重要,用于設備匹配驅動程序(換句話說是 Linux 內核根據該設備節點的兼容屬性為該設備分配一個設備驅動程序)。兼容屬性值是一個字符串列表,字符串列表用于選擇設備所要使用的驅動程序,具體格式如下。

compatible = "manufacturer,model";

其中 manufacturer 段表示廠商名稱,而 model 是指硬件模塊對應驅動程序的名稱,例如 compatible = “winbond,w25q128” 表示產商是 winbond(華邦),硬件模塊是 w25q128 (存儲芯片)。

我們知道屬性支持字符串列表數據類型,所以 compatible 可存屬性值列表,這樣設備就有多個兼容屬性值,設備將多個兼容值逐個的和 Linux 內核驅動程序匹配,直到有合適的驅動程序。

實例

驅動程序文件都會有一個 OF 匹配表,用來保存一些 compatible 值,如果設備節點的 compatible 屬性值和 OF 匹配表中的任何一個值相等,那么就表示設備可以使用這個驅動(那么這個節點就會引用相應的驅動文件)。

#ifdef CONFIG_OF
static const struct of_device_id i2c_nuvoton_of_match[] = {{.compatible = "nuvoton,npct501"},{.compatible = "winbond,wpct301"},{.compatible = "nuvoton,npct601", .data = OF_IS_TPM2},{},
};
MODULE_DEVICE_TABLE(of, i2c_nuvoton_of_match);
#endif

model 屬性

model 屬性用于描述設備名稱(這里的設備指的是具體設備產品比如電腦,而非芯片外設),該屬性屬于字符串數據類型,例如 model = “Lichee Pi Nano”。

status 屬性

status 屬性表示設備狀態,設備樹使用字符串描述設備狀態信息,所以 status 屬性的類型也是字符串,可選的狀態如下表所示:

status 值描述
“okay”說明設備是可操作(可讀可寫)的。
“disabled”說明設備當前不可操作(無法讀寫),但是狀態可再轉變為可操作的(比如熱插拔設備插入以后)詳細部分可以查看設備的綁定文檔。
“fail”說明設備不可操作(無法讀寫),設備出現了一系列的錯誤,并且狀態無法再轉變為可操作的。
“fail-sss”和 “fail” 相同,sss 部分用于表示檢測到的錯誤內容。

reg 屬性

reg 屬性的值一般是 <address,length> 對,該屬性一般用于描述設備地址空間資源信息或者設備地址(即寄存器)信息,比如描述 UART 寄存器地址范圍信息,或者 I2C 器件的設備地址。

其中 address 指的是起始地址,length 則指的是地址長度,reg 屬性可以同時存放多組 <address,length> 地址對,每個 <address length> 組合表示一個地址范圍,具體格式如下。

reg = <address1 length1 address2 length2 address3 length3 ...>;

下面 serial 設備節點描述了全志 F1C200S 芯片 UART0 相關信息,可以看到 reg 屬性中 UART0 的起始地址為 0x01c250,地址長度為 0x400。

uart0: serial@1c25000 {compatible = "snps,dw-apb-uart";reg = <0x01c25000 0x400>;interrupts = <1>;reg-shift = <2>;reg-io-width = <4>;clocks = <&ccu CLK_BUS_UART0>;resets = <&ccu RST_BUS_UART0>;status = "disabled";
};

但是在設置 reg 屬性時需要設置幾組 <address, length> 地址對,這如何確定?這就是下一節涉及的 #address-cells 和 #size-cells 屬性的作用。

#address-cells 和 #size-cells 屬性

這兩個屬性一般是配對使用的,所以一起講解,這兩個屬性的類型都是 32 位無符號整形,擁有子節點的設備節點用 #address-cells#size-cells 屬性設置其子節點的 reg 屬性字長。

#address-cells 屬性指定 reg 屬性的 address 所占用的字長,#size-cells 屬性指定 reg 屬性的 length 所占用的字長。

#address-cells = <value>
#size-cells = <value>

注意上一節說過 reg 屬性可以同時存放多組 <address,length> 地址對,所以這里的占用字長指的是 reg 屬性 address 值或 length 值得個數。

所以 #address-cells 屬性指定 reg 屬性中 address 的個數,#size-cells 屬性指定 reg 屬性中 length 的個數。

實例 1

soc {......#address-cells = <1>;#size-cells = <1>;ranges;uart0: serial@1c25000 {compatible = "snps,dw-apb-uart";reg = <0x01c25000 0x400>;interrupts = <1>;reg-shift = <2>;reg-io-width = <4>;clocks = <&ccu CLK_BUS_UART0>;resets = <&ccu RST_BUS_UART0>;status = "disabled";};......
}

實例 2

soc {......#address-cells = <1>;#size-cells = <0>;ranges;uart0: serial@1c25000 {compatible = "snps,dw-apb-uart";reg = <0x01c25000>;interrupts = <1>;reg-shift = <2>;reg-io-width = <4>;clocks = <&ccu CLK_BUS_UART0>;resets = <&ccu RST_BUS_UART0>;status = "disabled";};......
}

ranges 屬性

ranges 是一個地址映射/轉換表,ranges 屬性每個項目由子地址,父地址和地址空間長度這三部分組成:

rangs = <child-bus-address parent-bus-address length>;

(1) child-bus-address,子總線地址空間的物理地址,由父節點的 #address-cells 屬性確定此物理地址所占用的字長。
(2) parent-bus-address,父總線地址空間的物理地址,同樣由父節點的#address-cells 屬性確定此物理地址所占用的字長。
(3) length,子地址空間的長度,由父節點的 #size-cells 屬性確定此地址長度所占用的字長。

注意 ranges 屬性值可以為空,例如 rangs; 這樣,如果 ranges 屬性值為空值,說明子地址空間和父地址空間完全相同,不需要進行地址轉換。

對于一些芯片來說,子地址空間和父地址空間完全相同,因此會在其設備樹中看到不少設備節點得 ranges 屬性為空值。

實例

sram-controller@1c00000 {......#address-cells = <1>;#size-cells = <1>;......sram_d: sram@10000 {......ranges = <0 0x00010000 0x1000>;......};
};

name 屬性

name 屬性用于記錄節點名字,name 屬性值為字符串數據類型。不過 name 屬性已經被棄用,只能在較老的設備樹文件中看見 name 屬性,所以了解即可。

device_type 屬性

該屬性用于描述設備的 FCode,屬性值為字符串數據類型,IEEE 1275 會用到此屬性。該屬性只能用于 cpu 節點或者 memory 節點,但是設備樹沒有 FCode,所以該屬性也被棄用,所以了解即可。

5. 內核兼容檢查

普通設備的 compatible 兼容屬性用于在 Linux 內核中匹配設備驅動程序,而根節點 / 下的 compatible 兼容屬性則用于 Linux 內核檢查當前設備樹對應的設備類型(注意這里的設備不是指芯片外設,而是完整的硬件產品)。

因為設備樹是和硬件設備綁定的,所以 Linux 內核檢查設備樹的類型就可以知道當前內核是否支持該硬件設備,如果支持則啟動 Linux 內核。

以下是全志 F1C200S 芯片的設備樹,可以看到根節點的兼容屬性為 “licheepi,licheepi-nano” 和 “allwinner,suniv-f1c100s”。

/ {model = "Lichee Pi Nano";compatible = "licheepi,licheepi-nano", "allwinner,suniv-f1c100s";aliases {mmc0 = &mmc0;serial0 = &uart0;spi0 = &spi0;};chosen {stdout-path = "serial0:115200n8";};reg_vcc3v3: vcc3v3 {compatible = "regulator-fixed";regulator-name = "vcc3v3";regulator-min-microvolt = <3300000>;regulator-max-microvolt = <3300000>;};
};

設備檢查原理

在 Linux 內核的源碼目錄 arch/arm/include/asm/mach/ 目錄下的 arch.h 文件中定義了 machine_desc 結構體宏定義 DT_MACHINE_START,通過該宏定義可以根據芯片架構指定名稱定義一個專有名稱的 machine_desc 結構體,并初始化,宏定義如下。

#define DT_MACHINE_START(_name, _namestr)       \
static const struct machine_desc __mach_desc_##_name    \__used                         \__section(".arch.info.init") = {           \.nr     = ~0,               \.name       = _namestr,#endif

宏定義 DT_MACHINE_START 并不完整,因為結構體缺少了 } 括號,實際上還有配套宏定義 MACHINE_END,通過這兩個宏定義即可定義完整的結構體。

#define MACHINE_END                \
};

在 Linux 內核的源碼目錄 arch/arm/mach-xxx 目錄下包含各類芯片的設備描述machine_desc 結構體定義,例如全志 F1C200S 芯片對應的 machine_desc 結構體定義如下。

static const char * const suniv_board_dt_compat[] = {"allwinner,suniv-f1c100s",NULL,
};DT_MACHINE_START(SUNIV_DT, "Allwinner suniv Family").dt_compat  = suniv_board_dt_compat,
MACHINE_END

machine_desc 結構體成員變量 .dt_compat 保存著相應設備的兼容值,查看全志 F1C200S 設備樹根節點的 compatible 屬性值可知與 suniv_board_dt_compat 保存的兼容值相同,因此 Linux 內核支持該設備。

6. 節點追加內容

前面說過,芯片產商會把同一個系列芯片相同的外設信息提煉到一個 .dtsi 文件中,需要這部分信息的 .dts 設備樹文件就可以包含這個頭文件,這樣可減少代碼的冗余。

所以如果要添加或修改 .dtsi 頭文件中的節點內容,就不能直接在 .dtsi 文件修改,直接修改會影響包含該頭文件的其他設備樹,那該怎么辦呢。

通過前面子節點內容知道可以給子節點命名標簽(label),有了節點標簽后就可以在 .dts 設備樹文件中通過標簽訪問節點,此時即可體現子節點標簽的作用,通過標簽訪問節點的規則如下:

&label {}

比如現在要修改設備節點 serial@1c25000 的 status 屬性,那么在 .dts 文件直接通過它的 uart0 標簽訪問即可(如果要訪問的節點沒有標簽,先命名標簽)。

&uart0 {pinctrl-names = "default";pinctrl-0 = <&uart0_pe_pins>;status = "okay";
};

7. DTS與RootFS

Uboot 啟動 Linux 內核的同時會將設備樹 .dtb 文件傳遞給 Linux 內核,Linux 內核會解析出設備樹的節點信息,并根據節點名字在根文件系統 /proc/device-tree 目錄下創建不同文件夾,再將節點內容保存到這些文件夾下。

我們知道設備樹屬于樹狀層級結構,恰好文件系統目錄結構也是如此,節點類似文件夾,屬性類似于文件夾中的文件,所以 Linux 內核將解析的設備樹節點在根文件系統中表示為 文件夾,屬性表示為 文件

例如 clocks,soc 屬于 / 的子節點,所以它們是文件夾的形式,compatible,#address-cells,size-cells 屬于 / 的屬性,所以它們是文件的形式,如下圖。

請添加圖片描述

不僅根節點 / 如此,所有節點都是這樣,例如 soc 節點的子節點以文件夾的形式表示,屬性以文件的形式表示,如下圖。

請添加圖片描述

8. 特殊節點

8.1 aliases 節點

aliases 節點的主要作用是給節點定義別名,定義別名的目的就是為了方便訪問節點,不過這不常用,現在更多是使用節點標簽來訪問節點。

8.2 chosen 節點

chosen 節點主要作用是用于 Uboot 向 Linux 內核傳遞數據,重點用于 bootargs 參數傳遞。 Uboot 會在 chosen 節點添加 bootargs 屬性,并且設置 bootargs 屬性值為 bootargs 環境變量的值。

詳細查看:

https://blog.csdn.net/WANGYONGZIXUE/article/details/115600699

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

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

相關文章

JavaScript進階 第二天

深入對象內置構造函數 一. 深入對象 創建對象三種方式構造函數實例成員&靜態成員 1.1 創建對象三種方式 ① 利用對象字面量創建對象 const o {name: 哈哈 } ② 利用new Object 創建對象 const o new Object({ name: 哈哈 }) ③ 構造函數創建對象 1.2 構造函數 …

探索規律:Python地圖數據可視化藝術

文章目錄 一 基礎地圖使用二 國內疫情可視化圖表2.1 實現步驟2.2 完整代碼2.3 運行結果 一 基礎地圖使用 使用 Pyecharts 構建地圖可視化也是很簡單的。Pyecharts 支持多種地圖類型&#xff0c;包括普通地圖、熱力圖、散點地圖等。以下是一個構建簡單地圖的示例&#xff0c;以…

認識Transformer:入門知識

視頻鏈接&#xff1a; https://www.youtube.com/watch?vugWDIIOHtPA&listPLJV_el3uVTsOK_ZK5L0Iv_EQoL1JefRL4&index60 文章目錄 Self-Attention layerMulti-head self-attentionPositional encodingSeq2Seq with AttentionTransformerUniversal Transformer Seq2Seq …

淺談 EMP-SSL + 代碼解讀:自監督對比學習的一種極簡主義風

論文鏈接&#xff1a;https://arxiv.org/pdf/2304.03977.pdf 代碼&#xff1a;https://github.com/tsb0601/EMP-SSL 其他學習鏈接&#xff1a;突破自監督學習效率極限&#xff01;馬毅、LeCun聯合發布EMP-SSL&#xff1a;無需花哨trick&#xff0c;30個epoch即可實現SOTA 主要…

08 qt進程和網絡編程(cs模型)

一 、qt進程 qt中進程最主要的任務就是啟動額外應用程序 并且跟他們之間通信。進程類為QProcess 定義用途Header:#include qmake:QT += coreInherits:QIODevice//繼承于IO設備類1.1 QProcess基本使用 第一步:創建一個QProcess對象 // process = new QProcess(this); //說明…

資訊速遞 | ArkUI-X 預覽版已正式開源!

OpenHarmony項目群技術指導委員會&#xff08;以下簡稱“TSC”&#xff09;-跨平臺應用開發框架TSG所孵化項目 —— ArkUI-X&#xff0c;近期已正式開源 &#xff0c;開發者基于一套主代碼&#xff0c;就可以將在OpenHarmony上開發的精美、高性能應用同時運行在Android、iOS等其…

LNMP環境搭建wordpress以及跳轉后臺報404解決

基于上文配置好的LNMP環境繼續搭建wordpress 目錄 一.到官網下載tar.gz包&#xff0c;并上傳到Linux上&#xff0c;也可以通過復制鏈接地址進行下載 二. 將wordpress中的所有文件移動到你nginx.conf中指定目錄中 三.為wordpress配置數據庫 四.到瀏覽器進行注冊 1.剛開始…

maven編譯始終提示無效的目標發行版的解決方法

摘自個人印象筆記2021-05-07&#xff1a;https://app.yinxiang.com/fx/55e1d5f4-aeea-446a-a768-0f1a48195f5b(圖顯示不完整可查看原筆記內容)1&#xff1a;確保IDE中的編譯版本正確 在idea中&#xff0c;主要看項目屬性中和setting的java compiler中對應的jdk版本是否正確&…

好用的安卓手機投屏到mac分享

工具推薦&#xff1a;scrcpy github地址&#xff1a;https://github.com/Genymobile/scrcpy/tree/master mac使用方式 安裝環境&#xff0c;打開terminal&#xff0c;執行以下命令&#xff0c;沒有brew的先安裝brew brew install scrcpy brew install android-platform-too…

學習 Iterator 迭代器

今天看到一個面試題&#xff0c; 讓下面解構賦值成立。 let [a,b] {a:1,b:2} 如果我們直接在瀏覽器輸出這行代碼&#xff0c;會直接報錯&#xff0c;說是 {a:1,b:2} 不能迭代。 看了es6文檔后&#xff0c;具有迭代器的就一下幾種類型&#xff0c;沒有Object類型&#xff0c;…

404. 左葉子之和

給定二叉樹的根節點 root &#xff0c;返回所有左葉子之和。 示例 1&#xff1a; 輸入: root [3,9,20,null,null,15,7] 輸出: 24 解釋: 在這個二叉樹中&#xff0c;有兩個左葉子&#xff0c;分別是 9 和 15&#xff0c;所以返回 24示例 2: 輸入: root [1] 輸出: 0提示: 節點…

【NetCore】09-中間件

文章目錄 中間件&#xff1a;掌控請求處理過程的關鍵1. 中間件1.1 中間件工作原理1.2 中間件核心對象 2.異常處理中間件:區分真異常和邏輯異常2.1 處理異常的方式2.1.1 日常錯誤處理--定義錯誤頁的方法2.1.2 使用代理方法處理異常2.1.3 異常過濾器 IExceptionFilter2.1.4 特性過…

go web框架 gin-gonic源碼解讀02————router

go web框架 gin-gonic源碼解讀02————router 本來想先寫context&#xff0c;但是發現context能簡單講講的東西不多&#xff0c;就準備直接和router合在一起講好了 router是web服務的路由&#xff0c;是指講來自客戶端的http請求與服務器端的處理邏輯或者資源相映射的機制。&…

react實現對數組做增刪改操作自定義hook

需求 實現對數組的增刪改操作。 實現 import { useState } from react;const useArray (currList) > {const [list, setList] useState(currList);// 增const addItem (item) > {setList([...list, item]);};// 刪const removeItem (idx) > {const _arr [...l…

實戰指南,SpringBoot + Mybatis 如何對接多數據源

系列文章目錄 MyBatis緩存原理 Mybatis plugin 的使用及原理 MyBatisSpringboot 啟動到SQL執行全流程 數據庫操作不再困難&#xff0c;MyBatis動態Sql標簽解析 從零開始&#xff0c;手把手教你搭建Spring Boot后臺工程并說明 Spring框架與SpringBoot的關聯與區別 Spring監聽器…

輕松解決docker容器啟動閃退

docker run -p 3306:3306 --name mysql8 \ -v /usr/local/mysql/log:/var/log/mysql \ -v /usr/local/mysql/data:/var/lib/mysql \ -v /usr/local/mysql/conf:/etc/mysql \ -e MYSQL_ROOT_PASSWORD666 -d mysql:8.0.32執行這個命令的時候閃退&#xff0c;其實這個是命令是對你…

[cv] stable diffusion——2、公式

背景&#xff1a; 在圖像生成領域中&#xff0c;最常見的生成模型是GAN和VAE。然而&#xff0c;在2020年&#xff0c;提出了一種新的模型&#xff0c;即DDPM&#xff08;Denoising Diffusion Probabilistic Model&#xff09;&#xff0c;也被稱為擴散模型&#xff08;Diffusi…

基于eBPF技術構建一種應用層網絡管控解決方案

引言 隨著網絡應用的不斷發展&#xff0c;在linux系統中對應用層網絡管控的需求也日益增加&#xff0c;而傳統的iptables、firewalld等工具難以針對應用層進行網絡管控。因此需要一種創新的解決方案來提升網絡應用的可管理性。 本文將探討如何使用eBPF技術構建一種應用層網絡…

【CSS】禁用元素鼠標事件(例如實現元素禁用效果)

文章目錄 基本用法 基本用法 pointer-events 屬性指定在什么情況下 (如果有) 某個特定的圖形元素可以成為鼠標事件。實際運用中可以通過對auto 和none動態控制&#xff0c;來動態實現元素的禁用效果。 屬性描述auto與pointer-events屬性未指定時的表現效果相同&#xff0c;對…

【筆試題心得】排序算法總結整理

排序算法匯總 常用十大排序算法_calm_G的博客-CSDN博客 以下動圖參考 十大經典排序算法 Python 版實現&#xff08;附動圖演示&#xff09; - 知乎 冒泡排序 排序過程如下圖所示&#xff1a; 比較相鄰的元素。如果第一個比第二個大&#xff0c;就交換他們兩個。對每一對相鄰…