编译适用于mt7620a的OpenWrt

时间:2024-03-13 19:37:09

本篇博客同时发布于:https://lyq.blogd.club/2018/11/08/build-openwrt/

前言

由于本人酷爱刷机,可以说是几天不刷机手就痒的那种,于是最近想看看能否在安卓下写一个工具箱(当然必须要MD材料化的工具箱,Material Design YES!!!),去实现一些简单的操作,例如用linux的busybox里面的dd命令,比如:

$ dd if = .../recovery.img of = /dev/block/.../by-name/recovery 

这个命令去刷一下TWRP的第三方recovery。

但是吧,看了几天发现安卓入门怪复杂的,目前也仅仅看了看xml的几种布局,回头一想Java只会基本语法,高级特性啥也不会。

立即推 -> 放弃。。。

当然,放弃是不可能放弃的,这辈子都不可能放弃的,然后决定用Kotlin写吧,故又看了几天的Kotlin,话说这东西语法是真的牛批,简洁,面向对象。

上面说的这么多,和编译OpenWrt的笔记有什么关系吗?!

当然有,如果我今天不看Kotlin,就不会头昏脑胀,不头昏脑涨,就不会想着换点别的东西折腾折腾。

OpenWrt

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就不说了

同步源码

git clone https://github.com/lede-project/source.git

并不很大,几百Mb。主要是后面编译的时候还要在线下载很多东西。

目录结构如下

.
├── 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

更新源:

./scripts/feeds update -a

依据feeds.conf.default文件中的仓库地址来下载相应的软件,它提供了一些额外的扩展。

安装源:

./scripts/feeds install -a

如果少了一些依赖会提示:

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了一番。。。

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拥有一个文本界面,包括处理的目标平台,要编译的软件包,要被包含进固件的软件包和一些内核设置,长这样:
编译适用于mt7620a的OpenWrt

这边有三种选项:

  1. < > 该代码将不会被编译
  2. <M> 该代码将被交叉编译,生成的ipk软件包将被放在 /bin/packages/mipsel_24kc/base(以mt7620为例), 但该软件包不会放入固件中,需要你自己去安装
  3. <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)

编译适用于mt7620a的OpenWrt

弄完save一下,保存为默认的.config

按两下exit退出,输入

make V=99 -j1

开始编译,这里最好不要用多线程编译,我一开始-j4总是出错,编译的时候不能断网,会下载很多东西,然后就是漫长的等待了。
编译适用于mt7620a的OpenWrt

支持16Mb闪存

之前刷OP官方提供的固件,闪存只识别为8M,所以要修改一下 \source\target\linux\ramips\dts\PSG1218.dtsi

	[email protected] {
		compatible = "jedec,spi-nor";
		reg = <0>;
		spi-max-frequency = <10000000>;

		partitions {
			compatible = "fixed-partitions";
			#address-cells = <1>;
			#size-cells = <1>;

			[email protected] {
				label = "u-boot";
				reg = <0x0 0x30000>;
				read-only;
			};

			[email protected] {
				label = "u-boot-env";
				reg = <0x30000 0x10000>;
				read-only;
			};

			factory: [email protected] {
				label = "factory";
				reg = <0x40000 0x10000>;
				read-only;
			};

			[email protected] {
				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镜像:
编译适用于mt7620a的OpenWrt
可用空间只有可怜的4M…
刷入修改过的dts编译出来的img镜像:
编译适用于mt7620a的OpenWrt
可以看到有11M的可用空间,顺手scp上传了一首我B的歌到/root下,9.58M,证明确实可用10M空间。
编译适用于mt7620a的OpenWrt

如果输入cat /proc/mtd那么看到详细的分区大小,第一层分别是u-boot、u-boot(env)、factory、firmware,我们刷写固件就是刷写firmware分区。第二层分区kernel和rootfs,第三层分区rootfs_data。

Breed不死u-boot的原理就是在刷写的时候去除固件中的u-boot分区,达到自身不被覆盖、不死的效果。
编译适用于mt7620a的OpenWrt

添加编译自己的软件

首先于package/utils创建一个helloworld文件夹,然后

cp package/utils/nvram/Makefile package/utils/helloworld

拷贝一份写好的Makefile。
然后 nano Makeile

可以看到


#
# Copyright (C) 2009-2010 Jo-Philipp Wich <[email protected]>
#
# 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 <[email protected]>
  DEPENDS:[email protected]_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:

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:[email protected]
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:

#include <stdio.h>
#include <stdlib.h>

int main(int argc,char *argv[]){
    printf("Hello World!");
    return 0;
}

Makefile:

APP_NAME =  helloworld
OBJ = helloworld.o
ORC = helloworld.c

$(APP_NAME):$(OBJ)
%(OBJ):$(ORC)
        $(CC) $(CFLAGS) -c $(ORC)

clean:
        rm $(OBJ) $(APP_NAME)

目录结构如下:

.
├── Makefile
└── src
    ├── Makefile
    └── helloworld.c

1 directory, 3 files

返回顶层目录执行make menuconfig,选择Utilities,可以看到helloworld出现了,这时候可以选择编译进系统或者只编译单独的ipk。

编译适用于mt7620a的OpenWrt

当然,这样重新编译也太麻烦了,回到顶层目录执行

make package/utils/helloworld/compile V=99

可单独编译出ipk文件,这个文件位于bin/packages/mipsel_24kc/base/helloworld_1_mipsel_24kc.ipk

把这个文件上传到路由器上并安装:

scp bin/packages/mipsel_24kc/base/helloworld_1_mipsel_24kc.ipk [email protected]:/tmp
ssh [email protected]
cd /tmp
opkg install helloworld_1_mipsel_24kc.ipk

安装完成输出:

Installing helloworld (1) to root...
Configuring helloworld.

这时候输入helloworld,运行一下:

[email protected]:/tmp# helloworld
Hello World!

OK,这样就完成了编译自己的*.ipk程序。

当然,值得一提的是,如果你只需要交叉编译自己的软件,并不需要下载整个源码,可以去openwrt官网下载对应的sdk,例如mt7620 openwrt v18.06.01的sdk下载地址是:这里
,大体结构与openwrt源码一样。解压之后将要编译的程序放到package目录,执行

make menuconfig
make package/helloworld/compile V=99

即可生成ipk。

这种方法与我之前的交叉编译不同(见:12),虽略为繁琐,但是可以生成ipk文件,方便包管理。

这里的helloworld使用的是Makefile进行编译,如果对于一些使用Automake,需要./configure才能生成Makefile的程序,那么就要修改上一层目录的Makefile了。

添加自己的文件到固件中

如果有一个文件,hello.config想放到路由器固件目录的/etc/config/,那么把它移动到buildroot下的/files/etc/config/目录再执行make即可。文件夹不存在就自己创建。

烧录一下编译出来的bin:
编译适用于mt7620a的OpenWrt

执行ls /files/etc/config/hello.config看一下是否把文件编译进了系统:
编译适用于mt7620a的OpenWrt

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配置格式。

## 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

所以如果想加入本地项目,添加一行:

src custom file:///yours/bin/ramips/packages

添加远端项目同理,像src/gz这样既可。
编译固件img用make image ***这个命令,由于暂时没有使用过,所以就不写了。

未完待续…