前言 OpenWRT是一个高度模块化、自动化的嵌入式Linux系统,拥有强大的网络组建和扩展性,常常被用于工控设备、电话、小型机器人、智能家居、路由器以及VOIP设备中,其中在智能路由器上有广泛使用。同时它还提供了100多个已编译好的软件,而且数量还在不断增加。
OpenWRT支持各种处理器架构,无论是ARM、X86、PowerPC或者MIPS都有很好的支持。其多达3000多种软件包,囊括从工具链(toolchain),到内核(Linux Kernel),到软件包(packages),再到根文件系统(rootfs)整个体系,是的开发者只需要简单的一个make命令就可以方便快速的定制一个具有特定功能的嵌入式系统。
对于想学习嵌入式Linux开发的工程师来说,OpenWRT是非常适合的(引用)
。
我第一次接触Openwrt是在2013年,那是正是高二,家里有一个TP-Link的wr740路由器,mips架构,4M的Flash,16M的内存,当时刷过dd-wrt和openwrt。
第二次是在大二了,当时为了用路由器上校园网,撸了几台k2,研究了如何在openwrt等第三方路由器固件下实现锐捷和安腾的认证。
今天我要给k2编译一下Openwrt最新的Snapshot固件,顺便解决一下不识别16M闪存的问题。
编译环境
Ubuntu 18.06 Windows SubSystem Linux
硬盘 > 100G
编译所需dependencies就不说了
同步源码 1 git clone https://github.com/lede-project/source.git
并不很大,几百Mb。主要是后面编译的时候还要在线下载很多东西。
目录结构如下
1 2 3 4 5 6 7 8 . ├── tools – automake, autoconf, sed, cmake ├── toolchain/binutils – as, ld, … ├── toolchain/gcc – gcc, g++, cpp, … ├── target/linux – kernel modules ├── package – core and feed packages ├── target/linux – kernel image └── target/linux/image – firmware image file generation
Feeds 更新源:
1 ./scripts/feeds update -a
依据feeds.conf.default文件中的仓库地址来下载相应的软件,它提供了一些额外的扩展。
安装源:
1 ./scripts/feeds install -a
如果少了一些依赖会提示:
1 2 3 4 5 6 7 8 9 WARNING: Makefile 'package/utils/busybox/Makefile' has a dependency on 'libpam', which does not exist WARNING: Makefile 'package/utils/busybox/Makefile' has a build dependency on 'libpam', which does not exist WARNING: Makefile 'package/network/utils/curl/Makefile' has a dependency on 'libgnutls', which does not exist WARNING: Makefile 'package/network/utils/curl/Makefile' has a dependency on 'libopenldap', which does not exist WARNING: Makefile 'package/network/utils/curl/Makefile' has a dependency on 'libidn2', which does not exist WARNING: Makefile 'package/network/utils/curl/Makefile' has a dependency on 'libssh2', which does not exist WARNING: Makefile 'package/boot/kexec-tools/Makefile' has a dependency on 'liblzma', which does not exist WARNING: Makefile 'package/network/services/lldpd/Makefile' has a dependency on 'libnetsnmp', which does not exist WARNING: Makefile 'package/network/utils/nftables/Makefile' has a dependency on 'jansson', which does not exist
这时候我谷歌了一番 “And re-run ./scripts/feeds update -a successful, no error out.”
于是我也re-run了一番。。。
1 2 3 4 5 Collecting package info: done Installing all packages from feed packages. Installing all packages from feed luci. Installing all packages from feed routing. Installing all packages from feed telephony.
结果没报错。。。这真的是玄学吗 下载之后的文件位于feeds文件夹内。
编译 然后就是编译了,执行make menuconfig
,menuconfig拥有一个文本界面,包括处理的目标平台,要编译的软件包,要被包含进固件的软件包和一些内核设置,长这样:
这边有三种选项:
< >
该代码将不会被编译
<M>
该代码将被交叉编译,生成的ipk软件包将被放在 /bin/packages/mipsel_24kc/base(以mt7620为例), 但该软件包不会放入固件中,需要你自己去安装
<X>
该代码将被放入固件中 (on the SqashFS partition)
K2,故选择Target System 为(MediaTek Ralink MIPS),Subtarget为(MT 7620 based boards),由于K2是有官方资瓷的,所以Target Profile选择(Phicomm PSG1218 rev.A,rev.B应该是K2P)
同时LuCi要勾一下(Luci - Collections - luci和Luci - modules - translation - Chinese)
弄完save一下,保存为默认的.config
按两下exit退出,输入
开始编译,这里最好不要用多线程编译,我一开始-j4总是出错,编译的时候不能断网,会下载很多东西,然后就是漫长的等待了。
支持16Mb闪存 之前刷OP官方提供的固件,闪存只识别为8M,所以要修改一下 \source\target\linux\ramips\dts\PSG1218.dtsi
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 m25p80@0 { compatible = "jedec,spi-nor"; reg = <0>; spi-max-frequency = <10000000>; partitions { compatible = "fixed-partitions"; #address-cells = <1>; #size-cells = <1>; partition@0 { label = "u-boot"; reg = <0x0 0x30000>; read-only; }; partition@20000 { label = "u-boot-env"; reg = <0x30000 0x10000>; read-only; }; factory: partition@30000 { label = "factory"; reg = <0x40000 0x10000>; read-only; }; partition@40000 { label = "firmware"; reg = <0x50000 0x7b0000>; }; }; };
这个dts(devives tree source)定义了一系列板载参数,拉出来这一段代码与分区有关,<>第一个参数表示起始地址,第二个参数表示大小。
从0x0 -> 0x2FFFF
,一共是196608个地址,每个地址里面存放一个字节的数据,196608 / 1024 = 192, 192Kbit的存储空间保存的是u-boot,即引导文件所在分区。
同理,0x30000 -> 0x3FFFF
,的64Kbit存储空间保存的是u-boot-env,保存的是u-boot的环境变量(不太了解)。
0x40000 -> 0x4FFFF
的64Kbit保存的是factory,不知道是什么,估计存放的是MAC地址和一些原厂增益参数。
从0x50000 -> 0x7FFFFF
的7.6875Mbit空间是固件可用存储空间大小,总地址0x0 -> 0x7FFFFF
,0x800000个地址,8Mbit。
所以为了加大对存储空间的支持,把<0x50000 0x7b0000>
这个参数改成<0x50000 0xfb0000>
,再重新编译一下,这样就可以了。
验证一下是否识别16M闪存 刷入未修改dts编译出来的img镜像: 可用空间只有可怜的4M… 刷入修改过的dts编译出来的img镜像: 可以看到有11M的可用空间,顺手scp上传了一首我B的歌到/root下,9.58M,证明确实可用10M空间。
如果输入cat /proc/mtd
那么看到详细的分区大小,第一层分别是u-boot、u-boot(env)、factory、firmware,我们刷写固件就是刷写firmware分区。第二层分区kernel和rootfs,第三层分区rootfs_data。
Breed不死u-boot的原理就是在刷写的时候去除固件中的u-boot分区,达到自身不被覆盖、不死的效果。
添加编译自己的软件 首先于package/utils创建一个helloworld文件夹,然后
1 cp package/utils/nvram/Makefile package/utils/helloworld
拷贝一份写好的Makefile。 然后 nano Makeile
可以看到
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 # # Copyright (C) 2009-2010 Jo-Philipp Wich <xm@subsignal.org> # # This is free software, licensed under the GNU General Public License v2. # See /LICENSE for more information. # include $(TOPDIR)/rules.mk PKG_NAME:=nvram PKG_RELEASE:=10 PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) PKG_FLAGS:=nonshared include $(INCLUDE_DIR)/package.mk define Package/nvram SECTION:=utils CATEGORY:=Base system TITLE:=Userspace port of the Broadcom NVRAM manipulation tool MAINTAINER:=Jo-Philipp Wich <xm@subsignal.org> DEPENDS:=@TARGET_brcm47xx||@TARGET_bcm53xx||@TARGET_ar71xx||@TARGET_ath79 endef define Package/nvram/description This package contains an utility to manipulate NVRAM on Broadcom based devices. It works on bcm47xx (Linux 2.6) without using the kernel api. endef define Build/Compile $(MAKE) -C $(PKG_BUILD_DIR) \ CC="$(TARGET_CC)" \ CFLAGS="$(TARGET_CFLAGS) -Wall" \ LDFLAGS="$(TARGET_LDFLAGS)" endef define Package/nvram/install $(INSTALL_DIR) $(1)/usr/sbin $(INSTALL_BIN) $(PKG_BUILD_DIR)/nvram $(1)/usr/sbin/ ifneq ($(CONFIG_TARGET_brcm47xx),) $(INSTALL_DIR) $(1)/etc/init.d $(INSTALL_BIN) ./files/nvram.init $(1)/etc/init.d/nvram endif endef
我们只要修改一些必要的东西即可。 修改后的Makefile:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 include $(TOPDIR)/rules.mk PKG_NAME:=helloworld PKG_RELEASE:=1 PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) include $(INCLUDE_DIR)/package.mk define Package/helloworld SECTION:=utils CATEGORY:=Utilities TITLE:=helloworld MAINTAINER:=admin@lyq.blogd.club endef define Package/helloworld/description This is a Demo to test build-in package. endef define Build/Prepare mkdir -p $(PKG_BUILD_DIR) $(CP) ./src/* $(PKG_BUILD_DIR)/ endef define Build/Configure endef define Build/Compile $(MAKE) -C $(PKG_BUILD_DIR) \ CC="$(TARGET_CC)" \ CFLAGS="$(TARGET_CFLAGS) -Wall" \ LDFLAGS="$(TARGET_LDFLAGS)" endef define Package/helloworld/install $(INSTALL_DIR) $(1)/bin $(INSTALL_BIN) $(PKG_BUILD_DIR)/helloworld $(1)/bin/ endef $(eval $(call BuildPackage,helloworld))
再创建一个src文件夹,其中创建一个helloworld.c和Makefile。
helloworld.c:
1 2 3 4 5 6 7 #include <stdio.h> #include <stdlib.h> int main(int argc,char *argv[]){ printf("Hello World!"); return 0; }
Makefile:
1 2 3 4 5 6 7 8 9 10 APP_NAME = helloworld OBJ = helloworld.o ORC = helloworld.c $(APP_NAME):$(OBJ) %(OBJ):$(ORC) $(CC) $(CFLAGS) -c $(ORC) clean: rm $(OBJ) $(APP_NAME)
目录结构如下:
1 2 3 4 5 6 7 . ├── Makefile └── src ├── Makefile └── helloworld.c 1 directory, 3 files
返回顶层目录执行make menuconfig
,选择Utilities,可以看到helloworld出现了,这时候可以选择编译进系统或者只编译单独的ipk。
当然,这样重新编译也太麻烦了,回到顶层目录执行
1 make package/utils/helloworld/compile V=99
可单独编译出ipk文件,这个文件位于bin/packages/mipsel_24kc/base/helloworld_1_mipsel_24kc.ipk
把这个文件上传到路由器上并安装:
1 2 3 4 scp bin/packages/mipsel_24kc/base/helloworld_1_mipsel_24kc.ipk root@192.168.1.1:/tmp ssh root@192.168.1.1 cd /tmp opkg install helloworld_1_mipsel_24kc.ipk
安装完成输出:
1 2 Installing helloworld (1) to root... Configuring helloworld.
这时候输入helloworld
,运行一下:
1 2 root@OpenWrt:/tmp# helloworld Hello World!
OK,这样就完成了编译自己的*.ipk程序。
当然,值得一提的是,如果你只需要交叉编译自己的软件,并不需要下载整个源码,可以去openwrt官网下载对应的sdk,例如mt7620 openwrt v18.06.01的sdk下载地址是:这里 ,大体结构与openwrt源码一样。解压之后将要编译的程序放到package目录,执行
1 2 make menuconfig make package/helloworld/compile V=99
即可生成ipk。
这种方法与我之前的交叉编译不同(见:1 ,2 ),虽略为繁琐,但是可以生成ipk文件,方便包管理。
这里的helloworld使用的是Makefile进行编译,如果对于一些使用Automake,需要./configure才能生成Makefile的程序,那么就要修改上一层目录的Makefile了。
添加编译远程仓库的软件 假设在github上有一个软件,想要交叉编译成ipk安装,例如atclient 此程序需要编译三部曲: ./configure make make install
那么于package/utils/新建一个openwrt-atclient文件夹,目录结构如下:
1 2 3 utils └── openwrt-atclient └── Makefile
Makefile内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 # # Copyright (C) 2007-2009 OpenWrt.org # # This is free software, licensed under the GNU General Public License v2. # See /LICENSE for more information. # include $(TOPDIR)/rules.mk PKG_NAME:=atclient PKG_VERSION:=2.0.0 PKG_RELEASE:=1 PKG_REV:=249c959 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-r$(PKG_REV).tar.bz2 PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION) PKG_SOURCE_PROTO:=git PKG_SOURCE_VERSION:=$(PKG_REV) PKG_SOURCE_URL:=https://github.com/lyq1996/atclient.git PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION) include $(INCLUDE_DIR)/package.mk include $(INCLUDE_DIR)/nls.mk define Package/atclient SECTION:=utils CATEGORY:=Utilities TITLE:=A 3-party ANTENG BAS client endef define Package/atclient/install $(INSTALL_DIR) $(1)/bin $(INSTALL_BIN) $(PKG_BUILD_DIR)/src/atclient $(1)/bin/ endef $(eval $(call BuildPackage,atclient))
其中PKG_SOURCE_URL是仓库地址,PKG_REV是项目的head,PKG_VERSION是项目的版本,其他的都与上面相同。
执行
1 2 make menuconfig make package/openwrt-atclient/compile V=99
此时会先从远程仓库clone项目源码下来,然后根据head,切换至对应分支。 然后才会进行编译。
添加自己的文件到固件中 如果有一个文件,hello.config想放到路由器固件目录的/etc/config/
,那么把它移动到buildroot下的/files/etc/config/
目录再执行make即可。文件夹不存在就自己创建。
烧录一下编译出来的bin:
执行ls /files/etc/config/hello.config
看一下是否把文件编译进了系统:
Image Builder的使用 openwrt官方提供了一个imagebuilder工具,顾名思义,用来构建固件img的。根据官方介绍,这个东西对于以下方面很有用:
想在小Flash机器中塞入更多软件
想跟随snapshots开发版本
设备RAM小于等于32MB,OPKG不能正常工作
大闪存设备,想要一个特殊的固件。
Image Builder在编译系统时候会自动生成(编译需要生成img镜像,所以这个是必须的),可以在make menuconfig中勾选,这样在编译固件的时候会同时在bin/targets/ramips/mt7620/中生成Image Builder。当然,也可以自己下载,例如mt7620 openwrt v18.06.01的imgbuilder下载地址是:这里 。
在这个目录里,package的源是由repositories.conf所指定的,是opkg配置格式。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 ## Place your custom repositories here, they must match the architecture and version. # src/gz %n http://downloads.openwrt.org/releases/18.06.0-rc2 # src custom file:///usr/src/openwrt/bin/ramips/packages ## Remote package repositories src/gz openwrt_core http://downloads.openwrt.org/releases/18.06.0-rc2/targets/ramips/mt7621/packages src/gz openwrt_base http://downloads.openwrt.org/releases/18.06.0-rc2/packages/mipsel_24kc/base src/gz openwrt_luci http://downloads.openwrt.org/releases/18.06.0-rc2/packages/mipsel_24kc/luci src/gz openwrt_packages http://downloads.openwrt.org/releases/18.06.0-rc2/packages/mipsel_24kc/packages src/gz openwrt_routing http://downloads.openwrt.org/releases/18.06.0-rc2/packages/mipsel_24kc/routing src/gz openwrt_telephony http://downloads.openwrt.org/releases/18.06.0-rc2/packages/mipsel_24kc/telephony ## This is the local package repository, do not remove! src imagebuilder file:packages
所以如果想加入本地项目,添加一行:
1 src custom file:///yours/bin/ramips/packages
添加远端项目同理,像src/gz这样既可。 编译固件img用make image ***
这个命令,由于暂时没有使用过,所以就不写了。
未完待续…