博客

  • nft给符合条件的包打mark

    • 通过命令配置nft
      nft add chain inet fw4 gfw_prerouting { type filter hook prerouting priority mangle\; policy accept\; }
      nft add chain inet fw4 gfw_output { type route hook output priority mangle\; policy accept\; }
      nft add rule inet fw4 gfw_prerouting ip daddr @GFWLIST counter ct mark set 0x10
      nft add rule inet fw4 gfw_prerouting ip daddr @GFWLIST counter meta mark set ct mark
      nft add rule inet fw4 gfw_output ip daddr @GFWLIST counter ct mark set 0x10
      nft add rule inet fw4 gfw_output ip daddr @GFWLIST counter meta mark set ct mark
      

      以上gfw_output链处理本地发现的包,gfw_prerouting处理转发的包,在foward链中处理mark是不生效的(所以无法用uci配置)。

    • 通过配置文件配置nft
      创建文件/etc/nftables.d/11-gfw.nft
      文件内容:

      chain gfw_forward {
          type filter hook prerouting priority mangle; policy accept;
          ip daddr @GFWLIST counter ct mark set 0x10 
          ip daddr @GFWLIST counter meta mark set ct mark
      }
      chain gfw_output {
          type route hook output priority mangle; policy accept;
          ip daddr @GFWLIST counter ct mark set 0x10 
          ip daddr @GFWLIST counter meta mark set ct mark
      }
      

      service firewall restart
      这里要注意的是output hook只能是rotue链,不能是filter链,而prerouting则只能是filter链

    • 添加策略路由匹配mark
      ip rule add fwmark 0x10 table 50
      这条策略路由是可以从界面上添加的



      界面配置略繁锁一些。

    Views: 1

  • nftset使用

    nft中的set是属于某个table下面的,不像ipset是全局的,所以要先建立table

    nft list tables
    nft add table inet gfw
    nft add set inet gfw GFWLIST { type ipv4_addr\; }
    nft add set inet gfw GFWLIST6 { type ipv6_addr\; }
    

    添加IP地址

    nft add element inet gfw GFWLIST { 111.22.33.4 };
    nft list set inet gfw GFWLIST
    

    删除IP地址

    nft delete element inet gfw GFWLIST {20.205.243.166}
    

    openwrt中配置nftset

    openwrt中默认的table是fw4,family是inet

    关于family:
    ip ipv4协议
    ipv6 ipv6协议
    inet 双栈协议
    不指定family时nft默认是ipv4协议,dnsmasq中不指定family时默认也是ipv4协议

    Views: 3

  • openwrt编译时集成wireguard功能

    如果只内置luci-proto-wireguard,会出现cannot find dependency kmod-crypto-kpp for kmod-crypto-lib-curve25519错误,需要把kmod-crypto-kpp模块也内置

    这个编译错误还是个老问题,参考这里:
    https://forum.openwrt.org/t/build-fails-with-multiple-errors/124382

    Views: 2

  • openwrt升级后重新安装软件包

    openwrt升级后原来安装的软件包就没有了,用这条命令可以重新安装所有丢失的软件包(前提是升级前对软件列表进行了备份)
    opkg update && opkg list-installed | cut -f 1 -d ' '| sort -u > /tmp/currentpkg && cat /etc/backup/installed_packages.txt | cut -f 1 | sort -u > /tmp/oldpkg && grep -v -F -x -f /tmp/currentpkg /tmp/oldpkg > /tmp/inst && opkg install $(cat /tmp/inst | sort -u) && rm /tmp/currentpkg /tmp/oldpkg /tmp/inst

    Views: 1

  • gitlab同步仓库到github

    https同步

    • github上建立一个空仓库
    • 创建github token
    • 配置gitlab

      同步成功后的显示

    ssh同步

    • 配置gitlab
    • 配置完成后复制公钥

      上图是自动检测主机密钥(known_hosts),也可以手动添加

      github的公钥是在这里公布的:https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/githubs-ssh-key-fingerprints
      至于SSH私钥是自动生成的,没法从页面上指定。因为界面上把known_hosts显示为主机密钥,我以为这个是私钥走了不少弯路。
      另外用户名一定要指定git,可以在url中指定用户名,也可以在下面的文本框中指定用户名,这个地方也容易走弯路,可以都指定,也可以只指定一处。
      最后把ssh公钥添加到github中

    同步成功后显示如下

    Views: 6

  • openwrt编译所有模块

    • 下载加速
      1. gitea.hetao.me是我自用的git服务器,用于同步境外的git仓库以加速本地访问,下面的git拉取都是从这个域名。
      2. 按这里的方法配置下载加速

        openwrt编译时加速依赖下载

    • 下载openwrt代码

      git clone https://gitea.hetao.me/openwrt/openwrt
      cd openwrt
      
    • 下载配置文件
      curl https://downloads.openwrt.org/snapshots/targets/mediatek/filogic/config.buildinfo --output .config
      curl https://downloads.openwrt.org/snapshots/targets/mediatek/filogic/feeds.buildinfo --output feeds.conf
      

      config.buildinfo配置中已经包含了

      CONFIG_ALL=y
      CONFIG_ALL_KMODS=y
      CONFIG_ALL_NONSHARED=y
      

      对feeds.config中的域名替换为gitea.hetao.me,替换后如下

      src-git packages https://gitea.hetao.me/feed/packages.git
      src-git luci https://gitea.hetao.me/project/luci.git
      src-git routing https://gitea.hetao.me/feed/routing.git
      src-git telephony https://gitea.hetao.me/feed/telephony.git
      
    • 更新feeds
      ./scripts/feeds update -a
      ./scripts/feeds install -a
      
    • 编译配置

      对编译配置进行自定义修改,主要是编译目标板子改为bpi r3,集成luci和中文,开启ccache,修改opkg源和固件版本号,这是我用的配置

      http://openwrt.hetao.me/snapshots/targets/mediatek/filogic/config.buildinfo

      make menuconfig
      sed -i '/is not set/d' .config
      make defconfig
      
    • 开始编译

      IGNORE_ERRORS=1 make -j 70

    • 把编译后的镜像和ipk包复制到web服务器

      rsync -avP bin/* root@openwrt.hetao.me:/opt/web/data/nginx/www/openwrt/snapshots/
      这样就可以通过 https://openwrt.hetao.me/snapshots/ 访问openwrt源了

    Views: 14

  • openwrt编译时加速依赖下载

    openwrt编译时加速依赖下载

    • 环境变量方式
    export PIP_INDEX_URL=https://mirrors.hetao.me/pypi/simple
    export npm_config_registry=https://mirrors.hetao.me/npm-registry
    export RUSTUP_DIST_SERVER=https://mirror.sjtu.edu.cn/rust-static
    export RUSTUP_UPDATE_ROOT=https://mirror.sjtu.edu.cn/rust-static/rustup
    export GO111MODULE=on
    export GOPROXY=https://goproxy.cn
    export CARGO_REGISTRIES_MIRROR_INDEX=sparse+https://mirrors.sjtug.sjtu.edu.cn/crates.io-index/
    export CARGO_REGISTRY_DEFAULT="mirror"
    
    • 配置文件方式
    echo registry=https://mirrors.hetao.me/npm-registry > HOME/.npmrc
    mkdir -pHOME/.config/pip
    cat << EOF > HOME/.config/pip/pip.conf
    [global]
    index-url = https://mirrors.hetao.me/pypi/simple
    format = columns
    EOF
    mkdir -vpHOME/.cargo
    cat << EOF > HOME/.cargo/env
    RUSTUP_DIST_SERVER=https://mirror.sjtu.edu.cn/rust-static
    RUSTUP_UPDATE_ROOT=https://mirror.sjtu.edu.cn/rust-static/rustup
    EOF
    cat << EOF>HOME/.cargo/config
    [source]
    [source.mirror]
    registry = "sparse+https://mirrors.sjtug.sjtu.edu.cn/crates.io-index/"
    
    [source.crates-io]
    replace-with = "mirror"
    EOF
    
    • 其它无法使用镜像加速的则使用代理
    export http_proxy=http://192.168.33.6:3128
    export https_proxy=http://192.168.33.6:3128
    export no_proxy=127.0.0.1,172.16.0.0/12,192.168.0.0/16,.cn,.hetao.me,localhost,local,.local
    

    Views: 2

  • debian/ubuntu连接wifi

    • iw方式

    iw dev wlan0 scan #扫描wif列表
    iw dev wlan0 connect openwrt #连接到openwrt
    dhclient wlan0 #分配IP地址
    iw dev wlan0 disconnect #断开连接
    iw仅支持wep密码,但是wep已经没有路由器支持了,所以iw只能用于无密码的wifi连接
    – wpa_supplicant

    apt install wpasupplicant
    wpa_passphrase myssid my_very_secret_passphrase > /etc/wpa_supplicant/wpa_supplicant.conf
    #在/etc/network/interfaces中添加如下内容

    allow-hotplug wlan0
    iface wlan0 inet dhcp
            wpa-ssid myssid
            wpa-psk ccb290fd4fe6b22935cbae31449e050edd02ad44627b16ce0151668f5f53c01b
    

    其中wpa-psk与wpa_supplicant.conf中的一致
    systemctl enable wpa_supplicant
    systemctl restart wpa_supplicant
    ifup wlan0
    iw dev wlan0 link #查看连接状态

    参考:
    https://wireless.wiki.kernel.org/en/users/documentation/iw
    https://wiki.debian.org/WiFi/HowToUse
    https://w1.fi/wpa_supplicant/

    Views: 4

  • 封装mtk7986/7988启动镜像

    mk_image.sh -p mt7986a -d spim-nand -b openwrt-mediatek-filogic-bananapi_bpi-r3-snand-preloader.bin -f openwrt-mediatek-filogic-bananapi_bpi-r3-snand-bl31-uboot.fip -k openwrt-mediatek-mt7986-BPI-R3-NAND-WAN1-RJ45-squashfs-factory.bin -o -c nand.yaml r3.img
    u-boot可以用自己编译的(参考:https://blog.hetao.me/2024/07/02/mtk-7986-7988%e6%9d%bf%e5%ad%90%e5%90%af%e5%8a%a8%e8%bf%87%e7%a8%8b%e5%8f%8au-boot%e7%bc%96%e8%af%91/),也可以从openwrt上下载(https://downloads.openwrt.org/snapshots/targets/mediatek/filogic/)

    mk_image.sh内容
    这个脚本是搬运的

    #!/bin/bash
    # Copyright (C) 2021-2022 SkyLake Huang
    #
    # This program is free software; you can redistribute it and/or modify
    # it under the terms of the GNU General Public License as published by
    # the Free Software Foundation; either version 2 of the License, or
    # (at your option) any later version.
    #
    # This program is distributed in the hope that it will be useful,
    # but WITHOUT ANY WARRANTY; without even the implied warranty of
    # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    # GNU General Public License for more details.
    #
    # You should have received a copy of the GNU General Public License along
    # with this program; if not, write to the Free Software Foundation, Inc.,
    # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
    #
    # Use this script to compose single image.
    # Author: SkyLake Huang
    # Email: skylake.huang@mediatek.com
    
    #global variables:
    bl2_start_dec=0
    bl2_start_hex=0x0
    rf_start_dec=0
    rf_start_hex=0x0
    fip_start_dec=0
    fip_start_hex=0x0
    kernel_start_dec=0
    kernel_start_hex=0x0
    rootfs_start_dec=0
    rootfs_start_hex=0x0
    rootfs_image=""
    
    # Regular Colors
    RED='\033[0;31m'
    NC='\033[0m'
    
    usage() {
            printf 'Usage:\n'\
    '  ./mk_image -p <platform>\n'\
    '             -d <flash device type>\n'\
    '             -c <partition config>\n'\
    '             -b <BL2 image>, default=bl2.img\n'\
    '             -r <RF image>\n'\
    '             -f <FIP image>, default=fip.bin\n'\
    '             -k <kernel image>\n'\
    '             -g <GPT table>\n'\
    '             -h <usage menu>\n'\
    '             -o <single image name>\n'\
    '  example:\n'\
    '    ./mk_image.sh -p mt7986a -d emmc \\\n'\
    '                  -g GPT_EMMC-iap-20220125 \\\n'\
    '                  -f fip-iap-emmc-20220125.bin \\\n'\
    '                  -k OF_openwrt-mediatek-mt7986-mt7986a-ax6000-emmc-rfb-squashfs-sysupgrade.bin\n'\
    '    ./mk_image.sh -p mt7986a -d spim-nand \\\n'\
    '                  -b bl2-iap-snand-20220114.img \\\n'\
    '                  -f fip-snand-20220114.bin \\\n'\
    '                  -k OF_openwrt-mediatek-mt7986-mt7986a-ax6000-spim-nand-rfb-squashfs-factory.bin \\\n'
            exit
    }
    
    parse_yaml() {
            local prefix=2
            local s='[[:space:]]*' w='[a-zA-Z0-9_]*' fs=(echo @|tr @ '\034')
            sed -ne "s|^\(s\):|\1|" \
                    -e "s|^\(s\)\(w\)s:s[\"']\(.*\)[\"']s\|\1fs\2fs\3|p" \
                    -e "s|^\(s\)\(w\)s:s\(.*\)s\|\1fs\2fs\3|p"1 |
            awk -Ffs '{
                    indent = length(1)/2;
                    vname[indent] = 2;
                    for (i in vname) {if (i>indent) {delete vname[i]}}
                    if (length(3) > 0) {
                            vn=""; for (i=0; i<indent; i++) {vn=(vn)(vname[i])("_")}
                            printf("%s=%s\n", 2,3);
                    }
            }'
    }
    
    load_partition() {
            IFS='\r\n'
            for line in `parse_yamlpartition_config`; do
                    IFS='=' read -ra arr <<< "line"
                    case "{arr[0]}" in
                            bl2_start )
                                    bl2_start_hex={arr[1]}
                                    bl2_start_dec=`printf '%d'bl2_start_hex`
                                    ;;
                            rf_start )
                                    rf_start_hex={arr[1]}
                                    rf_start_dec=`printf '%d'rf_start_hex`
                                    ;;
                            fip_start )
                                    fip_start_hex={arr[1]}
                                    fip_start_dec=`printf '%d'fip_start_hex`
                                    ;;
                            kernel_start )
                                    kernel_start_hex={arr[1]}
                                    kernel_start_dec=`printf '%d'kernel_start_hex`
                                    ;;
                            rootfs_start )
                                    rootfs_start_hex={arr[1]}
                                    rootfs_start_dec=`printf '%d'rootfs_start_hex`
                    esac
            done
    }
    
    prepare_image() {
            # Pad empty bytes to single image first
            if [[ -z kernel_image ]]
            then
                    if [[flash_type == "emmc" ]] || [[ flash_type == "sd" ]]
                    then
                            dd if=/dev/zero ibs=fip_start_dec count=1 status=none \
                                    > single_image
                    else
                            dd if=/dev/zero ibs=fip_start_dec count=1 status=none \
                                    | tr "\000" "\377" > single_image
                    fi
            else
                    if [[flash_type == "emmc" ]] || [[ flash_type == "sd" ]]
                    then
                            dd if=/dev/zero ibs=kernel_start_dec count=1 status=none \
                                    > single_image 2>&1
                    else
                            dd if=/dev/zero ibs=kernel_start_dec count=1 status=none \
                                    | tr "\000" "\377" > single_image 2>&1
                    fi
            fi
    }
    
    extract_sdmmc_kernel() {
            output=`tar -xvfkernel_image | awk {'print 1'}`
            IFS='\n' read -d "\034" -r -a output_arr <<< "output"
    
            #For debugging
            #echo "There are{#output_arr[*]}" next lines in the output.
    
            for filename in "{output_arr[@]}";
            do
                    if [[ "filename" == *"kernel" ]]
                    then
                            kernel_image=filename
                    elif [[ "filename" == *"root" ]]
                    then
                            rootfs_image=filename
                    fi
            done
    }
    
    start_wrapping() {
            printf "[Start wrapping %s single image......]\n"flash_type
    
            if [[ flash_type != "emmc" ]]
            then
                    printf "[wrapping BL2 image......]\n"
                    dd if=bl2_image of=single_image bs=512 \
                            seek=(( (bl2_start_dec/512) )) conv=notrunc status=none
            fi
    
            if [[flash_type == "emmc" ]] || [[ flash_type == "sd" ]]
            then
                    printf "[wrapping GPT......]\n"
                    dd if=gpt of=single_image bs=512 seek=0 conv=notrunc status=none
            fi
    
            if [[ -nrf_image ]]
            then
                    printf "[wrapping RF image......]\n"
                    dd if=rf_image of=single_image bs=512 \
                            seek=(( (rf_start_dec/512) )) conv=notrunc status=none
            fi
    
            printf "[wrapping FIP image......]\n"
            dd if=fip_image of=single_image bs=512 \
                    seek=(( (fip_start_dec/512) )) conv=notrunc status=none
    
            if [[ -n kernel_image ]]
            then
                    printf "[wrapping kernel image......]\n"
                    if [[flash_type == "emmc" ]] || [[ flash_type == "sd" ]]
                    then
                            extract_sdmmc_kernel
                            dd if=kernel_image of=single_image bs=512 \
                                    seek=(( (kernel_start_dec/512) )) conv=notrunc status=none
                            printf "[wrapping rootfs image......]\n"
                            dd if=rootfs_image of=single_image bs=512 \
                                    seek=(( (rootfs_start_dec/512) )) conv=notrunc status=none
                    else
                            dd if=kernel_image of=single_image bs=512 \
                                    seek=(( (kernel_start_dec/512) )) conv=notrunc status=none
                    fi
            fi
    }
    
    if [# -lt 1 ]
    then
            usage
            exit 1
    fi
    
    ## We set default values for some arguments
    bl2_image="bl2.img"
    bl2_default=1
    fip_image="fip.bin"
    fip_default=1
    partition_config=""
    partition_config_default=1
    
    while [ "1" != "" ]; do
            case1 in
            -h )
                    usage
                    ;;
            -p )
                    shift
                    platform=1
                    ;;
            -d )
                    shift
                    flash_type=1
                    ;;
            -c )
                    shift
                    partition_config=1
                    partition_config_default=0
                    ;;
            -b )
                    shift
                    bl2_image=1
                    bl2_default=0
                    ;;
            -f )
                    shift
                    fip_image=1
                    fip_default=0
                    ;;
            -k )
                    shift
                    kernel_image=1
                    ;;
            -g )
                    shift
                    gpt=1
                    ;;
            -o )
                    shift
                    single_image=1
                    ;;
            -r )
                    shift
                    rf_image=1
                    ;;
            esac
            shift
    done
    
    
    ######## Check if variables are valid ########
    check_ok=1
    if ! [[platform =~ ^(mt7981abd|mt7981c|mt7986a|mt7986b)]]; then
            printf "{RED}Platform must be in mt7981abd|mt7981c|mt7986a|mt7986b\n{NC}"
            usage
            exit 1
    fi
    if ! [[flash_type =~ ^(snfi-nand|spim-nand|spim-nor|emmc|sd)]]; then
            printf "{RED}Flash type must be in snfi-nand|spim-nand|spim-nor|emmc|sd\n{NC}"
            usage
            exit 1
    fi
    
    if [[partition_config_default -eq 1 ]]; then
            partition_config="partitions/{flash_type}-default.yml"
    fi
    
    if [[flash_type =~ ^(emmc|sd)]] && [[ -zgpt ]]; then
            printf "{RED}GPT table must be provided if flash type is emmc or sd\n{NC}"
            usage
            exit 1
    fi
    
    if [[ -n gpt ]] && ! [[ -fgpt ]]; then
            printf "{RED}GPT table provided doesn't exist.\n{NC}"
            exit 1
    fi
    if [[ -n rf_image ]] && ! [[ -frf_image ]]; then
            printf "{RED}RF image provided doesn't exist.\n{NC}"
            exit 1
    fi
    if [[ -n kernel_image ]] && ! [[ -fkernel_image ]]; then
            printf "{RED}Kernel image provided doesn't exist.\n{NC}"
            exit 1
    fi
    
    ##############################################
    if ! [[ -f partition_config ]]
    then
            if [[partition_config_default -eq 1 ]]
            then
                    printf "{RED}Default partition config{NC}"
            else
                    printf "{RED}Partition config provided{NC}"
            fi
            printf "{RED} doesn't exist: %s\n{NC}" partition_config
            exit 1
    fi
    printf "* Partition config: %s\n"partition_config
    
    if ! [[ -f bl2_image ]]
    then
            if [[bl2_default -eq 1 ]]
            then
                    printf "{RED}Default BL2 image{NC}"
            else
                    printf "{RED}BL2 image provided{NC}"
            fi
            printf "{RED} doesn't exist: %s\n{NC}" bl2_image
            exit 1
    fi
    printf "* BL2 image name: %s\n"bl2_image
    
    if ! [[ -f fip_image ]]
    then
            if [[fip_default -eq 1 ]]
            then
                    printf "{RED}Default FIP image"
            else
                    printf "{RED}FIP image provided"
            fi
            printf "{RED} doesn't exist: %s\n{NC}" fip_image
            exit 1
    fi
    printf "* FIP image name: %s\n"fip_image
    
    if [[ -z single_image ]]
    then
            single_image="platform-flash_type-(date +%Y%m%d)-single-image.bin"
            printf "* Single image name: %s\n" single_image
    fi
    
    if [[check_ok == 1 ]]; then
            #printf "./mk_image -p %s -d %s\n" platformflash_type
            load_partition
            prepare_image
            start_wrapping
    fi
    

    nand镜像的分区配置文件(nand.yaml):

    # Copyright (C) 2021-2022 SkyLake Huang
    #
    # This program is free software; you can redistribute it and/or modify
    # it under the terms of the GNU General Public License as published by
    # the Free Software Foundation; either version 2 of the License, or
    # (at your option) any later version.
    #
    # This program is distributed in the hope that it will be useful,
    # but WITHOUT ANY WARRANTY; without even the implied warranty of
    # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    # GNU General Public License for more details.
    #
    # You should have received a copy of the GNU General Public License along
    # with this program; if not, write to the Free Software Foundation, Inc.,
    # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
    
    # NAND flash layout:
    #       0x0~0x100000: BL2,       1024K
    #  0x100000~0x180000: Uboot env,  512K
    #  0x180000~0x380000: RF,        2048K
    #  0x380000~0x580000: FIP,       2048K
    #  0x580000~        : firmware
    
    spim-nand:
      bl2_start: 0x0
      rf_start: 0x180000
      fip_start: 0x380000
      kernel_start: 0x580000
    

    Views: 11

  • mtk 7986/7988板子启动过程及u-boot编译

    mtk 7986/7988板子启动过程及u-boot编译

    系统上电后从BL1(存储在CPU内的BootRom中)开始执行,BL1会遍历所有可启动的设备(可以通过引脚改变引导顺序)

    BL1启动后会对系统架构和平台进行初始化,注意BL1是在CPU内置的RAM中运行的,不使用外部DDR内存,然后BL1会从指定的存储设备上加载BL2程序(安全启动过程中也叫ATF),BL2也是在内置RAM中运行的,但BL2对DDR内存进行初始化,然后加载BL31(SRAM)和BL33(DDR内存),然后运行BL31对BL33进行初始化并把执行权限交给BL33(U-Boot本体)。

    在mtk 7986板子上生成bl2,bl31,bl33镜像

    https://downloads.openwrt.org/snapshots/targets/mediatek/filogic/

    这里面preloader.bin 结尾的文件就是BL2,镜像格式是MediaTek BootROM Loadable Image

    编译生成的bl2.bin是不能被mtk cpu识别的,需要用mkimage把bin封装为BootROM可解析的格式,即BootROM Image格式,里面有一个头部描述的bl2的基本信息。

    查看BootROM镜像信息

    bl31-uboot.fip 这个是BL31和BL33的合体,镜像格式是FIP(Firmware Image Package),FIP可以包含多个区段,每个区段一个镜像。查看fip的信息:

    uboot编译

    • 编译bl33

    git clone https://github.com/frank-w/u-boot.git

    git checkout 2022-10-r3

    修改build.sh修改启动设备(board和device)

    ./build.sh importconfig

    ./build.sh build

    • 编译bl2和bl31并生成u-boot镜像

    git checkout r3-atf

    修改build.sh中的启动设备(board和device)

    ./build.sh importconfig

    ./build.sh build

    ./build.sh rename

    最后得到bpi-r3_spim_nand_bl2.img和bpi-r3_spim_nand_fip.bin

    如果想要emmc,nor等介质的u-boot修改build.sh里在的device即可。

    参考

    https://www.cnblogs.com/arnoldlu/p/14175126.html

    https://wiki.fw-web.de/doku.php?id=en:bpi-r3:uboot

    Views: 16