程序项目代做,有需求私信(vue、React、Java、爬虫、电路板设计、嵌入式linux等)

Rockchip RK3399 - 移植linux 5.2.8

----------------------------------------------------------------------------------------------------------------------------

开发板 :NanoPC-T4开发板
eMMC16GB
LPDDR34GB
显示屏 :15.6英寸HDMI接口显示屏
u-bootRockchip官方uboot 2017.09
linux5.2.8
----------------------------------------------------------------------------------------------------------------------------

在前面的章节,我们已经介绍了在RK3399上面移植Rockchip官方提供的uboot 2017.09,这一节我们将移植linux 5.2.8RK3399上。

一、linux内核

uboot一样,linux内核通常有三种:

  • linux官方源码:《https://github.com/torvalds/linux》,linux官方源码是由linux官方维护,支持非常全面的芯片,但对具体某款开发板支持情况一般;
  • 半导体厂商瑞芯微官方源码:《https://github.com/rockchip-linux/kernel》,半导体厂商基于linux官方源码进行修改,对自家的芯片进行完善的支持,针对某款处理器支持情况较好;
  • 开发板友善之家官方源码:《https://github.com/friendlyarm/kernel-rockchip》,开发板厂商基于半导体厂商维护的linux,对自家的开发板进行板级支持,针对某款开发板支持情况较好;

由于Rockchip官方提供的内核版本较低,所以这里我们直接去linux官方去下载,然后后面参考开发板友善之家官方源码修改使其能够支持NanoPC-T4开发板。

1.1 源码下载

内核源码下载地址为:《https://www.kernel.org/》,这里我们不下载最新的6.3.2版本,我们和之前介绍的《Mini2440内核移植》一样,选择5.2.8版本:

也可以到内核镜像网址下载https://mirrors.edge.kernel.org/pub/linux/kernel/,这里下载速度更快。

如果下载速度太慢,无法下载,提供另一个链接:http://ftp.sjtu.edu.cn/sites/ftp.kernel.org/pub/linux/kernel/

我们这里下载linux-5.2.8版本,执行如下命令:

root@zhengyang:/work/sambashare/rk3399# wget http://ftp.sjtu.edu.cn/sites/ftp.kernel.org/pub/linux/kernel/v5.x/linux-5.2.8.tar.gz

这里我是下载到/work/sambashare/rk3399路径下的,这个路径是用来专门存放与rk3399相关的内容。

解压源码:

root@zhengyang:/work/sambashare/rk3399# tar -xvf linux-5.2.8.tar.gz

关于《linux内核的目录结构》我们之前已经介绍过,这里就不再重复叙述了。

root@zhengyang:/work/sambashare/rk3399# cd linux-5.2.8/
root@zhengyang:/work/sambashare/rk3399/linux-5.2.8# ll
总用量 840
drwxrwxr-x  24 root root   4096 Aug  9  2019 ./
drwxr-xr-x   8 root root   4096 May 17 04:16 ../
drwxrwxr-x  27 root root   4096 Aug  9  2019 arch/
drwxrwxr-x   3 root root   4096 Aug  9  2019 block/
drwxrwxr-x   2 root root   4096 Aug  9  2019 certs/
-rw-rw-r--   1 root root  14943 Aug  9  2019 .clang-format
-rw-rw-r--   1 root root     59 Aug  9  2019 .cocciconfig
-rw-rw-r--   1 root root    423 Aug  9  2019 COPYING
-rw-rw-r--   1 root root  99486 Aug  9  2019 CREDITS
drwxrwxr-x   4 root root   4096 Aug  9  2019 crypto/
drwxrwxr-x 122 root root  12288 Aug  9  2019 Documentation/
drwxrwxr-x 140 root root   4096 Aug  9  2019 drivers/
drwxrwxr-x  73 root root   4096 Aug  9  2019 fs/
-rw-rw-r--   1 root root     71 Aug  9  2019 .get_maintainer.ignore
-rw-rw-r--   1 root root     30 Aug  9  2019 .gitattributes
-rw-rw-r--   1 root root   1658 Aug  9  2019 .gitignore
drwxrwxr-x  27 root root   4096 Aug  9  2019 include/
drwxrwxr-x   2 root root   4096 Aug  9  2019 init/
drwxrwxr-x   2 root root   4096 Aug  9  2019 ipc/
-rw-rw-r--   1 root root   1513 Aug  9  2019 Kbuild
-rw-rw-r--   1 root root    563 Aug  9  2019 Kconfig
drwxrwxr-x  18 root root   4096 Aug  9  2019 kernel/
drwxrwxr-x  15 root root  12288 Aug  9  2019 lib/
drwxrwxr-x   6 root root   4096 Aug  9  2019 LICENSES/
-rw-rw-r--   1 root root  12316 Aug  9  2019 .mailmap
-rw-rw-r--   1 root root 512407 Aug  9  2019 MAINTAINERS
-rw-rw-r--   1 root root  60262 Aug  9  2019 Makefile
drwxrwxr-x   3 root root   4096 Aug  9  2019 mm/
drwxrwxr-x  70 root root   4096 Aug  9  2019 net/
-rw-rw-r--   1 root root    727 Aug  9  2019 README
drwxrwxr-x  29 root root   4096 Aug  9  2019 samples/
drwxrwxr-x  15 root root   4096 Aug  9  2019 scripts/
drwxrwxr-x  11 root root   4096 Aug  9  2019 security/
drwxrwxr-x  26 root root   4096 Aug  9  2019 sound/
drwxrwxr-x  36 root root   4096 Aug  9  2019 tools/
drwxrwxr-x   2 root root   4096 Aug  9  2019 usr/
drwxrwxr-x   4 root root   4096 Aug  9  2019 virt/

1.2 配置Makefile

修改顶层的Makefile,打开Makefile文件,找到下面语句:

ARCH        ?= $(SUBARCH)

修改为:

ARCH        ?= arm64
CROSS_COMPILE    ?= arm-linux-

其中,ARCH是指定目标平台为arm64CROSS_COMPILE是指定交叉编译器,这里指定的是系统默认的交叉编译器,如要使用其它的,则要把编译器的全路径在这里写出。

1.3 内核defconfig配置

接下来要做的就是内核配置、编译了。单板的默认配置文件在arch/arm64/configs目录下:

root@zhengyang:/work/sambashare/rk3399/linux-5.2.8# ll arch/arm64/configs/defconfig
-rw-rw-r-- 1 root root 18417 Aug  9  2019 arch/arm64/configs/defconfig

在这个目录下就这一个配置,我们也没有其它选择了,那只能走一步看一步了。

配置文件defconfig其定义如下:

CONFIG_SYSVIPC=y
CONFIG_POSIX_MQUEUE=y
CONFIG_AUDIT=y
CONFIG_NO_HZ_IDLE=y
CONFIG_HIGH_RES_TIMERS=y
CONFIG_PREEMPT=y
CONFIG_IRQ_TIME_ACCOUNTING=y
CONFIG_BSD_PROCESS_ACCT=y
CONFIG_BSD_PROCESS_ACCT_V3=y
CONFIG_TASKSTATS=y
CONFIG_TASK_DELAY_ACCT=y
CONFIG_TASK_XACCT=y
CONFIG_TASK_IO_ACCOUNTING=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_NUMA_BALANCING=y
CONFIG_MEMCG=y
CONFIG_MEMCG_SWAP=y
CONFIG_BLK_CGROUP=y
CONFIG_CGROUP_PIDS=y
CONFIG_CGROUP_HUGETLB=y
CONFIG_CPUSETS=y
CONFIG_CGROUP_DEVICE=y
CONFIG_CGROUP_CPUACCT=y
CONFIG_CGROUP_PERF=y
CONFIG_USER_NS=y
CONFIG_SCHED_AUTOGROUP=y
CONFIG_BLK_DEV_INITRD=y
CONFIG_KALLSYMS_ALL=y
# CONFIG_COMPAT_BRK is not set
CONFIG_PROFILING=y
CONFIG_ARCH_AGILEX=y
CONFIG_ARCH_SUNXI=y
CONFIG_ARCH_ALPINE=y
CONFIG_ARCH_BCM2835=y
CONFIG_ARCH_BCM_IPROC=y
CONFIG_ARCH_BERLIN=y
CONFIG_ARCH_BRCMSTB=y
CONFIG_ARCH_EXYNOS=y
CONFIG_ARCH_K3=y
CONFIG_ARCH_LAYERSCAPE=y
CONFIG_ARCH_LG1K=y
CONFIG_ARCH_HISI=y
CONFIG_ARCH_MEDIATEK=y
CONFIG_ARCH_MESON=y
CONFIG_ARCH_MVEBU=y
CONFIG_ARCH_MXC=y
CONFIG_ARCH_QCOM=y
CONFIG_ARCH_RENESAS=y
CONFIG_ARCH_ROCKCHIP=y
CONFIG_ARCH_SEATTLE=y
CONFIG_ARCH_STRATIX10=y
CONFIG_ARCH_SYNQUACER=y
CONFIG_ARCH_TEGRA=y
CONFIG_ARCH_SPRD=y
CONFIG_ARCH_THUNDER=y
CONFIG_ARCH_THUNDER2=y
CONFIG_ARCH_UNIPHIER=y
CONFIG_ARCH_VEXPRESS=y
CONFIG_ARCH_XGENE=y
CONFIG_ARCH_ZX=y
CONFIG_ARCH_ZYNQMP=y
CONFIG_ARM64_VA_BITS_48=y
CONFIG_SCHED_MC=y
CONFIG_NUMA=y
CONFIG_SECCOMP=y
CONFIG_KEXEC=y
CONFIG_CRASH_DUMP=y
CONFIG_XEN=y
CONFIG_COMPAT=y
CONFIG_HIBERNATION=y
CONFIG_WQ_POWER_EFFICIENT_DEFAULT=y
CONFIG_ARM_CPUIDLE=y
CONFIG_CPU_FREQ=y
CONFIG_CPU_FREQ_STAT=y
CONFIG_CPU_FREQ_GOV_POWERSAVE=m
CONFIG_CPU_FREQ_GOV_USERSPACE=y
CONFIG_CPU_FREQ_GOV_ONDEMAND=y
CONFIG_CPU_FREQ_GOV_CONSERVATIVE=m
CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y
CONFIG_CPUFREQ_DT=y
CONFIG_ACPI_CPPC_CPUFREQ=m
CONFIG_ARM_ARMADA_37XX_CPUFREQ=y
CONFIG_ARM_SCPI_CPUFREQ=y
CONFIG_ARM_TEGRA186_CPUFREQ=y
CONFIG_ARM_SCPI_PROTOCOL=y
CONFIG_RASPBERRYPI_FIRMWARE=y
CONFIG_INTEL_STRATIX10_SERVICE=y
CONFIG_TI_SCI_PROTOCOL=y
CONFIG_EFI_CAPSULE_LOADER=y
CONFIG_IMX_SCU=y
CONFIG_IMX_SCU_PD=y
CONFIG_ACPI=y
CONFIG_ACPI_APEI=y
CONFIG_ACPI_APEI_GHES=y
CONFIG_ACPI_APEI_MEMORY_FAILURE=y
CONFIG_ACPI_APEI_EINJ=y
CONFIG_VIRTUALIZATION=y
CONFIG_KVM=y
CONFIG_ARM64_CRYPTO=y
CONFIG_CRYPTO_SHA1_ARM64_CE=y
CONFIG_CRYPTO_SHA2_ARM64_CE=y
CONFIG_CRYPTO_SHA512_ARM64_CE=m
CONFIG_CRYPTO_SHA3_ARM64=m
CONFIG_CRYPTO_SM3_ARM64_CE=m
CONFIG_CRYPTO_GHASH_ARM64_CE=y
CONFIG_CRYPTO_CRCT10DIF_ARM64_CE=m
CONFIG_CRYPTO_AES_ARM64_CE_CCM=y
CONFIG_CRYPTO_AES_ARM64_CE_BLK=y
CONFIG_CRYPTO_CHACHA20_NEON=m
CONFIG_CRYPTO_AES_ARM64_BS=m
CONFIG_JUMP_LABEL=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
CONFIG_KSM=y
CONFIG_MEMORY_FAILURE=y
CONFIG_TRANSPARENT_HUGEPAGE=y
CONFIG_CMA=y
CONFIG_NET=y
CONFIG_PACKET=y
CONFIG_UNIX=y
CONFIG_INET=y
CONFIG_IP_MULTICAST=y
CONFIG_IP_PNP=y
CONFIG_IP_PNP_DHCP=y
CONFIG_IP_PNP_BOOTP=y
CONFIG_IPV6=m
CONFIG_NETFILTER=y
CONFIG_NF_CONNTRACK=m
CONFIG_NF_CONNTRACK_EVENTS=y
CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m
CONFIG_NETFILTER_XT_TARGET_LOG=m
CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=m
CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
CONFIG_IP_NF_IPTABLES=m
CONFIG_IP_NF_FILTER=m
CONFIG_IP_NF_TARGET_REJECT=m
CONFIG_IP_NF_NAT=m
CONFIG_IP_NF_TARGET_MASQUERADE=m
CONFIG_IP_NF_MANGLE=m
CONFIG_IP6_NF_IPTABLES=m
CONFIG_IP6_NF_FILTER=m
CONFIG_IP6_NF_TARGET_REJECT=m
CONFIG_IP6_NF_MANGLE=m
CONFIG_IP6_NF_NAT=m
CONFIG_IP6_NF_TARGET_MASQUERADE=m
CONFIG_BRIDGE=m
CONFIG_BRIDGE_VLAN_FILTERING=y
CONFIG_VLAN_8021Q=m
CONFIG_VLAN_8021Q_GVRP=y
CONFIG_VLAN_8021Q_MVRP=y
CONFIG_QRTR=m
CONFIG_QRTR_SMD=m
CONFIG_QRTR_TUN=m
CONFIG_BPF_JIT=y
CONFIG_BT=m
CONFIG_BT_HIDP=m
# CONFIG_BT_HS is not set
# CONFIG_BT_LE is not set
CONFIG_BT_LEDS=y
# CONFIG_BT_DEBUGFS is not set
CONFIG_BT_HCIBTUSB=m
CONFIG_BT_HCIUART=m
CONFIG_BT_HCIUART_LL=y
CONFIG_BT_HCIUART_BCM=y
CONFIG_CFG80211=m
CONFIG_MAC80211=m
CONFIG_MAC80211_LEDS=y
CONFIG_RFKILL=m
CONFIG_NET_9P=y
CONFIG_NET_9P_VIRTIO=y
CONFIG_PCI=y
CONFIG_PCIEPORTBUS=y
CONFIG_PCI_IOV=y
CONFIG_HOTPLUG_PCI=y
CONFIG_HOTPLUG_PCI_ACPI=y
CONFIG_PCI_AARDVARK=y
CONFIG_PCI_TEGRA=y
CONFIG_PCIE_RCAR=y
CONFIG_PCI_HOST_GENERIC=y
CONFIG_PCI_XGENE=y
CONFIG_PCIE_ALTERA=y
CONFIG_PCIE_ALTERA_MSI=y
CONFIG_PCI_HOST_THUNDER_PEM=y
CONFIG_PCI_HOST_THUNDER_ECAM=y
CONFIG_PCIE_ROCKCHIP_HOST=m
CONFIG_PCI_LAYERSCAPE=y
CONFIG_PCI_HISI=y
CONFIG_PCIE_QCOM=y
CONFIG_PCIE_ARMADA_8K=y
CONFIG_PCIE_KIRIN=y
CONFIG_PCIE_HISI_STB=y
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_DEVTMPFS=y
CONFIG_DEVTMPFS_MOUNT=y
CONFIG_HISILICON_LPC=y
CONFIG_SIMPLE_PM_BUS=y
CONFIG_MTD=y
CONFIG_MTD_BLOCK=y
CONFIG_MTD_M25P80=y
CONFIG_MTD_RAW_NAND=y
CONFIG_MTD_NAND_DENALI_DT=y
CONFIG_MTD_NAND_MARVELL=y
CONFIG_MTD_NAND_QCOM=y
CONFIG_MTD_SPI_NOR=y
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_NBD=m
CONFIG_VIRTIO_BLK=y
CONFIG_BLK_DEV_NVME=m
CONFIG_SRAM=y
CONFIG_EEPROM_AT25=m
# CONFIG_SCSI_PROC_FS is not set
CONFIG_BLK_DEV_SD=y
CONFIG_SCSI_SAS_ATA=y
CONFIG_SCSI_HISI_SAS=y
CONFIG_SCSI_HISI_SAS_PCI=y
CONFIG_SCSI_UFSHCD=y
CONFIG_SCSI_UFSHCD_PLATFORM=y
CONFIG_SCSI_UFS_QCOM=m
CONFIG_SCSI_UFS_HISI=y
CONFIG_ATA=y
CONFIG_SATA_AHCI=y
CONFIG_SATA_AHCI_PLATFORM=y
CONFIG_AHCI_CEVA=y
CONFIG_AHCI_MVEBU=y
CONFIG_AHCI_XGENE=y
CONFIG_AHCI_QORIQ=y
CONFIG_SATA_SIL24=y
CONFIG_SATA_RCAR=y
CONFIG_PATA_PLATFORM=y
CONFIG_PATA_OF_PLATFORM=y
CONFIG_NETDEVICES=y
CONFIG_MACVLAN=m
CONFIG_MACVTAP=m
CONFIG_TUN=y
CONFIG_VETH=m
CONFIG_VIRTIO_NET=y
CONFIG_AMD_XGBE=y
CONFIG_NET_XGENE=y
CONFIG_ATL1C=m
CONFIG_MACB=y
CONFIG_THUNDER_NIC_PF=y
CONFIG_FEC=y
CONFIG_HIX5HD2_GMAC=y
CONFIG_HNS_DSAF=y
CONFIG_HNS_ENET=y
CONFIG_HNS3=y
CONFIG_HNS3_HCLGE=y
CONFIG_HNS3_ENET=y
CONFIG_E1000E=y
CONFIG_IGB=y
CONFIG_IGBVF=y
CONFIG_MVNETA=y
CONFIG_MVPP2=y
CONFIG_SKY2=y
CONFIG_QCOM_EMAC=m
CONFIG_RAVB=y
CONFIG_SMC91X=y
CONFIG_SMSC911X=y
CONFIG_SNI_AVE=y
CONFIG_SNI_NETSEC=y
CONFIG_STMMAC_ETH=m
CONFIG_MDIO_BUS_MUX_MMIOREG=y
CONFIG_AT803X_PHY=m
CONFIG_MARVELL_PHY=m
CONFIG_MARVELL_10G_PHY=m
CONFIG_MESON_GXL_PHY=m
CONFIG_MICREL_PHY=y
CONFIG_REALTEK_PHY=m
CONFIG_ROCKCHIP_PHY=y
CONFIG_USB_PEGASUS=m
CONFIG_USB_RTL8150=m
CONFIG_USB_RTL8152=m
CONFIG_USB_LAN78XX=m
CONFIG_USB_USBNET=m
CONFIG_USB_NET_DM9601=m
CONFIG_USB_NET_SR9800=m
CONFIG_USB_NET_SMSC75XX=m
CONFIG_USB_NET_SMSC95XX=m
CONFIG_USB_NET_PLUSB=m
CONFIG_USB_NET_MCS7830=m
CONFIG_ATH10K=m
CONFIG_ATH10K_PCI=m
CONFIG_BRCMFMAC=m
CONFIG_MWIFIEX=m
CONFIG_MWIFIEX_PCIE=m
CONFIG_WL18XX=m
CONFIG_WLCORE_SDIO=m
CONFIG_INPUT_EVDEV=y
CONFIG_KEYBOARD_ADC=m
CONFIG_KEYBOARD_GPIO=y
CONFIG_KEYBOARD_CROS_EC=y
CONFIG_INPUT_TOUCHSCREEN=y
CONFIG_TOUCHSCREEN_ATMEL_MXT=m
CONFIG_INPUT_MISC=y
CONFIG_INPUT_PM8941_PWRKEY=y
CONFIG_INPUT_HISI_POWERKEY=y
# CONFIG_SERIO_SERPORT is not set
CONFIG_SERIO_AMBAKMI=y
CONFIG_LEGACY_PTY_COUNT=16
CONFIG_SERIAL_8250=y
CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_SERIAL_8250_EXTENDED=y
CONFIG_SERIAL_8250_SHARE_IRQ=y
CONFIG_SERIAL_8250_BCM2835AUX=y
CONFIG_SERIAL_8250_DW=y
CONFIG_SERIAL_8250_OMAP=y
CONFIG_SERIAL_8250_MT6577=y
CONFIG_SERIAL_8250_UNIPHIER=y
CONFIG_SERIAL_OF_PLATFORM=y
CONFIG_SERIAL_AMBA_PL011=y
CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
CONFIG_SERIAL_MESON=y
CONFIG_SERIAL_MESON_CONSOLE=y
CONFIG_SERIAL_SAMSUNG=y
CONFIG_SERIAL_SAMSUNG_CONSOLE=y
CONFIG_SERIAL_TEGRA=y
CONFIG_SERIAL_TEGRA_TCU=y
CONFIG_SERIAL_IMX=y
CONFIG_SERIAL_IMX_CONSOLE=y
CONFIG_SERIAL_SH_SCI=y
CONFIG_SERIAL_MSM=y
CONFIG_SERIAL_MSM_CONSOLE=y
CONFIG_SERIAL_QCOM_GENI=y
CONFIG_SERIAL_QCOM_GENI_CONSOLE=y
CONFIG_SERIAL_XILINX_PS_UART=y
CONFIG_SERIAL_XILINX_PS_UART_CONSOLE=y
CONFIG_SERIAL_FSL_LPUART=y
CONFIG_SERIAL_FSL_LPUART_CONSOLE=y
CONFIG_SERIAL_MVEBU_UART=y
CONFIG_SERIAL_DEV_BUS=y
CONFIG_VIRTIO_CONSOLE=y
CONFIG_IPMI_HANDLER=m
CONFIG_IPMI_DEVICE_INTERFACE=m
CONFIG_IPMI_SI=m
CONFIG_TCG_TPM=y
CONFIG_TCG_TIS_I2C_INFINEON=y
CONFIG_I2C_CHARDEV=y
CONFIG_I2C_MUX=y
CONFIG_I2C_MUX_PCA954x=y
CONFIG_I2C_BCM2835=m
CONFIG_I2C_DESIGNWARE_PLATFORM=y
CONFIG_I2C_GPIO=m
CONFIG_I2C_IMX=y
CONFIG_I2C_MESON=y
CONFIG_I2C_MV64XXX=y
CONFIG_I2C_PXA=y
CONFIG_I2C_QUP=y
CONFIG_I2C_RK3X=y
CONFIG_I2C_SH_MOBILE=y
CONFIG_I2C_TEGRA=y
CONFIG_I2C_UNIPHIER_F=y
CONFIG_I2C_RCAR=y
CONFIG_I2C_CROS_EC_TUNNEL=y
CONFIG_SPI=y
CONFIG_SPI_ARMADA_3700=y
CONFIG_SPI_BCM2835=m
CONFIG_SPI_BCM2835AUX=m
CONFIG_SPI_NXP_FLEXSPI=y
CONFIG_SPI_MESON_SPICC=m
CONFIG_SPI_MESON_SPIFC=m
CONFIG_SPI_ORION=y
CONFIG_SPI_PL022=y
CONFIG_SPI_ROCKCHIP=y
CONFIG_SPI_QUP=y
CONFIG_SPI_S3C64XX=y
CONFIG_SPI_SPIDEV=m
CONFIG_SPI_SUN6I=y
CONFIG_SPMI=y
CONFIG_PINCTRL_SINGLE=y
CONFIG_PINCTRL_MAX77620=y
CONFIG_PINCTRL_IMX8MQ=y
CONFIG_PINCTRL_IMX8QXP=y
CONFIG_PINCTRL_IPQ8074=y
CONFIG_PINCTRL_MSM8916=y
CONFIG_PINCTRL_MSM8994=y
CONFIG_PINCTRL_MSM8996=y
CONFIG_PINCTRL_MSM8998=y
CONFIG_PINCTRL_QCS404=y
CONFIG_PINCTRL_QDF2XXX=y
CONFIG_PINCTRL_QCOM_SPMI_PMIC=y
CONFIG_PINCTRL_SDM845=y
CONFIG_GPIO_DWAPB=y
CONFIG_GPIO_MB86S7X=y
CONFIG_GPIO_PL061=y
CONFIG_GPIO_RCAR=y
CONFIG_GPIO_UNIPHIER=y
CONFIG_GPIO_XGENE=y
CONFIG_GPIO_XGENE_SB=y
CONFIG_GPIO_PCA953X=y
CONFIG_GPIO_PCA953X_IRQ=y
CONFIG_GPIO_MAX77620=y
CONFIG_POWER_AVS=y
CONFIG_ROCKCHIP_IODOMAIN=y
CONFIG_POWER_RESET_MSM=y
CONFIG_POWER_RESET_XGENE=y
CONFIG_POWER_RESET_SYSCON=y
CONFIG_SYSCON_REBOOT_MODE=y
CONFIG_BATTERY_SBS=m
CONFIG_BATTERY_BQ27XXX=y
CONFIG_SENSORS_ARM_SCPI=y
CONFIG_SENSORS_LM90=m
CONFIG_SENSORS_PWM_FAN=m
CONFIG_SENSORS_RASPBERRYPI_HWMON=m
CONFIG_SENSORS_INA2XX=m
CONFIG_THERMAL_GOV_POWER_ALLOCATOR=y
CONFIG_CPU_THERMAL=y
CONFIG_THERMAL_EMULATION=y
CONFIG_ROCKCHIP_THERMAL=m
CONFIG_RCAR_THERMAL=y
CONFIG_RCAR_GEN3_THERMAL=y
CONFIG_ARMADA_THERMAL=y
CONFIG_BCM2835_THERMAL=m
CONFIG_BRCMSTB_THERMAL=m
CONFIG_EXYNOS_THERMAL=y
CONFIG_TEGRA_BPMP_THERMAL=m
CONFIG_QCOM_TSENS=y
CONFIG_UNIPHIER_THERMAL=y
CONFIG_WATCHDOG=y
CONFIG_ARM_SP805_WATCHDOG=y
CONFIG_S3C2410_WATCHDOG=y
CONFIG_IMX2_WDT=y
CONFIG_MESON_GXBB_WATCHDOG=m
CONFIG_MESON_WATCHDOG=m
CONFIG_RENESAS_WDT=y
CONFIG_UNIPHIER_WATCHDOG=y
CONFIG_BCM2835_WDT=y
CONFIG_MFD_ALTERA_SYSMGR=y
CONFIG_MFD_BD9571MWV=y
CONFIG_MFD_AXP20X_I2C=y
CONFIG_MFD_AXP20X_RSB=y
CONFIG_MFD_CROS_EC=y
CONFIG_MFD_CROS_EC_CHARDEV=m
CONFIG_MFD_EXYNOS_LPASS=m
CONFIG_MFD_HI6421_PMIC=y
CONFIG_MFD_HI655X_PMIC=y
CONFIG_MFD_MAX77620=y
CONFIG_MFD_SPMI_PMIC=y
CONFIG_MFD_RK808=y
CONFIG_MFD_SEC_CORE=y
CONFIG_REGULATOR_FIXED_VOLTAGE=y
CONFIG_REGULATOR_AXP20X=y
CONFIG_REGULATOR_BD9571MWV=y
CONFIG_REGULATOR_FAN53555=y
CONFIG_REGULATOR_GPIO=y
CONFIG_REGULATOR_HI6421V530=y
CONFIG_REGULATOR_HI655X=y
CONFIG_REGULATOR_MAX77620=y
CONFIG_REGULATOR_MAX8973=y
CONFIG_REGULATOR_PFUZE100=y
CONFIG_REGULATOR_PWM=y
CONFIG_REGULATOR_QCOM_RPMH=y
CONFIG_REGULATOR_QCOM_SMD_RPM=y
CONFIG_REGULATOR_QCOM_SPMI=y
CONFIG_REGULATOR_RK808=y
CONFIG_REGULATOR_S2MPS11=y
CONFIG_REGULATOR_VCTRL=m
CONFIG_RC_CORE=m
CONFIG_RC_DECODERS=y
CONFIG_RC_DEVICES=y
CONFIG_IR_MESON=m
CONFIG_MEDIA_SUPPORT=m
CONFIG_MEDIA_CAMERA_SUPPORT=y
CONFIG_MEDIA_ANALOG_TV_SUPPORT=y
CONFIG_MEDIA_DIGITAL_TV_SUPPORT=y
CONFIG_MEDIA_CONTROLLER=y
CONFIG_VIDEO_V4L2_SUBDEV_API=y
# CONFIG_DVB_NET is not set
CONFIG_MEDIA_USB_SUPPORT=y
CONFIG_USB_VIDEO_CLASS=m
CONFIG_V4L_PLATFORM_DRIVERS=y
CONFIG_VIDEO_SUN6I_CSI=m
CONFIG_V4L_MEM2MEM_DRIVERS=y
CONFIG_VIDEO_SAMSUNG_S5P_JPEG=m
CONFIG_VIDEO_SAMSUNG_S5P_MFC=m
CONFIG_VIDEO_SAMSUNG_EXYNOS_GSC=m
CONFIG_VIDEO_RENESAS_FCP=m
CONFIG_VIDEO_RENESAS_VSP1=m
CONFIG_DRM=m
CONFIG_DRM_NOUVEAU=m
CONFIG_DRM_EXYNOS=m
CONFIG_DRM_EXYNOS5433_DECON=y
CONFIG_DRM_EXYNOS7_DECON=y
CONFIG_DRM_EXYNOS_DSI=y
# CONFIG_DRM_EXYNOS_DP is not set
CONFIG_DRM_EXYNOS_HDMI=y
CONFIG_DRM_EXYNOS_MIC=y
CONFIG_DRM_ROCKCHIP=m
CONFIG_ROCKCHIP_ANALOGIX_DP=y
CONFIG_ROCKCHIP_CDN_DP=y
CONFIG_ROCKCHIP_DW_HDMI=y
CONFIG_ROCKCHIP_DW_MIPI_DSI=y
CONFIG_ROCKCHIP_INNO_HDMI=y
CONFIG_DRM_RCAR_DU=m
CONFIG_DRM_SUN4I=m
CONFIG_DRM_SUN8I_DW_HDMI=m
CONFIG_DRM_SUN8I_MIXER=m
CONFIG_DRM_TEGRA=m
CONFIG_DRM_PANEL_SIMPLE=m
CONFIG_DRM_SII902X=m
CONFIG_DRM_I2C_ADV7511=m
CONFIG_DRM_VC4=m
CONFIG_DRM_HISI_HIBMC=m
CONFIG_DRM_HISI_KIRIN=m
CONFIG_DRM_MESON=m
CONFIG_DRM_PL111=m
CONFIG_FB=y
CONFIG_FB_MODE_HELPERS=y
CONFIG_BACKLIGHT_GENERIC=m
CONFIG_BACKLIGHT_PWM=m
CONFIG_BACKLIGHT_LP855X=m
CONFIG_LOGO=y
# CONFIG_LOGO_LINUX_MONO is not set
# CONFIG_LOGO_LINUX_VGA16 is not set
CONFIG_SOUND=y
CONFIG_SND=y
CONFIG_SND_HDA_TEGRA=m
CONFIG_SND_HDA_CODEC_HDMI=m
CONFIG_SND_SOC=y
CONFIG_SND_BCM2835_SOC_I2S=m
CONFIG_SND_MESON_AXG_SOUND_CARD=m
CONFIG_SND_SOC_ROCKCHIP=m
CONFIG_SND_SOC_ROCKCHIP_SPDIF=m
CONFIG_SND_SOC_ROCKCHIP_RT5645=m
CONFIG_SND_SOC_RK3399_GRU_SOUND=m
CONFIG_SND_SOC_SAMSUNG=y
CONFIG_SND_SOC_RCAR=m
CONFIG_SND_SOC_AK4613=m
CONFIG_SND_SOC_ES7134=m
CONFIG_SND_SOC_ES7241=m
CONFIG_SND_SOC_PCM3168A_I2C=m
CONFIG_SND_SOC_TAS571X=m
CONFIG_SND_SIMPLE_CARD=m
CONFIG_SND_AUDIO_GRAPH_CARD=m
CONFIG_I2C_HID=m
CONFIG_USB=y
CONFIG_USB_OTG=y
CONFIG_USB_XHCI_HCD=y
CONFIG_USB_XHCI_TEGRA=y
CONFIG_USB_EHCI_HCD=y
CONFIG_USB_EHCI_EXYNOS=y
CONFIG_USB_EHCI_HCD_PLATFORM=y
CONFIG_USB_OHCI_HCD=y
CONFIG_USB_OHCI_EXYNOS=y
CONFIG_USB_OHCI_HCD_PLATFORM=y
CONFIG_USB_RENESAS_USBHS=m
CONFIG_USB_STORAGE=y
CONFIG_USB_MUSB_HDRC=y
CONFIG_USB_MUSB_SUNXI=y
CONFIG_USB_DWC3=y
CONFIG_USB_DWC2=y
CONFIG_USB_CHIPIDEA=y
CONFIG_USB_CHIPIDEA_UDC=y
CONFIG_USB_CHIPIDEA_HOST=y
CONFIG_USB_ISP1760=y
CONFIG_USB_HSIC_USB3503=y
CONFIG_NOP_USB_XCEIV=y
CONFIG_USB_ULPI=y
CONFIG_USB_GADGET=y
CONFIG_USB_RENESAS_USBHS_UDC=m
CONFIG_USB_RENESAS_USB3=m
CONFIG_MMC=y
CONFIG_MMC_BLOCK_MINORS=32
CONFIG_MMC_ARMMMCI=y
CONFIG_MMC_SDHCI=y
CONFIG_MMC_SDHCI_ACPI=y
CONFIG_MMC_SDHCI_PLTFM=y
CONFIG_MMC_SDHCI_OF_ARASAN=y
CONFIG_MMC_SDHCI_OF_ESDHC=y
CONFIG_MMC_SDHCI_CADENCE=y
CONFIG_MMC_SDHCI_ESDHC_IMX=y
CONFIG_MMC_SDHCI_TEGRA=y
CONFIG_MMC_SDHCI_F_SDH30=y
CONFIG_MMC_MESON_GX=y
CONFIG_MMC_SDHCI_MSM=y
CONFIG_MMC_SPI=y
CONFIG_MMC_SDHI=y
CONFIG_MMC_UNIPHIER=y
CONFIG_MMC_DW=y
CONFIG_MMC_DW_EXYNOS=y
CONFIG_MMC_DW_HI3798CV200=y
CONFIG_MMC_DW_K3=y
CONFIG_MMC_DW_ROCKCHIP=y
CONFIG_MMC_SUNXI=y
CONFIG_MMC_BCM2835=y
CONFIG_MMC_SDHCI_XENON=y
CONFIG_NEW_LEDS=y
CONFIG_LEDS_CLASS=y
CONFIG_LEDS_GPIO=y
CONFIG_LEDS_PWM=y
CONFIG_LEDS_SYSCON=y
CONFIG_LEDS_TRIGGER_DISK=y
CONFIG_LEDS_TRIGGER_HEARTBEAT=y
CONFIG_LEDS_TRIGGER_CPU=y
CONFIG_LEDS_TRIGGER_DEFAULT_ON=y
CONFIG_LEDS_TRIGGER_PANIC=y
CONFIG_EDAC=y
CONFIG_EDAC_GHES=y
CONFIG_RTC_CLASS=y
CONFIG_RTC_DRV_MAX77686=y
CONFIG_RTC_DRV_RK808=m
CONFIG_RTC_DRV_RX8581=m
CONFIG_RTC_DRV_S5M=y
CONFIG_RTC_DRV_DS3232=y
CONFIG_RTC_DRV_EFI=y
CONFIG_RTC_DRV_CROS_EC=y
CONFIG_RTC_DRV_S3C=y
CONFIG_RTC_DRV_PL031=y
CONFIG_RTC_DRV_SUN6I=y
CONFIG_RTC_DRV_ARMADA38X=y
CONFIG_RTC_DRV_TEGRA=y
CONFIG_RTC_DRV_IMX_SC=m
CONFIG_RTC_DRV_XGENE=y
CONFIG_DMADEVICES=y
CONFIG_FSL_EDMA=y
CONFIG_DMA_BCM2835=m
CONFIG_K3_DMA=y
CONFIG_MV_XOR=y
CONFIG_MV_XOR_V2=y
CONFIG_PL330_DMA=y
CONFIG_TEGRA20_APB_DMA=y
CONFIG_QCOM_BAM_DMA=y
CONFIG_QCOM_HIDMA_MGMT=y
CONFIG_QCOM_HIDMA=y
CONFIG_RCAR_DMAC=y
CONFIG_RENESAS_USB_DMAC=m
CONFIG_VFIO=y
CONFIG_VFIO_PCI=y
CONFIG_VIRTIO_PCI=y
CONFIG_VIRTIO_BALLOON=y
CONFIG_VIRTIO_MMIO=y
CONFIG_XEN_GNTDEV=y
CONFIG_XEN_GRANT_DEV_ALLOC=y
CONFIG_CROS_EC_I2C=y
CONFIG_CROS_EC_SPI=y
CONFIG_COMMON_CLK_RK808=y
CONFIG_COMMON_CLK_SCPI=y
CONFIG_COMMON_CLK_CS2000_CP=y
CONFIG_COMMON_CLK_S2MPS11=y
CONFIG_CLK_QORIQ=y
CONFIG_COMMON_CLK_PWM=y
CONFIG_CLK_IMX8MQ=y
CONFIG_CLK_IMX8QXP=y
CONFIG_TI_SCI_CLK=y
CONFIG_COMMON_CLK_QCOM=y
CONFIG_QCOM_CLK_SMD_RPM=y
CONFIG_QCOM_CLK_RPMH=y
CONFIG_IPQ_GCC_8074=y
CONFIG_MSM_GCC_8916=y
CONFIG_MSM_GCC_8994=y
CONFIG_MSM_MMCC_8996=y
CONFIG_MSM_GCC_8998=y
CONFIG_QCS_GCC_404=y
CONFIG_SDM_GCC_845=y
CONFIG_HWSPINLOCK=y
CONFIG_HWSPINLOCK_QCOM=y
CONFIG_ARM_MHU=y
CONFIG_IMX_MBOX=y
CONFIG_PLATFORM_MHU=y
CONFIG_BCM2835_MBOX=y
CONFIG_TI_MESSAGE_MANAGER=y
CONFIG_QCOM_APCS_IPC=y
CONFIG_ROCKCHIP_IOMMU=y
CONFIG_TEGRA_IOMMU_SMMU=y
CONFIG_ARM_SMMU=y
CONFIG_ARM_SMMU_V3=y
CONFIG_QCOM_IOMMU=y
CONFIG_REMOTEPROC=m
CONFIG_QCOM_Q6V5_MSS=m
CONFIG_QCOM_Q6V5_PAS=m
CONFIG_QCOM_SYSMON=m
CONFIG_RPMSG_QCOM_GLINK_RPM=y
CONFIG_RPMSG_QCOM_GLINK_SMEM=m
CONFIG_RPMSG_QCOM_SMD=y
CONFIG_RASPBERRYPI_POWER=y
CONFIG_QCOM_COMMAND_DB=y
CONFIG_QCOM_GENI_SE=y
CONFIG_QCOM_GLINK_SSR=m
CONFIG_QCOM_RPMH=y
CONFIG_QCOM_SMEM=y
CONFIG_QCOM_SMD_RPM=y
CONFIG_QCOM_SMP2P=y
CONFIG_QCOM_SMSM=y
CONFIG_ARCH_R8A774A1=y
CONFIG_ARCH_R8A774C0=y
CONFIG_ARCH_R8A7795=y
CONFIG_ARCH_R8A7796=y
CONFIG_ARCH_R8A77965=y
CONFIG_ARCH_R8A77970=y
CONFIG_ARCH_R8A77980=y
CONFIG_ARCH_R8A77990=y
CONFIG_ARCH_R8A77995=y
CONFIG_ROCKCHIP_PM_DOMAINS=y
CONFIG_ARCH_TEGRA_132_SOC=y
CONFIG_ARCH_TEGRA_210_SOC=y
CONFIG_ARCH_TEGRA_186_SOC=y
CONFIG_ARCH_TEGRA_194_SOC=y
CONFIG_ARCH_K3_AM6_SOC=y
CONFIG_SOC_TI=y
CONFIG_TI_SCI_PM_DOMAINS=y
CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND=y
CONFIG_EXTCON_USB_GPIO=y
CONFIG_EXTCON_USBC_CROS_EC=y
CONFIG_MEMORY=y
CONFIG_IIO=y
CONFIG_EXYNOS_ADC=y
CONFIG_ROCKCHIP_SARADC=m
CONFIG_IIO_CROS_EC_SENSORS_CORE=m
CONFIG_IIO_CROS_EC_SENSORS=m
CONFIG_IIO_CROS_EC_LIGHT_PROX=m
CONFIG_IIO_CROS_EC_BARO=m
CONFIG_PWM=y
CONFIG_PWM_BCM2835=m
CONFIG_PWM_CROS_EC=m
CONFIG_PWM_MESON=m
CONFIG_PWM_RCAR=m
CONFIG_PWM_ROCKCHIP=y
CONFIG_PWM_SAMSUNG=y
CONFIG_PWM_SUN4I=m
CONFIG_PWM_TEGRA=m
CONFIG_RESET_TI_SCI=y
CONFIG_PHY_XGENE=y
CONFIG_PHY_SUN4I_USB=y
CONFIG_PHY_HI6220_USB=y
CONFIG_PHY_HISTB_COMBPHY=y
CONFIG_PHY_HISI_INNO_USB2=y
CONFIG_PHY_MVEBU_CP110_COMPHY=y
CONFIG_PHY_QCOM_QMP=m
CONFIG_PHY_QCOM_USB_HS=y
CONFIG_PHY_RCAR_GEN3_PCIE=y
CONFIG_PHY_RCAR_GEN3_USB2=y
CONFIG_PHY_RCAR_GEN3_USB3=m
CONFIG_PHY_ROCKCHIP_EMMC=y
CONFIG_PHY_ROCKCHIP_INNO_HDMI=m
CONFIG_PHY_ROCKCHIP_INNO_USB2=y
CONFIG_PHY_ROCKCHIP_PCIE=m
CONFIG_PHY_ROCKCHIP_TYPEC=y
CONFIG_PHY_UNIPHIER_USB2=y
CONFIG_PHY_UNIPHIER_USB3=y
CONFIG_PHY_TEGRA_XUSB=y
CONFIG_HISI_PMU=y
CONFIG_QCOM_L2_PMU=y
CONFIG_QCOM_L3_PMU=y
CONFIG_QCOM_QFPROM=y
CONFIG_ROCKCHIP_EFUSE=y
CONFIG_UNIPHIER_EFUSE=y
CONFIG_MESON_EFUSE=m
CONFIG_FPGA=y
CONFIG_FPGA_MGR_STRATIX10_SOC=m
CONFIG_FPGA_BRIDGE=m
CONFIG_ALTERA_FREEZE_BRIDGE=m
CONFIG_FPGA_REGION=m
CONFIG_OF_FPGA_REGION=m
CONFIG_TEE=y
CONFIG_OPTEE=y
CONFIG_EXT2_FS=y
CONFIG_EXT3_FS=y
CONFIG_EXT4_FS_POSIX_ACL=y
CONFIG_BTRFS_FS=m
CONFIG_BTRFS_FS_POSIX_ACL=y
CONFIG_FANOTIFY=y
CONFIG_FANOTIFY_ACCESS_PERMISSIONS=y
CONFIG_QUOTA=y
CONFIG_AUTOFS4_FS=y
CONFIG_FUSE_FS=m
CONFIG_CUSE=m
CONFIG_OVERLAY_FS=m
CONFIG_VFAT_FS=y
CONFIG_HUGETLBFS=y
CONFIG_CONFIGFS_FS=y
CONFIG_EFIVAR_FS=y
CONFIG_SQUASHFS=y
CONFIG_NFS_FS=y
CONFIG_NFS_V4=y
CONFIG_NFS_V4_1=y
CONFIG_NFS_V4_2=y
CONFIG_ROOT_NFS=y
CONFIG_9P_FS=y
CONFIG_NLS_CODEPAGE_437=y
CONFIG_NLS_ISO8859_1=y
CONFIG_SECURITY=y
CONFIG_CRYPTO_ECHAINIV=y
CONFIG_CRYPTO_ANSI_CPRNG=y
CONFIG_DMA_CMA=y
CONFIG_CMA_SIZE_MBYTES=32
CONFIG_PRINTK_TIME=y
CONFIG_DEBUG_INFO=y
CONFIG_DEBUG_FS=y
CONFIG_MAGIC_SYSRQ=y
CONFIG_DEBUG_KERNEL=y
# CONFIG_SCHED_DEBUG is not set
# CONFIG_DEBUG_PREEMPT is not set
# CONFIG_FTRACE is not set
CONFIG_MEMTEST=y

在linux内核根目录下执行如下命令,执行完之后会在内核根目录下生成默认配置文件.config:

root@zhengyang:/work/sambashare/rk3399/linux-5.2.8#  make defconfig
  HOSTCC  scripts/basic/fixdep
  HOSTCC  scripts/kconfig/conf.o
  HOSTCC  scripts/kconfig/confdata.o
  HOSTCC  scripts/kconfig/expr.o
  LEX     scripts/kconfig/lexer.lex.c
  YACC    scripts/kconfig/parser.tab.h
  HOSTCC  scripts/kconfig/lexer.lex.o
  YACC    scripts/kconfig/parser.tab.c
  HOSTCC  scripts/kconfig/parser.tab.o
  HOSTCC  scripts/kconfig/preprocess.o
  HOSTCC  scripts/kconfig/symbol.o
  HOSTLD  scripts/kconfig/conf
*** Default configuration is based on 'defconfig'
#
# configuration written to .config
#

1.4 内核裁切

我们可以通过make menuconfig配置内核支持的功能:

root@zhengyang:/work/sambashare/rk3399/linux-5.2.8# make menuconfig

打开如下页面:

1.4.1 支持设备树

实际上在linux 5.2.8版本内核已经把设备树作为默认配置项了,因此也不需要我们配置了。

内核在启动时,会执行setup_arch函数,该函数用于在内核启动期间对硬件进行初始化,包括设置CPU、内存、设备树等等。该函数的实现是针对特定架构的,因此不同的架构会有不同的setup_arch实现。以ARM(非ARM64)为例:

setup_arch(&command_line);  // arch/arm/kernel/setup.c
    mdesc = setup_machine_fdt(__atags_pointer);  // arch/arm/kernel/devtree.c
        // 检验设备树头部,判断设备树有效性
        early_init_dt_verify(phys_to_virt(dt_phys)  //  drivers/of/fdt.c
                  initial_boot_params = params;
            // 找到最匹配的machine_desc
            mdesc = of_flat_dt_match_machine(mdesc_best, arch_get_next_mach);  // drivers/of/fdt.c
            early_init_dt_scan_nodes()  // drivers/of/fdt.c
                // 从dtb文件中读取chosen节点的信息,包括命令行boot_command_line,initrd location及size
                of_scan_flat_dt(early_init_dt_scan_chosen, boot_command_line)
                // 得到根节点的 #address-cells 和 #size-cells属性信息
                of_scan_flat_dt(early_init_dt_scan_root, NULL)
                // 得到/memory节点的reg属性
                of_scan_flat_dt(early_init_dt_scan_memory, NULL)
        machine_desc = mdesc;
    ......
       

of_flat_dt_match_machine函数通过遍历所有的machine_desc,找到与设备树中compatible最匹配的一个machine_desc(每一个开发板都对应一个machine_desc,通过它定义开发板相关的一些属性及函数,比如机器类型ID、中断初始化函数、I/O映射函数、machine初始化函数等;这些函数会在内核启动阶段被回调,在较早的版本中,init_machine会包含大量的平台设备注册的代码)。

然而在ARM64中,其实现发生了改变:

setup_arch(&command_line);  // arch/arm64/kernel/setup.c
    // 参数为dtb在内存的首地址
    setup_machine_fdt(__fdt_pointer)   // arch/arm64/kernel/setup.c
        // 为fdt建立地址映射,在该函数的最后,顺便就调用memblock_reserve保留了该段内存
        void *dt_virt = fixmap_remap_fdt(dt_phys) 
        // 校验并解析dtb文件
        early_init_dt_scan(dt_virt)   // drivers/of/fdt.c  
            // 检验设备树头部,判断设备树有效性
            early_init_dt_verify() 
            early_init_dt_scan_nodes()  // drivers/of/fdt.c
                // 从dtb文件中读取chosen节点的信息,包括命令行boot_command_line,initrd location及size
                of_scan_flat_dt(early_init_dt_scan_chosen, boot_command_line)
                // 得到根节点的 #address-cells 和 #size-cells属性信息
                of_scan_flat_dt(early_init_dt_scan_root, NULL)
                // 得到/memory节点的reg属性
                of_scan_flat_dt(early_init_dt_scan_memory, NULL)
        // 获取machine名称
        name = of_flat_dt_get_machine_name();  // drivers/of/fdt.c
            // 获取设备树的根节点
            unsigned long dt_root = of_get_flat_dt_root() 
            // 这里直接获取设备树的model属性
            name = of_get_flat_dt_prop(dt_root, "model", NULL)   
    parse_early_param();
    ......
    arm64_memblock_init()
    ......
    // 解析dtb文件,转换成节点是device_node的树状结构, 其中设备节点会被转换为device_node结构
    unflatten_device_tree()  
    ......

可以看到这里没有了设备树和machine_desc的匹配过程了,也就是说ARM64已经完全抛弃了machine_desc,全部采用设备树的实现方式,关于《为什么要采用设备树》我在设备树章节已经具体介绍过。

1.4.2 支持NFS文件系统

使用NFS作为根文件系统,因为文件系统在宿主机中,这样在修改文件系统就非常方便,主要用于开发阶段使用。

File systems --->
    [*] Network File Systems --->
          <*> NFS client support
    	      <*> NFS client support for NFS version 2
    	      <*> NFS client support for NFS version 3
              <*> NFS client support for NFS version 4
          [*]   Root file system on NFS

勾选NFS client support for NFS version 4

1.4.3 配置uevent helper

配置Support for uevent helper

Device Drivers --->
     Generic Driver Options --->
            [*] Support for uevent helper 
            (/sbin/mdev)    path to uevent helper (NEW) 

该选项的作用是启用uevent helper程序的支持。uevent是内核与用户空间之间通信的一种方式,当内核检测到新的设备时,会生成一个uevent来通知用户空间,使得用户空间能够及时响应设备插拔事件,并做出相应的处理。其中, uevent helper程序就是在接收到uevent后执行的用户空间程序,用来完成设备的热插拔处理。

在内核中,CONFIG_UEVENT_HELPER=y的设定可以确保uevent helper程序能够被编译到内核中,从而能够正常地接收并响应uevent事件。

path to uevent helper配置为/sbin/mdev;即指定uevent helper程序为/sbin/mdev

具体参考:《dev下无法生成节点的分析思路和解决方法及原理》。

1.4.4 支持RAM块设备

如果我们需要使用ramdisk根文件系统,就需要配置RAM块设备驱动,否者不用配置这个。

ram disk顾名思义,内存磁盘。我们平常接触的一些存储介质,如:Nor FlashNand FlasheMMC、ufs、以及机械硬盘固态硬盘等,都是用来存储数据的,同理内存也是可以当成磁盘来存储数据的,唯一不同的就是ram是掉电不保存的,而前面提到的那些存储介质掉电都是保存数据的。

我们都知道,在linux中,上面介绍的Flash这些存储介质,都是需要有对应的驱动,注册成块设备。并向上层提供接口。如NorNand等都抽象成mtdblock块设备。

同理,linux中的ram disk意思就是拿出ram中的一部分大小,用对应的驱动注册层块设备,提供给上层调用。一般的ram disk注册成的块设备,在文件系统中设备节点体现为/dev/ramx

我们需要配置内核支持ramdisk

General setup  ---> 
    [*] Initial RAM filesystem and RAM disk (initramfs/initrd) support

这里的意思是配置内核初始化时,去寻找initramfsinitrdinitrd就是我们的ramdisk文件系统,至于initramfs,是一个可以编译进内核的根文件映像。

Device Drivers  ---> 
     [*] Block devices  --->
          <*>   RAM block device support
          (1)     Default number of RAM disks
        (327680) Default RAM disk size (kbytes)    

勾选第一项RAM block device support,才会出来第二项和第三项的选项;

  • 第一项的意思是内核支持ram disk块设备驱动;
  • 第二项是注册的块设备数量,内核默认是16,我这里就写了1,内核启动后会有/dev/ram0块设备节点,配置16则会有/dev/ram0~ram15
  • 第三项的意思是ram disk占得最大内存,这里我写的是32M,一般来说可以写的再小点。实际在使用/dev/ramx设备时,并不是一下子就占系统32M内存,而是根据实际使用情况而分配的;
1.4.5 支持ext4文件系统

由于后面我们会制作ext4类型的根文件系统,因此需要勾选对ext4文件系统格式的支持,内核默认已经勾选了。

File systems --->
     -*- The Extended 4 (ext4) filesystem     
     [*]  Ext4 POSIX Access Control Lists
     [  ]  Ext4 Security Labels                                                                         
     [  ]  Ext4 debugging support   
1.4.6 配置DRM驱动

DRM,全称Direct Rending Manger。是目前Linux主流的图形显示框架。配置这个的目的是为了在移植了带有桌面的ubuntu根文件系统后,通过显示器来显示ubuntu桌面;

Device Drivers  ---> 
    Graphics support  --->     
        [*] Direct Rendering Manager (XFree86 4.1.0 and higher DRI support)  ---> 
        [*] DRM Support for Rockchip
1.4.7 配置有线网卡驱动

RK3399内置了以太网控制器,所以只要搭配一颗以太网PHY芯片就可以实现以太网功能。这里我使用的NanoPC-T4开发板搭载的以太网PHY芯片型号为RTL8211E-VB-CG,是Realtek瑞昱推出的一款高集成的网络接收PHY芯片,它符合10Base-T100Base-TX1000Base-T IEEE802.3标准,该芯片在网络通信中属于物理层,用于MACPHY之间的数据通信。

10/100M以太网PHYMAC之间的接口主要有MIIRMII,而10/100/1000M以太网PHYMAC之间的接口主要有RGMII。而RK3399RMIIRGMII接口均支持,也就是说RK3399支持100M网卡、1000M网卡。

因此我们需要配置:

Device Drivers  ---> 
  [*] Network device support  --->
     [*] Ethernet driver support  --->    
        [*] STMicroelectronics 10/100/1000/EQOS Ethernet driver     
            [*] STMMAC Platform bus support
                [*] Rockchip dwmac support

需要注意RTL8211和我们之前接触的DM9000有很大的差异:

  • 功能不同:RTL8211E是一款物理层网络接口芯片,主要负责物理层的处理和传输;而DM9000是一款以太网控制器芯片,主要负责数据链路层的处理和管理;
  • 高度不同:RTL8211E是一个高度集成化的单芯片方案,可直接与处理器连接,不需要外部存储器;DM9000则需要和存储器结合使用,并且需要外部时钟电路的支持;
  • 传输速率不同:RTL8211E支持千兆以太网(1000Mbps)和百兆以太网(100Mbps)的数据传输,而DM9000只支持百兆以太网(100Mbps);
  • 接口不同:RTL8211E采用RGMII接口标准,而DM9000采用MII接口标准;
  • 芯片封装不同:RTL8211E常见的封装形式是QFN,很容易焊接到PCB上;而DM9000常见的封装形式是QFP,需要进行插件式安装;
1.4.8 配置无线网卡驱动

我使用的NanoPC-T4开发板搭载的WiFi模组为AP6356,符合IEEE802.11a/b/g/n/ac 2x2 MIMO标准,并可在802.11n中通过双流达到867Mbps的速度以连接无线局域网。该集成模块提供SDIO/PCIe接口用于WiFiUART/PCM接口用于蓝牙。

由于linux 5.2.8版本并没有直接支持AP6356,因此需要对源码和设备树进行大量调整,就不在这里介绍了。如果需要支持无线网卡的话具体参考:《Rockchip RK3399 - WiFi AP6356驱动》。

屏蔽内核启动开机logo

Device Drivers  --->
    Graphics support  --->
        [] Bootup logo --->
1.4.10 保存配置

保存配置:

存档:

root@zhengyang:/work/sambashare/rk3399/linux-5.2.8# mv rk3399_defconfig ./arch/arm64/configs/

重新配置内核:

root@zhengyang:/work/sambashare/rk3399/linux-5.2.8# make rk3399_defconfig

1.5 修改设备树

1.5.1 配置display-subsystem设备节点

执行如下命令:

root@zhengyang:/work/sambashare/rk3399/linux-5.2.8# vim arch/arm64/boot/dts/rockchip/rk3399.dtsi

将以下节点:

display-subsystem {
        compatible = "rockchip,display-subsystem";
        ports = <&vopl_out>, <&vopb_out>;
};

修改为:

display_subsystem: display-subsystem {
        compatible = "rockchip,display-subsystem";
        ports = <&vopl_out>, <&vopb_out>;
};
1.5.2 配置gmac设备节点

arch/arm64/boot/dts/rockchip/rk3399-evb.dts中为以下节点新增属性:

&gmac {
	assigned-clock-parents = <&clkin_gmac>;
	assigned-clocks = <&cru SCLK_RMII_SRC>;
	clock_in_out = "input";
	pinctrl-names = "default";
	pinctrl-0 = <&rgmii_pins>, <&phy_intb>, <&phy_rstb>;
	phy-handle = <&rtl8211e>;
	phy-mode = "rgmii";
	phy-supply = <&vcc3v3_s3>;
	tx_delay = <0x28>;
	rx_delay = <0x11>;
	status = "okay";

	mdio {
		compatible = "snps,dwmac-mdio";
		#address-cells = <1>;
		#size-cells = <0>;

		rtl8211e: ethernet-phy@1 {
			reg = <1>;
			interrupt-parent = <&gpio3>;
			interrupts = <RK_PB2 IRQ_TYPE_LEVEL_LOW>;
			reset-assert-us = <10000>;
			reset-deassert-us = <30000>;
			reset-gpios = <&gpio3 RK_PB7 GPIO_ACTIVE_LOW>;
		};
	};
};

同时配置引脚配置节点:

&pinctrl {
	......

	gmac {
		phy_intb: phy-intb {
			rockchip,pins = <3 RK_PB2 RK_FUNC_GPIO &pcfg_pull_up>;
		};

		phy_rstb: phy-rstb {
			rockchip,pins = <3 RK_PB7 RK_FUNC_GPIO &pcfg_pull_none>;
		};
	};
	.....
}
1.5.2 新增子节点属性

同时在arch/arm64/boot/dts/rockchip/rk3399-evb.dts中为以下节点新增属性:

&i2c7 {
        status = "okay";
};

&display_subsystem {
         status = "okay";
};

&vopl {
        status = "okay";
};

&vopl_mmu {
        status = "okay";
};
     
&vopb {
        status = "okay";
};

&vopb_mmu {
        status = "okay";
};

&hdmi {
        ddc-i2c-bus = <&i2c7>;
        pinctrl-names = "default";
        pinctrl-0 = <&hdmi_cec>;
        status = "okay";
};

1.6 编译内核

1.6.1 编译内核

linux内核根目录下执行如下命令:

root@zhengyang:/work/sambashare/rk3399/linux-5.2.8# make -j8
  HOSTCC  scripts/extract-cert
scripts/extract-cert.c:21:10: fatal error: openssl/bio.h: 没有那个文件或目录
   21 | #include <openssl/bio.h>
      |          ^~~~~~~~~~~~~~~
compilation terminated.
make[1]: *** [scripts/Makefile.host:95:scripts/extract-cert] 错误 1
make: *** [Makefile:1204:scripts] 错误 2
make: *** 正在等待未完成的任务....

如果出现如上错误,安装libssl-dev即可:

root@zhengyang:/work/sambashare/rk3399/linux-5.2.8# sudo apt install libssl-dev

这个编译属实有点久,如果可以的话,尽量裁切掉一些没用的驱动。

编译完成后会在linux根目录下生成vmlinux文件,elf格式:这个文件属实有点大214M,真是惊呆了;

root@zhengyang:/work/sambashare/rk3399/linux-5.2.8# ll vmlinux
-rwxr-xr-x 1 root root 223823704 May 23 21:00 vmlinux*
root@zhengyang:/work/sambashare/rk3399/linux-5.2.8# du -sh vmlinux
214M    vmlinux

此外,在arch/arm64/boot/文件夹下生成Image镜像文件,以及设备树dst/rockchip/xxx.dtb文件;

root@zhengyang:/work/sambashare/rk3399/linux-5.2.8# ll arch/arm64/boot
总用量 44032
drwxr-xr-x  3 root root     4096 May 16 11:28 ./
drwxr-xr-x 14 root root     4096 May 16 11:15 ../
drwxr-xr-x 33 root root     4096 May 16 10:27 dts/
-rw-r--r--  1 root root       55 May 16 10:27 .gitignore
-rw-r--r--  1 root root 33616384 May 16 11:27 Image
-rw-r--r--  1 root root      134 May 16 11:27 .Image.cmd
-rw-r--r--  1 root root 11617499 May 16 11:28 Image.gz
-rw-r--r--  1 root root      101 May 16 11:28 .Image.gz.cmd
-rw-r--r--  1 root root     1562 May 16 10:27 install.sh
-rw-r--r--  1 root root      960 May 16 10:27 Makefile
root@zhengyang:/work/sambashare/rk3399/linux-5.2.8/arch/arm64# cd arch/arm64/boot
root@zhengyang:/work/sambashare/rk3399/linux-5.2.8/arch/arm64/boot# ls dts/rockchip/*rk3399*.dtb
dts/rockchip/rk3399-evb.dtb              dts/rockchip/rk3399-gru-scarlet-kd.dtb  dts/rockchip/rk3399-rock960.dtb
dts/rockchip/rk3399-ficus.dtb            dts/rockchip/rk3399-nanopc-t4.dtb       dts/rockchip/rk3399-rock-pi-4.dtb
dts/rockchip/rk3399-firefly.dtb          dts/rockchip/rk3399-nanopi-m4.dtb       dts/rockchip/rk3399-rockpro64.dtb
dts/rockchip/rk3399-gru-bob.dtb          dts/rockchip/rk3399-nanopi-neo4.dtb     dts/rockchip/rk3399-roc-pc.dtb
dts/rockchip/rk3399-gru-kevin.dtb        dts/rockchip/rk3399-orangepi.dtb        dts/rockchip/rk3399-sapphire.dtb
dts/rockchip/rk3399-gru-scarlet-inx.dtb  dts/rockchip/rk3399-puma-haikou.dtb     dts/rockchip/rk3399-sapphire-excavator.dtb

除此之外在arch/arm64/boot/路径下也生成了Image.gz文件,需要注意的是该文件和zImage文件并不一样,该文件并没有内嵌gzip解压缩代码,就是单纯的gzip压缩后的文件。

1.6.2 编译dts

如果需要单独编译设备树,在linux内核根目录执行如下命令:

root@zhengyang:/work/sambashare/rk3399/linux-5.2.8# make  arch/arm64/boot/dts/rockchip/rk3399-evb.dts  dtbs V=1

即可把arch/arm64/boot/dts/rockchip里的dts文件编译成dtb文件。

二、内核镜像文件介绍

linux内核常用的镜像文件格式有以下几种:

  • vmlinuxlinux内核编译出来的原始的内核文件,elf格式。该文件包含了符号表、重定位等信息,可以用来调试,但不能直接引导linux系统启动;可以使用arm-linx-readelf -h vmlinux查看文件信息;
  • Imagelinux内核编译时,使用arm-linux-objcopy处理vmlinux后生成的二进制文件。该文件是raw binary二进制文件,bin文件是将elf文件中的代码段,数据段,还有一些自定义的段抽取出来做成的一个内存的镜像,可直接引导linux系统启动;
  • Image.gz:使用gzip压缩Image后得到的压缩文件;
  • zImage:首先将Image.gz文件开头嵌入gzip解压缩代码,然后编译得到elf格式文件arch/arm/boot/compressed/vmlinux,最后使用arm-linux-objcopy命令对其处理生成的linux内核镜像;
  • uImageuImage又分为两种Legacy uImageFIT uImage。以Legacy uImage为例,其在zImage前面增加一个64字节的头,描述镜像文件类型,加载位置,大小等信息,比如我们熟悉的Mini2440使用的就是这种;

下图展示了不同类型的linux镜像生成过程:

2.1 vmlinux

linux根目录下的.vmlinux.cmd文件可以看到vmlinux的生成命令:

root@zhengyang:/work/sambashare/rk3399/linux-5.2.8# cat .vmlinux.cmd
cmd_vmlinux := /bin/bash scripts/link-vmlinux.sh arm-linux-ld  -EL  -maarch64elf --no-undefined -X --fix-cortex-a53-843419  --build-id ;  true

2.2 Image

linux根目录下的arch/arm64/boot/.Image.cmd文件可以看到vmlinux的生成命令:

cmd_arch/arm64/boot/Image := arm-linux-objcopy  -O binary -R .note -R .note.gnu.build-id -R .comment -S vmlinux arch/arm64/boot/Image

这里利用arm-linux-objcopy命令将elf格式的vmlinux文件转换为二进制文件Image。其中 :

  • -O binary:指定输出的文件格式为二进制文件;
  • -R note:从输出文件中删除掉所有名为.note的段;
  • -R .note.gnu.build-id:从输出文件中删除掉所有名为.not.build-id的段;
  • -R .comment:从输出文件中删除掉所有名为.comment的段;
  • -S:不从源文件中复制重定位信息和符号信息到目标文件中;

2.3 Image.gz

linux根目录下的arch/arm64/boot/.Image.gz.cmd文件可以看到vmlinux的生成命令:

root@zhengyang:/work/sambashare/rk3399/linux-5.2.8# cat arch/arm64/boot/.Image.gz.cmd
cmd_arch/arm64/boot/Image.gz := cat arch/arm64/boot/Image | gzip -n -f -9 > arch/arm64/boot/Image.gz

这里使用gzip文件对Image文件进行压缩,处理得到Image.gz文件;其中:

  • -n:压缩文件时,不保存原来的文件名称及时间戳记;
  • -f:强行压缩文件。不理会文件名称或硬连接是否存在以及该文件是否为符号连接;
  • -9:表示高压缩比,多在创建压缩包时使用;

2.4 zImage

arm64arch/arm64/boot路径下并没有生成zImage文件,但是我们在为Mini2440开发板编译内核时,在arch/arm/boot/路径下是生成了zImage文件的。

其编译命令位于arch/arm/boot/.zImage.cmd文件:

root@zhengyang:/work/sambashare/linux-5.2.8-dt# cat arch/arm/boot/.zImage.cmd
cmd_arch/arm/boot/zImage := arm-linux-objcopy -O binary -R .comment -S  arch/arm/boot/compressed/vmlinux arch/arm/boot/zImage

可以看到这里利用arm-linux-objcopy命令将arch/arm/boot/compressed/vmlinux转换为二进制位zImage。那问题来了arch/arm/boot/compressed/vmlinux是哪里来的呢?

arch/arm/boot/compressed/vmlinux的生成包括两步:

(1) 使用gzip命令将Image进行压缩得到piggy_data文件;

root@zhengyang:/work/sambashare/linux-5.2.8-dt# cat arch/arm/boot/compressed/.piggy_data.cmd
cmd_arch/arm/boot/compressed/piggy_data := cat arch/arm/boot/compressed/../Image | gzip -n -f -9 > arch/arm/boot/compressed/piggy_data

(2) 将piggy_data文件开头嵌入gzip解压缩代码编译得到elf格式文件arch/arm/boot/compressed/vmlinux

root@zhengyang:/work/sambashare/linux-5.2.8-dt# cat arch/arm/boot/compressed/.vmlinux.cmd
cmd_arch/arm/boot/compressed/vmlinux := arm-linux-ld  -EL  \
 --defsym _kernel_bss_size=202320 \
 --defsym zreladdr=0x30008000 \
 --no-undefined  \
 -X  \
 -T arch/arm/boot/compressed/vmlinux.lds \
 arch/arm/boot/compressed/head.o  \
 arch/arm/boot/compressed/piggy.o  \
 arch/arm/boot/compressed/misc.o  \
 arch/arm/boot/compressed/decompress.o  \
 arch/arm/boot/compressed/string.o  \
 arch/arm/boot/compressed/lib1funcs.o \ 
 arch/arm/boot/compressed/ashldi3.o  \
 arch/arm/boot/compressed/bswapsdi2.o  \
 -o arch/arm/boot/compressed/vmlinux

这里是将压缩的内核镜像数据(arch/arm/boot/compressed/piggy_data.piggydata段中,并定义符号 input_datainput_data_end引用该段的开始和结束地址,具体实现在arch/arm/boot/compressed/piggy.S文件,该文件会被编译成arch/arm/boot/compressed/piggy.o

/* SPDX-License-Identifier: GPL-2.0 */
        .section .piggydata,#alloc
        .globl  input_data
input_data:
        .incbin "arch/arm/boot/compressed/piggy_data"
        .globl  input_data_end
input_data_end:

其中,.section指令用于切换当前段至.piggydata段,#alloc表示告知编译器该段需要分配内存,input_datainput_data_end为符号名,用于访问所在段的起始地址和结束地址。最关键的是.incbin "arch/arm/boot/compressed/piggy_data" 指令,它用于将arch/arm/boot/compressed/piggy_data中的二进制数据按字节复制到.piggydata段中,从而实现内核镜像数据的加载。

内核镜像数据的解压是在arch/arm/boot/compressed/misc.c文件实现的:

extern char input_data[];
extern char input_data_end[];
extern int do_decompress(u8 *input, int len, u8 *output, void (*error)(char *x));

void
decompress_kernel(unsigned long output_start, unsigned long free_mem_ptr_p,
                unsigned long free_mem_ptr_end_p,
                int arch_id)
{
        int ret;

        output_data             = (unsigned char *)output_start;
        free_mem_ptr            = free_mem_ptr_p;
        free_mem_end_ptr        = free_mem_ptr_end_p;
        __machine_arch_type     = arch_id;

        arch_decomp_setup();

        putstr("Uncompressing Linux...");
        ret = do_decompress(input_data, input_data_end - input_data,
                            output_data, error);
        if (ret)
                error("decompressor returned an error");
        else
                putstr(" done, booting the kernel.\n");
}

在链接arch/arm/boot/compressed/vmlinux.lds中将段.piggydata链接在后面:

OUTPUT_ARCH(arm)
ENTRY(_start)
SECTIONS
{
  /DISCARD/ : {
    *(.ARM.exidx*)
    *(.ARM.extab*)
    *(.data)
  }
  . = 0;
  _text = .;
  .text : {
    _start = .;
    *(.start)
    *(.text)
    *(.text.*)
    *(.fixup)
    *(.gnu.warning)
    *(.glue_7t)
    *(.glue_7)
  }
  .table : ALIGN(4) {
    _table_start = .;
    LONG((2))
    LONG((0x5a534c4b))
    LONG((__piggy_size_addr - _start))
    LONG((_kernel_bss_size))
    LONG(0)
    _table_end = .;
  }
  .rodata : {
    *(.rodata)
    *(.rodata.*)
    *(.data.rel.ro)
  }
  .piggydata : {
    *(.piggydata)
    __piggy_size_addr = . - 4;
  }
  . = ALIGN(4);
  _etext = .;
  .got.plt : { *(.got.plt) }
  _got_start = .;
  .got : { *(.got) }
  _got_end = .;
  .pad : { BYTE(0); . = ALIGN(8); }
  _edata = .;
  .image_end (NOLOAD) : {
    _edata_real = .;
  }
  _magic_sig = (0x016f2818);
  _magic_start = (_start);
  _magic_end = (_edata);
  _magic_table = (_table_start - _start);
  . = ALIGN(8);
  __bss_start = .;
  .bss : { *(.bss) }
  _end = .;
  . = ALIGN(8);
  .stack : { *(.stack) }
  PROVIDE(__pecoff_data_size = ALIGN(512) - ADDR(.data));
  PROVIDE(__pecoff_end = ALIGN(512));
  .stab 0 : { *(.stab) }
  .stabstr 0 : { *(.stabstr) }
  .stab.excl 0 : { *(.stab.excl) }
  .stab.exclstr 0 : { *(.stab.exclstr) }
  .stab.index 0 : { *(.stab.index) }
  .stab.indexstr 0 : { *(.stab.indexstr) }
  .comment 0 : { *(.comment) }
}
ASSERT(_edata_real == _edata, "error: zImage file size is incorrect");

2.5 uImage

arm64arch/arm64/boot路径下并没有生成uImage文件。但是我们在为Mini2440开发板编译内核时,在arch/arm/boot/路径下是生成了uImage文件的,更具体的说是Legacy uImage

其编译命令位于arch/arm/boot/.uImage.cmd文件:

root@zhengyang:/work/sambashare/linux-5.2.8-dt# cat arch/arm/boot/.uImage.cmd
cmd_arch/arm/boot/uImage := /bin/bash ./scripts/mkuboot.sh    \
-A arm \           // 架构
-O linux \         // 操作系统
-C none  \         // 压缩类型为none,这样uboot就不会对镜像文件进行解压操作了;解压工作交由内核镜像头部的gzip解压代码完成
-T kernel \        // 镜像类型
-a 0x30008000 \    // 加载地址
-e 0x30008000 \    // 入口地址
-n 'Linux-5.2.8' \  // 镜像名称
-d arch/arm/boot/zImage arch/arm/boot/uImage // 输入文件

这里使用使用./scripts/mkuboot.sh脚本来制作uImage,最终调用mkimage工具来制作uImage

#!/bin/bash
# SPDX-License-Identifier: GPL-2.0

#
# Build U-Boot image when `mkimage' tool is available.
#

MKIMAGE=$(type -path "${CROSS_COMPILE}mkimage")

if [ -z "${MKIMAGE}" ]; then
        MKIMAGE=$(type -path mkimage)
        if [ -z "${MKIMAGE}" ]; then
                # Doesn't exist
                echo '"mkimage" command not found - U-Boot images will not be built' >&2
                exit 1;
        fi
fi

# Call "mkimage" to create U-Boot image
${MKIMAGE} "$@"
2.5.1 加载/入口地址等

在内核移植中我们经常提到load addressentry pointbootm addresskernel运行地址,那这些地址有什么关系;

  • load address:加载地址load_addr ,由mkimage -a 指定;
  • entry point: 入口地址entry_point,由mkimage -e指定;
  • bootm addressbootm命令后面紧跟的地址,也就是加载地址addr
  • kernel运行地址:zImage自解压后将kernel解压到实际运行的物理地址;

所谓加载地址是指bootm将内核镜像文件拷贝到内存空间的位置,入口地址是加载地址确定后bootm从内核镜像文件中开始执行的地址。

理论上zImage转化为uImage需要添加0x40长度的header头, 所以entry_point == load_addr + 0x40

2.5.2 bootmuImage处理

(1) addr != load_addr

addr所在地址提取取出内核镜像头部信息中进行处理, 并将去掉头部的内核直接加载到-a指定的地址load_addr

然后进入load_addr进行内核引导(entry_point)。所以此时地址:addr != load_addr == entry_point

(2) addr == load_addr

也就是说bootm后的地址等于加载地址,即已经将内核镜像(带头部)加载到-a指定的内存地址load_addr中。

此时:addr == load_addr == entry_point - 0x40;

2.5.3 制作镜像

Mini2440开发板为例,制作镜像头以及下载地址有以下两种情况:

(1) 情景一(内核linux-5.2.8使用)

mkimage -n 'Linux-5.2.8'  -A arm -O linux -T kernel -C none -a 0x30008000 -e 0x30008000 -d zImage uImage

加载地址和入口地址相同:load_addr == entry_point,烧录和启动命令;

tftp 0x31000000 uImage
bootm 0x31000000
# Starting kernel...之前有内核搬移(从0x31000040->0x0x30008000),并从0x30008000启动

下载地址可以任意放,也可以指定为0x30008000,此时也进行了内核搬移,从0x30008040->0x0x30008000

(2) 情景二

mkimage -n  'Linux-5.2.8' -A arm -O linux -T kernel -C none -a 0x30008000 -e 0x30008040 -d zImage uImage

入口地址在加载地址后面64个字节:entry_point == load_addr + 0x40;烧录和启动命令;

tftp 0x30008000 uImage
bootm 0x30008000
# 没有内核搬移,从从0x30008040启动

下载地址一定要在指定的加载地址上。

三、boot启动命令解析

当我们在uboot命令行执行了boot命令时,uboot会获取bootcmd环境变量的内容,然后执行bootcmd中保存的启动命令。接下来我们来分析一下bootcmd默认配置。

3.1 bootcmd

uboot include/configs/evb_rk3399.h文件中配置了默认的启动命令:

#ifndef CONFIG_SPL_BUILD
#undef CONFIG_BOOTCOMMAND
#define CONFIG_BOOTCOMMAND RKIMG_BOOTCOMMAND
#endif

RKIMG_BOOTCOMMAND定义在include/configs/rockchip-common.h文件中:

#if defined(CONFIG_AVB_VBMETA_PUBLIC_KEY_VALIDATE)
#define RKIMG_BOOTCOMMAND                       \
        "boot_android ${devtype} ${devnum};"
#elif defined(CONFIG_FIT_SIGNATURE)
#define RKIMG_BOOTCOMMAND                       \
        "boot_fit;"
#else
#define RKIMG_BOOTCOMMAND                       \        #  这里这个会生效
        "boot_android ${devtype} ${devnum};"    \
        "boot_fit;"                             \
        "bootrkp;"                              \
        "run distro_bootcmd;"
#endif

可以看到:

  • 如果配置了CONFIG_AVB_VBMETA_PUBLIC_KEY_VALIDATE,则执行命令boot_android \${devtype} \${devnum}
  • 如果配置了CONFIG_FIT_SIGNATURE,则执行命令boot_fitboot_fit命令是用来执行FIT uImage的;
  • 由于前两个我们都没有配置,因此执行的命令是最后一个;

我们在uboot命令行执行print也可以看到cmdline环境变量的值:

bootcmd=boot_android ${devtype} ${devnum};boot_fit;bootrkp;run distro_bootcmd;

如果后面实验环境我们烧录的内核镜像是boot.img,那么其内核镜像格式既不是Android,也不是FIT uImage,因此前两种启动方式都会失败,我们从内核启动日志可以看到:

=> boot
Could not find misc partition
ANDROID: reboot reason: "(none)"
No valid android hdr
Android image load failed
Android boot failed, error -1.
## Booting FIT Image FIT: No fit blob
do_boot_fit 1
FIT: No FIT image

3.2 boot_fit启动方式

boot_fit启动方式使用的内核镜像为FIT uImage。由于Rockchip官方提供的uboot在启动方式上做了大量魔改,尤其是bootm命令:

do_bootm  // cmd/bootm.c
    // 支持
    //   - Android: bootm [aosp addr]
    //     - FIT:     bootm [fit addr]
    //   - uImage:  bootm [uimage addr]
    board_do_bootm(argc,argv)    // arch/arm/mach-rockchip/board.c   Rockchip自己扩充的,用于从不同位置加载内核镜像
        // 获取内核镜像格式  支持三种Android、FIT uImage、以及Legacy uImage;不同的内核镜像格式,处理逻辑不一样
        format = (genimg_get_format(img))  //common/image.c
        // 当镜像格式为FIT uImage时,会走下面的代码
        bootm_image_populate_dtb(img)     
            rockchip_ram_read_dtb_file(img, (void *)gd->fdt_blob)   // arch/arm/mach-rockchip/boot_rkimg.c
                // 如果配置了CONFIG_ROCKCHIP_RESOURCE_IMAGE,这节点名字就是resource,否者就是fdt
                // 关于resource节点指向的文件,应该是Rockchip自己定义的资源文件格式,相关代码位于arch/arm/mach-rockchip/resource_img.c
                // 我们以fdt节点为例介绍,获取/images/fdt节点偏移
                noffset = fdt_path_offset(img,"/images/fdt)     // lib/libfdt/fdt_ro.c 207
                //获取fdt节点data属性以及指定的dtb文件的大小             
                fit_image_get_data(img, noffset, &data, &size) // common/image-fit.c:900
                    // 获取"data"属性(返回的是指针)以及dtb文件的长度 即/incbin/("rk3399-evb.dtb")
                    *data = fdt_getprop(fit, noffset, FIT_DATA_PROP, &len);
                    // 获取"data-size"属性,从而得dtb文件
                    fit_image_get_data_size(fit, noffset, &len)
                    // 获取"data-offset"属性,从而得到dtb文件的偏移
                    fit_image_get_data_offset(fit, noffset, (int *)&data_off)
                    // 获取"data-position"属性,该属性并不存在
                    fit_image_get_data_position(fit, noffset, (int *)&data_pos)
        
                fdt_check_header(data)
                memcpy(fdt, data, size)
                sysmem_alloc_base(MEM_FDT, (phys_addr_t)fdt,ALIGN(fdt_totalsize(fdt), RK_BLK_SIZE) + CONFIG_SYS_FDT_PAD)
        run_command(boot_cmd, 0)    // boot_cmd设置为"boot_fit <addr>" 执行bootcmd中的命令,相当于执行boot_fit  addr命令
                                   
    do_bootm_states(....)   

这里为了适配各种镜像格式,Rockchip自己实现了一个board_do_bootm的逻辑,尤其是bootm_image_populate_dtb里面又搞了一些幺蛾子,而且我对这段逻辑也没啥兴趣,所以干脆我就放弃使用bootm命令去启动内核了,直接采用boot_fit命令启动FIT uImage镜像,其启动命令格式如下

=> help boot_fit
boot_fit - Boot FIT Image from memory or boot/recovery partition

Usage:
boot_fit boot_fit [addr]

其实现位于cmd/bootfit.c以及arch/arm/mach-rockchip/fit.c等文件,阅读代码我发现几处比较有意思的地方。

当我们把FIT uImage下载到内存某个地址,比如0x10000000,运行boot_fit 0x10000000启动内核,该命令会执行do_boot_fit函数,函数位于cmd/bootfit.c

static int do_boot_fit(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
{
        char *bootm_args[1];
        char fit_addr[12];
        ulong size;
        void *fit;
        int ret;

        if (argc > 2)
                return CMD_RET_USAGE;

        printf("## Booting FIT Image ");

        if (argc == 1)
                fit = do_boot_fit_storage(&size);
        else
                fit = do_boot_fit_ram(argv, &size);

        if (!fit) {
                FIT_I("No FIT image\n");
                goto out;
        }

        if (fdt_check_header(fit)) {
                FIT_I("Invalid FIT format\n");
                goto out;
        }

        /* fixup entry/load and alloc sysmem */
        if (fit_image_pre_process(fit)){
                goto out;
        }

        env_set("bootm-no-reloc", "y");
        snprintf(fit_addr, sizeof(fit_addr), "0x%lx", (ulong)fit);
        bootm_args[0] = fit_addr;

        printf("at %s with size 0x%08lx\n", fit_addr, size);

        ret = do_bootm_states(NULL, 0, ARRAY_SIZE(bootm_args), bootm_args,
                BOOTM_STATE_START |
                BOOTM_STATE_FINDOS | BOOTM_STATE_FINDOTHER |
                BOOTM_STATE_LOADOS |
#ifdef CONFIG_SYS_BOOT_RAMDISK_HIGH
                BOOTM_STATE_RAMDISK |
#endif
                BOOTM_STATE_OS_PREP | BOOTM_STATE_OS_FAKE_GO |
                BOOTM_STATE_OS_GO, &images, 1);

        if (ret && argc != 1) {
                fit_image_fail_process(fit);
                goto out;
        }

        return CMD_RET_SUCCESS;
out:
        return CMD_RET_FAILURE;
}

如果boot_fit命令只有1个参数:比如boot_fit ,则从eMMC存储设备加载FIT uImage并启动 。

如果boot_fit命令有2个参数: 比如boot_fit <load_addr> ,则从RAM启动;采用boot_fit <load_addr>需要先将FIT-uImage加载到内存,然后根据传入的加载地址启动内核。

3.2.1 支持fit启动

支持从fit启动,需要进行如下配置:

(1) 取消CONFIG_ROCKCHIP_RESOURCE_IMAGE配置,不使用Rockchip resource镜像; 配置CONFIG_ROCKCHIP_FIT_IMAGE,即使用fit镜像;

ARM architecture   --->
	[ ] Enable support for rockchip resource image
	[*] Enable support for FIT image 

(2) 配置CONFIG_CMD_BOOT_FITCONFIG_CMD_BOOT_FIT依赖CONFIG_ROCKCHIP_FIT_IMAGE

Command line interface  --->
	Device access commands   --->
		 -*-  boot_fit        

cmd/Makefile中定义有:

obj-$(CONFIG_CMD_BOOT_FIT) += bootfit.o

include/image.h定义有:

#define IMAGE_ENABLE_FIT     CONFIG_IS_ENABLED(FIT)   // 配置了CONFIG_FIT
3.2.2 do_boot_fit_storage

这里我们看一下do_boot_fit_storage函数是如何从eMMC存储设备加载FIT uImage镜像到内存的 。

fit = do_boot_fit_storage(&size);  //  cmd/bootfit.c
    fit_image_load_bootables(size)    // arch/arm/mach-rockchip/fit.c
        // 获取启动设备
        dev_desc = rockchip_get_bootdev();
        fit = fit_get_blob(dev_desc, &part, false)
             // 根据分区名获取分区信息 part_name = PART_BOOT 即"boot"  
             // 分区名称是写在gpt分区表中的,开始扇区0x8000,占用扇区数量0x38000 扇区大小112MB
              part_get_info_by_name(dev_desc, part_name, &part)   // disk/part.c
              // 除法运算,向上取整 应该为 1 
              blk_num = DIV_ROUND_UP(sizeof(struct fdt_header), dev_desc->blksz);
			  // 分配一个512字节大小,地址是ARCH_DMA_MINALIGN的倍数的内存块
              fdt = memalign(ARCH_DMA_MINALIGN, blk_num * dev_desc->blksz);
			  // 读取第一个扇区数据到fdt,地址范围0x00000000~0x00000027表示的是fdt_header结构体的成员信息
			  blk_dread(dev_desc, part.start, blk_num, fdt);
              // 首先获取totalsize->totalsize,即计算kernel.its文件打包后在kernel.itb中所占的大小,由于我们编译指定了-E属性,因此这里计算的是不包含image data file文件的大小,更准确的说应该是fdt blob的大小
              blk_num = DIV_ROUND_UP(fdt_totalsize(fdt), dev_desc->blksz);
			  // 分配一个blk_num*dev_desc->blksz大小,地址是ARCH_DMA_MINALIGN的倍数的内存块
              fit = memalign(ARCH_DMA_MINALIGN, blk_num * dev_desc->blksz);
         	  // 将fdt blob(不包含image)加载到内存地址fit
	          blk_dread(dev_desc, part.start, blk_num, fit);   

经过分析我们可以推断出: 采用boot_fit命令启动内核,必须要设置GPT分区, 默认boot_fit命令从eMMCboot分区加载FIT-uImage实际使用到的镜像文件到内存,然后启动内核 。

3.2.3 fit_image_pre_process

函数fit_image_pre_process用于对FIT uImage进行预处理:包括检查其格式是否合法、修正镜像元素的入口地址和加载地址等信息,并且在必要时分配系统内存。

fit_image_pre_process(fit)   // arch/arm/mach-rockchip/fit.c
    fit_image_fixup_alloc(fit, FIT_FDT_PROP,"fdt_addr_r", MEM_FDT)  // 检查fdt节点
        // 从环境变量获取fdt_addr_r地址  环境变量默认配置的fdt_addr_r=0x08300000
        addr = env_get_ulong(addr_name, 16, 0); // addr_name="fdt_addr_r"
        // 获取fdt节点data-offset属性值保存到offset变量 
        // 获取fdt节点data-size属性值保存到size变量 
        // 获取fdt镜像加载到内存的地址,保存到load变量 
        fit_image_get_param(fit, prop_name, &load, &offset, &size)  // prop_name="fdt"
            fdt_image_get_offset_size(fit, prop_name, offset, size)
                // 获取fdt节点
                noffset = fit_default_conf_get_node(fit, prop_name);
                // 获取"data-size"属性,保存到sz
                fit_image_get_data_size(fit, noffset, &sz)
                // 获取"data-position"属性 没有该属性
                ret = fit_image_get_data_position(fit, noffset, &offs);
                if (!ret)
                    offs -= fdt_totalsize(fit);
                else
                    // 获取"data-offset"属性,保存到offs
                    ret = fit_image_get_data_offset(fit, noffset, &offs);
            // 获取fdt镜像在内存中的地址,保存到load
            fdt_image_get_load(fit, prop_name, load)            
        // 修正fdt的入口地址和加载地址
        fix_image_set_addr(fit, prop_name, load, addr);  // 入参:old=load, new=addr(环境变量中的地址)            
            /* do not fix if verified-boot */
            if (!fit_image_addr_is_placeholder(old) ||  // 默认不使用环境变量中的地址修正,就使用its文件文件中配置的load、entry地址
                fit_sig_require_conf(fit, gd_fdt_blob()))  
                return 0;

            // 设置fit节点entry属性值为new
            fit_image_set_entry(fit, noffset, new);  // common/image-fit.c
            // 设置load节点entry属性值为new
            fit_image_set_load(fit, noffset, new);

        sysmem_alloc_base(mem, (phys_addr_t)addr,ALIGN(size, RK_BLK_SIZE))                
    fit_image_fixup_alloc(fit, FIT_KERNEL_PROP,"kernel_addr_r", MEM_KERNEL) // 检查kernel节点
    fit_image_fixup_alloc(fit, FIT_RAMDISK_PROP,"ramdisk_addr_r", MEM_RAMDISK) // 检查ramdisk节点
    
do_bootm_states(....);

从这段代码中不难看出FIT uImage必须满足以下条件:

  • 必须要有ramdiskkernelfdt节点;(这里就很烦人,ramdisk你限制个屁,为此我还去做了ramdisk镜像);
  • 校验kernelramdiskftddata-offsetdata-size属性,这个就导致在使用tools/mkimage工具生成FIT uImage镜像的时候必须要指定-E参数,不然生成的FIT uImage是不会有这两个属性的;

上面有一块内容我们需要单独提一下,就是啥时候我们会使用环境变量中的fdt_addr_rkernel_addr_rramdisk_addr_r值去修正its文件中配置的loadentry地址。具体需要看一下fit_image_addr_is_placeholder函数实现;

#define FIT_PLACEHOLDER_ADDR            0xffffff00

static inline int fit_image_addr_is_placeholder(ulong addr)
{
        return (addr & 0xffffff00) == FIT_PLACEHOLDER_ADDR;
}

可以看到如果addr满足(addr & 0xffffff00) == 0xffffff00时该函数就会返回true,这样就会执行fit_image_set_entryfit_image_set_load函数进行修正its文件中配置的loadentry地址。

3.3 distro boot启动方式

有关distro boot启动方式的内容就比较多了,但这不是我们这一节的重点,我们大概看一下distro_bootcmd命令的内容:

distro_bootcmd=for target in ${boot_targets}; do run bootcmd_${target}; done 

有关bistro boot启动相关的环境变量定义在include/config_distro_bootcmd.h文件中,有兴趣可以自行研究。

cat include/config_distro_bootcmd.h
/*
 * (C) Copyright 2014
 * NVIDIA Corporation <www.nvidia.com>
 *
 * Copyright 2014 Red Hat, Inc.
 *
 * SPDX-License-Identifier:     GPL-2.0+
 */

#ifndef _CONFIG_CMD_DISTRO_BOOTCMD_H
#define _CONFIG_CMD_DISTRO_BOOTCMD_H

/*
 * A note on error handling: It is possible for BOOT_TARGET_DEVICES to
 * reference a device that is not enabled in the U-Boot configuration, e.g.
 * it may include MMC in the list without CONFIG_CMD_MMC being enabled. Given
 * that BOOT_TARGET_DEVICES is a macro that's expanded by the C pre-processor
 * at compile time, it's not  possible to detect and report such problems via
 * a simple #ifdef/#error combination. Still, the code needs to report errors.
 * The best way I've found to do this is to make BOOT_TARGET_DEVICES expand to
 * reference a non-existent symbol, and have the name of that symbol encode
 * the error message. Consequently, this file contains references to e.g.
 * BOOT_TARGET_DEVICES_references_MMC_without_CONFIG_CMD_MMC. Given the
 * prevalence of capitals here, this looks like a pre-processor macro and
 * hence seems like it should be all capitals, but it's really an error
 * message that includes some other pre-processor symbols in the text.
 */

#define BOOTENV_SHARED_BLKDEV_BODY(devtypel) \
                "if " #devtypel " dev ${devnum}; then " \
                        "setenv devtype " #devtypel "; " \
                        "run scan_dev_for_boot_part; " \
                "fi\0"

#define BOOTENV_SHARED_BLKDEV(devtypel) \
        #devtypel "_boot=" \
        BOOTENV_SHARED_BLKDEV_BODY(devtypel)

#define BOOTENV_DEV_BLKDEV(devtypeu, devtypel, instance) \
        "bootcmd_" #devtypel #instance "=" \
                "setenv devnum " #instance "; " \
                "run " #devtypel "_boot\0"

#define BOOTENV_DEV_NAME_BLKDEV(devtypeu, devtypel, instance) \
        #devtypel #instance " "

#ifdef CONFIG_SANDBOX
#define BOOTENV_SHARED_HOST     BOOTENV_SHARED_BLKDEV(host)
#define BOOTENV_DEV_HOST        BOOTENV_DEV_BLKDEV
#define BOOTENV_DEV_NAME_HOST   BOOTENV_DEV_NAME_BLKDEV
#else
#define BOOTENV_SHARED_HOST
#define BOOTENV_DEV_HOST \
        BOOT_TARGET_DEVICES_references_HOST_without_CONFIG_SANDBOX
#define BOOTENV_DEV_NAME_HOST \
        BOOT_TARGET_DEVICES_references_HOST_without_CONFIG_SANDBOX
#endif

#ifdef CONFIG_CMD_MMC
#define BOOTENV_SHARED_MMC      BOOTENV_SHARED_BLKDEV(mmc)
#define BOOTENV_DEV_MMC         BOOTENV_DEV_BLKDEV
#define BOOTENV_DEV_NAME_MMC    BOOTENV_DEV_NAME_BLKDEV
#else
#define BOOTENV_SHARED_MMC
#define BOOTENV_DEV_MMC \
        BOOT_TARGET_DEVICES_references_MMC_without_CONFIG_CMD_MMC
#define BOOTENV_DEV_NAME_MMC \
        BOOT_TARGET_DEVICES_references_MMC_without_CONFIG_CMD_MMC
#endif

#ifdef CONFIG_CMD_UBIFS
#define BOOTENV_SHARED_UBIFS \
        "ubifs_boot=" \
                "if ubi part UBI && ubifsmount ubi${devnum}:boot; then "  \
                        "setenv devtype ubi; "                            \
                        "setenv bootpart 0; "                             \
                        "run scan_dev_for_boot; "                         \
                "fi\0"
#define BOOTENV_DEV_UBIFS       BOOTENV_DEV_BLKDEV
#define BOOTENV_DEV_NAME_UBIFS  BOOTENV_DEV_NAME_BLKDEV
#else
#define BOOTENV_SHARED_UBIFS
#define BOOTENV_DEV_UBIFS \
        BOOT_TARGET_DEVICES_references_UBIFS_without_CONFIG_CMD_UBIFS
#define BOOTENV_DEV_NAME_UBIFS \
        BOOT_TARGET_DEVICES_references_UBIFS_without_CONFIG_CMD_UBIFS
#endif

#ifdef CONFIG_EFI_LOADER
#if defined(CONFIG_ARM64)
#define BOOTEFI_NAME "bootaa64.efi"
#elif defined(CONFIG_ARM)
#define BOOTEFI_NAME "bootarm.efi"
#endif
#endif

#ifdef BOOTEFI_NAME
#if defined(CONFIG_ARM) && !defined(CONFIG_ARM64)
/*
 * On 32bit ARM systems there is a reasonable number of systems that follow
 * the $soc-$board$boardver.dtb name scheme for their device trees. Use that
 * scheme if we don't have an explicit fdtfile variable.
 */
#define BOOTENV_EFI_SET_FDTFILE_FALLBACK                                  \
        "if test -z \"${fdtfile}\" -a -n \"${soc}\"; then "               \
          "setenv efi_fdtfile ${soc}-${board}${boardver}.dtb; "           \
        "fi; "
#else
#define BOOTENV_EFI_SET_FDTFILE_FALLBACK
#endif

#define BOOTENV_SHARED_EFI                                                \
        "boot_efi_binary="                                                \
                "load ${devtype} ${devnum}:${distro_bootpart} "           \
                        "${kernel_addr_r} efi/boot/"BOOTEFI_NAME"; "      \
                "if fdt addr ${fdt_addr_r}; then "                        \
                        "bootefi ${kernel_addr_r} ${fdt_addr_r};"         \
                "else "                                                    \
                        "bootefi ${kernel_addr_r} ${fdtcontroladdr};"     \
                "fi\0"                                                    \
        \
        "load_efi_dtb="                                                   \
                "load ${devtype} ${devnum}:${distro_bootpart} "           \
                        "${fdt_addr_r} ${prefix}${efi_fdtfile}\0"         \
        \
        "efi_dtb_prefixes=/ /dtb/ /dtb/current/\0"                        \
        "scan_dev_for_efi="                                               \
                "setenv efi_fdtfile ${fdtfile}; "                         \
                BOOTENV_EFI_SET_FDTFILE_FALLBACK                          \
                "for prefix in ${efi_dtb_prefixes}; do "                  \
                        "if test -e ${devtype} "                          \
                                        "${devnum}:${distro_bootpart} "   \
                                        "${prefix}${efi_fdtfile}; then "  \
                                "run load_efi_dtb; "                      \
                        "fi;"                                             \
                "done;"                                                   \
                "if test -e ${devtype} ${devnum}:${distro_bootpart} "     \
                                        "efi/boot/"BOOTEFI_NAME"; then "  \
                                "echo Found EFI removable media binary "  \
                                        "efi/boot/"BOOTEFI_NAME"; "       \
                                "run boot_efi_binary; "                   \
                                "echo EFI LOAD FAILED: continuing...; "   \
                "fi; "                                                    \
                "setenv efi_fdtfile\0"
#define SCAN_DEV_FOR_EFI "run scan_dev_for_efi;"
#else
#define BOOTENV_SHARED_EFI
#define SCAN_DEV_FOR_EFI
#endif

#ifdef CONFIG_SATA
#define BOOTENV_SHARED_SATA     BOOTENV_SHARED_BLKDEV(sata)
#define BOOTENV_DEV_SATA        BOOTENV_DEV_BLKDEV
#define BOOTENV_DEV_NAME_SATA   BOOTENV_DEV_NAME_BLKDEV
#else
#define BOOTENV_SHARED_SATA
#define BOOTENV_DEV_SATA \
        BOOT_TARGET_DEVICES_references_SATA_without_CONFIG_SATA
#define BOOTENV_DEV_NAME_SATA \
        BOOT_TARGET_DEVICES_references_SATA_without_CONFIG_SATA
#endif

#ifdef CONFIG_SCSI
#define BOOTENV_RUN_SCSI_INIT "run scsi_init; "
#define BOOTENV_SET_SCSI_NEED_INIT "setenv scsi_need_init; "
#define BOOTENV_SHARED_SCSI \
        "scsi_init=" \
                "if ${scsi_need_init}; then " \
                        "setenv scsi_need_init false; " \
                        "scsi scan; " \
                "fi\0" \
        \
        "scsi_boot=" \
                BOOTENV_RUN_SCSI_INIT \
                BOOTENV_SHARED_BLKDEV_BODY(scsi)
#define BOOTENV_DEV_SCSI        BOOTENV_DEV_BLKDEV
#define BOOTENV_DEV_NAME_SCSI   BOOTENV_DEV_NAME_BLKDEV
#else
#define BOOTENV_RUN_SCSI_INIT
#define BOOTENV_SET_SCSI_NEED_INIT
#define BOOTENV_SHARED_SCSI
#define BOOTENV_DEV_SCSI \
        BOOT_TARGET_DEVICES_references_SCSI_without_CONFIG_SCSI
#define BOOTENV_DEV_NAME_SCSI \
        BOOT_TARGET_DEVICES_references_SCSI_without_CONFIG_SCSI
#endif

#ifdef CONFIG_IDE
#define BOOTENV_SHARED_IDE      BOOTENV_SHARED_BLKDEV(ide)
#define BOOTENV_DEV_IDE         BOOTENV_DEV_BLKDEV
#define BOOTENV_DEV_NAME_IDE    BOOTENV_DEV_NAME_BLKDEV
#else
#define BOOTENV_SHARED_IDE
#define BOOTENV_DEV_IDE \
        BOOT_TARGET_DEVICES_references_IDE_without_CONFIG_IDE
#define BOOTENV_DEV_NAME_IDE \
        BOOT_TARGET_DEVICES_references_IDE_without_CONFIG_IDE
#endif

#if defined(CONFIG_DM_PCI)
#define BOOTENV_RUN_NET_PCI_ENUM "run boot_net_pci_enum; "
#define BOOTENV_SHARED_PCI \
        "boot_net_pci_enum=pci enum\0"
#else
#define BOOTENV_RUN_NET_PCI_ENUM
#define BOOTENV_SHARED_PCI
#endif

#ifdef CONFIG_CMD_USB
#define BOOTENV_RUN_NET_USB_START "run boot_net_usb_start; "
#define BOOTENV_SHARED_USB \
        "boot_net_usb_start=usb start\0" \
        "usb_boot=" \
                "usb start; " \
                BOOTENV_SHARED_BLKDEV_BODY(usb)
#define BOOTENV_DEV_USB         BOOTENV_DEV_BLKDEV
#define BOOTENV_DEV_NAME_USB    BOOTENV_DEV_NAME_BLKDEV
#else
#define BOOTENV_RUN_NET_USB_START
#define BOOTENV_SHARED_USB
#define BOOTENV_DEV_USB \
        BOOT_TARGET_DEVICES_references_USB_without_CONFIG_CMD_USB
#define BOOTENV_DEV_NAME_USB \
        BOOT_TARGET_DEVICES_references_USB_without_CONFIG_CMD_USB
#endif

#if defined(CONFIG_CMD_DHCP)
#if defined(CONFIG_EFI_LOADER)
#if defined(CONFIG_ARM64)
#define BOOTENV_EFI_PXE_ARCH "0xb"
#define BOOTENV_EFI_PXE_VCI "PXEClient:Arch:00011:UNDI:003000"
#elif defined(CONFIG_ARM)
#define BOOTENV_EFI_PXE_ARCH "0xa"
#define BOOTENV_EFI_PXE_VCI "PXEClient:Arch:00010:UNDI:003000"
#elif defined(CONFIG_X86)
/* Always assume we're running 64bit */
#define BOOTENV_EFI_PXE_ARCH "0x7"
#define BOOTENV_EFI_PXE_VCI "PXEClient:Arch:00007:UNDI:003000"
#else
#error Please specify an EFI client identifier
#endif

/*
 * Ask the dhcp server for an EFI binary. If we get one, check for a
 * device tree in the same folder. Then boot everything. If the file was
 * not an EFI binary, we just return from the bootefi command and continue.
 */
#define BOOTENV_EFI_RUN_DHCP \
        "setenv efi_fdtfile ${fdtfile}; "                                 \
        BOOTENV_EFI_SET_FDTFILE_FALLBACK                                  \
        "setenv efi_old_vci ${bootp_vci};"                                \
        "setenv efi_old_arch ${bootp_arch};"                              \
        "setenv bootp_vci " BOOTENV_EFI_PXE_VCI ";"                       \
        "setenv bootp_arch " BOOTENV_EFI_PXE_ARCH ";"                     \
        "if dhcp ${kernel_addr_r}; then "                                 \
                "tftpboot ${fdt_addr_r} dtb/${efi_fdtfile};"              \
                "if fdt addr ${fdt_addr_r}; then "                        \
                        "bootefi ${kernel_addr_r} ${fdt_addr_r}; "        \
                "else "                                                   \
                        "bootefi ${kernel_addr_r} ${fdtcontroladdr};"     \
                "fi;"                                                     \
        "fi;"                                                             \
        "setenv bootp_vci ${efi_old_vci};"                                \
        "setenv bootp_arch ${efi_old_arch};"                              \
        "setenv efi_fdtfile;"                                             \
        "setenv efi_old_arch;"                                            \
        "setenv efi_old_vci;"
#else
#define BOOTENV_EFI_RUN_DHCP
#endif
#define BOOTENV_DEV_DHCP(devtypeu, devtypel, instance) \
        "bootcmd_dhcp=" \
                BOOTENV_RUN_NET_USB_START \
                BOOTENV_RUN_NET_PCI_ENUM \
                "if dhcp ${scriptaddr} ${boot_script_dhcp}; then " \
                        "source ${scriptaddr}; " \
                "fi;" \
                BOOTENV_EFI_RUN_DHCP \
                "\0"
#define BOOTENV_DEV_NAME_DHCP(devtypeu, devtypel, instance) \
        "dhcp "
#else
#define BOOTENV_DEV_DHCP \
        BOOT_TARGET_DEVICES_references_DHCP_without_CONFIG_CMD_DHCP
#define BOOTENV_DEV_NAME_DHCP \
        BOOT_TARGET_DEVICES_references_DHCP_without_CONFIG_CMD_DHCP
#endif

#if defined(CONFIG_CMD_DHCP) && defined(CONFIG_CMD_PXE)
#define BOOTENV_DEV_PXE(devtypeu, devtypel, instance) \
        "bootcmd_pxe=" \
                BOOTENV_RUN_NET_USB_START \
                BOOTENV_RUN_NET_PCI_ENUM \
                "dhcp; " \
                "if pxe get; then " \
                        "pxe boot; " \
                "fi\0"
#define BOOTENV_DEV_NAME_PXE(devtypeu, devtypel, instance) \
        "pxe "
#else
#define BOOTENV_DEV_PXE \
        BOOT_TARGET_DEVICES_references_PXE_without_CONFIG_CMD_DHCP_or_PXE
#define BOOTENV_DEV_NAME_PXE \
        BOOT_TARGET_DEVICES_references_PXE_without_CONFIG_CMD_DHCP_or_PXE
#endif

#define BOOTENV_DEV_NAME(devtypeu, devtypel, instance) \
        BOOTENV_DEV_NAME_##devtypeu(devtypeu, devtypel, instance)
#define BOOTENV_BOOT_TARGETS \
        "boot_targets=" BOOT_TARGET_DEVICES(BOOTENV_DEV_NAME) "\0"

#define BOOTENV_DEV(devtypeu, devtypel, instance) \
        BOOTENV_DEV_##devtypeu(devtypeu, devtypel, instance)
#define BOOTENV \
        BOOTENV_SHARED_HOST \
        BOOTENV_SHARED_MMC \
        BOOTENV_SHARED_PCI \
        BOOTENV_SHARED_USB \
        BOOTENV_SHARED_SATA \
        BOOTENV_SHARED_SCSI \
        BOOTENV_SHARED_IDE \
        BOOTENV_SHARED_UBIFS \
        BOOTENV_SHARED_EFI \
        "boot_prefixes=/ /boot/\0" \
        "boot_scripts=boot.scr.uimg boot.scr\0" \
        "boot_script_dhcp=boot.scr.uimg\0" \
        BOOTENV_BOOT_TARGETS \
        \
        "boot_extlinux="                                                  \
                "sysboot ${devtype} ${devnum}:${distro_bootpart} any "    \
                        "${scriptaddr} ${prefix}extlinux/extlinux.conf\0" \
        \
        "scan_dev_for_extlinux="                                          \
                "if test -e ${devtype} "                                  \
                                "${devnum}:${distro_bootpart} "           \
                                "${prefix}extlinux/extlinux.conf; then "  \
                        "echo Found ${prefix}extlinux/extlinux.conf; "    \
                        "run boot_extlinux; "                             \
                        "echo SCRIPT FAILED: continuing...; "             \
                "fi\0"                                                    \
        \
        "boot_a_script="                                                  \
                "load ${devtype} ${devnum}:${distro_bootpart} "           \
                        "${scriptaddr} ${prefix}${script}; "              \
                "source ${scriptaddr}\0"                                  \
        \
        "scan_dev_for_scripts="                                           \
                "for script in ${boot_scripts}; do "                      \
                        "if test -e ${devtype} "                          \
                                        "${devnum}:${distro_bootpart} "   \
                                        "${prefix}${script}; then "       \
                                "echo Found U-Boot script "               \
                                        "${prefix}${script}; "            \
                                "run boot_a_script; "                     \
                                "echo SCRIPT FAILED: continuing...; "     \
                        "fi; "                                            \
                "done\0"                                                  \
        \
        "scan_dev_for_boot="                                              \
                "echo Scanning ${devtype} "                               \
                                "${devnum}:${distro_bootpart}...; "       \
                "for prefix in ${boot_prefixes}; do "                     \
                        "run scan_dev_for_extlinux; "                     \
                        "run scan_dev_for_scripts; "                      \
                "done;"                                                   \
                SCAN_DEV_FOR_EFI                                          \
                "\0"                                                      \
        \
        "scan_dev_for_boot_part="                                         \
                "part list ${devtype} ${devnum} -bootable devplist; "     \
                "env exists devplist || setenv devplist 1; "              \
                "for distro_bootpart in ${devplist}; do "                 \
                        "if fstype ${devtype} "                           \
                                        "${devnum}:${distro_bootpart} "   \
                                        "bootfstype; then "               \
                                "run scan_dev_for_boot; "                 \
                        "fi; "                                            \
                "done\0"                                                  \
        \
        BOOT_TARGET_DEVICES(BOOTENV_DEV)                                  \
        \
        "distro_bootcmd=" BOOTENV_SET_SCSI_NEED_INIT                      \
                "for target in ${boot_targets}; do "                      \
                        "run bootcmd_${target}; "                         \
                "done\0"

#ifndef CONFIG_BOOTCOMMAND
#define CONFIG_BOOTCOMMAND "run distro_bootcmd"
#endif

#endif  /* _CONFIG_CMD_DISTRO_BOOTCMD_H */

最终distro boot启动机制会从我们的eMMCboot分区加载内核镜像,然后启动内核,因此需要确保GPT分区表没有问题,不然uboot是无法找到boot分区的内核镜像的。

而根路径的挂载是由内核完成的,内核通过启动命令中配置的root=PARTUUID=B921B045-1D找到根文件系统所在的分区(块设备号为179:5、即/dev/mmcblk0p5),然后将根路径挂载到/dev/mmcblk0p5设备节点。

[    1.856037] EXT4-fs (mmcblk0p5): mounted filesystem with ordered data mode. Opts: (null)
[    1.865144] VFS: Mounted root (ext4 filesystem) on device 179:5.
[    1.873579] devtmpfs: mounted

四、distro boot启动内核镜像制作

Rockchp官方uboot给出的使用教程就是使用distro boot方式启动内核,其需要我们制作一个包含内核镜像和设备树的启动分区。

4.1 目录结构

创建一个名为boot的文件夹:

root@zhengyang:/work/sambashare/rk3399/linux-5.2.8# mkdir boot

然后,将设备树二进制文件复制到该文件夹中,这里我们和uboot移植一样,选择官方的评估板对应的设备树文件rk3399-evb.dtb

root@zhengyang:/work/sambashare/rk3399/linux-5.2.8# cp arch/arm64/boot/dts/rockchip/rk3399-evb.dtb boot/rk3399.dtb

接着,将内核镜像复制到该文件夹中:

root@zhengyang:/work/sambashare/rk3399/linux-5.2.8# cp arch/arm64/boot/Image boot/

为了实现distro引导,我们需要在启动分区中添加extlinux引导程序以及相应的配置文件。

我们需要创建一个名为extlinux的文件夹,在其中创建一个名为extlinux.conf的文件:

root@zhengyang:/work/sambashare/rk3399/linux-5.2.8# mkdir boot/extlinux
root@zhengyang:/work/sambashare/rk3399/linux-5.2.8# touch boot/extlinux/extlinux.conf

在所有这些文件都准备好之后,boot文件夹结构如下:

boot
├── extlinux
│   └── extlinux.conf
├── Image
└── rk3399-evb.dtb

4.2 extlinux.conf

extlinux.conf文件中编写配置信息,指定内核镜像和设备树的路径,以及其它启动参数。配置文件内容如下:

label rockchip-kernel-5.2.8
    kernel /Image
    fdt /rk3399.dtb
    append earlycon=uart8250,mmio32,0xff1a0000 console=ttyS2,1500000n8 root=PARTUUID=B921B045-1D rw rootwait rootfstype=ext4 init=/sbin/init
4.2.1 earlycon

这里最后一行实际上就是配置ubootbootargs参数,这里首先设置了:

earlycon=uart8250,mmio32,0xff1a0000 

ARM64kernel未建立console之前,使用earlycon,实现日志信息的打印,因此首先配置了earlycon:其中:

  • uart8250表示针对uart8250这个串口设备;
  • mio32表示内存I/O资源32位,0xff1a0000RK3399 UART2寄存器基地址,这里没有配置波特率,默认还是使用uboot中配置的波特率。
4.2.2 console

接着设置了控制台console,当RK3399 UART2控制台驱动注册之后,将会注销earlycon驱动,将内核输出的日志通过指定的console打印出来。

console=ttyS2,1500000n8

如果我们没有设置console,那么console将会使用tty0这个终端(tty0表示当前所使用虚拟终端的一个别名,系统所产生的信息会发送到该终端上。有关虚拟终端的信息,可以参考《linux驱动移植-tty架构)》,这将导致内核启动日志输出到如下这个位置将会停止(即无法通过串口输出):

[    0.015084] printk: console [tty0] enabled
[    0.019585] printk: bootconsole [uart8250] disabled

注意:我们需要根据自己的开发板配置串口。

4.2.3 root

指定根文件系统以及根文件系统类型;通过root属性指定根文件系统所在位置,通常这是一个必须明确设置的选项,格式如下:

root=字符串 rw rootwait rootfstype=ext4

rw表示可以对根文件系统进行读写,默认配置是只读;

rootwait表示在根文件系统就绪之前无限等待。主要用于等待那些反应速度较慢的异步检测的设备就绪(例如USB/MMC/FireWire)

rootfstype为根文件系统类型;

“字符串”可以采用如下几种形式:

  • XXxx:一个16进制数,其中XX是主设备号,xx是次设备号。例如/dev/sdc15(主设备号是8,次设备号是47),可以表示成082F;
  • /dev/nfs:表示使用nfsroot选项指定的NFS磁盘,仅在根文件系统位于NFS文件系统上的时候才可以使用,比如配置成root=/dev/nfs rw rootwait nfsroot=192.168.0.200:/work/nfs_root/ubuntu,vers=4 ip=192.168.0.105:192.168.0.200:192.168.0.1:255.255.255.0::eth0:off
  • /dev/disk:表示一块完整的无分区块设备。比如/dev/mmcblk0/dev/sdb
  • /dev/diskN:表示disk磁盘的第N个分区,这是最常见的写法,比如:/dev/mtdblock3/dev/mmcblk0p5/dev/sda2
  • PARTUUID=b921b045-1df0-41c3-af44-4c6f280d3fae:仅用于EFI/GPT格式的磁盘,表示分区表中UUID值为b921b045-1df0-41c3-af44-4c6f280d3fae的分区;
  • PARTUUID=SSSSSSSS-PP :仅用于传统的MSDOS分区表,SSSSSSSS是用16进制表示的32NT disk signaturePP是用16进制表示的分区号。比如:PARTUUID=97531ACF-02 可能相当于/dev/sda2
  • major:minor由一对十进制数组成,其中major是主设备号,minor是次设备号。例如/dev/sdc15(主设备号是8,次设备号是47),可以表示成8:47

uboot命令行下我们使用mmc part查看分区UUID

=> mmc part
Partition Map for MMC device 0  --   Partition Type: EFI
Part    Start LBA       End LBA         Name
        Attributes
        Type GUID
        Partition GUID
  1     0x00000040      0x00001f7f      "loader1"
        attrs:  0x0000000000000000
        type:   ebd0a0a2-b9e5-4433-87c0-68b6b72699c7
        guid:   8ef917d1-5bd0-2c4f-9a33-b225b21cf919
  2     0x00004000      0x00005fff      "loader2"
        attrs:  0x0000000000000000
        type:   ebd0a0a2-b9e5-4433-87c0-68b6b72699c7
        guid:   77877125-2374-ad40-8b02-609e37971c59
  3     0x00006000      0x00007fff      "trust"
        attrs:  0x0000000000000000
        type:   ebd0a0a2-b9e5-4433-87c0-68b6b72699c7
        guid:   b4b84b8a-f8ae-0443-b5af-3605b195c4c9
  4     0x00008000      0x0003ffff      "boot"
        attrs:  0x0000000000000004
        type:   ebd0a0a2-b9e5-4433-87c0-68b6b72699c7
        guid:   35219908-db08-c643-9133-2213191e57ff
  5     0x00040000      0x01d1efde      "rootfs"
        attrs:  0x0000000000000000
        type:   ebd0a0a2-b9e5-4433-87c0-68b6b72699c7
        guid:   b921b045-1df0-41c3-af44-4c6f280d3fae

我们发现rootfs分区对应的UUIDb921b045-1df0-41c3-af44-4c6f280d3fae,而我们上面配置的root=PARTUUID=B921B045-1D并不是上面我们介绍的任意一种方式,但是这个是Rockchip官方给的示例,运行也是没问题的。如果采用PARTUUID的方式。按照我们上面说的应该配置为:

root=PARTUUID=b921b045-1df0-41c3-af44-4c6f280d3fae

4.3 ext2镜像

使用genext2fs工具可以生成一个ext2文件系统镜像文件。在使用genext2fs命令时,需要指定生成文件系统的大小、块大小、inode大小等参数,以及输出的镜像文件名称和所在路径。

执行以下命令,将boot文件夹中的文件和目录打包成一个ext2文件系统镜像:

root@zhengyang:/work/sambashare/rk3399/linux-5.2.8# sudo apt-get install genext2fs
root@zhengyang:/work/sambashare/rk3399/linux-5.2.8# genext2fs -b 32768 -B $((64*1024*1024/32768)) -d boot/ -i 8192 -U boot.img
root@zhengyang:/work/sambashare/rk3399/linux-5.2.8# ll boot.img
-rw-r--r-- 1 root root 33554432 May 17 05:17 boot.img

其中:

  • -b :表示文件系统块的数量;
  • -B : 表示文件系统块的大小,单位为字节;
  • -d :从指定目录开始创建文件系统
  • -i 8192;每个inode使用的字节数;
  • -U:选项表示创建一个唯一的文件系统UUID

这里我们设置了32768个块,每个块大小为64*1024*1024/32768,所以文件系统总大小为64MB,足够放下boot文件夹内的所有文件。

五、FIT uImage镜像制作

我们在《Mini2440uboot移植流程之linux内核启动分析》中介绍过FIT uImage的制作流程,其通过一定语法和格式将一些需要使用到的镜像(例如kerneldtb以及文件系统)组合到一起生成一个image file

5.1 Image.gz

linux内核5.2.8版本的编译完成后会在arch/arm64/boot/文件夹下生成内核镜像文件Image,其中Image是内核镜像原生二进制文件,可以直接在芯片上运行的,由于Image文件较大,我们将Image压缩转换为Image.gz(内核编译默认也会生成这个文件):

cat arch/arm64/boot/Image | gzip -n -f -9 > arch/arm64/boot/Image.gz

5.2 创建its文件

因为mkimage是根据its文件中的描述来打包镜像生成itb文件(FIT uImage),所以首先需要制作一个its文件,在its文件中描述需要被打包的镜像,主要是kernel镜像,dtb文件,ramdisk镜像。

我们创建一个kernel.its文件,内容如下:

/*
 * Simple U-Boot uImage source file containing a single kernel and FDT blob
 */
/dts-v1/;

/ {
        description = "Simple image with single Linux kernel and FDT blob";
        #address-cells = <1>;

        images {

                kernel {
                        description = "Vanilla Linux kernel";
                        data = /incbin/("arch/arm64/boot/Image.gz");
                        type = "kernel";
                        arch = "arm64";
                        os = "linux";
                        compression = "gzip";
                        load = <0x280000>;
                        entry = <0x280000>;
                        hash-1 {
                                algo = "crc32";
                        };
                        hash-2 {
                                algo = "sha1";
                        };
                };

               fdt {
                        description = "Flattened Device Tree blob";
                        data = /incbin/("arch/arm64/boot/dts/rockchip/rk3399-evb.dtb");
                        type = "flat_dt";
                        arch = "arm64";
                        compression = "none";
                        load = <0x8300000>;
                        entry = <0x8300000>;
                        hash-1 {
                                algo = "crc32";
                        };
                        hash-2 {
                                algo = "sha1";
                        };
                };

                ramdisk {
                       description = "Ramdisk for project-x";
                       data = /incbin/("ramdisk.gz");
                       type = "ramdisk";
                       arch = "arm64";
                       os = "linux";
                       load = <00000000>;
                       entry = <00000000>;
                       compression = "gzip";
                       hash-1 {
                               algo = "crc32";
                       };
                };

        };

        configurations {
                default = "conf-1";
                conf-1 {
                        description = "Boot Linux kernel with FDT blob";
                        kernel = "kernel";
                        fdt = "fdt";
                        ramdisk = "ramdisk";
                };
        };
};

这里我们内核镜像使用的Image.gz文件,该文件是通过gzipImage进行压缩得到的,因此需要在kernel属性中指定compression,这样uboot才知道如何解压。

5.2.1 内核加载地址0x280000

这里有一点一定要注意:kernelloadentry地址一定要指定为0x280000;我最初将loadentry都指定为0x200000000x20080000,后来又尝试了0x200000uboot启动内核时都会卡在Starting kernel ...,就这个小小的问题我排查了好多天,说多了这都是泪啊;那我后来是怎么发现loadentry加载地址有问题的呢?

因为distro boot启动内核的方式(Rockchip官方推荐的)是可以成功启动内核的。所以我修改了arch/arm/lib/bootm.c文件,将images->epImage镜像的加载地址)、images->fd_addrfdt的加载地址)信息打印出来。

/* Subcommand: GO */
static void boot_jump_linux(bootm_headers_t *images, int flag)
{
#ifdef CONFIG_ARM64
        void (*kernel_entry)(void *fdt_addr, void *res0, void *res1,
                        void *res2);
        int fake = (flag & BOOTM_STATE_OS_FAKE_GO);
        int es_flag = 0;

#if defined(CONFIG_AMP)
        es_flag = arm64_switch_amp_pe(images);
#elif defined(CONFIG_ARM64_SWITCH_TO_AARCH32)
        es_flag = arm64_switch_aarch32(images);
#endif
        kernel_entry = (void (*)(void *fdt_addr, void *res0, void *res1,
                                void *res2))images->ep;

        printf("## Transferring control to Linux (at address %lx)...\n",
                (ulong) kernel_entry);
        printf("%s 0x%x=0x%x \n",__func__,images->ep,*((unsigned int *)images->ep));
        printf("%s 0x%x=0x%x \n",__func__,images->ep + 4,*((unsigned int *)(images->ep + 4) ));
                printf("%s 0x%x=0x%x \n",__func__,images->ep + 20,*((unsigned int *)(images->ep + 20) ));
        printf("%s 0x%x=0x%x \n",__func__,images->ft_addr,*((unsigned int *)images->ft_addr));
        printf("%s 0x%x=0x%x \n",__func__,((unsigned int *)images->ft_addr)+1,*((unsigned int *)images->ft_addr+1));
                printf("%s 0x%x=0x%x \n",__func__,((unsigned int *)images->ft_addr)+5,*((unsigned int *)images->ft_addr+5));

        bootstage_mark(BOOTSTAGE_ID_RUN_OS);

        announce_and_cleanup(images, fake);  // 这里面会输出Starting kernel

        if (!fake) {
#ifdef CONFIG_ARMV8_PSCI         // 不会走
                armv8_setup_psci();#endif
                do_nonsec_virt_switch();

                update_os_arch_secondary_cores(images->os.arch);

#ifdef CONFIG_ARMV8_SWITCH_TO_EL1      // 不会走
                armv8_switch_to_el2((u64)images->ft_addr, 0, 0, 0,
                                    (u64)switch_to_el1, ES_TO_AARCH64);
#else
                if ((IH_ARCH_DEFAULT == IH_ARCH_ARM64) &&
                    (images->os.arch == IH_ARCH_ARM)){           
                        armv8_switch_to_el2(0, (u64)gd->bd->bi_arch_number,
                                            (u64)images->ft_addr, es_flag,
                                            (u64)images->ep,
                                            ES_TO_AARCH32);
                }else {                // 走这里
                        armv8_switch_to_el2((u64)images->ft_addr, 0, 0, es_flag,
                                            images->ep,
                                            ES_TO_AARCH64);
                }
#endif
        }
 ......    // 后面是非CONFIG_ARM64成立时,才会走的代码
}

当采用distro boot方式启动内核时,这是当时打印出来的内容:

## Transferring control to Linux (at address 280000)...
boot_jump_linux 0x280000=0x91005a4d
boot_jump_linux 0x280004=0x14433fff
boot_jump_linux 0x280014=0x0
boot_jump_linux 0x8300000=0xedfe0dd0
boot_jump_linux 0x8300004=0xc00000
boot_jump_linux 0x8300014=0x11000000
Total: 5818.548 ms

Starting kernel ...

而采用boot_fit启动方式时,我配置的kernel.its文件kernel节点loadentry0x20000000时,打印出来的内容:

## Transferring control to Linux (at address 20000000)...
boot_jump_linux 0x20000000=0x91005a4d
boot_jump_linux 0x20000004=0x14433fff
boot_jump_linux 0x20000014=0x0
boot_jump_linux 0xf4606000=0xedfe0dd0
boot_jump_linux 0xf4606004=0xc00000
boot_jump_linux 0xf4606014=0x11000000

同时比对这两次启动输出的epfd_addr内容差异:我发现kernelfdt都成功加载到内存了,除了加载的地址不一样,但是内存的数据是完全一样的。

最开始我也没有往加载地址这方面去想,然后就开始百度,各种尝试。然而网上相关资料少之又少;后来我尝试了很多办法:

(1) 最初我想的是会不会是内核启动时卡住了,所以我就去定位内核日志缓冲区log_buf在内存的地址,然后去查看该内存的内容,但是该缓冲区并没有任何有用的数据;我就开始怀疑人生了,难道是我排查的方法有问题,在文章结尾我会记录这种方法;实际上现在回想起来,内核代码应该都没有执行到,直接卡在了armv8_switch_to_el2函数;该函数等后面我们有时间再研究;

(2) 然后又在想是不是启动参数bootargs配置的有问题,导致内核日志没有通过串口打印出来,专文为此我还去研究了一下earlycon控制台驱动和uart8250串口驱动;但是同样的bootargs配置,采用distro boot方式启动内核内核时时有日志输出的,所以就排除了这个原因;

(3) 后来我发现distro boot方式启动内核会从环境变量中获取kernel以及fdt的加载地址,我就想着要不按照这个改一下,后来尝试发现内核竟然真的可以启动了,撒花啊......,至于为啥一定要配置kernelload地址为0x280000,目前我还不知道原因,等后面有时间研究一下。

fdt_addr_r=0x08300000
kernel_addr_r=0x00280000
5.2.2 ramdisk

关于ramdisk根文件系统的制作可以参考《ramdisk根文件系统镜像》。

5.3 生成kernel.itb

FIT image文件的编译过程很简单,这里我们需要将uboot路径下的mkimage工具拷贝过来,然后在命令行使用mkimage工具编译即可:

root@zhengyang:/work/sambashare/rk3399/linux-5.2.8# cp ../u-boot/tools/mkimage ./
root@zhengyang:/work/sambashare/rk3399/linux-5.2.8# ./mkimage -f kernel.its  -E kernel.itb

需要注意的是这里一定要指定-E参数,不然image data file就会被放到FIT结构里面。

Rockchip RK3399 - 移植uboot 2023.04 & linux 6.3》中移植uboot 2023.04版本的时候,烧录的FIT uImage在编译的的时候是不可以指定-E参数的。

六、烧录内核

6.1 准备镜像

我们按照之前的流程得到了如下文件idbloader.imgu-boot.itbboot.imgkernel.itbbusybox_ext4_rootfs.img

关于Rockchip官方uboot 2017.09镜像制作参考:《Rockchip RK3399 - TPL/SPL方式加载uboot》。

关于ext4根文件系统镜像制作参考:《Rockchip RK3399 - busybox 1.36.0制作根文件系统制作》。

按照Rockchip官方要求将:

  • idbloader.img烧录到eMMC0x40扇区;
  • u-boot.itb烧录到0x4000扇区;
  • 如果采用boot_fit启动方式,烧录kernel.itb0x8000扇区;如果采用distro boot启动机制,烧录boot.img烧录到0x8000扇区;
  • busybox_ext4_rootfs.img烧录到0x40000扇区;

我们需要将idbloader.imgu-boot.itbboot.imgkernel.itbbusybox_ext4_rootfs.img拷贝到rkdeveloptool路径下:

root@zhengyang:/work/sambashare/rk3399/rkdeveloptool# cp ../u-boot/idbloader.img ./
root@zhengyang:/work/sambashare/rk3399/rkdeveloptool# cp ../u-boot/u-boot.itb ./
root@zhengyang:/work/sambashare/rk3399/rkdeveloptool# cp ../linux-5.2.8/boot.img ./
root@zhengyang:/work/sambashare/rk3399/rkdeveloptool# cp ../linux-5.2.8/kernel.itb ./
root@zhengyang:/work/sambashare/rk3399/rkdeveloptool# cp ../rootfs/busybox_ext4_rootfs.img ./

6.2 进入MASKROM升级模式

NanoPC-T4开发板如需进入MASKROM升级模式,需要进入如下操作:

  • 将开发板连接上电源,并且连接Type-C数据线到PC
  • 按住BOOT键再长按Power键开机(保持按下BOOT键5秒以上),将强制进入MASKROM模式。

一般电脑识别到USB连接,都会发出声音。或者观察虚拟机右下角是否突然多个USB设备:右键点击链接;

6.3 烧录boot.img

使用下载引导命令去使目标机器初始化DDR与运行usbplug(初始化DDR的原因是由于升级需要很大的内存,所以需要使用到DDR);

root@zhengyang:/work/sambashare/rk3399/rkdeveloptool# rkdeveloptool db rk3399_loader_v1.27.126.bin
Downloading bootloader succeeded.

由于BootROM启动会将rk3399_loader_v1.27.126.bin将在到内部SRAM中,然后跳转到ddr.bin代码进行DDR的初始化,ddr.bin执行之后会回跳到BootROM程序,BootROM程序继续加载usbplug.bin,由usbplug.bin完成程序的下载以及烧录到eMMC

使用wl命令烧写镜像到目标机器的eMMC,需要注意的是访问DDR所需的所有其他命令都应在使用db命令之后才能使用;

root@zhengyang:/work/sambashare/rk3399/rkdeveloptool# rkdeveloptool wl 0x40 idbloader.img
Write LBA from file (100%)
root@zhengyang:/work/sambashare/rk3399/rkdeveloptool# rkdeveloptool wl 0x4000 u-boot.itb
Write LBA from file (100%)
root@zhengyang:/work/sambashare/rk3399/rkdeveloptool# rkdeveloptool wl 0x8000 boot.img 
root@zhengyang:/work/sambashare/rk3399/rkdeveloptool# rkdeveloptool wl 0x40000 busybox_ext4_rootfs.img 
root@zhengyang:/work/sambashare/rk3399/rkdeveloptool# rkdeveloptool rd

需要注意我们这里烧录的时内核镜像是boot.img,也就意味着采用distro boot启动方式。

在烧写镜像完成后使用rd命令重启目标机器:

root@zhengyang:/work/sambashare/rk3399/rkdeveloptool# rkdeveloptool rd
Reset Device OK.
6.3.1 设置GPT分区表

重启开发板,在倒计时执行完之前,按CTRL+C即可进入uboot命令行。使用以下命令将分区信息写入GPT分区表:

=> gpt write mmc 0 $partitions
Writing GPT: success!

其中mmc 0表示eMMC设备编号为0partitions是存储分区表的环境变量,定义在include/configs/rockchip-common.h文件:

#ifdef CONFIG_ARM64
#define ROOT_UUID "B921B045-1DF0-41C3-AF44-4C6F280D3FAE;\0"
#else
#define ROOT_UUID "69DAD710-2CE4-4E3C-B16C-21A1D49ABED3;\0"
#endif
#define PARTS_DEFAULT \
        "uuid_disk=${uuid_gpt_disk};" \
        "name=loader1,start=32K,size=4000K,uuid=${uuid_gpt_loader1};" \
        "name=loader2,start=8MB,size=4MB,uuid=${uuid_gpt_loader2};" \
        "name=trust,size=4M,uuid=${uuid_gpt_atf};" \
        "name=boot,size=112M,bootable,uuid=${uuid_gpt_boot};" \
        "name=rootfs,size=-,uuid="ROOT_UUID

通过uboot命令行环境变量可以看到分区信息:

partitions=uuid_disk=${uuid_gpt_disk};  \
    name=loader1,start=32K,size=4000K,uuid=${uuid_gpt_loader1}; \           // eMMC 0x40扇区
    name=loader2,start=8MB,size=4MB,uuid=${uuid_gpt_loader2};   \           // eMMC 0x4000扇区 
    name=trust,size=4M,uuid=${uuid_gpt_atf};  \                             // eMMC 0x6000扇区
    name=boot,size=112M,bootable,uuid=${uuid_gpt_boot}; \                   // eMMC 0x8000扇区 
    name=rootfs,size=-,uuid=B921B045-1DF0-41C3-AF44-4C6F280D3FAE;           // eMMC 0x40000扇区
6.3.2 验证GPT分区表

使用以下命令验证GPT分区表是否成功写入:

=> gpt verify mmc 0 $partitions
Verify GPT: success!
6.3.3 boot命令启动内核

我们在uboot命令行输入boot命令,将会进行内核的启动,输出内容比较多:

U-Boot TPL 2017.09-gef1dd65-dirty #root (May 25 2023 - 20:51:38)
Channel 0: LPDDR3, 800MHz
BW=32 Col=10 Bk=8 CS0 Row=15 CS1 Row=15 CS=2 Die BW=32 Size=2048MB
Channel 1: LPDDR3, 800MHz
BW=32 Col=10 Bk=8 CS0 Row=15 CS1 Row=15 CS=2 Die BW=32 Size=2048MB
256B stride
Returning to boot ROM...
U-Boot SPL board init
U-Boot SPL 2017.09-gef1dd65-dirty #root (May 25 2023 - 20:51:38)
 rockchip_sdhci_probe
Trying to boot from MMC1
Trying fit image at 0x4000 sector
## Verified-boot: 0
## Checking atf@1 0x00040000 ... sha256(5c636c7ea9...) + OK
## Checking uboot 0x00200000 ... sha256(900454cc1d...) + OK
## Checking fdt 0x002d4820 ... sha256(5416082316...) + OK
## Checking atf@2 0xff3b0000 ... sha256(ce42caf496...) + OK
## Checking atf@3 0xff8c0000 ... sha256(68c573972f...) + OK
## Checking atf@4 0xff8c1000 ... sha256(50a7da66c2...) + OK
## Checking atf@5 0xff8c2000 ... sha256(e3b0c44298...) + OK
board_init_r
addr 0x00000000 = 0x14000001
addr 0x00000004 = 0x14000009
addr 0x00000008 = 0x0
addr 0x00040000 = 0xaa0003f4
addr 0x00050018 = 0xb8656883
addr 0xff8c2000 = 0x33334b52
Jumping to U-Boot(0x00200000) via ARM Trusted Firmware(0x00040000)
Total: 921.750 ms

NOTICE:  BL31: v2.8(release):41914de
NOTICE:  BL31: Built : 09:31:58, May 11 2023

U-Boot 2017.09-gef1dd65-dirty #root (May 25 2023 - 20:51:51 +0800)

Model: Rockchip RK3399 Evaluation Board
Serial: raw, 0xff1a0000
DRAM:  3.9 GiB
Sysmem: init
Relocation Offset: f5ba2000
Relocation fdt: f3d89500 - f3d98ce0
CR: M/C/I
I2c0 speed: 400000Hz
PMIC:  RK808
vdd_center init 950000 uV
Using default environment

MMC:    rockchip_sdhci_probe
dwmmc@fe320000: 1, sdhci@fe330000: 0
Card did not respond to voltage select!
mmc_init: -95, time 12
switch to partitions #0, OK
mmc0(part 0) is current device
Bootdev(scan): mmc 0
MMC0: HS400, 150Mhz
PartType: EFI
Could not find baseparameter partition
In:    serial
Out:   serial
Err:   serial
Model: Rockchip RK3399 Evaluation Board
No misc partition
boot mode: None
failed to display uboot logo
CLK: (uboot. arml: enter 816000 KHz, init 816000 KHz, kernel 0N/A)
CLK: (uboot. armb: enter 816000 KHz, init 816000 KHz, kernel 0N/A)
  aplll 816000 KHz
  apllb 816000 KHz
  dpll 800000 KHz
  cpll 24000 KHz
  gpll 800000 KHz
  npll 600000 KHz
  vpll 24000 KHz
  aclk_perihp 133333 KHz
  hclk_perihp 66666 KHz
  pclk_perihp 33333 KHz
  aclk_perilp0 266666 KHz
  hclk_perilp0 88888 KHz
  pclk_perilp0 44444 KHz
  hclk_perilp1 100000 KHz
  pclk_perilp1 50000 KHz
No misc partition
Net:   eth0: ethernet@fe300000
Hit key to stop autoboot('CTRL+C'):  0
=> boot
Could not find misc partition
ANDROID: reboot reason: "(none)"
No valid android hdr
Android image load failed
Android boot failed, error -1.
## Booting FIT Image FIT: No fit blob
do_boot_fit 1
FIT: No FIT image

## Booting Rockchip Format Image
Could not find kernel partition, ret=-1
Card did not respond to voltage select!
mmc_init: -95, time 13
switch to partitions #0, OK
mmc0(part 0) is current device
Scanning mmc 0:4...
Found /extlinux/extlinux.conf
Retrieving file: /extlinux/extlinux.conf
204 bytes read in 3 ms (66.4 KiB/s)
1:      rockchip-kernel-5.2.8
Retrieving file: /Image
20945408 bytes read in 104 ms (192.1 MiB/s)
append: earlycon=uart8250,mmio32,0xff1a0000  console=ttyS2,1500000n8 root=PARTUUID=B921B045-1D rootwait rootfstype=ext4 init=/sbin/init
Retrieving file: /rk3399.dtb
47365 bytes read in 3 ms (15.1 MiB/s)
Fdt Ramdisk skip relocation
No misc partition
## Flattened Device Tree blob at 0x08300000
   Booting using the fdt blob at 0x08300000
   Using Device Tree in place at 0000000008300000, end 000000000830e904
can't found rockchip,drm-logo, use rockchip,fb-logo
WARNING: could not set reg FDT_ERR_BADOFFSET.
failed to reserve fb-loader-logo memory
Adding bank: 0x00200000 - 0xf8000000 (size: 0xf7e00000)
Total: 8842.674 ms

Starting kernel ...

[    0.000000] Booting Linux on physical CPU 0x0000000000 [0x410fd034]
[    0.000000] Linux version 5.2.8 (root@zhengyang) (gcc version 12.2.1 20221205 (Arm GNU Toolchain 12.2.Rel1 (Build arm-12.24))) #2 SMP PREEMPT Tue May 23 20:59:23 CST 2023
[    0.000000] Machine model: Rockchip RK3399 Evaluation Board
[    0.000000] earlycon: uart8250 at MMIO32 0x00000000ff1a0000 (options '')
[    0.000000] printk: bootconsole [uart8250] enabled
[    0.000000] efi: Getting EFI parameters from FDT:
[    0.000000] efi: UEFI not found.
[    0.000000] cma: Reserved 32 MiB at 0x00000000f6000000
[    0.000000] kmemleak: Kernel memory leak detector disabled
[    0.000000] NUMA: No NUMA configuration found
[    0.000000] NUMA: Faking a node at [mem 0x0000000000200000-0x00000000f7ffffff]
[    0.000000] NUMA: NODE_DATA [mem 0xf57fb840-0xf57fcfff]
[    0.000000] Zone ranges:
[    0.000000]   DMA32    [mem 0x0000000000200000-0x00000000f7ffffff]
[    0.000000]   Normal   empty
[    0.000000] Movable zone start for each node
[    0.000000] Early memory node ranges
[    0.000000]   node   0: [mem 0x0000000000200000-0x00000000f7ffffff]
[    0.000000] Initmem setup node 0 [mem 0x0000000000200000-0x00000000f7ffffff]
[    0.000000] psci: probing for conduit method from DT.
[    0.000000] psci: PSCIv1.1 detected in firmware.
[    0.000000] psci: Using standard PSCI v0.2 function IDs
[    0.000000] psci: MIGRATE_INFO_TYPE not supported.
[    0.000000] psci: SMC Calling Convention v1.0
[    0.000000] percpu: Embedded 23 pages/cpu s56728 r8192 d29288 u94208
[    0.000000] Detected VIPT I-cache on CPU0
[    0.000000] CPU features: detected: ARM erratum 845719
[    0.000000] CPU features: detected: GIC system register CPU interface
[    0.000000] Built 1 zonelists, mobility grouping on.  Total pages: 999432
[    0.000000] Policy zone: DMA32
[    0.000000] Kernel command line: earlycon=uart8250,mmio32,0xff1a0000  console=ttyS2,1500000n8 root=PARTUUID=B921B045-1D rw rootwait rootfstype=ext4 init=/sbin/init
[    0.000000] Memory: 3933112K/4061184K available (11324K kernel code, 1766K rwdata, 5836K rodata, 1472K init, 444K bss, 95304K reserved, 32768K cma-reserved)
[    0.000000] SLUB: HWalign=64, Order=0-3, MinObjects=0, CPUs=6, Nodes=1
[    0.000000] rcu: Preemptible hierarchical RCU implementation.
[    0.000000] rcu:     RCU restricting CPUs from NR_CPUS=256 to nr_cpu_ids=6.
[    0.000000]  Tasks RCU enabled.
[    0.000000] rcu: RCU calculated value of scheduler-enlistment delay is 25 jiffies.
[    0.000000] rcu: Adjusting geometry for rcu_fanout_leaf=16, nr_cpu_ids=6
[    0.000000] NR_IRQS: 64, nr_irqs: 64, preallocated irqs: 0
[    0.000000] GICv3: GIC: Using split EOI/Deactivate mode
[    0.000000] GICv3: Distributor has no Range Selector support
[    0.000000] GICv3: no VLPI support, no direct LPI support
[    0.000000] GICv3: CPU0: found redistributor 0 region 0:0x00000000fef00000
[    0.000000] ITS [mem 0xfee20000-0xfee3ffff]
[    0.000000] ITS@0x00000000fee20000: allocated 65536 Devices @f1080000 (flat, esz 8, psz 64K, shr 0)
[    0.000000] ITS: using cache flushing for cmd queue
[    0.000000] GICv3: using LPI property table @0x00000000f1040000
[    0.000000] GIC: using cache flushing for LPI property table
[    0.000000] GICv3: CPU0: using allocated LPI pending table @0x00000000f1050000
[    0.000000] GICv3: GIC: PPI partition interrupt-partition-0[0] { /cpus/cpu@0[0] /cpus/cpu@1[1] /cpus/cpu@2[2] /cpus/cpu@3[3] }
[    0.000000] GICv3: GIC: PPI partition interrupt-partition-1[1] { /cpus/cpu@100[4] /cpus/cpu@101[5] }
[    0.000000] random: get_random_bytes called from start_kernel+0x2a8/0x440 with crng_init=0
[    0.000000] rockchip_mmc_get_phase: invalid clk rate
[    0.000000] rockchip_mmc_get_phase: invalid clk rate
[    0.000000] rockchip_mmc_get_phase: invalid clk rate
[    0.000000] rockchip_mmc_get_phase: invalid clk rate
[    0.000000] arch_timer: cp15 timer(s) running at 24.00MHz (phys).
[    0.000000] clocksource: arch_sys_counter: mask: 0xffffffffffffff max_cycles: 0x588fe9dc0, max_idle_ns: 440795202592 ns
[    0.000005] sched_clock: 56 bits at 24MHz, resolution 41ns, wraps every 4398046511097ns
[    0.010210] Console: colour dummy device 80x25
[    0.015130] kmemleak: Early log buffer exceeded (4684), please increase DEBUG_KMEMLEAK_EARLY_LOG_SIZE
[    0.025317] Calibrating delay loop (skipped), value calculated using timer frequency.. 48.00 BogoMIPS (lpj=96000)
[    0.036588] pid_max: default: 32768 minimum: 301
[    0.041738] LSM: Security Framework initializing
[    0.048451] Dentry cache hash table entries: 524288 (order: 10, 4194304 bytes)
[    0.057192] Inode-cache hash table entries: 262144 (order: 9, 2097152 bytes)
[    0.064982] Mount-cache hash table entries: 8192 (order: 4, 65536 bytes)
[    0.072380] Mountpoint-cache hash table entries: 8192 (order: 4, 65536 bytes)
[    0.104306] ASID allocator initialised with 32768 entries
[    0.118264] rcu: Hierarchical SRCU implementation.
[    0.131636] Platform MSI: interrupt-controller@fee20000 domain created
[    0.139066] PCI/MSI: /interrupt-controller@fee00000/interrupt-controller@fee20000 domain created
[    0.151625] EFI services will not be available.
[    0.164627] smp: Bringing up secondary CPUs ...
[    0.201789] Detected VIPT I-cache on CPU1
[    0.201821] GICv3: CPU1: found redistributor 1 region 0:0x00000000fef20000
[    0.201834] GICv3: CPU1: using allocated LPI pending table @0x00000000f1060000
[    0.201873] CPU1: Booted secondary processor 0x0000000001 [0x410fd034]
[    0.233839] Detected VIPT I-cache on CPU2
[    0.233861] GICv3: CPU2: found redistributor 2 region 0:0x00000000fef40000
[    0.233872] GICv3: CPU2: using allocated LPI pending table @0x00000000f1070000
[    0.233898] CPU2: Booted secondary processor 0x0000000002 [0x410fd034]
[    0.265908] Detected VIPT I-cache on CPU3
[    0.265928] GICv3: CPU3: found redistributor 3 region 0:0x00000000fef60000
[    0.265939] GICv3: CPU3: using allocated LPI pending table @0x00000000f1100000
[    0.265962] CPU3: Booted secondary processor 0x0000000003 [0x410fd034]
[    0.297987] CPU features: detected: EL2 vector hardening
[    0.297992] ARM_SMCCC_ARCH_WORKAROUND_1 missing from firmware
[    0.297998] Detected PIPT I-cache on CPU4
[    0.298023] GICv3: CPU4: found redistributor 100 region 0:0x00000000fef80000
[    0.298034] GICv3: CPU4: using allocated LPI pending table @0x00000000f1110000
[    0.298061] CPU4: Booted secondary processor 0x0000000100 [0x410fd082]
[    0.330060] Detected PIPT I-cache on CPU5
[    0.330078] GICv3: CPU5: found redistributor 101 region 0:0x00000000fefa0000
[    0.330089] GICv3: CPU5: using allocated LPI pending table @0x00000000f1120000
[    0.330110] CPU5: Booted secondary processor 0x0000000101 [0x410fd082]
[    0.330195] smp: Brought up 1 node, 6 CPUs
[    0.482328] SMP: Total of 6 processors activated.
[    0.487494] CPU features: detected: 32-bit EL0 Support
[    0.493154] CPU features: detected: CRC32 instructions
[    0.499591] CPU: All CPU(s) started at EL2
[    0.504131] alternatives: patching kernel code
[    0.511658] devtmpfs: initialized
[    0.521401] clocksource: jiffies: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 7645041785100000 ns
[    0.532153] futex hash table entries: 2048 (order: 5, 131072 bytes)
[    0.539757] pinctrl core: initialized pinctrl subsystem
[    0.546795] DMI not present or invalid.
[    0.551385] NET: Registered protocol family 16
[    0.556675] audit: initializing netlink subsys (disabled)
[    0.562708] audit: type=2000 audit(0.436:1): state=initialized audit_enabled=0 res=1
[    0.571254] cpuidle: using governor menu
[    0.575737] hw-breakpoint: found 6 breakpoint and 4 watchpoint registers.
[    0.588022] DMA: preallocated 256 KiB pool for atomic allocations
[    0.595917] Serial: AMBA PL011 UART driver
[    0.629686] HugeTLB registered 1.00 GiB page size, pre-allocated 0 pages
[    0.637059] HugeTLB registered 32.0 MiB page size, pre-allocated 0 pages
[    0.644438] HugeTLB registered 2.00 MiB page size, pre-allocated 0 pages
[    0.651795] HugeTLB registered 64.0 KiB page size, pre-allocated 0 pages
[    0.661374] cryptd: max_cpu_qlen set to 1000
[    0.670618] ACPI: Interpreter disabled.
[    0.676345] vcc5v0_host: supplied by vcc5v0_sys
[    0.683098] vgaarb: loaded
[    0.686335] SCSI subsystem initialized
[    0.690832] usbcore: registered new interface driver usbfs
[    0.696950] usbcore: registered new interface driver hub
[    0.702855] usbcore: registered new device driver usb
[    0.709212] pps_core: LinuxPPS API ver. 1 registered
[    0.714722] pps_core: Software ver. 5.3.6 - Copyright 2005-2007 Rodolfo Giometti <giometti@linux.it>
[    0.724769] PTP clock support registered
[    0.729207] EDAC MC: Ver: 3.0.0
[    0.733803] FPGA manager framework
[    0.737647] Advanced Linux Sound Architecture Driver Initialized.
[    0.744843] clocksource: Switched to clocksource arch_sys_counter
[    0.751682] VFS: Disk quotas dquot_6.6.0
[    0.756035] VFS: Dquot-cache hash table entries: 512 (order 0, 4096 bytes)
[    0.763739] pnp: PnP ACPI: disabled
[    0.774794] NET: Registered protocol family 2
[    0.779903] tcp_listen_portaddr_hash hash table entries: 2048 (order: 3, 32768 bytes)
[    0.788617] TCP established hash table entries: 32768 (order: 6, 262144 bytes)
[    0.796898] TCP bind hash table entries: 32768 (order: 7, 524288 bytes)
[    0.804683] TCP: Hash tables configured (established 32768 bind 32768)
[    0.811979] UDP hash table entries: 2048 (order: 4, 65536 bytes)
[    0.818685] UDP-Lite hash table entries: 2048 (order: 4, 65536 bytes)
[    0.826011] NET: Registered protocol family 1
[    0.831125] RPC: Registered named UNIX socket transport module.
[    0.837822] RPC: Registered udp transport module.
[    0.842988] RPC: Registered tcp transport module.
[    0.848153] RPC: Registered tcp NFSv4.1 backchannel transport module.
[    0.855229] PCI: CLS 0 bytes, default 64
[    0.860245] hw perfevents: enabled with armv8_cortex_a53 PMU driver, 7 counters available
[    0.869489] hw perfevents: enabled with armv8_cortex_a72 PMU driver, 7 counters available
[    0.878720] kvm [1]: IPA Size Limit: 40bits
[    0.883831] kvm [1]: vgic-v2@fff20000
[    0.887871] kvm [1]: GIC system register CPU interface enabled
[    0.894409] kvm [1]: vgic interrupt IRQ10
[    0.898990] kvm [1]: Hyp mode initialized successfully
[    0.912062] Initialise system trusted keyrings
[    0.917100] workingset: timestamp_bits=44 max_order=20 bucket_order=0
[    0.930050] squashfs: version 4.0 (2009/01/31) Phillip Lougher
[    0.937099] NFS: Registering the id_resolver key type
[    0.942663] Key type id_resolver registered
[    0.947254] Key type id_legacy registered
[    0.951791] 9p: Installing v9fs 9p2000 file system support
[    0.958926] Key type asymmetric registered
[    0.963434] Asymmetric key parser 'x509' registered
[    0.968822] Block layer SCSI generic (bsg) driver version 0.4 loaded (major 245)
[    0.976947] io scheduler mq-deadline registered
[    0.981921] io scheduler kyber registered
[    0.999882] EINJ: ACPI disabled.
[    1.009768] dma-pl330 ff6d0000.dma-controller: Loaded driver for PL330 DMAC-241330
[    1.018096] dma-pl330 ff6d0000.dma-controller:       DBUFF-32x8bytes Num_Chans-6 Num_Peri-12 Num_Events-12
[    1.029384] dma-pl330 ff6e0000.dma-controller: Loaded driver for PL330 DMAC-241330
[    1.037715] dma-pl330 ff6e0000.dma-controller:       DBUFF-128x8bytes Num_Chans-8 Num_Peri-20 Num_Events-16
[    1.051833] pwm-regulator: supplied by regulator-dummy
[    1.061368] Serial: 8250/16550 driver, 4 ports, IRQ sharing enabled
[    1.070090] printk: console [ttyS2] disabled
[    1.074831] ff1a0000.serial: ttyS2 at MMIO 0xff1a0000 (irq = 30, base_baud = 1500000) is a 16550A
[    1.084727] printk: console [ttyS2] enabled
[    1.084727] printk: console [ttyS2] enabled
[    1.094100] printk: bootconsole [uart8250] disabled
[    1.094100] printk: bootconsole [uart8250] disabled
[    1.106191] SuperH (H)SCI(F) driver initialized
[    1.111853] msm_serial: driver initialized
[    1.117561] cacheinfo: Unable to detect cache hierarchy for CPU 0
[    1.130723] loop: module loaded
[    1.138942] libphy: Fixed MDIO Bus: probed
[    1.143793] tun: Universal TUN/TAP device driver, 1.6
[    1.150296] thunder_xcv, ver 1.0
[    1.153950] thunder_bgx, ver 1.0
[    1.157584] nicpf, ver 1.0
[    1.161283] hclge is initializing
[    1.164996] hns3: Hisilicon Ethernet Network Driver for Hip08 Family - version
[    1.173074] hns3: Copyright (c) 2017 Huawei Corporation.
[    1.179072] e1000e: Intel(R) PRO/1000 Network Driver - 3.2.6-k
[    1.185598] e1000e: Copyright(c) 1999 - 2015 Intel Corporation.
[    1.192250] igb: Intel(R) Gigabit Ethernet Network Driver - version 5.6.0-k
[    1.200035] igb: Copyright (c) 2007-2014 Intel Corporation.
[    1.206301] igbvf: Intel(R) Gigabit Virtual Function Network Driver - version 2.4.0-k
[    1.215058] igbvf: Copyright (c) 2009 - 2012 Intel Corporation.
[    1.222064] sky2: driver version 1.30
[    1.226917] VFIO - User Level meta-driver version: 0.3
[    1.234341] ehci_hcd: USB 2.0 'Enhanced' Host Controller (EHCI) Driver
[    1.241654] ehci-pci: EHCI PCI platform driver
[    1.246655] ehci-platform: EHCI generic platform driver
[    1.254702] ehci-platform fe380000.usb: EHCI Host Controller
[    1.261053] ehci-platform fe380000.usb: new USB bus registered, assigned bus number 1
[    1.270465] ehci-platform fe380000.usb: irq 26, io mem 0xfe380000
[    1.292861] ehci-platform fe380000.usb: USB 2.0 started, EHCI 1.00
[    1.300232] hub 1-0:1.0: USB hub found
[    1.304451] hub 1-0:1.0: 1 port detected
[    1.311237] ehci-platform fe3c0000.usb: EHCI Host Controller
[    1.317590] ehci-platform fe3c0000.usb: new USB bus registered, assigned bus number 2
[    1.326551] ehci-platform fe3c0000.usb: irq 28, io mem 0xfe3c0000
[    1.348863] ehci-platform fe3c0000.usb: USB 2.0 started, EHCI 1.00
[    1.356191] hub 2-0:1.0: USB hub found
[    1.360410] hub 2-0:1.0: 1 port detected
[    1.365174] ehci-orion: EHCI orion driver
[    1.369817] ehci-exynos: EHCI EXYNOS driver
[    1.374597] ohci_hcd: USB 1.1 'Open' Host Controller (OHCI) Driver
[    1.381523] ohci-pci: OHCI PCI platform driver
[    1.386543] ohci-platform: OHCI generic platform driver
[    1.392534] ohci-platform fe3a0000.usb: Generic Platform OHCI controller
[    1.400044] ohci-platform fe3a0000.usb: new USB bus registered, assigned bus number 3
[    1.409015] ohci-platform fe3a0000.usb: irq 27, io mem 0xfe3a0000
[    1.477372] hub 3-0:1.0: USB hub found
[    1.481593] hub 3-0:1.0: 1 port detected
[    1.486344] ohci-platform fe3e0000.usb: Generic Platform OHCI controller
[    1.493856] ohci-platform fe3e0000.usb: new USB bus registered, assigned bus number 4
[    1.502774] ohci-platform fe3e0000.usb: irq 29, io mem 0xfe3e0000
[    1.573281] hub 4-0:1.0: USB hub found
[    1.577506] hub 4-0:1.0: 1 port detected
[    1.582250] ohci-exynos: OHCI EXYNOS driver
[    1.587560] usbcore: registered new interface driver usb-storage
[    1.597324] i2c /dev entries driver
[    1.607951] sdhci: Secure Digital Host Controller Interface driver
[    1.614864] sdhci: Copyright(c) Pierre Ossman
[    1.620222] Synopsys Designware Multimedia Card Interface Driver
[    1.627946] sdhci-pltfm: SDHCI platform and OF driver helper
[    1.635763] mmc0: CQHCI version 5.10
[    1.665711] mmc0: SDHCI controller on fe330000.sdhci [fe330000.sdhci] using ADMA
[    1.675725] ledtrig-cpu: registered to indicate activity on CPUs
[    1.683873] usbcore: registered new interface driver usbhid
[    1.690167] usbhid: USB HID core driver
[    1.698423] NET: Registered protocol family 17
[    1.703575] 9pnet: Installing 9P2000 support
[    1.708396] Key type dns_resolver registered
[    1.714078] registered taskstats version 1
[    1.718701] Loading compiled-in X.509 certificates
[    1.744185] hctosys: unable to open rtc device (rtc0)
[    1.750572] ALSA device list:
[    1.753925]   No soundcards found.
[    1.757934] ttyS2 - failed to request DMA
[    1.762531] Waiting for root device PARTUUID=B921B045-1D...
[    1.787575] mmc0: Command Queue Engine enabled
[    1.792572] mmc0: new HS400 Enhanced strobe MMC card at address 0001
[    1.804391] mmcblk0: mmc0:0001 AJNB4R 14.6 GiB
[    1.809668] mmcblk0boot0: mmc0:0001 AJNB4R partition 1 4.00 MiB
[    1.816490] mmcblk0boot1: mmc0:0001 AJNB4R partition 2 4.00 MiB
[    1.823672] mmcblk0rpmb: mmc0:0001 AJNB4R partition 3 4.00 MiB, chardev (237:0)
[    1.836490]  mmcblk0: p1 p2 p3 p4 p5
[    1.856037] EXT4-fs (mmcblk0p5): mounted filesystem with ordered data mode. Opts: (null)
[    1.865144] VFS: Mounted root (ext4 filesystem) on device 179:5.
[    1.873579] devtmpfs: mounted
[    1.877696] Freeing unused kernel memory: 1472K
[    1.921261] Run /sbin/init as init process
[    1.985061] usb 4-1: new low-speed USB device number 2 using ohci-platform

Please press Enter to activate this console. [    2.229953] input: SIGMACHIP Usb Mouse as /devices/platform/fe3e0000.usb/usb4/4-1/4-1:1.0/0003:1C4F:0065.0001/input/input0
[    2.242646] hid-generic 0003:1C4F:0065.0001: input: USB HID v1.10 Mouse [SIGMACHIP Usb Mouse] on usb-fe3e0000.usb-1/input0
[    4.628916] usb 4-1: USB disconnect, device number 2
[    5.017065] usb 4-1: new low-speed USB device number 3 using ohci-platform
[    5.261859] input: SIGMACHIP Usb Mouse as /devices/platform/fe3e0000.usb/usb4/4-1/4-1:1.0/0003:1C4F:0065.0002/input/input1
[    5.274573] hid-generic 0003:1C4F:0065.0002: input: USB HID v1.10 Mouse [SIGMACHIP Usb Mouse] on usb-fe3e0000.usb-1/input0
[    7.663956] usb 4-1: USB disconnect, device number 3
[    7.720959] random: fast init done
[    8.053066] usb 4-1: new low-speed USB device number 4 using ohci-platform
[    8.297920] input: SIGMACHIP Usb Mouse as /devices/platform/fe3e0000.usb/usb4/4-1/4-1:1.0/0003:1C4F:0065.0003/input/input2
[    8.310618] hid-generic 0003:1C4F:0065.0003: input: USB HID v1.10 Mouse [SIGMACHIP Usb Mouse] on usb-fe3e0000.usb-1/input0
[   10.699883] usb 4-1: USB disconnect, device number 4
[   11.089066] usb 4-1: new low-speed USB device number 5 using ohci-platform
[   11.333832] input: SIGMACHIP Usb Mouse as /devices/platform/fe3e0000.usb/usb4/4-1/4-1:1.0/0003:1C4F:0065.0004/input/input3
[   11.346505] hid-generic 0003:1C4F:0065.0004: input: USB HID v1.10 Mouse [SIGMACHIP Usb Mouse] on usb-fe3e0000.usb-1/input0
[   13.736998] usb 4-1: USB disconnect, device number 5
[   14.105066] usb 4-1: new low-speed USB device number 6 using ohci-platform
[   14.349886] input: SIGMACHIP Usb Mouse as /devices/platform/fe3e0000.usb/usb4/4-1/4-1:1.0/0003:1C4F:0065.0005/input/input4
[   14.362579] hid-generic 0003:1C4F:0065.0005: input: USB HID v1.10 Mouse [SIGMACHIP Usb Mouse] on usb-fe3e0000.usb-1/input0
[   17.735239] usb 4-1: USB disconnect, device number 6
[   18.145064] usb 4-1: new low-speed USB device number 7 using ohci-platform
[   18.388670] input: SIGMACHIP Usb Mouse as /devices/platform/fe3e0000.usb/usb4/4-1/4-1:1.0/0003:1C4F:0065.0006/input/input5
[   18.401560] hid-generic 0003:1C4F:0065.0006: input: USB HID v1.10 Mouse [SIGMACHIP Usb Mouse] on usb-fe3e0000.usb-1/input0

6.4 烧录kernel.itb

使用下载引导命令去使目标机器初始化DDR与运行usbplug(初始化DDR的原因是由于升级需要很大的内存,所以需要使用到DDR);

root@zhengyang:/work/sambashare/rk3399/rkdeveloptool# rkdeveloptool db rk3399_loader_v1.27.126.bin
Downloading bootloader succeeded.

由于BootROM启动会将rk3399_loader_v1.27.126.bin将在到内部SRAM中,然后跳转到ddr.bin代码进行DDR的初始化,ddr.bin执行之后会回跳到BootROM程序,BootROM程序继续加载usbplug.bin,由usbplug.bin完成程序的下载以及烧录到eMMC

使用wl命令烧写镜像到目标机器的eMMC,需要注意的是访问DDR所需的所有其他命令都应在使用db命令之后才能使用;

root@zhengyang:/work/sambashare/rk3399/rkdeveloptool# rkdeveloptool wl 0x40 idbloader.img
Write LBA from file (100%)
root@zhengyang:/work/sambashare/rk3399/rkdeveloptool# rkdeveloptool wl 0x4000 u-boot.itb
Write LBA from file (100%)
root@zhengyang:/work/sambashare/rk3399/rkdeveloptool# rkdeveloptool wl 0x8000 kernel.itb
root@zhengyang:/work/sambashare/rk3399/rkdeveloptool# rkdeveloptool wl 0x40000 busybox_ext4_rootfs.img 
root@zhengyang:/work/sambashare/rk3399/rkdeveloptool# rkdeveloptool rd

需要注意我们这里烧录的时内核镜像是kernel.itb,也就意味着采用boo_fit启动方式。

在烧写镜像完成后使用rd命令重启目标机器:

root@zhengyang:/work/sambashare/rk3399/rkdeveloptool# rkdeveloptool rd
Reset Device OK.
6.4.1 设置GPT分区表

重启开发板,在倒计时执行完之前,按CTRL+C即可进入uboot命令行。使用以下命令将分区信息写入GPT分区表:

=> gpt write mmc 0 $partitions
Writing GPT: success!
6.4.2 验证GPT分区表

使用以下命令验证GPT分区表是否成功写入:

=> gpt verify mmc 0 $partitions
Verify GPT: success!
6.4.3 设置ip以及bootargs

这里我们这是本机和服务器的ip地址:

=> setenv ipaddr 192.168.0.105
=> setenv serverip 192.168.0.200
=> saveenv
Saving Environment to MMC... Writing to MMC(0)... OK

设置启动命令参数:

=> setenv bootargs earlycon=uart8250,mmio32,0xff1a0000 console=ttyS2,1500000n8 root=PARTUUID=B921B045-1D rw rootwait rootfstype=ext4 init=/sbin/init
=> saveenv
Saving Environment to MMC... Writing to MMC(0)... OK
=> print bootargs
bootargs=earlycon=uart8250,mmio32,0xff1a0000 console=ttyS2,1500000n8 root=PARTUUID=B921B045-1D rw rootwait rootfstype=ext4 init=/sbin/init
6.4.4 boot_fit命令启动内核

我们在uboot命令行输入boot_fit命令,将会进行内核的启动,输出内容比较多:

=> boot_fit
## Booting FIT Image fdt_image_get_offset_size noffset=464
fdt_image_get_offset_size sz=47365
fdt_image_get_offset_size offs=8648704
fdt_image_get_offset_size noffset=148
fdt_image_get_offset_size sz=8648300
fdt_image_get_offset_size offs=0
fdt_image_get_offset_size noffset=760
fdt_image_get_offset_size sz=134661
fdt_image_get_offset_size offs=8696320
fdt_image_get_offset_size noffset=464
fdt_image_get_offset_size sz=47365
fdt_image_get_offset_size offs=8648704
fit_image_fixup_alloc fdt offset=0x83f800,size=47365,fit=0xf331bf00,load=0x8300000
fit_image_fixup_alloc fdt addr=0x8300000
fdt_image_get_offset_size noffset=148
fdt_image_get_offset_size sz=8648300
fdt_image_get_offset_size offs=0
fit_image_fixup_alloc kernel offset=0x0,size=8648300,fit=0xf331bf00,load=0x280000
fit_image_fixup_alloc kernel addr=0x280000
fdt_image_get_offset_size noffset=760
fdt_image_get_offset_size sz=134661
fdt_image_get_offset_size offs=8696320
fit_image_fixup_alloc ramdisk offset=0x84b200,size=134661,fit=0xf331bf00,load=0x0
fit_image_fixup_alloc ramdisk addr=0xa200000
at 0xf331bf00 with size 0x0086c800
Fdt Ramdisk skip relocation
No misc partition
## Loading kernel from FIT Image at f331bf00 ...
   Using 'conf-1' configuration
## Verified-boot: 0
   Trying 'kernel' kernel subimage
     Description:  Vanilla Linux kernel
     Type:         Kernel Image
     Compression:  gzip compressed
     Data Start:   0xf331c500
     Data Size:    8648300 Bytes = 8.2 MiB
     Architecture: AArch64
     OS:           Linux
     Load Address: 0x00280000
     Entry Point:  0x00280000
     Hash algo:    crc32
     Hash value:   6470c524
     Hash algo:    sha1
     Hash value:   b0f2e3608a5689b77fc110e7c399cf6a0398c691
   Verifying Hash Integrity ... crc32+ sha1+ OK
## Loading ramdisk from FIT Image at f331bf00 ...
   Using 'conf-1' configuration
   Trying 'ramdisk' ramdisk subimage
     Description:  Ramdisk for project-x
     Type:         RAMDisk Image
     Compression:  gzip compressed
     Data Start:   0xf3b67700
     Data Size:    134661 Bytes = 131.5 KiB
     Architecture: AArch64
     OS:           Linux
     Load Address: 0x00000000
     Entry Point:  0x00000000
     Hash algo:    crc32
     Hash value:   649c78d3
   Verifying Hash Integrity ... crc32+ OK
## Loading fdt from FIT Image at f331bf00 ...
   Using 'conf-1' configuration
   Trying 'fdt' fdt subimage
     Description:  Flattened Device Tree blob
     Type:         Flat Device Tree
     Compression:  uncompressed
     Data Start:   0xf3b5bd00
     Data Size:    47365 Bytes = 46.3 KiB
     Architecture: AArch64
     Load Address: 0x08300000
     Hash algo:    crc32
     Hash value:   2489ab59
     Hash algo:    sha1
     Hash value:   002b18a40044056ce9097742d3cf5f4480338521
   Verifying Hash Integrity ... crc32+ sha1+ OK
   Loading fdt from 0xf3b5bd00 to 0x08300000
   Booting using the fdt blob at 0x08300000
   Uncompressing GZIP Kernel Image from 0xf331c500 to 0x00280000 ... with 013f9a00 bytes OK
   kernel loaded at 0x00280000, end = 0x01679a00
   Using Device Tree in place at 0000000008300000, end 000000000830e904
can't found rockchip,drm-logo, use rockchip,fb-logo
WARNING: could not set reg FDT_ERR_BADOFFSET.
failed to reserve fb-loader-logo memory
Adding bank: 0x00200000 - 0xf8000000 (size: 0xf7e00000)
## Transferring control to Linux (at address 280000)...
boot_jump_linux 0x280000=0x91005a4d
boot_jump_linux 0x280004=0x14433fff
boot_jump_linux 0x280014=0x0
boot_jump_linux 0x8300000=0xedfe0dd0
boot_jump_linux 0x8300004=0x80c00000
boot_jump_linux 0x8300014=0x11000000
Total: 13990.773 ms

Starting kernel ...

4
[    0.000000] Booting Linux on physical CPU 0x0000000000 [0x410fd034]
[    0.000000] Linux version 5.2.8 (root@zhengyang) (gcc version 12.2.1 20221205 (Arm GNU Toolchain 12.2.Rel1 (Build arm-12.24))) #2 SMP PREEMPT Tue May 23 20:59:23 CST 2023
[    0.000000] Machine model: Rockchip RK3399 Evaluation Board
[    0.000000] earlycon: uart8250 at MMIO32 0x00000000ff1a0000 (options '')
[    0.000000] printk: bootconsole [uart8250] enabled
[    0.000000] efi: Getting EFI parameters from FDT:
[    0.000000] efi: UEFI not found.
[    0.000000] cma: Reserved 32 MiB at 0x00000000f6000000
[    0.000000] kmemleak: Kernel memory leak detector disabled
[    0.000000] NUMA: No NUMA configuration found
[    0.000000] NUMA: Faking a node at [mem 0x0000000000200000-0x00000000f7ffffff]
[    0.000000] NUMA: NODE_DATA [mem 0xf57fb840-0xf57fcfff]
[    0.000000] Zone ranges:
[    0.000000]   DMA32    [mem 0x0000000000200000-0x00000000f7ffffff]
[    0.000000]   Normal   empty
[    0.000000] Movable zone start for each node
[    0.000000] Early memory node ranges
[    0.000000]   node   0: [mem 0x0000000000200000-0x00000000f7ffffff]
[    0.000000] Initmem setup node 0 [mem 0x0000000000200000-0x00000000f7ffffff]
[    0.000000] psci: probing for conduit method from DT.
[    0.000000] psci: PSCIv1.1 detected in firmware.
[    0.000000] psci: Using standard PSCI v0.2 function IDs
[    0.000000] psci: MIGRATE_INFO_TYPE not supported.
[    0.000000] psci: SMC Calling Convention v1.0
[    0.000000] percpu: Embedded 23 pages/cpu s56728 r8192 d29288 u94208
[    0.000000] Detected VIPT I-cache on CPU0
[    0.000000] CPU features: detected: ARM erratum 845719
[    0.000000] CPU features: detected: GIC system register CPU interface
[    0.000000] Built 1 zonelists, mobility grouping on.  Total pages: 999432
[    0.000000] Policy zone: DMA32
[    0.000000] Kernel command line: earlycon=uart8250,mmio32,0xff1a0000 console=ttyS2,1500000n8 root=PARTUUID=B921B045-1D rw rootwait rootfstype=ext4 init=/sbin/init
[    0.000000] Memory: 3932392K/4061184K available (11324K kernel code, 1766K rwdata, 5836K rodata, 1472K init, 444K bss, 96024K reserved, 32768K cma-reserved)
[    0.000000] SLUB: HWalign=64, Order=0-3, MinObjects=0, CPUs=6, Nodes=1
[    0.000000] rcu: Preemptible hierarchical RCU implementation.
[    0.000000] rcu:     RCU restricting CPUs from NR_CPUS=256 to nr_cpu_ids=6.
[    0.000000]  Tasks RCU enabled.
[    0.000000] rcu: RCU calculated value of scheduler-enlistment delay is 25 jiffies.
[    0.000000] rcu: Adjusting geometry for rcu_fanout_leaf=16, nr_cpu_ids=6
[    0.000000] NR_IRQS: 64, nr_irqs: 64, preallocated irqs: 0
[    0.000000] GICv3: GIC: Using split EOI/Deactivate mode
[    0.000000] GICv3: Distributor has no Range Selector support
[    0.000000] GICv3: no VLPI support, no direct LPI support
[    0.000000] GICv3: CPU0: found redistributor 0 region 0:0x00000000fef00000
[    0.000000] ITS [mem 0xfee20000-0xfee3ffff]
[    0.000000] ITS@0x00000000fee20000: allocated 65536 Devices @f5080000 (flat, esz 8, psz 64K, shr 0)
[    0.000000] ITS: using cache flushing for cmd queue
[    0.000000] GICv3: using LPI property table @0x00000000f5040000
[    0.000000] GIC: using cache flushing for LPI property table
[    0.000000] GICv3: CPU0: using allocated LPI pending table @0x00000000f5050000
[    0.000000] GICv3: GIC: PPI partition interrupt-partition-0[0] { /cpus/cpu@0[0] /cpus/cpu@1[1] /cpus/cpu@2[2] /cpus/cpu@3[3] }
[    0.000000] GICv3: GIC: PPI partition interrupt-partition-1[1] { /cpus/cpu@100[4] /cpus/cpu@101[5] }
[    0.000000] random: get_random_bytes called from start_kernel+0x2a8/0x440 with crng_init=0
[    0.000000] rockchip_mmc_get_phase: invalid clk rate
[    0.000000] rockchip_mmc_get_phase: invalid clk rate
[    0.000000] rockchip_mmc_get_phase: invalid clk rate
[    0.000000] rockchip_mmc_get_phase: invalid clk rate
[    0.000000] arch_timer: cp15 timer(s) running at 24.00MHz (phys).
[    0.000000] clocksource: arch_sys_counter: mask: 0xffffffffffffff max_cycles: 0x588fe9dc0, max_idle_ns: 440795202592 ns
[    0.000005] sched_clock: 56 bits at 24MHz, resolution 41ns, wraps every 4398046511097ns
[    0.010121] Console: colour dummy device 80x25
[    0.015042] kmemleak: Early log buffer exceeded (4684), please increase DEBUG_KMEMLEAK_EARLY_LOG_SIZE
[    0.025233] Calibrating delay loop (skipped), value calculated using timer frequency.. 48.00 BogoMIPS (lpj=96000)
[    0.036504] pid_max: default: 32768 minimum: 301
[    0.041653] LSM: Security Framework initializing
[    0.048374] Dentry cache hash table entries: 524288 (order: 10, 4194304 bytes)
[    0.057122] Inode-cache hash table entries: 262144 (order: 9, 2097152 bytes)
[    0.064911] Mount-cache hash table entries: 8192 (order: 4, 65536 bytes)
[    0.072307] Mountpoint-cache hash table entries: 8192 (order: 4, 65536 bytes)
[    0.104234] ASID allocator initialised with 32768 entries
[    0.118192] rcu: Hierarchical SRCU implementation.
[    0.131559] Platform MSI: interrupt-controller@fee20000 domain created
[    0.138983] PCI/MSI: /interrupt-controller@fee00000/interrupt-controller@fee20000 domain created
[    0.151314] EFI services will not be available.
[    0.164315] smp: Bringing up secondary CPUs ...
[    0.201476] Detected VIPT I-cache on CPU1
[    0.201508] GICv3: CPU1: found redistributor 1 region 0:0x00000000fef20000
[    0.201521] GICv3: CPU1: using allocated LPI pending table @0x00000000f5060000
[    0.201559] CPU1: Booted secondary processor 0x0000000001 [0x410fd034]
[    0.233526] Detected VIPT I-cache on CPU2
[    0.233549] GICv3: CPU2: found redistributor 2 region 0:0x00000000fef40000
[    0.233560] GICv3: CPU2: using allocated LPI pending table @0x00000000f5070000
[    0.233587] CPU2: Booted secondary processor 0x0000000002 [0x410fd034]
[    0.265596] Detected VIPT I-cache on CPU3
[    0.265616] GICv3: CPU3: found redistributor 3 region 0:0x00000000fef60000
[    0.265627] GICv3: CPU3: using allocated LPI pending table @0x00000000f5100000
[    0.265652] CPU3: Booted secondary processor 0x0000000003 [0x410fd034]
[    0.297676] CPU features: detected: EL2 vector hardening
[    0.297682] ARM_SMCCC_ARCH_WORKAROUND_1 missing from firmware
[    0.297688] Detected PIPT I-cache on CPU4
[    0.297713] GICv3: CPU4: found redistributor 100 region 0:0x00000000fef80000
[    0.297724] GICv3: CPU4: using allocated LPI pending table @0x00000000f5110000
[    0.297750] CPU4: Booted secondary processor 0x0000000100 [0x410fd082]
[    0.329749] Detected PIPT I-cache on CPU5
[    0.329768] GICv3: CPU5: found redistributor 101 region 0:0x00000000fefa0000
[    0.329778] GICv3: CPU5: using allocated LPI pending table @0x00000000f5120000
[    0.329799] CPU5: Booted secondary processor 0x0000000101 [0x410fd082]
[    0.329885] smp: Brought up 1 node, 6 CPUs
[    0.482017] SMP: Total of 6 processors activated.
[    0.487183] CPU features: detected: 32-bit EL0 Support
[    0.492843] CPU features: detected: CRC32 instructions
[    0.499277] CPU: All CPU(s) started at EL2
[    0.503817] alternatives: patching kernel code
[    0.511344] devtmpfs: initialized
[    0.521079] clocksource: jiffies: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 7645041785100000 ns
[    0.531837] futex hash table entries: 2048 (order: 5, 131072 bytes)
[    0.539489] pinctrl core: initialized pinctrl subsystem
[    0.546498] DMI not present or invalid.
[    0.551092] NET: Registered protocol family 16
[    0.556389] audit: initializing netlink subsys (disabled)
[    0.562426] audit: type=2000 audit(0.436:1): state=initialized audit_enabled=0 res=1
[    0.570968] cpuidle: using governor menu
[    0.575462] hw-breakpoint: found 6 breakpoint and 4 watchpoint registers.
[    0.587730] DMA: preallocated 256 KiB pool for atomic allocations
[    0.595616] Serial: AMBA PL011 UART driver
[    0.601747] OF: amba_device_add() failed (-19) for /amba/dma-controller@ff6d0000
[    0.610030] OF: amba_device_add() failed (-19) for /amba/dma-controller@ff6e0000
[    0.643533] HugeTLB registered 1.00 GiB page size, pre-allocated 0 pages
[    0.650912] HugeTLB registered 32.0 MiB page size, pre-allocated 0 pages
[    0.658281] HugeTLB registered 2.00 MiB page size, pre-allocated 0 pages
[    0.665640] HugeTLB registered 64.0 KiB page size, pre-allocated 0 pages
[    0.675116] cryptd: max_cpu_qlen set to 1000
[    0.683936] ACPI: Interpreter disabled.
[    0.689577] vcc5v0_host: supplied by vcc5v0_sys
[    0.696370] vgaarb: loaded
[    0.699587] SCSI subsystem initialized
[    0.704058] usbcore: registered new interface driver usbfs
[    0.710127] usbcore: registered new interface driver hub
[    0.716023] usbcore: registered new device driver usb
[    0.722315] pps_core: LinuxPPS API ver. 1 registered
[    0.727778] pps_core: Software ver. 5.3.6 - Copyright 2005-2007 Rodolfo Giometti <giometti@linux.it>
[    0.737825] PTP clock support registered
[    0.742263] EDAC MC: Ver: 3.0.0
[    0.746861] FPGA manager framework
[    0.750680] Advanced Linux Sound Architecture Driver Initialized.
[    0.757903] clocksource: Switched to clocksource arch_sys_counter
[    0.764743] VFS: Disk quotas dquot_6.6.0
[    0.769094] VFS: Dquot-cache hash table entries: 512 (order 0, 4096 bytes)
[    0.776803] pnp: PnP ACPI: disabled
[    0.787910] NET: Registered protocol family 2
[    0.793099] tcp_listen_portaddr_hash hash table entries: 2048 (order: 3, 32768 bytes)
[    0.801837] TCP established hash table entries: 32768 (order: 6, 262144 bytes)
[    0.810118] TCP bind hash table entries: 32768 (order: 7, 524288 bytes)
[    0.818112] TCP: Hash tables configured (established 32768 bind 32768)
[    0.825411] UDP hash table entries: 2048 (order: 4, 65536 bytes)
[    0.832119] UDP-Lite hash table entries: 2048 (order: 4, 65536 bytes)
[    0.839460] NET: Registered protocol family 1
[    0.844644] RPC: Registered named UNIX socket transport module.
[    0.851151] RPC: Registered udp transport module.
[    0.856318] RPC: Registered tcp transport module.
[    0.861482] RPC: Registered tcp NFSv4.1 backchannel transport module.
[    0.868559] PCI: CLS 0 bytes, default 64
[    0.872973] Unpacking initramfs...
[    0.877160] Initramfs unpacking failed: no cpio magic
[    0.882782] Freeing initrd memory: 128K
[    0.887603] hw perfevents: enabled with armv8_cortex_a53 PMU driver, 7 counters available
[    0.896841] hw perfevents: enabled with armv8_cortex_a72 PMU driver, 7 counters available
[    0.906114] kvm [1]: IPA Size Limit: 40bits
[    0.911224] kvm [1]: vgic-v2@fff20000
[    0.915265] kvm [1]: GIC system register CPU interface enabled
[    0.921821] kvm [1]: vgic interrupt IRQ10
[    0.926399] kvm [1]: Hyp mode initialized successfully
[    0.939158] Initialise system trusted keyrings
[    0.944178] workingset: timestamp_bits=44 max_order=20 bucket_order=0
[    0.957046] squashfs: version 4.0 (2009/01/31) Phillip Lougher
[    0.964109] NFS: Registering the id_resolver key type
[    0.969684] Key type id_resolver registered
[    0.974278] Key type id_legacy registered
[    0.978811] 9p: Installing v9fs 9p2000 file system support
[    0.986490] Key type asymmetric registered
[    0.990995] Asymmetric key parser 'x509' registered
[    0.996386] Block layer SCSI generic (bsg) driver version 0.4 loaded (major 245)
[    1.004511] io scheduler mq-deadline registered
[    1.009485] io scheduler kyber registered
[    1.026955] EINJ: ACPI disabled.
[    1.038567] pwm-regulator: supplied by regulator-dummy
[    1.047940] Serial: 8250/16550 driver, 4 ports, IRQ sharing enabled
[    1.056629] printk: console [ttyS2] disabled
[    1.061362] ff1a0000.serial: ttyS2 at MMIO 0xff1a0000 (irq = 30, base_baud = 1500000) is a 16550A
[    1.071269] printk: console [ttyS2] enabled
[    1.071269] printk: console [ttyS2] enabled
[    1.080632] printk: bootconsole [uart8250] disabled
[    1.080632] printk: bootconsole [uart8250] disabled
[    1.092670] SuperH (H)SCI(F) driver initialized
[    1.098303] msm_serial: driver initialized
[    1.103952] cacheinfo: Unable to detect cache hierarchy for CPU 0
[    1.117068] loop: module loaded
[    1.125140] libphy: Fixed MDIO Bus: probed
[    1.130004] tun: Universal TUN/TAP device driver, 1.6
[    1.136468] thunder_xcv, ver 1.0
[    1.140113] thunder_bgx, ver 1.0
[    1.143747] nicpf, ver 1.0
[    1.147397] hclge is initializing
[    1.151109] hns3: Hisilicon Ethernet Network Driver for Hip08 Family - version
[    1.159184] hns3: Copyright (c) 2017 Huawei Corporation.
[    1.165176] e1000e: Intel(R) PRO/1000 Network Driver - 3.2.6-k
[    1.171701] e1000e: Copyright(c) 1999 - 2015 Intel Corporation.
[    1.178352] igb: Intel(R) Gigabit Ethernet Network Driver - version 5.6.0-k
[    1.186138] igb: Copyright (c) 2007-2014 Intel Corporation.
[    1.192400] igbvf: Intel(R) Gigabit Virtual Function Network Driver - version 2.4.0-k
[    1.201156] igbvf: Copyright (c) 2009 - 2012 Intel Corporation.
[    1.208124] sky2: driver version 1.30
[    1.212945] VFIO - User Level meta-driver version: 0.3
[    1.220244] ehci_hcd: USB 2.0 'Enhanced' Host Controller (EHCI) Driver
[    1.227585] ehci-pci: EHCI PCI platform driver
[    1.232590] ehci-platform: EHCI generic platform driver
[    1.240636] ehci-platform fe380000.usb: EHCI Host Controller
[    1.246985] ehci-platform fe380000.usb: new USB bus registered, assigned bus number 1
[    1.256766] ehci-platform fe380000.usb: irq 26, io mem 0xfe380000
[    1.281914] ehci-platform fe380000.usb: USB 2.0 started, EHCI 1.00
[    1.289325] hub 1-0:1.0: USB hub found
[    1.293545] hub 1-0:1.0: 1 port detected
[    1.300331] ehci-platform fe3c0000.usb: EHCI Host Controller
[    1.306683] ehci-platform fe3c0000.usb: new USB bus registered, assigned bus number 2
[    1.315663] ehci-platform fe3c0000.usb: irq 28, io mem 0xfe3c0000
[    1.337920] ehci-platform fe3c0000.usb: USB 2.0 started, EHCI 1.00
[    1.345257] hub 2-0:1.0: USB hub found
[    1.349479] hub 2-0:1.0: 1 port detected
[    1.354242] ehci-orion: EHCI orion driver
[    1.358879] ehci-exynos: EHCI EXYNOS driver
[    1.363655] ohci_hcd: USB 1.1 'Open' Host Controller (OHCI) Driver
[    1.370581] ohci-pci: OHCI PCI platform driver
[    1.375601] ohci-platform: OHCI generic platform driver
[    1.381602] ohci-platform fe3a0000.usb: Generic Platform OHCI controller
[    1.389112] ohci-platform fe3a0000.usb: new USB bus registered, assigned bus number 3
[    1.398077] ohci-platform fe3a0000.usb: irq 27, io mem 0xfe3a0000
[    1.466467] hub 3-0:1.0: USB hub found
[    1.470686] hub 3-0:1.0: 1 port detected
[    1.475435] ohci-platform fe3e0000.usb: Generic Platform OHCI controller
[    1.482945] ohci-platform fe3e0000.usb: new USB bus registered, assigned bus number 4
[    1.491858] ohci-platform fe3e0000.usb: irq 29, io mem 0xfe3e0000
[    1.562345] hub 4-0:1.0: USB hub found
[    1.566571] hub 4-0:1.0: 1 port detected
[    1.571312] ohci-exynos: OHCI EXYNOS driver
[    1.576584] usbcore: registered new interface driver usb-storage
[    1.586235] i2c /dev entries driver
[    1.596590] sdhci: Secure Digital Host Controller Interface driver
[    1.603515] sdhci: Copyright(c) Pierre Ossman
[    1.608855] Synopsys Designware Multimedia Card Interface Driver
[    1.616528] sdhci-pltfm: SDHCI platform and OF driver helper
[    1.624312] mmc0: CQHCI version 5.10
[    1.654146] mmc0: SDHCI controller on fe330000.sdhci [fe330000.sdhci] using ADMA
[    1.664112] ledtrig-cpu: registered to indicate activity on CPUs
[    1.672264] usbcore: registered new interface driver usbhid
[    1.678516] usbhid: USB HID core driver
[    1.686341] NET: Registered protocol family 17
[    1.691503] 9pnet: Installing 9P2000 support
[    1.696321] Key type dns_resolver registered
[    1.701584] registered taskstats version 1
[    1.706174] Loading compiled-in X.509 certificates
[    1.731572] hctosys: unable to open rtc device (rtc0)
[    1.737418] mmc0: Command Queue Engine enabled
[    1.738022] ALSA device list:
[    1.742418] mmc0: new HS400 Enhanced strobe MMC card at address 0001
[    1.745717]   No soundcards found.
[    1.753421] mmcblk0: mmc0:0001 AJNB4R 14.6 GiB
[    1.761881] ttyS2 - failed to request DMA
▒    1.761936] mmcblk0boot0: mmc0:0001 AJNB4R partition 1 4.00 MiB
[    1.773212] mmcblk0boot1: mmc0:0001 AJNB4R partition 2 4.00 MiB
[    1.780028] mmcblk0rpmb: mmc0:0001 AJNB4R partition 3 4.00 MiB, chardev (237:0)
[    1.796358]  mmcblk0: p1 p2 p3 p4 p5
[    1.809072] EXT4-fs (mmcblk0p5): recovery complete
[    1.814985] EXT4-fs (mmcblk0p5): mounted filesystem with ordered data mode. Opts: (null)
[    1.824092] VFS: Mounted root (ext4 filesystem) on device 179:5.
[    1.831559] devtmpfs: mounted
[    1.835657] Freeing unused kernel memory: 1472K
[    1.878335] Run /sbin/init as init process
[    1.978009] usb 4-1: new low-speed USB device number 2 using ohci-platform

Please press Enter to activate this console. [    2.454069] usb 4-1: device descriptor read/64, error -62
[    2.803691] input: SIGMACHIP Usb Mouse as /devices/platform/fe3e0000.usb/usb4/4-1/4-1:1.0/0003:1C4F:0065.0001/input/input0
[    2.816298] hid-generic 0003:1C4F:0065.0001: input: USB HID v1.10 Mouse [SIGMACHIP Usb Mouse] on usb-fe3e0000.usb-1/input0

6.5 linux命令测试

6.5.1 查看块设备

查看eMMC块设备文件:

[root@zy:/]# ls /dev/mmc* -l
brw-rw----    1 0        0         179,   0 Jan  1 00:00 /dev/mmcblk0
brw-rw----    1 0        0         179,  32 Jan  1 00:00 /dev/mmcblk0boot0
brw-rw----    1 0        0         179,  64 Jan  1 00:00 /dev/mmcblk0boot1
brw-rw----    1 0        0         179,   1 Jan  1 00:00 /dev/mmcblk0p1
brw-rw----    1 0        0         179,   2 Jan  1 00:00 /dev/mmcblk0p2
brw-rw----    1 0        0         179,   3 Jan  1 00:00 /dev/mmcblk0p3
brw-rw----    1 0        0         179,   4 Jan  1 00:00 /dev/mmcblk0p4
brw-rw----    1 0        0         179,   5 Jan  1 00:00 /dev/mmcblk0p5
crw-rw----    1 0        0         237,   0 Jan  1 00:00 /dev/mmcblk0rpmb

这里一共有8个块设备节点和1个字符设备节点;其中:

  • /dev/mmcblk0表示的是eMMC这个设备,其主设备号为179,次设备号为0;
  • mmcblk0boot0mmcblk0boot1对应两个Boot Area Partition;每一个Boot Area Partition大小都是4MB
  • mmcblk0rpmb则为RPMB Partition;大小为4MB
  • mcblk0pxUser Data Area划分出来的SW Partitions;实际上就是通过解析GPT分区表创建的分区,分区编号依次为1,2,3,4,5

使用cat /proc/partitions,可以查看全部分区信息:

[root@zy:/]# cat /proc/partitions
major minor  #blocks  name

 179        0   15267840 mmcblk0
 179        1       4000 mmcblk0p1
 179        2       4096 mmcblk0p2
 179        3       4096 mmcblk0p3
 179        4     114688 mmcblk0p4
 179        5   15136751 mmcblk0p5

其中blocks表示分区的容量,每个blocks1KB。这里:

  • mmcblk0p1对应loader1分区,大小为4000KB
  • mmcblk0p2对应loader2分区,大小为4MB
  • mmcblk0p3对应trust分区,大小为4MB
  • mmcblk0p4对应boot分区,大小为112MB
  • mmcblk0p5对应rootfs分区,大小为剩余所有空间;
6.5.2 查看磁盘空间

这里我们可以通过df -hT查看磁盘空间信息;

[root@zy:/]# df -hT
Filesystem           Type            Size      Used Available Use% Mounted on
/dev/root            ext4          274.6M     97.7M    155.9M  39% /
devtmpfs             devtmpfs        1.9G         0      1.9G   0% /dev
tmpfs                tmpfs           1.9G         0      1.9G   0% /tmp

显示内容参数说明:

  • Filesystem:文件系统;
  • Type:文件系统类型;
  • Size: 分区大小;
  • Used: 已使用容量;
  • Avail: 还可以使用的容量;
  • Use%: 已用百分比;
  • Mounted on: 挂载点;

这里我们可以看到根目录挂载在/dev/root设备节点上,文件系统格式是ext4,然后通过查看/dev/root链接关系,看到/dev/root其实就是/dev/mmcblk0p5,也就是eMMC设备的rootfs分区;

[root@zy:/]# readlink /dev/root
mmcblk0p5

但是为什么这里看到的/dev/root大小只有274MB呢?不是应该有十几个G么?这主要是因为我们的根文件系统镜像制作的就是那么大,剩余的eMMC空间并未使用。

6.5.3 fdisk分区命令

使用fdisk -l查看磁盘分区情况:

[root@zy:/]# fdisk -l
Disk /dev/mmcblk0: 15 GB, 15634268160 bytes, 30535680 sectors
1908480 cylinders, 1 heads, 16 sectors/track
Units: sectors of 1 * 512 = 512 bytes

Device       Boot StartCHS    EndCHS        StartLBA     EndLBA    Sectors  Size Id Type
/dev/mmcblk0p1    0,0,0       0,0,0                1   30535679   30535679 14.5G ee EFI GPT

从上面的内容可以看到磁盘/dev/mmcblk0大小为15GB,包含1个磁头、1个磁头有1904840个柱面,每个柱面有16个扇区,所以总容量为1908480*16*512=15,634,268,160字节。

这里fdisk -l只识别到了eMMC设备的1号分区/dev/mmcblk0p1,并没有识别到/dev/mmcblk0p2~5分区,比较奇怪,网上搜索了一下好像是由于fdisk不支持GPT,所以才导致无法识别GPT分区表。更多fdisk命令相关能容可以参考:《使用fdisk对磁盘分区》。

6.5.4 parted分区命令

对于GPT格式的分区,fdisk工具是无能为力的,同时,fdisk工具对分区是有大小限制的,它只能划分小于2T的磁盘。

但是现在的磁盘空间很多都已经是远远大于2T,此时就需要另外一个磁盘管理工具parted来完成大于2T的磁盘分区工作。

但是不幸的是buxybox并不支持parted命令,这里我也懒得去整了,后面我们直接移植ubuntu根文件系统,然后通过resize2fs指令进行扩容。

七、启动卡在Starting kernel排查方法

如果你在内核启动时,卡在了Starting kernel ...。如果想解决问题,就必须知道问题出现在了哪里,因此一般通过内核启动的时候打印的信息来定位问题产生的原因。我们在linux内核调试-printk说过printk函数输出的日志都会被保存到内核日志缓冲区__log_buf中,因此我们可以直接读取该缓冲区, __log_buf其地址在System.map被标记出来,我们可以找到具体的位置。具体步骤如下:

(1) 首先去内核编译目录找到System.map文件。

(2) 找到System.map_text(代码段起始地址)的虚拟地址,执行:

root@zhengyang:/work/sambashare/rk3399/linux-5.2.8# nm vmlinux | grep _text
ffff000010080000 T _text

(3) 找到System.map__log_buf对应的虚拟地址,执行:

root@zhengyang:/work/sambashare/rk3399/linux-5.2.8# nm vmlinux | grep __log_buf
ffff000011493358 __log_buf

(4) 直接从eMMC0x8000个扇区加载内核,启动内核,内核此时卡在Starting kernel …位置;7

=> mmc read 0x10000000 0x8000 0xA000

MMC read: dev # 0, block # 32768, count 40960 ... 40960 blocks read: OK
=> bootm 0x10000000

(5) 重新启动系统(注意:不要断电启动,按下复位键即可),进入uboot命令行界面;

(6) 计算__log_buf在内存的物理地址:

PA__log_buf = __log_buf - _text + PA

其中PA为内核在内存的起始地址,这里是0x280000;这里通过计算得到0x1693358

在命令行输入(数字是刚才得到的数字):

md 0x1693358

(7) 不停的敲击回车键,直到为全为0。

这个内容在内存中是使用struct prink_log结构存储的,每个struct prink_log后面跟着需要输出的内容,内容长度由text_len字段确定。

struct printk_log {
    u64 ts_nsec;  // 时间ns
    u16 len;      // 该条消息在内存占用的长度,包括当前结构体
    u16 text_len;  // 输出的内容长度
    u16 dict_len;
    u8 facility;
    u8 flags:5;
    u8 level:3;
#iddef CONFIG_PRINTK_CALLER
    u32 caller_id
#endif
}

如果想解析内核日志缓冲区log_buf的内容,可以参考《DUMP kernel log_buf以及解析log_buf字符的办法》这篇博客,这篇博客提供了python脚本解析内核日志缓存器的内容。

参考文章

[1] Rockchip Kernel

[2] 嵌入式ARM64 Linux内核编译及根文件系统构建

[3] Mini2440linux内核移植

[4] linux设备树-linux内核设备树移植

[5] Rochchip Partitions

[6] rk3399rockpi 4b)上运行linux-5.3mainline内核

[7] 简单介绍MBRGPT的特点

[8] 利用parted工具规划磁盘分区

[9] RK3568外接AP6275S WIFI模块调试

[10] RK3399-HDMI音频

posted @ 2023-05-16 22:16  大奥特曼打小怪兽  阅读(4868)  评论(0编辑  收藏  举报
如果有任何技术小问题,欢迎大家交流沟通,共同进步