最小固件:
3604643
openwrt-ramips-mt76x8-mt7628-squashfs-sysupgrade.bin
带LUCI:
./scripts/feeds update -a
./scripts/feeds install -a
make defconfig
make check
make download
make menuconfig
make V=s
1.修改固件大小限制和flash分区
在target中主要是针对各个平台对应的makefile和编译规则等,
当然也有通用的部分
openwrt-master/target/linux/ramips/image/mt76x8.mk
可以查看到当前平台所对应的各种路由器固件配置
这是当前的目标板
define Device/mt7628
DTS := MT7628
BLOCKSIZE := 64k
IMAGE_SIZE := $(ralink_default_fw_size_4M)
DEVICE_TITLE := MediaTek MT7628 EVB
DEVICE_PACKAGES := kmod-usb2 kmod-usb-ohci kmod-usb-ledtrig-usbport
endef
TARGET_DEVICES += mt7628
由于固件大小被限制为4m,所以当固件超过4M的时候就会出现编译错误
partition@50000 {
label = "firmware";
reg = <0x50000 0x7b0000>;
};
这里默认是7m多一点,根据flash大小设置
partition@50000 {
label = "firmware";
// reg = <0x50000 0x7b0000>; //8MB flash
// reg = <0x50000 0xfb0000>; //16MB flash
reg = <0x50000 0x1fb0000>; //32MB flash
};
2.修改内存大小
MT7628.dts文件有
memory@0 {
device_type = “memory”;
reg = <0x0 0x10000000>; //256MB RAM
// reg = <0x0 0x8000000>; //128MB RAM
// reg = <0x0 0x4000000>; //64MB RAM
};
但是据说lede很多在修改dts后不生效的。
//在menuconfig(make kenerl_menuconfig)的时候搜索Machine selection --> DRAM Size
3.修改波特率
target/linux/ramips/dts/mt7628an.dtsi
chosen {
bootargs = “console=ttyS0,115200”;
};
4.修改主机名、时区等,
package/base-files/files/bin/config_generate
generate_static_system() {
224 uci -q batch <<-EOF
225 delete system.@system[0]
226 add system system
227 set system.@system[-1].hostname=‘Jiamu’
228 set system.@system[-1].timezone=‘CTS-8’
229 set system.@system[-1].zonename=‘Asia/Shanghai’
230 set system.@system[-1].ttylogin=‘0’
231 set system.@system[-1].log_size=‘64’
232 set system.@system[-1].urandom_seed=‘0’
233
234 delete system.ntp
235 set system.ntp=‘timeserver’
236 set system.ntp.enabled=‘1’
237 set system.ntp.enable_server=‘0’
238 add_list system.ntp.server=‘0.openwrt.pool.ntp.org’
239 add_list system.ntp.server=‘1.openwrt.pool.ntp.org’
240 add_list system.ntp.server=‘2.openwrt.pool.ntp.org’
241 add_list system.ntp.server=‘3.openwrt.pool.ntp.org’
242 EOF
5.默认启动wifi,修改wifi名字
package/kernel/mac80211/files/lib/wifi/mac80211.sh
uci -q batch <<-EOF
set wireless.radio${devidx}=wifi-device
set wireless.radio${devidx}.type=mac80211
set wireless.radio${devidx}.channel=${channel}
set wireless.radio${devidx}.hwmode=11${mode_band}
${dev_id}
${ht_capab}
set wireless.radio${devidx}.disabled=0 //使能
set wireless.default_radio${devidx}=wifi-iface
set wireless.default_radio${devidx}.device=radio${devidx}
set wireless.default_radio${devidx}.network=lan
set wireless.default_radio${devidx}.mode=ap
set wireless.default_radio${devidx}.ssid=jiamu //ssid名
set wireless.default_radio${devidx}.encryption=psk //wifi加密方式
set wireless.default_radio${devidx}.key=12345678
EOF
6.自定义busybox
Base system
打开ftpget/ftpput tftp等功能
7.设置串口登录密码
在inittab中添加
::respawn:/sbin/getty -L ttyS0 115200 vt100
主要配置busybox支持gettty
文件系统挂载:
启动流程:
kernel_init -->内核启动
try_to_run_init_process("/sbin/init") --> 启动init程序,似乎和cc不同的是没有直接从/etc/preinit启动
这个init是procd中的init.c的init编译的
early挂载proc等节点,所以在文件系统中不需要fatab了,初始化环境变量(init: Console is alive)
cmdline();解析传递过来的init_debug参数
watchdog_init();初始化看门狗,怎么用这个看门狗???(init: - watchdog -)
execvp(kmod[0], kmod);开始加载/etc/modules-boot.d/的所有驱动/etc/modules-boot.d/*
preinit();(init: - preinit -)
a):先执行/sbin/procd -h /etc/hotplug-preinit.json
b):sh /etc/preinit 执行preinit
c):最后会调用spawn_procd,Exec to real procd now
uloop_run();这个是libubox的函数
到这里init程序就初始化完成
结果:
1.执行/etc/preinit
2.执行/sbin/procd
/etc/preinit:
1:定义函数链表头,共有下面五种链表
boot_hook_init preinit_essential
boot_hook_init preinit_main
boot_hook_init failsafe
boot_hook_init initramfs
boot_hook_init preinit_mount_root、
boot_hook_init在preinit.sh中定义
2.执行脚本,脚本主要是
for pi_source_file in /lib/preinit/*; do
. $pi_source_file
done
3.执行preinit_essential和preinit_main这个链表中的函数
boot_run_hook preinit_essential
boot_run_hook preinit_main
这里在分析脚本的时候,需要关注package/base-files/Makefile
这里会初始化一份变量,在执行preinit的时候会用到
环境变量会echo到/lib/preinit/00_preinit.conf
这里的参数生成依赖于menuconfig的结果
pi_suppress_stderr=""
fs_failsafe_wait_timeout=2
pi_init_path="/usr/sbin:/usr/bin:/sbin:/bin"
pi_init_env=""
pi_init_cmd="/sbin/init"
pi_init_suppress_stderr="y"
pi_ifname=""
pi_ip="192.168.1.1"
pi_netmask="255.255.255.0"
pi_broadcast="192.168.1.255"
pi_preinit_net_messages="y"
pi_preinit_no_failsafe_netmsg=""
pi_preinit_no_failsafe="y"
/lib/preinit/在源码中的package/base-file/里面
主要分析函数链表:
preinit_essential
-->
好像什么都没有
preinit_main
-->
define_default_set_state
do_sysinfo_generic
preinit_ip
pi_indicate_preinit
failsafe_wait
run_failsafe_hook
indicate_regular_preinit
initramfs_test
do_mount_root
do_urandom_seed
run_init
failsafe
-->
indicate_failsafe
failsafe_netlogin
failsafe_shell
initramfs
-->
好想也是空的
preinit_mount_root
-->
move_config
在添加的函数链表里面主要是这两种,在preinit最后执行了preinit_main链表
define_default_set_state:
target/linux/ramips/base-files/etc/diag.sh
应该是执行了这个脚本
这里应该是和led相关
由于未传递参数,这里应该什么都没有做
do_sysinfo_generic:
主要是创建了/tmp/sysinfo/model和 /tmp/sysinfo/board_name
根据/proc/device-tree里面的
后面应该会用到这两个文件
preinit_ip:
由于CONFIG_TARGET_PREINIT_DISABLE_FAILSAFE禁止了故障模式
所以pi_preinit_no_failsafe="y"
这里就不执行啥子了
preinit_ip_config:
preinit_config_board:
pi_indicate_preinit:
set_state preinit 执行set_state,传递preinit
status_led_blink_preinit 应该是led的相关信息,暂时不管
failsafe_wait 故障模式等待
fs_wait_for_key "" "" $fs_failsafe_wait_timeout执行这个
这里应该就是在处理故障模式
在启动的时候打印出来的
Press the [1], [2], [3] or [4] key and hit [enter] to select the debug level
故障模式暂时不管
run_failsafe_hook
[ "$pi_preinit_no_failsafe" = "y" ] && return 什么都不做
indicate_regular_preinit
set_state preinit_regular 还是led
initramfs_test
if [ -n "$INITRAMFS" ];
initramfs
preinit_ip_deconfig
好像由于没有设置INITRAMFS而没有执行
do_mount_root
执行/sbin/mount_root
应该是用于执行sysupgrade升级
输出mount_root: jffs2 not ready yet, using temporary tmpfs overlay
do_urandom_seed
这里应该是设置随机数的种子一类的东西
输出了urandom-seed: Seeding with /etc/urandom.seed
到这里preinit就执行完了
根据前面在
init.c
main
preinit
中的分析
preinit_proc.cb = spawn_procd;
preinit_proc.pid = fork();
if (!preinit_proc.pid) {
execvp(init[0], init);
ERROR("Failed to start preinit: %m\n");
exit(-1);
}
fork自后先执行execvp(init[0], init);,即/etc/preinit脚本
然后在执行完之后执行
spawn_procd
启动/sbin/procd
/sbin/procd:
prod在终端的输出信息
[ 7.684634] procd: - early -
[ 7.688519] procd: - watchdog -
[ 8.385976] procd: - watchdog -
[ 8.389466] procd: - ubus -
1.procd_state_next
state_enter
-->
STATE_EARLY
LOG("- early -\n");
watchdog_init(0); //
hotplug("/etc/hotplug.json"); //很具json文件初始化一些热插拔时间,里面使用了netlink套接字
procd_coldplug(); //应该是对部分文件系统进行挂载
里面会执行一个udevtrigger的命令
并且注册udevtrigger.cb = udevtrigger_complete;
在执行完毕之后调用udevtrigger_complete
coldplug_complete
procd_state_next
STATE_UBUS
STATE_UBUS //ubus是比较重要的
watchdog_init(0);
set_stdio("console"); //设置控制终端
LOG("- ubus -\n");
procd_connect_ubus();
service_start_early("ubus", ubus_cmd);
STATE_INIT
inittab的内容
::sysinit:/etc/init.d/rcS S boot
::shutdown:/etc/init.d/rcS K shutdown
::askconsole:/usr/libexec/login.sh
procd_inittab_run
会去匹配static struct init_handler handlers
然后执行对应的回调函数
runrc
rcS
_rc(&q, "/etc/rc.d", pattern, "*", param);
会去执行/etc/rc.d/下的脚本
但是这些脚本是在哪里生成的呢?
全是链接文件,执行了/etc/init.d/下面的对应文件
sysinit:
会去执行S开头的脚本,传入参数为boot,
脚本里面都有boot函数,会执行每个脚本的booton
这是调用顺序
Now cycle init scripts 0 /etc/rc.d/S00sysfixtime boot
Now cycle init scripts 1 /etc/rc.d/S10boot boot
Now cycle init scripts 2 /etc/rc.d/S10system boot
Now cycle init scripts 3 /etc/rc.d/S11sysctl boot
Now cycle init scripts 4 /etc/rc.d/S12log boot
Now cycle init scripts 5 /etc/rc.d/S12rpcd boot
Now cycle init scripts 6 /etc/rc.d/S19dnsmasq boot
Now cycle init scripts 7 /etc/rc.d/S19firewall boot
Now cycle init scripts 8 /etc/rc.d/S20network boot
Now cycle init scripts 9 /etc/rc.d/S30adblock boot
Now cycle init scripts 10 /etc/rc.d/S35odhcpd boot
Now cycle init scripts 11 /etc/rc.d/S50cron boot
Now cycle init scripts 12 /etc/rc.d/S50dropbear boot
Now cycle init scripts 13 /etc/rc.d/S50uhttpd boot
Now cycle init scripts 14 /etc/rc.d/S65wifidog boot
Now cycle init scripts 15 /etc/rc.d/S80ucitrack boot
Now cycle init scripts 16 /etc/rc.d/S94gpio_switch boot
Now cycle init scripts 17 /etc/rc.d/S95done boot
Now cycle init scripts 18 /etc/rc.d/S96led boot
Now cycle init scripts 19 /etc/rc.d/S98sysntpd boot
Now cycle init scripts 20 /etc/rc.d/S99bootcount boot
Now cycle init scripts 21 /etc/rc.d/S99urandom_seed boot
这部分处理过程由ubox部分接管,不像Preinit直接由shell启动
所以,看不到打印,还是恼火
不过可以将打印输出到指定文件测试
S00sysfixtime:
对开机时间进行一定处理
S10boot:
1.创建了一大堆系统文件/var/lock啥的
2.挂载debugfs
3./sbin/kmodloader装载一大堆驱动模块,上面好像已经装过一次啥子了
4./bin/config_generate
这是个脚本文件,就是源码目录中的同名文件·
CFG=/etc/board.json
. /usr/share/libubox/jshn.sh
echo "!!!!!!!!!!!!!!!!!luo:Now need run bord_detect"
[ -s $CFG ] || /bin/board_detect || exit 1
[ -s /etc/config/network -a -s /etc/config/system ] && exit 0
a).首先判断了/etc/board.json存在并且为非空[-s],如果不存在则执行/bin/board_detect生成board.json
board_detect中依次执行了/etc/board.d/*具有可执行权限的脚本
01_leds:
board=$(board_name) 获取板子名称,board_name是一个函数包含在/package/base-files/files/lib/functions.sh
board_name() {
[ -e /tmp/sysinfo/board_name ] && cat /tmp/sysinfo/board_name || echo "generic"
}
如果/tmp/sysinfo/board_name存在,则执行cat
这个文件在之前preinit中由do_sysinfo_generic读取/proc/device-tree创建了
现在打印出来是mt7628
board_config_update
如果文件存在则加载到json
如果model对象不存在,添加name和id
!!!!!!!!!!!!!!!!!!!!!!luochao:
{
"model": {
"id": "mt7628",
"name": "Mediatek MT7628AN evaluation board"
}
}
设置wifi,led,switch的一些led参数,默认并没有7628评估板,暂时不处理
board_config_flush
先输出到/tmp/.board.json,然后移动到/etc/下面的对应文件
这里如果刚开始不存在,则就已经存在了,如果本身就是存在的
也不影响,因为是先load进来的
如果是首次启动,则现在board.json只有model一个对象
02_network:
这个文件应该就是配置了lan,wan,vlan等参数
board_config_update
board=$(board_name)
和上面同样的操作
ramips_setup_interfaces $board
根据板子名字设置交换机对象
区分lan和wan
找到mt7628对应的设置
ucidef_add_switch "switch0" \
"0:lan" "1:lan" "2:lan" "3:lan" "4:wan" "6@eth0"
;;
这里就是把交换机的端口4设置为wan,0-3设置为lan,6是cpu口,接到eth0
那么端口5呢???????????
如果要在源码中修改lan和wan,则修改这里
ucidef_add_switch
lan和wan匹配
[0-9]*:*)
num="${port%%:*}"
role="${port##*:}"
;;
"6@eth0"匹配
[0-9]*@*)
num="${port%%@*}"
device="${port##*@}"
need_tag=0
want_untag=0
[ "${num%t}" != "$num" ] && {
num="${num%t}"
need_tag=1
}
[ "${num%u}" != "$num" ] && {
num="${num%u}"
want_untag=1
}
;;
成功解析后调用_ucidef_add_switch_port,添加到switch对象中
最后执行_ucidef_finish_switch_roles根据添加的switch对象生成roles对象
ramips_setup_macs $board
根据板子获取mac地址并设置
又没有7628,使用default
lan_mac=$(cat /sys/class/net/eth0/address)
wan_mac=$(macaddr_add "$lan_mac" 1)
如果lan_mac和wan_mac存在则执行
[ -n "$lan_mac" ] && ucidef_set_interface_macaddr "lan" $lan_mac
[ -n "$wan_mac" ] && ucidef_set_interface_macaddr "wan" $wan_mac
但是这里有个问题,再启动,mac会变,会设置lan_mac为eth0的地址????
board_config_flush
同理更新一次,这次更新的是model+switch对象,因为是已经存在Load进来的
这就生成了完整的board.json文件
这里默认配置eth0.1是lan包含0-3口,eth0.2是wan包含4口,cpu口是6,且wan和lan都要包含cpu口
b).如果/etc/config/network文件存在,并且/etc/config/system也存在则退出
如果不存在/etc/config/network:
generate_static_network 先生成默认的配置
1.先生成会还设备loopback
2.json_is_a dsl object不清楚是什么
1.从board.json的network对象中获取信息,只生成了lan和wan两个接口
这里就把lan和wan在/etc/network中的信息设置好
lan设置为桥接,静态ip模式,ip和掩码都在这里,然后对应的接口是eth0.1
wan设置为dhcp,对应设备是eth0.2
这里有个问题lan口设置Ip为192.168.1.1,但是eth0.1上并没有Ip
而是在br-lan,lan桥上有ip,为什么?????
lan-->eth0.1-->0 1 2 3
wan-->eth0.2-->4
这是什么时候生成的
config interface 'wan6'
option ifname 'eth0.2'
option proto 'dhcpv6'
2.从board.json的switch对象中获取信息
只有一个交换机生成一个switch配置
config switch
option name 'switch0'
option reset '1'
option enable_vlan '1'
generate_switch_vlans_ports "$1"生成当前交换机的vlan信息
1.生成switch_vlan条目
2.生成switch_port条目,为什么没有生成这个???
generate_static_system:
生成了主机名和ntp参数
修改主机名就在这里
暂时没有设置rssimon,gpioswitch,led
基本网络参数就已经配置好了
5.uci_apply_defaults
执行etc/uci-defaults下的配置
这里的文件只是在首次上电执行一次
然后删除,里面包含有一些在menuconfig后根据选项生成的
6./sbin/reload_config
装载配置文件
基本配置就在这里配置完毕
S10system
脚本的解释器注意一下
#!/bin/sh /etc/rc.common
是执行了/etc/rc.common
里面将参数进行转化的
这里会调用
start_service
装载系统配置
S11sysctl:
通过配置文件中定义的值
使用sysctl调整内核参数,如tcp超时等
这些都是通过脚本启动配置应用
使用的方式是procd
shutdown
Now cycle init scripts 0 /etc/rc.d/K10gpio_switch shutdown
Now cycle init scripts 1 /etc/rc.d/K50dropbear shutdown
Now cycle init scripts 2 /etc/rc.d/K85odhcpd shutdown
Now cycle init scripts 3 /etc/rc.d/K89log shutdown
Now cycle init scripts 4 /etc/rc.d/K90network shutdown
Now cycle init scripts 5 /etc/rc.d/K90sysfixtime shutdown
Now cycle init scripts 6 /etc/rc.d/K98boot shutdown
Now cycle init scripts 7 /etc/rc.d/K99umount shutdown
启动流程和分析基本如上了
应用篇
网桥:
1.brctl
通过ioctl命令操作内核,对网桥进行设置
S20network负责了这块的初始化
默认情况下开启eth0.1 eth0.2 wlan0,建立br-lan
将eth0.1和wlan桥接在一起,即无线和LAN桥接
交换机的0-3设置为lan,vid为1,绑定到eth0.1
接口设置参考:
https://wiki.openwrt.org/doc/networking/network.interfaces
默认启动有:
Dev des
br-lan 192.168.1.1
eth0 真实网卡
eth0.1 虚拟网卡,vlan 1 --> lan
eth0.2 虚拟网卡,vlan 2 --> wan
wlan0 无线网卡,桥接到lan上
AP:
配置为普通路由器:
1.设置0为wan,其余为wan
按照上面分析的,在ramips_setup_interfaces设置wan和lan对应的端口即可
2.将wan口接到可上网的路由器上的lan口上,pc接到设备的lan口即可上网
3.设置dhcp参数
在dhcp.conf里面,设置Ip分配范围,租约时间
在dnsmasq_start中,-k参数后添加 --dhcp-sequential-ip
procd_set_param command $PROG -C C O N F I G F I L E − k − x / v a r / r u n / d n s m a s q / d n s m a s q . " CONFIGFILE -k -x /var/run/dnsmasq/dnsmasq." CONFIGFILE−k−x/var/run/dnsmasq/dnsmasq."{cfg}".pid
配置为无线交换机:
将所有口设置为lan,任意口连接到可上网设备lan口
STA:
SSID:
wifi相关配置参数
https://wiki.openwrt.org/doc/uci/wireless
原创,转载请声明来源