linux设备树-linux内核设备树移植(一)
----------------------------------------------------------------------------------------------------------------------------
内核版本:linux 5.2.8
根文件系统:busybox 1.25.0
u-boot:2016.05
----------------------------------------------------------------------------------------------------------------------------
一、linux内核启动
我们回顾一下uboot引导linux内核启动过程, uboot通过执行bootcmd命令启动内核:
bootcmd="nand read 0x30000000 kernel; bootm 0x30000000"
uboot首先将内核镜像从NAND拷贝到内存地址0x30000000,然后执行bootm 0x30000000命令。
1.1 bootm命令
bootm这个命令用于启动一个操作系统映射,实际上调用的是do_bootm_linux函数,还函数位于arch/arm/lib/bootm.c文件:
/* Main Entry point for arm bootm implementation * * Modeled after the powerpc implementation * DIFFERENCE: Instead of calling prep and go at the end * they are called if subcommand is equal 0. */ int do_bootm_linux(int flag, int argc, char * const argv[], bootm_headers_t *images) { /* No need for those on ARM */ if (flag & BOOTM_STATE_OS_BD_T || flag & BOOTM_STATE_OS_CMDLINE) // 不执行 return -1; if (flag & BOOTM_STATE_OS_PREP) { // 执行 boot_prep_linux(images); return 0; } if (flag & (BOOTM_STATE_OS_GO | BOOTM_STATE_OS_FAKE_GO)) { // 执行 boot_jump_linux(images, flag); return 0; } boot_prep_linux(images); boot_jump_linux(images, flag); return 0; }
boot_prep_linux函数跟内核传递参数有关系,为内核设置启动参数,u-boot向内核传递参数就是在这里做的准备:
boot_jump_linux会将tags的开始地址也就是gd->bd->bi_boot_params传给内核,并跳转到内核地址、启动内核,让内核解析这些tags。
1.2 boot_jump_linux
/* Subcommand: GO */ static void boot_jump_linux(bootm_headers_t *images, int flag) { unsigned long machid = gd->bd->bi_arch_number; // 获取机器码 char *s; void (*kernel_entry)(int zero, int arch, uint params); // 内核入口函数 unsigned long r2; int fake = (flag & BOOTM_STATE_OS_FAKE_GO); kernel_entry = (void (*)(int, int, uint))images->ep; // 指定为内核入口地址 s = getenv("machid"); if (s) { if (strict_strtoul(s, 16, &machid) < 0) { debug("strict_strtoul failed!\n"); return; } printf("Using machid 0x%lx from environment\n", machid); } debug("## Transferring control to Linux (at address %08lx)" \ "...\n", (ulong) kernel_entry); bootstage_mark(BOOTSTAGE_ID_RUN_OS); announce_and_cleanup(fake); if (IMAGE_ENABLE_OF_LIBFDT && images->ft_len) // 如果使能FDT,并且扁平设备树长度大于0 r2 = (unsigned long)images->ft_addr; else r2 = gd->bd->bi_boot_params; if (!fake) { kernel_entry(0, machid, r2); } }
1.2.1 matchid
在之前内核移植的博客中,由于我们没有使用设备树,而是通过uboo传递一个machid给linux 内核(uboot在不设置machid环境变量时,uboot会使用默认的机器id),我们在Mini2440之linux内核移植中将其修改为了168:
#define MACH_TYPE_SMDK2440 168 // 新增的
内核启动的时候会根据machid来比较内核machine_desc中的.nr,machine_desc定义在内核arch/arm/mach-s3c24xx/mach-smdk2440.c文件:
MACHINE_START(S3C2440, "SMDK2440") /* Maintainer: Ben Dooks <ben-linux@fluff.org> */ .atag_offset = 0x100, .init_irq = s3c2440_init_irq, .map_io = smdk2440_map_io, .init_machine = smdk2440_machine_init, .init_time = smdk2440_init_time, MACHINE_END
宏MACHINE_START定义在arch/arm/include/asm/mach/arch.h,如下:
/* * Set of macros to define architecture features. This is built into * a table by the linker. */ #define MACHINE_START(_type,_name) \ static const struct machine_desc __mach_desc_##_type \ __used \ __attribute__((__section__(".arch.info.init"))) = { \ .nr = MACH_TYPE_##_type, \ .name = _name, #define MACHINE_END \ };
这里attribute((section(“.arch.info.init”)))就是利用了编译器的特性,把machine_desc放到了.arch.info.init段。
.init.arch.info : { __arch_info_begin = .; *(.arch.info.init) __arch_info_end = .; }
回到前面的MACHINE_START(_type,_name)宏,_type是S3C2440。经过##连接.nr = MACH_TYPE_##_type就变为:.nr = MACH_TYPE_S3C2440。
MACH_TYPE_S3C2440定义在arch/arm/include/generated/asm/mach-types.h:
#define MACH_TYPE_S3C2440 168
现在使用设备树的话,这个参数就不需要设置了。
1.2.2 r2
如果我们使用了设备树,r2将会被设备为dtb文件的开始地址:
r2 = (unsigned long)images->ft_addr;
否则r2为tags的开始地址。
二、linux内核设备树移植
为了学习设备树相关内容,这里我们重新克隆一个linux 5.2.8源码,然后在Mini2440之linux内核移植的基础上,介绍设备树移植相关的内容。
2.1 内核源码下载
我们这里下载linuxz-5.2.8版本,虚拟机ubuntu系统运行:
wget https://mirrors.edge.kernel.org/pub/linux/kernel/v5.x/linux-5.2.8.tar.gz
将源码解压:
tar -zvxf linux-5.2.8.tar.gz mv linux-5.2.8 linux-5.2.8-dt mv linux-5.2.8-dt /work/sambashare/ cd /work/sambashare/linux-5.2.8-dt/
2.2 配置Makefile
修改顶层的 Makefile,打开 Makefile 文件,找到下面语句:
ARCH ?= $(SUBARCH)
修改为:
ARCH ?= arm
CROSS_COMPILE ?= arm-linux-
其中,ARCH 是指定目标平台为arm,CROSS_COMPILE是指定交叉编译器,这里指定的 是系统默认的交叉编译器,如要使用其它的,则要把编译器的全路径在这里写出。
2.3 内核s3c2440_defconfig配置
接下来要做的就是内核配置、编译了。单板的默认配置文件在arch/arm/configs 目录下,如果没有2440相关的默认配置,可以选择比较相近的2410的配置修改。
root@zhengyang:/work/sambashare/linux-5.2.8-dt# ls arch/arm/configs | grep 24 mini2440_defconfig s3c2410_defconfig
虽然该目录下有Mini2440开发板相关的配置,但是本着学习的原则,并没有选择mini2440_defconfig;这里我直接选择s3c2410_defconfig。
配置文件s3c2410_defconfig支持很多单板,包括2440、2410,其定义如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
CONFIG_SYSVIPC=y CONFIG_IKCONFIG=m CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=16 CONFIG_BLK_DEV_INITRD=y CONFIG_SLAB=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y # CONFIG_BLK_DEV_BSG is not set CONFIG_PARTITION_ADVANCED=y CONFIG_BSD_DISKLABEL=y CONFIG_SOLARIS_X86_PARTITION=y CONFIG_ARCH_S3C24XX=y CONFIG_CPU_S3C2412=y CONFIG_CPU_S3C2416=y CONFIG_CPU_S3C2440=y CONFIG_CPU_S3C2442=y CONFIG_CPU_S3C2443=y CONFIG_MACH_AML_M5900=y CONFIG_ARCH_BAST=y CONFIG_ARCH_H1940=y CONFIG_MACH_N30=y CONFIG_MACH_OTOM=y CONFIG_MACH_QT2410=y CONFIG_ARCH_SMDK2410=y CONFIG_MACH_TCT_HAMMER=y CONFIG_MACH_VR1000=y CONFIG_MACH_JIVE=y CONFIG_MACH_SMDK2412=y CONFIG_MACH_VSTMS=y CONFIG_MACH_SMDK2416=y CONFIG_MACH_ANUBIS=y CONFIG_MACH_AT2440EVB=y CONFIG_MACH_MINI2440=y CONFIG_MACH_NEXCODER_2440=y CONFIG_MACH_OSIRIS=y CONFIG_MACH_OSIRIS_DVS=m CONFIG_MACH_RX3715=y CONFIG_ARCH_S3C2440=y # 会链接mach-smdk2440.o CONFIG_MACH_NEO1973_GTA02=y CONFIG_MACH_RX1950=y CONFIG_MACH_SMDK2443=y CONFIG_S3C_ADC=y CONFIG_ZBOOT_ROM_TEXT=0x0 CONFIG_ZBOOT_ROM_BSS=0x0 CONFIG_CMDLINE="root=/dev/hda1 ro init=/bin/bash console=ttySAC0" CONFIG_FPE_NWFPE=y CONFIG_FPE_NWFPE_XP=y CONFIG_APM_EMULATION=m CONFIG_NET=y CONFIG_PACKET=y CONFIG_UNIX=y CONFIG_XFRM_USER=m CONFIG_NET_KEY=m CONFIG_INET=y CONFIG_IP_MULTICAST=y CONFIG_IP_PNP=y CONFIG_IP_PNP_DHCP=y CONFIG_IP_PNP_BOOTP=y CONFIG_NET_IPIP=m CONFIG_INET_AH=m CONFIG_INET_ESP=m CONFIG_INET_IPCOMP=m CONFIG_TCP_CONG_ADVANCED=y CONFIG_TCP_CONG_HSTCP=m CONFIG_TCP_CONG_HYBLA=m CONFIG_TCP_CONG_SCALABLE=m CONFIG_TCP_CONG_LP=m CONFIG_TCP_CONG_VENO=m CONFIG_TCP_CONG_YEAH=m CONFIG_TCP_CONG_ILLINOIS=m CONFIG_IPV6_ROUTER_PREF=y CONFIG_INET6_AH=m CONFIG_INET6_ESP=m CONFIG_INET6_IPCOMP=m CONFIG_IPV6_MIP6=m CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION=m CONFIG_IPV6_TUNNEL=m CONFIG_NETFILTER=y CONFIG_NF_CONNTRACK=m CONFIG_NF_CONNTRACK_EVENTS=y CONFIG_NF_CONNTRACK_AMANDA=m CONFIG_NF_CONNTRACK_FTP=m CONFIG_NF_CONNTRACK_H323=m CONFIG_NF_CONNTRACK_IRC=m CONFIG_NF_CONNTRACK_NETBIOS_NS=m CONFIG_NF_CONNTRACK_PPTP=m CONFIG_NF_CONNTRACK_SANE=m CONFIG_NF_CONNTRACK_SIP=m CONFIG_NF_CONNTRACK_TFTP=m CONFIG_NF_CT_NETLINK=m CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m CONFIG_NETFILTER_XT_TARGET_CONNMARK=m CONFIG_NETFILTER_XT_TARGET_LED=m CONFIG_NETFILTER_XT_TARGET_LOG=m CONFIG_NETFILTER_XT_TARGET_MARK=m CONFIG_NETFILTER_XT_TARGET_NFLOG=m CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m CONFIG_NETFILTER_XT_TARGET_TCPMSS=m CONFIG_NETFILTER_XT_MATCH_CLUSTER=m CONFIG_NETFILTER_XT_MATCH_COMMENT=m CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=m CONFIG_NETFILTER_XT_MATCH_CONNMARK=m CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m CONFIG_NETFILTER_XT_MATCH_DCCP=m CONFIG_NETFILTER_XT_MATCH_DSCP=m CONFIG_NETFILTER_XT_MATCH_ESP=m CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m CONFIG_NETFILTER_XT_MATCH_HELPER=m CONFIG_NETFILTER_XT_MATCH_IPRANGE=m CONFIG_NETFILTER_XT_MATCH_LENGTH=m CONFIG_NETFILTER_XT_MATCH_LIMIT=m CONFIG_NETFILTER_XT_MATCH_MAC=m CONFIG_NETFILTER_XT_MATCH_MARK=m CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m CONFIG_NETFILTER_XT_MATCH_OWNER=m CONFIG_NETFILTER_XT_MATCH_POLICY=m CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m CONFIG_NETFILTER_XT_MATCH_QUOTA=m CONFIG_NETFILTER_XT_MATCH_RATEEST=m CONFIG_NETFILTER_XT_MATCH_REALM=m CONFIG_NETFILTER_XT_MATCH_RECENT=m CONFIG_NETFILTER_XT_MATCH_SCTP=m CONFIG_NETFILTER_XT_MATCH_STATE=m CONFIG_NETFILTER_XT_MATCH_STATISTIC=m CONFIG_NETFILTER_XT_MATCH_STRING=m CONFIG_NETFILTER_XT_MATCH_TCPMSS=m CONFIG_NETFILTER_XT_MATCH_TIME=m CONFIG_NETFILTER_XT_MATCH_U32=m CONFIG_IP_VS=m CONFIG_NF_CONNTRACK_IPV4=m CONFIG_IP_NF_IPTABLES=m CONFIG_IP_NF_MATCH_AH=m CONFIG_IP_NF_MATCH_ECN=m CONFIG_IP_NF_MATCH_TTL=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_TARGET_NETMAP=m CONFIG_IP_NF_TARGET_REDIRECT=m CONFIG_IP_NF_MANGLE=m CONFIG_IP_NF_TARGET_CLUSTERIP=m CONFIG_IP_NF_TARGET_ECN=m CONFIG_IP_NF_TARGET_TTL=m CONFIG_IP_NF_RAW=m CONFIG_IP_NF_ARPTABLES=m CONFIG_IP_NF_ARPFILTER=m CONFIG_IP_NF_ARP_MANGLE=m CONFIG_NF_CONNTRACK_IPV6=m CONFIG_IP6_NF_IPTABLES=m CONFIG_IP6_NF_MATCH_AH=m CONFIG_IP6_NF_MATCH_EUI64=m CONFIG_IP6_NF_MATCH_FRAG=m CONFIG_IP6_NF_MATCH_OPTS=m CONFIG_IP6_NF_MATCH_HL=m CONFIG_IP6_NF_MATCH_IPV6HEADER=m CONFIG_IP6_NF_MATCH_MH=m CONFIG_IP6_NF_MATCH_RT=m CONFIG_IP6_NF_TARGET_HL=m CONFIG_IP6_NF_FILTER=m CONFIG_IP6_NF_TARGET_REJECT=m CONFIG_IP6_NF_MANGLE=m CONFIG_IP6_NF_RAW=m CONFIG_BT=m CONFIG_BT_RFCOMM=m CONFIG_BT_RFCOMM_TTY=y CONFIG_BT_BNEP=m CONFIG_BT_BNEP_MC_FILTER=y CONFIG_BT_BNEP_PROTO_FILTER=y CONFIG_BT_HIDP=m CONFIG_BT_HCIUART=m CONFIG_BT_HCIUART_BCSP=y CONFIG_BT_HCIUART_LL=y CONFIG_BT_HCIBCM203X=m CONFIG_BT_HCIBPA10X=m CONFIG_BT_HCIBFUSB=m CONFIG_BT_HCIVHCI=m CONFIG_CFG80211=m CONFIG_MAC80211=m CONFIG_MAC80211_MESH=y CONFIG_MAC80211_LEDS=y CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" CONFIG_MTD=y CONFIG_MTD_REDBOOT_PARTS=y CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED=y CONFIG_MTD_CMDLINE_PARTS=y CONFIG_MTD_BLOCK=y CONFIG_MTD_CFI=y CONFIG_MTD_JEDECPROBE=y CONFIG_MTD_CFI_INTELEXT=y CONFIG_MTD_CFI_AMDSTD=y CONFIG_MTD_ROM=y CONFIG_MTD_RAW_NAND=y CONFIG_MTD_NAND_S3C2410=y CONFIG_PARPORT=y CONFIG_PARPORT_PC=m CONFIG_PARPORT_AX88796=m CONFIG_PARPORT_1284=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_NBD=m CONFIG_BLK_DEV_RAM=y CONFIG_ATA_OVER_ETH=m CONFIG_EEPROM_AT24=y CONFIG_BLK_DEV_SD=y CONFIG_CHR_DEV_ST=m CONFIG_BLK_DEV_SR=y CONFIG_BLK_DEV_SR_VENDOR=y CONFIG_CHR_DEV_SG=y CONFIG_CHR_DEV_SCH=m CONFIG_SCSI_CONSTANTS=y CONFIG_SCSI_SCAN_ASYNC=y CONFIG_ATA=y CONFIG_PATA_PLATFORM=y CONFIG_NETDEVICES=y CONFIG_DM9000=y CONFIG_INPUT_EVDEV=y CONFIG_MOUSE_APPLETOUCH=m CONFIG_MOUSE_BCM5974=m CONFIG_INPUT_JOYSTICK=y CONFIG_JOYSTICK_ANALOG=m CONFIG_JOYSTICK_A3D=m CONFIG_JOYSTICK_ADI=m CONFIG_JOYSTICK_COBRA=m CONFIG_JOYSTICK_GF2K=m CONFIG_JOYSTICK_GRIP=m CONFIG_JOYSTICK_GRIP_MP=m CONFIG_JOYSTICK_GUILLEMOT=m CONFIG_JOYSTICK_INTERACT=m CONFIG_JOYSTICK_SIDEWINDER=m CONFIG_JOYSTICK_TMDC=m CONFIG_JOYSTICK_IFORCE=m CONFIG_JOYSTICK_MAGELLAN=m CONFIG_JOYSTICK_SPACEORB=m CONFIG_JOYSTICK_SPACEBALL=m CONFIG_JOYSTICK_STINGER=m CONFIG_JOYSTICK_TWIDJOY=m CONFIG_JOYSTICK_ZHENHUA=m CONFIG_JOYSTICK_DB9=m CONFIG_JOYSTICK_GAMECON=m CONFIG_JOYSTICK_TURBOGRAFX=m CONFIG_JOYSTICK_JOYDUMP=m CONFIG_JOYSTICK_XPAD=m CONFIG_JOYSTICK_XPAD_FF=y CONFIG_JOYSTICK_XPAD_LEDS=y CONFIG_INPUT_TOUCHSCREEN=y CONFIG_TOUCHSCREEN_USB_COMPOSITE=m CONFIG_INPUT_MISC=y CONFIG_INPUT_ATI_REMOTE2=m CONFIG_INPUT_KEYSPAN_REMOTE=m CONFIG_INPUT_POWERMATE=m CONFIG_INPUT_YEALINK=m CONFIG_INPUT_CM109=m CONFIG_INPUT_UINPUT=m CONFIG_INPUT_GPIO_ROTARY_ENCODER=m CONFIG_SERIAL_NONSTANDARD=y CONFIG_SERIAL_8250=y CONFIG_SERIAL_8250_CONSOLE=y CONFIG_SERIAL_8250_NR_UARTS=8 CONFIG_SERIAL_8250_EXTENDED=y CONFIG_SERIAL_8250_MANY_PORTS=y CONFIG_SERIAL_8250_SHARE_IRQ=y CONFIG_SERIAL_SAMSUNG=y CONFIG_SERIAL_SAMSUNG_CONSOLE=y CONFIG_SERIAL_DEV_BUS=m CONFIG_PRINTER=y CONFIG_PPDEV=y CONFIG_HW_RANDOM=y CONFIG_I2C_CHARDEV=m CONFIG_I2C_S3C2410=y CONFIG_I2C_SIMTEC=y CONFIG_SPI=y CONFIG_SPI_GPIO=m CONFIG_SPI_S3C24XX=m CONFIG_SPI_SPIDEV=m CONFIG_SPI_TLE62X0=m CONFIG_SENSORS_LM75=m CONFIG_SENSORS_LM78=m CONFIG_SENSORS_LM85=m CONFIG_WATCHDOG=y CONFIG_S3C2410_WATCHDOG=y CONFIG_MFD_SM501=y CONFIG_TPS65010=y CONFIG_FB=y CONFIG_FIRMWARE_EDID=y CONFIG_FB_MODE_HELPERS=y CONFIG_FB_S3C2410=y CONFIG_FB_SM501=y CONFIG_BACKLIGHT_PWM=m CONFIG_FRAMEBUFFER_CONSOLE=y CONFIG_SOUND=y CONFIG_SND=y CONFIG_SND_SEQUENCER=m CONFIG_SND_MIXER_OSS=m CONFIG_SND_PCM_OSS=m CONFIG_SND_SEQUENCER_OSS=y CONFIG_SND_VERBOSE_PRINTK=y # CONFIG_SND_DRIVERS is not set # CONFIG_SND_ARM is not set # CONFIG_SND_SPI is not set CONFIG_SND_USB_AUDIO=m CONFIG_SND_USB_CAIAQ=m CONFIG_SND_SOC=y # CONFIG_USB_HID is not set CONFIG_USB=y CONFIG_USB_MON=y CONFIG_USB_OHCI_HCD=y CONFIG_USB_ACM=m CONFIG_USB_PRINTER=m CONFIG_USB_WDM=m CONFIG_USB_STORAGE=m CONFIG_USB_STORAGE_DATAFAB=m CONFIG_USB_STORAGE_FREECOM=m CONFIG_USB_STORAGE_ISD200=m CONFIG_USB_STORAGE_USBAT=m CONFIG_USB_STORAGE_SDDR09=m CONFIG_USB_STORAGE_SDDR55=m CONFIG_USB_STORAGE_JUMPSHOT=m CONFIG_USB_STORAGE_ALAUDA=m CONFIG_USB_STORAGE_ONETOUCH=m CONFIG_USB_STORAGE_KARMA=m CONFIG_USB_STORAGE_CYPRESS_ATACB=m CONFIG_USB_MDC800=m CONFIG_USB_MICROTEK=m CONFIG_USB_USS720=m CONFIG_USB_SERIAL=y CONFIG_USB_SERIAL_GENERIC=y CONFIG_USB_SERIAL_FTDI_SIO=y CONFIG_USB_SERIAL_NAVMAN=m CONFIG_USB_SERIAL_PL2303=y CONFIG_USB_SERIAL_OPTION=m CONFIG_USB_EMI62=m CONFIG_USB_EMI26=m CONFIG_USB_ADUTUX=m CONFIG_USB_SEVSEG=m CONFIG_USB_RIO500=m CONFIG_USB_LEGOTOWER=m CONFIG_USB_LCD=m CONFIG_USB_CYPRESS_CY7C63=m CONFIG_USB_CYTHERM=m CONFIG_USB_IDMOUSE=m CONFIG_USB_FTDI_ELAN=m CONFIG_USB_APPLEDISPLAY=m CONFIG_USB_LD=m CONFIG_USB_TRANCEVIBRATOR=m CONFIG_USB_IOWARRIOR=m CONFIG_USB_TEST=m CONFIG_MMC=y CONFIG_SDIO_UART=m CONFIG_MMC_TEST=m CONFIG_MMC_SDHCI=m CONFIG_MMC_SPI=m CONFIG_MMC_S3C=y CONFIG_LEDS_S3C24XX=m CONFIG_LEDS_PCA9532=m CONFIG_LEDS_GPIO=m CONFIG_LEDS_PCA955X=m CONFIG_LEDS_DAC124S085=m CONFIG_LEDS_PWM=m CONFIG_LEDS_BD2802=m CONFIG_LEDS_TRIGGER_TIMER=m CONFIG_LEDS_TRIGGER_HEARTBEAT=m CONFIG_LEDS_TRIGGER_GPIO=m CONFIG_LEDS_TRIGGER_DEFAULT_ON=m CONFIG_RTC_CLASS=y CONFIG_RTC_DRV_S3C=y CONFIG_DMADEVICES=y CONFIG_S3C24XX_DMAC=y CONFIG_EXT2_FS=y CONFIG_EXT2_FS_XATTR=y CONFIG_EXT2_FS_POSIX_ACL=y CONFIG_EXT2_FS_SECURITY=y CONFIG_EXT3_FS=y CONFIG_EXT3_FS_POSIX_ACL=y CONFIG_AUTOFS4_FS=m CONFIG_FUSE_FS=m CONFIG_ISO9660_FS=y CONFIG_JOLIET=y CONFIG_UDF_FS=m CONFIG_MSDOS_FS=y CONFIG_VFAT_FS=y CONFIG_NTFS_FS=m CONFIG_TMPFS=y CONFIG_TMPFS_POSIX_ACL=y CONFIG_CONFIGFS_FS=m CONFIG_JFFS2_FS=y CONFIG_JFFS2_SUMMARY=y CONFIG_CRAMFS=y CONFIG_SQUASHFS=m CONFIG_ROMFS_FS=y CONFIG_NFS_FS=y CONFIG_NFS_V3_ACL=y CONFIG_ROOT_NFS=y CONFIG_NFSD=m CONFIG_NFSD_V3_ACL=y CONFIG_NFSD_V4=y CONFIG_CIFS=m CONFIG_NLS_CODEPAGE_437=y CONFIG_NLS_CODEPAGE_737=m CONFIG_NLS_CODEPAGE_775=m CONFIG_NLS_CODEPAGE_850=y CONFIG_NLS_CODEPAGE_852=m CONFIG_NLS_CODEPAGE_855=m CONFIG_NLS_CODEPAGE_857=m CONFIG_NLS_CODEPAGE_860=m CONFIG_NLS_CODEPAGE_861=m CONFIG_NLS_CODEPAGE_862=m CONFIG_NLS_CODEPAGE_863=m CONFIG_NLS_CODEPAGE_864=m CONFIG_NLS_CODEPAGE_865=m CONFIG_NLS_CODEPAGE_866=m CONFIG_NLS_CODEPAGE_869=m CONFIG_NLS_CODEPAGE_936=m CONFIG_NLS_CODEPAGE_950=m CONFIG_NLS_CODEPAGE_932=m CONFIG_NLS_CODEPAGE_949=m CONFIG_NLS_CODEPAGE_874=m CONFIG_NLS_ISO8859_8=m CONFIG_NLS_CODEPAGE_1250=m CONFIG_NLS_CODEPAGE_1251=m CONFIG_NLS_ASCII=y CONFIG_NLS_ISO8859_1=y CONFIG_NLS_ISO8859_2=m CONFIG_NLS_ISO8859_3=m CONFIG_NLS_ISO8859_4=m CONFIG_NLS_ISO8859_5=m CONFIG_NLS_ISO8859_6=m CONFIG_NLS_ISO8859_7=m CONFIG_NLS_ISO8859_9=m CONFIG_NLS_ISO8859_13=m CONFIG_NLS_ISO8859_14=m CONFIG_NLS_ISO8859_15=m CONFIG_NLS_KOI8_R=m CONFIG_NLS_KOI8_U=m CONFIG_NLS_UTF8=m CONFIG_DEBUG_INFO=y CONFIG_MAGIC_SYSRQ=y CONFIG_DEBUG_KERNEL=y CONFIG_DEBUG_MUTEXES=y CONFIG_DEBUG_USER=y CONFIG_DEBUG_LL=y
然后复制一份,得到s3c2440_defconfig:
cp arch/arm/configs/s3c2410_defconfig arch/arm/configs/s3c2440_defconfig
在linux内核根目录下执行如下命令,执行完之后会在内核根目录下生成默认配置文件.config:
root@zhengyang:/work/sambashare/linux-5.2.8-dt# make s3c2440_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 # # configuration written to .config #
2.4 设备树配置
在linux内核中,既然要使用设备树,我们先看内核中是否已有支持S3C2440的设备树文件。进入linux内核源代码目录,内核根路径下运行命令:
root@zhengyang:/work/sambashare/linux-5.2.8-dt# ls arch/arm/boot/dts | grep s3c s3c2416.dtsi s3c2416-pinctrl.dtsi s3c2416-smdk2416.dts s3c24xx.dtsi s3c6400.dtsi s3c6410.dtsi s3c6410-mini6410.dts s3c6410-smdk6410.dts s3c64xx.dtsi s3c64xx-pinctrl.dtsi
s3c24xx.dtsi 中存放的是s3c24xx系列SoC公共的一些属性,如中断控制器、串口、看门狗、RTC、I2C控制器等等,具体如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
// SPDX-License-Identifier: GPL-2.0 /* * Samsung's S3C24XX family device tree source * * Copyright (c) 2013 Heiko Stuebner <heiko@sntech.de> */ / { compatible = "samsung,s3c24xx"; interrupt-parent = <&intc>; #address-cells = <1>; #size-cells = <1>; aliases { pinctrl0 = &pinctrl_0; serial0 = &uart0; serial1 = &uart1; serial2 = &uart2; }; intc:interrupt-controller@4a000000 { compatible = "samsung,s3c2410-irq"; reg = <0x4a000000 0x100>; interrupt-controller; #interrupt-cells = <4>; }; pinctrl_0: pinctrl@56000000 { reg = <0x56000000 0x1000>; wakeup-interrupt-controller { compatible = "samsung,s3c2410-wakeup-eint"; interrupts = <0 0 0 3>, <0 0 1 3>, <0 0 2 3>, <0 0 3 3>, <0 0 4 4>, <0 0 5 4>; }; }; timer@51000000 { compatible = "samsung,s3c2410-pwm"; reg = <0x51000000 0x1000>; interrupts = <0 0 10 3>, <0 0 11 3>, <0 0 12 3>, <0 0 13 3>, <0 0 14 3>; #pwm-cells = <4>; }; uart0: serial@50000000 { compatible = "samsung,s3c2410-uart"; reg = <0x50000000 0x4000>; interrupts = <1 28 0 4>, <1 28 1 4>; status = "disabled"; }; uart1: serial@50004000 { compatible = "samsung,s3c2410-uart"; reg = <0x50004000 0x4000>; interrupts = <1 23 3 4>, <1 23 4 4>; status = "disabled"; }; uart2: serial@50008000 { compatible = "samsung,s3c2410-uart"; reg = <0x50008000 0x4000>; interrupts = <1 15 6 4>, <1 15 7 4>; status = "disabled"; }; watchdog@53000000 { compatible = "samsung,s3c2410-wdt"; reg = <0x53000000 0x100>; interrupts = <0 0 9 3>; status = "disabled"; }; rtc@57000000 { compatible = "samsung,s3c2410-rtc"; reg = <0x57000000 0x100>; interrupts = <0 0 30 3>, <0 0 8 3>; status = "disabled"; }; i2c@54000000 { compatible = "samsung,s3c2410-i2c"; reg = <0x54000000 0x100>; interrupts = <0 0 27 3>; #address-cells = <1>; #size-cells = <0>; status = "disabled"; }; };
此外,并没有支持2440的设备树,最接近的只有2416的设备树。
2.4.1 添加设备树
仿照s3c2416-smdk2416.dts的结构添加了Mini2440的设备树需要的文件。执行如下命令:
root@zhengyang:/work/sambashare/linux-5.2.8-dt# cd arch/arm/boot/dts root@zhengyang:/work/sambashare/linux-5.2.8-dt/arch/arm/boot/dts# cp s3c2416.dtsi s3c2440.dtsi root@zhengyang:/work/sambashare/linux-5.2.8-dt/arch/arm/boot/dts# cp s3c2416-pinctrl.dtsi s3c2440-pinctrl.dtsi root@zhengyang:/work/sambashare/linux-5.2.8-dt/arch/arm/boot/dts# cp s3c2416-smdk2416.dts s3c2440-smdk2440.dts
代码含义:
- 复制s3c2416.dtsi为s3c2440.dtsi;
- 复制s3c2416-pinctrl.dtsi为s3c2440-pinctrl.dtsi;
- 复制s3c2416-smdk2416.dts为s3c2440-smdk2440.dts;
下面是设备树的结构:
s3c2440-smdk2440.dts ----> s3c2440.dtsi ----> s3c24xx.dtsi ----> skeleton.dtsi ----> s3c2440-pinctrl.dtsi
大概介绍一下上面各个文件:
- s3c2440.dtsi存放的是s3c2440这个SoC跟其他s3c24xx系列不同的一些硬件信息,如clock控制器、串口等等;
- s3c2440-pinctrl.dtsi存放的是s3c2440这个SoC中GPIO控制器、外部中断控制器、引脚复用等信息的配置;
- s3c2440-smdk2440.dts存放的是Mini2440的硬件信息;
- skeleton.dtsi 存放的是一个设备树必备的一些基本属性;
这些文件之前是有包含关系的,设备树这样一层层包含的好处是:在同名节点中,后出现的属性会覆盖前面出现的同名属性,不同的属性将来会合并到所隶属的同名的节点下面。
2.4.2 修改设备树Makefile
先修改设备树的Makefile:
root@zhengyang:/work/sambashare/linux-5.2.8-dt/arch/arm/boot/dts# vim Makefile
新增s3c2440-smdk2440.dtb:
dtb-$(CONFIG_ARCH_S3C24XX) += \ s3c2416-smdk2416.dtb \ s3c2440-smdk2440.dtb
由于CONFIG_ARCH_S3C24XX在arch/arm/configs/s3c2440_defconfig文件中定义,这样make dtbs的时候就会编译s3c2440-smdk2440.dtb。
2.5 支持Mini2440开发板
修改Makefile和Kconfig,并添加Mini2440的板子信息,使内核在启动时能从设备树文件中解析到的信息匹配到Mini2440板子。
2.5.1 修改arch/arm/mach-s3c24xx/Kconfig
添加ARCH_S3C2440_DT信息:
config ARCH_S3C2440 bool "SMDK2440" select S3C2440_XTAL_16934400 select S3C24XX_SMDK select S3C_DEV_NAND select S3C_DEV_USB_HOST help Say Y here if you are using the SMDK2440. config SMDK2440_CPU2440 bool "SMDK2440 with S3C2440 CPU module" default y if ARCH_S3C2440 select S3C2440_XTAL_16934400 config ARCH_S3C2440_DT bool "MINI2440 using devicetree" select TIMER_OF select USE_OF select PINCTRL select PINCTRL_S3C24XX help Say Y here if you are using the MINI2440 with device tree enabled.
这样的话,在make menuconfig的時候,选择ARCH_S3C2440_DT这个配置。选择了这个配置,CONFIG_TIMER_OF、CONFIG_USE_OF、CONFIG_PINCTRL、CONFIG_S3C24XX都会被配置上。
2.5.2 修改arch/arm/mach-s3c24xx/Makefile
obj-$(CONFIG_MACH_SMDK2416) += mach-smdk2416.o obj-$(CONFIG_MACH_S3C2416_DT) += mach-s3c2416-dt.o obj-$(CONFIG_MACH_ANUBIS) += mach-anubis.o obj-$(CONFIG_MACH_AT2440EVB) += mach-at2440evb.o obj-$(CONFIG_MACH_MINI2440) += mach-mini2440.o obj-$(CONFIG_MACH_NEXCODER_2440) += mach-nexcoder.o obj-$(CONFIG_MACH_OSIRIS) += mach-osiris.o obj-$(CONFIG_MACH_RX3715) += mach-rx3715.o obj-$(CONFIG_ARCH_S3C2440) += mach-smdk2440.o obj-$(CONFIG_ARCH_S3C2440_DT) += mach-smdk2440-dt.o # 新增
在menuconfig上选择了ARCH_S3C2440_DT后, 在make uImage的时候会定义CONFIG_ARCH_S3C2440_DT宏,这样就会编译链接mach-smdk2440-dt.c。
2.5.3 新增arch/arm/mach-s3c24xx/mach-smdk2440-dt.c
mach-smdk2440-dt.c文件内容参考mach-s3c2416-dt.c:
#include <linux/clocksource.h> #include <linux/irqchip.h> #include <linux/serial_s3c.h> #include <asm/mach/arch.h> #include <mach/map.h> #include <plat/cpu.h> #include <plat/pm.h> #include "common.h" static void __init s3c2440_dt_map_io(void) { s3c24xx_init_io(NULL, 0); } static void __init s3c2440_dt_machine_init(void) { s3c_pm_init(); } static const char *const s3c2440_dt_compat[] __initconst = { "samsung,s3c2440", "samsung,mini2440", NULL }; DT_MACHINE_START(S3C2440_DT, "Samsung S3C2440 (Flattened Device Tree)") /* Maintainer: Heiko Stuebner <heiko@sntech.de> */ .dt_compat = s3c2440_dt_compat, .map_io = s3c2440_dt_map_io, .init_irq = irqchip_init, .init_machine = s3c2440_dt_machine_init, MACHINE_END
这里我们需要注意的是dt_compat数组,其中的值要跟设备树中的compatible匹配,后面会介绍arch/arm/boot/dts/s3c2440-smdk2440-dt.dts的配置。
2.6 内核裁切
由于我们默认配置编译生成的内核文件是比较大,大概有3.5M的样子,这其中我们编译了许多无用的配置。因此需要对内核进行裁切。
然后可以通过make menuconfig修改配置:
make menuconfig
2.6.1 支持设备树
配置内核支持设备树,实际上linux 5.2.8已经默认支持设备树了:那么内核在启动时,不会通过uboot传入的machid来找到单板文件;而是通过上面的dt_compat数组中的信息和设备树中的compatible进行匹配,以此来找到相应单板文件;
Boot options ---> -*- Flattened Device Tree support
2.6.2 单板裁切
比如,默认编译的的内核,支持了多种单板。配置内核支持Mini2440单板文件,如下图所示,SoC下只选择S3C2440,单板文件下只选择MINI2440 using devicetree:
2.6.3 支持DM9000网卡
配置内核支持DM9000网卡:linux驱动移植-DM9000网卡驱动;
Device Drivers ---> [*] Network device support ---> [*] Ethernet driver support ---> <*> DM9000 support
即可找到DM9000的配置项,可以看到DM9000已经被选中,这是因为linux-5.2.8 默认的内核配置已经加入了DM9000的支持:
2.6.4 支持NFS文件系统
使用NFS作为根文件系统,因为文件系统在宿主机中,这样在修改文件系统就非常方便,主要用于开发阶段使用。
File systems ---> [*] Network File Systems ---> <*> NFS client support for NFS version 4
勾选NFS client support for NFS version 4。
2.6.5 支持内核调试日志
配置打开内核调试,为了能够尽量看到更多内核启动早期的log,一定要在内核配置文件中把内核早期的log配置打开:
Kernel hacking ---> [*] Kernel low-level debugging functions (read help!) Kernel low-level debugging port (Use Samsung S3C UART 0 for low-level debug) ---> [*] Early printk
这里串口选择启动参数bootargs中控制台指定的串口。
除了上面的配置,还必须在bootargs中添加一个earlyprintk字符串,否则这些log还是打印不出来。此外,建议再在bootargs中添加一个ignore_loglevel参数,防止有些模块的log由于loglevel的问题无法输出log。
2.6.6 配置EABI编译属性
因为arm-none-linux-gnueabi 4.8.3使用了EABI方式,所以这就需要内核同样配置EABI编译属性:
Kernel Features ---> [*] Use the ARM EABI to compile the kernel [*] Allow old ABI binaries to run with this kernel (EXPERIMENTAL)
2.6.7 配置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下无法生成节点的分析思路和解决方法及原理。
2.6.8 保存配置
保存配置:
存档:
mv s3c2440_defconfig ./arch/arm/configs/
重新配置内核:
root@zhengyang:/work/sambashare/linux-5.2.8-dt# make s3c2440_defconfig
2.7 编译内核
2.7.1 编译内核
在linux内核根目录下执行如下命令:
make V=1 uImage
uImage内核内核是通过如下命令得到的:
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 -T kernel -a 0x30008000 -e 0x30008000 -n 'Linux-5.2.8' -d arch/arm/boot/zImage arch/arm/boot/uImage
其中:
- -a : 设置内核镜像加载地址;zImage解压之后得到Image会加载到这个地址上;
- -e :设置内核镜像入口地址;内核启动的入口地址;
将uImage复制到tftp服务器路径下:
root@zhengyang:/work/sambashare/linux-5.2.8-dt# cp /work/sambashare/linux-5.2.8-dt/arch/arm/boot/uImage /work/tftpboot/
2.7.2 编译dts
在linux内核根目录执行如下命令:
root@zhengyang:/work/sambashare/linux-5.2.8-dt# make dtbs DTC arch/arm/boot/dts/s3c2416-smdk2416.dtb DTC arch/arm/boot/dts/s3c2440-smdk2440.dtb
编译设备树文件,把前面配置过的arch/arm/boot/dts里的dts文件编译成dtb文件。
将s3c2440-smdk2440.dtb复制到tftp服务器路径下:
root@zhengyang:/work/sambashare/linux-5.2.8-dt# cp /work/sambashare/linux-5.2.8-dt/arch/arm/boot/dts/s3c2440-smdk2440.dtb /work/tftpboot/
三、uboot支持FDT
关于Mini2440 uboot移植我们之前已经介绍过了,因此就不重新介绍了。具体参考Young / s3c2440_project[u-boot-2016.05-linux]。
3.1 支持FDT(扁平设备树)
我们如何修改uboot使其支持FDT呢,我们需要在uboot源码configs/smdk2440_defconfig文件中配置(或者通过make menuconfig进行配置):
CONFIG_OF_LIBFDT=y
配置CONFIG_OF_LIBFDT之后,uboot编译时将会链接lib/libfdt文件夹下文件:
lib/Makefile:54:obj-$(CONFIG_OF_LIBFDT) += libfdt/
3.1.1 编译uboot
make distclean make smdk2440_defconfig make ARCH=arm CROSS_COMPILE=arm-linux- V=1
需要注意的是,如果编译得到的u-boot.bin文件大于256KB,无法通过MiniTools工具下载的,因此需要进行裁切,使其小于256KB。比如配置include/configs/smdk2440.h :
/* support additional compression methods */ #if 0 #define CONFIG_BZIP2 #define CONFIG_LZO #define CONFIG_LZMA #endif
3.1.2 下载uboot
使用MiniTools下载uboot程序到NAND FLASH。
3.2 启动内核
开发板uboot启动完成后,内核启动前,按下任意键,进入uboot。uboot启动后,需要设置启动参数:
set bootargs "noinitrd console=ttySAC0,115200 root=/dev/nfs rw nfsroot=192.168.0.200:/work/nfs_root/rootfs ip=192.168.0.105:192.168.0.200:192.168.0.1:255.255.255.0::eth0:off ignore_loglevel earlyprintk" save
这里我们通过bootargs告知内核根文件系统为NFS网络文件系统,并详细的设置了ip,服务器ip,网关等网络参数信息,方便内核启动时直接通过这些参数去挂载NFS网络文件系统。关于根文件系统制作参考:Mini2440之linux内核移植之yaffs2根文件系统移植。
uboot支持FDT后,我们便可以将dtb下载到内存地址0x30001000中:
SMDK2440 # tftp 0x30001000 s3c2440-smdk2440.dtb
然后将内核镜像加载到内存0x30008000地址,并烧录内核到NAND FLASH:
SMDK2440 # tftp 30008000 uImage SMDK2440 # nand erase.part kernel SMDK2440 # nand write 30008000 kernel
然后可以使用如下命令启动内核:
SMDK2440 # bootm 0x30008000 - 0x30001000 // 无设备树时,直接bootm 0x30008000 //bootm uImage地址 ramdisk地址 设备树镜像地址
其中:
- 第一个参数为内核映像在内存的地址;
- 第二个参数为initrd的地址,若不存在initrd,可以用“-”符号代替;
- 第三个参数dtb_address为.dtb文件在内存的地址;
此外对于dtb的地址0x30001000,我们需要遵循以下原则:
- 不要破坏uboot本身;
- 不要破坏内核本身: 内核本身的空间不能占用, 内核要用到的内存区域也不能占用;
由于Mini2440的内存区间为0x30000000~0x34000000,并且:
- 高地位为uboot,以及uboot使用的栈空间;
- 这里我们将内核加载地址修改为0x30008000地址,内核启动时一般会在它所处位置的下边放置页表,这块空间(一般是0x4000即16K字节)不能被占用;
3.3 开发板测试
开发板运行上电运行后,结果如下:
U-Boot 2016.05 (Apr 11 2023 - 22:47:36 +0800) CPUID: 32440001 FCLK: 400 MHz HCLK: 100 MHz PCLK: 50 MHz UCLK: 48 MHz DRAM: 64 MiB WARNING: Caches not enabled Flash: 0 Bytes NAND: 128 MiB In: serial Out: serial Err: serial Net: dm9000 Hit any key to stop autoboot: 0 SMDK2440 # tftp 0x30001000 s3c2440-smdk2440.dtb dm9000 i/o: 0x20000000, id: 0x90000a46 DM9000: running in 16 bit mode MAC: 08:00:3e:26:0a:5b operating at unknown: 0 mode Using dm9000 device TFTP from server 192.168.0.200; our IP address is 192.168.0.188 Filename 's3c2440-smdk2440.dtb'. Load address: 0x30001000 Loading: # 1000 Bytes/s done Bytes transferred = 5851 (16db hex) SMDK2440 # tftp 30008000 uImage dm9000 i/o: 0x20000000, id: 0x90000a46 DM9000: running in 16 bit mode MAC: 08:00:3e:26:0a:5b operating at unknown: 0 mode Using dm9000 device TFTP from server 192.168.0.200; our IP address is 192.168.0.188 Filename 'uImage'. Load address: 0x30008000 Loading: ################################################################# ################################################################# ################################################################# ################################################################# ###### 1.1 MiB/s done Bytes transferred = 3896232 (3b73a8 hex) SMDK2440 # bootm 0x30008000 - 0x30001000 ## Booting kernel from Legacy Image at 30008000 ... Image Name: Linux-5.2.8 Image Type: ARM Linux Kernel Image (uncompressed) Data Size: 3896168 Bytes = 3.7 MiB Load Address: 30008000 Entry Point: 30008000 Verifying Checksum ... OK Loading Kernel Image ... OK Using machid 0xa8 from environment Starting kernel ...
结果发现,内核和设备树加载到内存后,内核无法正常运行;后续就是设备树的修改工作了。
如果修改设备树中的设备节点信息,有两种办法;
- 修改dts文件,重新编译得到dtb并上传烧写
- 使用uboot提供的一些命令来修改dtb文件,修改后再把它保存到板子上;
关于设备树修改我们在下一节单独介绍。
参考文章
[1]linux设备驱动(19)设备树详解3-u-boot传输dts
[2]linux设备驱动(20)设备树详解4-kernel解析dts
[9]TQ2440设备树
[10]Exynos4412的Linux5.4.174时钟驱动开发(五)——时钟设备树的修改方法
[12]https://www.kernelconfig.io/(内核配置项)