Exynos4412开发板Linux系统移植步骤

本文围绕Linux系统移植展开,介绍了系统移植课程大纲,包括BootLoader、系统内核和根文件系统。阐述了系统启动流程、环境搭建,如TFTP和NFS服务器搭建。还说明了不同阶段的启动方式、线路连接、开发板IP配置等,最后详细讲解了根文件系统的制作、固化及镜像制作与使用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

随着工程复杂度 愈来愈高,  移植 操作系统  避不开的问题 

一个操作系统 可以给 编程提供 很大的便利:  极大的发挥硬件性能 

1. 进程管理  多任务 并发    使得程序设计更加模块化 结构化 
2. 内存管理  堆栈管理       动态内存分配  
3. 进程线程间 提供通信  实现消息传递,同步互斥 
Linux: 
4. 内核安全机制  
5. 硬件管理  驱动管理  

系统移植课程大纲: 
    分3个大步骤:
    BootLoader:  开机引导程序  是一段裸机程序, 用于引导操作系统   例如:PC 中的BIOS 
    系统内核:    系统核心组成部件,通常不能缺少  
    根文件系统:  用于存放用户程序, 管理用户文件, 或系统配置  
    
应用程序移植:   库,应用程序 等的移植    在项目阶段学习 

系统与内核:
    操作系统,  
    包含内核部分,以及 相关工具,软件,库,甚至有界面   是一个完整的 系统  
    
    内核: 
    仅有系统的 核心组成部件, 通常包括 进程管理  内存管理  设备管理 
    没有任何 应用程序以及库等  
    
系统的启动流程: 
    上电, 1. BootLoader启动:  初始化CPU  初始化一些必要的外设   引导系统内核 (搬移内核代码到指定内存中)
          2. 内核启动      :  再次初始化CPU 初始化外设  以及各种设备  挂载根文件系统  
          3. 根文件系统        执行用户应用程序 
        
环境搭建: 
    资料下载
    
    1. 交叉编译工具    arm-none-linux-gnueabi-gcc
    2. 文件的下载   使用网络  tftp下载  
        1) 搭建 TFTP 服务器 在 Ubuntu上 
        2) 搭建 NFS  服务器 在 Ubuntu上

服务器的搭建 需要外网支持   
1. 安装TFTP 服务器    用于上传或下载文件 
    sudo apt-get install tftpd-hpa               // 安装服务器 
    sudo apt-get install tftp                    // 安装客户端

查看安装是否成功   dpkg -l | grep tftp
ii  tftp         0.17-18ubuntu2                  amd64   Trivial file transfer protocol client
ii  tftpd-hpa    5.2+20150808-1ubuntu1.16.04.1   amd64   HPA's tftp server

2. 配置服务器    
    1) 准备 tftp工作目录 
        mkdir  ~/tftpboot
    2) 修改工作目录权限  
        chmod 0777 ~/tftpboot
    3) 修改配置文件
        sudo vim /etc/default/tftpd-hpa
参考如下配置:
# /etc/default/tftpd-hpa

TFTP_USERNAME="tftp"
# TFTP_DIRECTORY="/var/lib/tftpboot"   # 改工作目录 为刚刚创建的 
TFTP_DIRECTORY="/home/xwq/tftpboot"

TFTP_ADDRESS=":69"
TFTP_OPTIONS="--secure -c"   #  添加-c 选项 可以允许客户端上传文件 

    4) 重启服务 使配置生效 
    sudo /etc/init.d/tftpd-hpa restart
    
[ ok ] Restarting tftpd-hpa (via systemctl): tftpd-hpa.service.

    5) 查看tftp服务器启动成功否 
    ps -aux | grep tftp

root       3363  0.0  0.0  15180   148 ?        Ss   10:17   0:00 /usr/sbin/in.tftpd --listen --user tftp --address :69 --secure -c /home/xwq/tftpboot


搭建NFS服务器:   主要用于文件共享的   主要是通过nfs共享的方式 来实现 网络挂载 根文件系统
    1) 安装nfs服务器 
    sudo apt-get install nfs-kernel-server

    2) 准备 nfs工作目录 nfshome
        mkdir  ~/nfshome
    3) 修改工作目录权限  
        chmod 0777 ~/nfshome
    4) 修改配置文件
        sudo vim /etc/exports
参考如下配置: 添加一行     
    /home/xwq/nfshome  *(rw,sync,no_subtree_check) 
    工作路径          * 任意IP都可以访问  rw 可读可写 权限 
    
    5) 重启nfs服务器 
        sudo /etc/init.d/nfs-kernel-server restart 
[ ok ] Restarting nfs-kernel-server (via systemctl): nfs-kernel-server.service.    
    
    6) 测试NFS 服务 
    挂载服务器上的  目录  到本地位置  
    sudo mount 192.168.124.101:/home/xwq/nfshome /mnt/nfs
         挂载   服务器IP       |                       |-> 挂载到本地路径 /mnt/nfs
                               |-> 工作目录 /home/xwq/nfshome 
    
    卸载 sudo umount nfs/

问题: nfs 服务器版本过高 导致开发板无法挂载 
    
    在nfs配置文件末尾加入一句:
    RPCNFSDOPTS="--nfs-version 2,3,4 --debug --syslog"

系统的启动方式: 
    开发者阶段:  网络启动
    1. 启动 板载uboot   
        通过拨码开关 确定是从flash(emmc)启动 还是从 sd卡启动 
        
    2. 通过uboot 下载 Linux内核  到内存中  
    3. 通过uboot 下载 设备树     到内存中 
    4. 通过nfs 挂载 根文件系统  
    
    系统固化阶段:
    1. 下载并烧录  uboot
    2. 下载并烧录  内核 
    3, 下载并烧录  设备树 
    4, 固化 根文件系统 
    
    产品阶段:    脱机运行
    1. 启动uboot 
    2. uboot 加载 内核到内存  从flash或sd卡 
    3. uboot 加载 设备树  
    4. 加载根文件系统 

开发者阶段: 
    线路连接:
        1. 串口线   串口输出 调试信息 或进行 与开发板交互 
        2. 网线     
            方式1)  教学用  使用交换机机 将 开发板 PC 以及 教室路由器 连一起
                    PC 即可以访问 开发板   开发板 也可以访问PC 
                    同时PC 机 可以通过 路由器访问外网和局域网 
                    开发板IP 与 教室在一个局域网 
                    
            方式2)  将开发板 与 PC 直接通过一根 网线 连接 
                    PC(Ubuntu) 通过有线网卡 访问开发板 
                    PC 机使用 无线网卡 访问 外网或屏幕共享 
                    
                    Linux使用的虚拟网卡 : 通过桥接方式  连接物理网卡  
                        若 Linux虚拟机访问 开发板 就需要桥接到 接物理有线网卡
                        若 Linux虚拟机访问 外网   就需要桥接到 接物理无线网卡
                Ubuntu 虚拟机ip配置问题: 
                    参考 设置虚拟机使用指定网卡.doc 
                    
                1. 网卡桥接, 参考 配置文档设置
                2. 目的 实现 虚拟机Ubuntu 与开发板 通过 网线  TCP/IP 协议通信 
                    推荐设置:  Ubuntu 使用固定IP  192.168.3.200
                               子网掩码           255.255.255.0
                               网关               192.168.3.1 
                               
                    开发板IP:                     192.168.3.201           
                               子网掩码           255.255.255.0
                               网关               192.168.3.1 
        开发板IP配置:
uboot相关命令: 
    1. pri 命令  打印环境变量      
       printenv
FS4412[general] # pri
baudrate=115200
bootargs=root=/dev/nfs nfsroot=192.168.124.150:/home/xwq/nfshome/rootfs rw conso
le=ttySAC2,115200 init=linuxrc ip=192.168.124.250
bootcmd=loadb 0x40008000;go 0x40008000
bootdelay=1                  // 自启动倒计时 
ethact=dm9000
ethaddr=11:22:33:44:55:66
fileaddr=41000000
filesize=2E3EF0
gatewayip=192.168.124.1      // 网关
ipaddr=192.168.124.250       // 开发板IP地址
netmask=255.255.255.0        // 子网掩码
serverip=192.168.124.150     // 服务器ip 即 Ubuntu系统IP
stderr=serial
stdin=serial
stdout=serial

Environment size: 437/16380 bytes

    2. 修改环境变量  
    set gatewayip 192.168.3.1
    set ipaddr    192.168.3.201
    set netmask   255.255.255.0 
    set serverip  192.168.3.200
    save 
    
    3. 删除环境变量  
    set 环境变量名
    
    开发板验证 是否能够通过网络访问 Ubuntu  
    ping 192.168.3.200

dm9000 i/o: 0x5000000, id: 0x90000a46
DM9000: running in 16 bit mode
MAC: 11:22:33:44:55:66
operating at 100M full duplex mode
Using dm9000 device
host 192.168.3.200 is alive
FS4412[general] #


3. 准备 需要的文件 放到到tftp 与 nfs    在Ubuntu上操作 
    1) uImage 复制到  tftpboot目录中 
    2) 设备树文件 exynos4412-fs4412.dtb 到 tftpboot目录中
    3) 复制根文件系统 rootfs.tar.xz  到 nfshom目录中  
    4) 解压根文件系统  
        tar -xvf rootfs.tar.xz
    5) 修改rootfs目录权限 
        chmod 0777 rootfs
    
4. 通过网络 TFTP 下载uImage 和 设备树  通过 网络 nfs 挂载 根文件系统  测试 

    1) 在开发板上操作 
设置 bootargs参数 :  该参数用于 给内核提供启动参数 

    set bootargs  root=/dev/nfs nfsroot=192.168.124.150:/home/xwq/nfshome/rootfs rw console=ttySAC2,115200 init=linuxrc ip=192.168.124.250
                     
参数的含义:
root=/dev/nfs                  :    表示根文件系统 使用nfs访问挂载 对应修改 
nfsroot=192.168.124.150      :    表示根文件系统的 服务器IP      对应修改 
/home/xwq/nfshome/rootfs     :    表示根文件系统的 服务器路径    对应修改
rw                          :      权限 可读可写 
console=ttySAC2,115200      :     调试串口为 ttySAC2 波特率 115200
init=linuxrc                :      初始化进程 为 linuxrc
ip=192.168.124.250            :     开发板IP 开发板Linux中的       对应修改


    set bootargs  root=/dev/nfs nfsroot=192.168.3.200:/home/xwq/nfshome/rootfs rw console=ttySAC2,115200 init=linuxrc ip=192.168.3.201
    save 
    2) 下载 uImage :   tftp 41000000 uImage
    
    使用TFTP协议 从服务器(serverip) 上下载 文件 uImage 存放到 内存地址 41000000 位置 
FS4412[general] # tftp 41000000 uImage
dm9000 i/o: 0x5000000, id: 0x90000a46
DM9000: running in 16 bit mode
MAC: 11:22:33:44:55:66
operating at 100M full duplex mode
Using dm9000 device
TFTP from server 192.168.3.200; our IP address is 192.168.3.201
Filename 'uImage'.
Load address: 0x41000000
Loading: #################################################################
         #################################################################
         #################################################################
         ############
         867.2 KiB/s
done
Bytes transferred = 3028040 (2e3448 hex)
    
    3) 下载 设备树 exynos4412-fs4412.dtb : 
        tftp 42000000 exynos4412-fs4412.dtb
    
FS4412[general] # tftp 42000000 exynos4412-fs4412.dtb
dm9000 i/o: 0x5000000, id: 0x90000a46
DM9000: running in 16 bit mode
MAC: 11:22:33:44:55:66
operating at 100M full duplex mode
Using dm9000 device
TFTP from server 192.168.3.200; our IP address is 192.168.3.201
Filename 'exynos4412-fs4412.dtb'.
Load address: 0x42000000
Loading: ###
         780.3 KiB/s
done
Bytes transferred = 34358 (8636 hex)    
    
5. 加载内核 设备树  启动系统 
    bootm 41000000 - 42000000
    
参数说明:
boom 引导内核的uboot命令 
41000000  :  uImage 内核镜像的内存位置  
 -        :  根文件系统 的位置  - 表示根文件系统不在内存  
42000000  :  设备树 的 内存位置  

系统启动:

设置uboot  自动下载 uImage 设备树 以及  自动启动系统
    set  bootcmd tftp 41000000 uImage\;tftp 42000000 exynos4412-fs4412.dtb\;bootm 41000000 - 42000000
    save
    
开发者阶段下: uboot环境变量
baudrate=115200
bootargs=root=/dev/nfs nfsroot=192.168.3.200:/home/xwq/nfshome/rootfs rw console=ttySAC2,115200 init=linuxrc ip=192.168.3.201
bootcmd=tftp 41000000 uImage;tftp 42000000 exynos4412-fs4412.dtb;bootm 41000000 - 42000000
bootdelay=1
ethact=dm9000
ethaddr=11:22:33:44:55:66
fileaddr=41000000
filesize=2E3EF0
gatewayip=192.168.3.1
ipaddr=192.168.3.201
netmask=255.255.255.0
serverip=192.168.3.200
stderr=serial
stdin=serial
stdout=serial
Environment size: 479/16380 bytes

uboot移植: 
    BootLoader: 用于加载内核 引导操作系统的 一段裸机程序, 开机最先运行 
    uboot  通用的 Linux 引导程序, 支持多种芯片架构, 使用者众多 

uboot启动打印: 

U-Boot 2013.01.general (Sep 24 2019 - 11:31:49) for FS4412

CPU:    Exynos4412@1000MHz

Board: FS4412
DRAM:  1 GiB
WARNING: Caches not enabled
MMC:   MMC0:    3728 MB
In:    serial
Out:   serial
Err:   serial

MMC read: dev # 0, block # 48, count 16 ...16 blocks read: OK
eMMC CLOSE Success.!!


Checking Boot Mode ... EMMC4.41
Net:   dm9000
Hit any key to stop autoboot:  0

uboot 工作模式: 
    1. 自启动模式    倒计时没有操作, 自动执行bootcmd变量中的命令  
    2. 交互模式      倒计时输入任何按键, 进入交互模式 可以手动输入命令执行 
    
uboot命令: 
    pri   : 打印环境变量
    set   : 设置环境变量
    save  : 保存环境变量 
    bootm : 引导操作系统 
    tftp  : 下载文件命令   前提 IP配置,网络OK,服务器ok 
        tftp  addr   fileName
    ping  : 检查网络连接 

    loadb :  串口下载  使用Kermit协议 
        loadb addr 
    go    :  跳转到指定内存运行 
        go addr  

    mmcinfo  : 查看uboot支持的flash信息 
    
    movi:  命令用于 写入或读取mmc分区(flash或SD卡)中的 数据
    
uboot mmc分区:  FS4412[general]   多用于系统固化时 
    1.  uboot   分区   存储uboot本身 
    2.  kernel  分区   存储uImage           4M
    3.  dtb     分区   存储dtb文件          1M 
    4.  rootfs  分区   存储根文件系统镜像   10M
    
    movi read  分区名   addr    <根文件系统需要 size>
        从分区中 读数据 到内存 addr   
    movi write 分区名   addr    <根文件系统需要 size>
        写入数据 到分区中  从addr内存除获取数据

uboot源码目录:  u-boot-2013.01.tar.bz2 
    解压到 ~/sys_230901/ 目录 
    
    arch:  体系架构相关的  不同架构的CPU  初始化代码不同 
        Exynos4412   arch/arm/cpu/armv7   
    board:  开发板 相关代码  厂商提供的 一些 标准板子的 配置  以及相关代码  
        
    common: 通用的代码, 与体系架构和开发板 无关 
    //....  参考图片 
    
uboot 运行过程: 走读程序:

    1. 第一行代码在哪? 
    
汇编部分:    开始时 uboot 运行在flash中 
    b reset   复位异常入口 
    
    bl cpu_init_cp15: 初始化协处理器
    bl cpu_init_crit:基本硬件初始化 
        b lowlevel_init
        //    关闭看门狗,关闭中断,初始时钟。
       lowlevel_init: //在文件 u-boot-2013.01/board/samsung/origen/lowlevel_init.S 
           system_clock_init  系统时钟初始化
           mem_ctrl_asm_init  内存初始化
           srom_ctrl_init       存储器初始化
    
        代码运行位置检查 
        若运行在flash中   会进行 relocate_code 代码自搬移 
    
    内存自 搬移 :  b  relocate_code   为了提高运行速度 
        拷贝uboot代码 到RAM中 
        跳转 RAM中的 uboot运行 
    
    bl _main:    //在文件 arch/arm/lib/crt0.S
        bl board_init_f:  C代码,  在arch/arm/lib/board.c 中
        b  board_init_r:  C代码,  在arch/arm/lib/board.c 中
        
总结汇编部分: 1, 初始化基本硬件 关闭不必要的功能  单纯化  
              2, 代码自搬移  提高运行速度 
            
C语言部分:       1. 大部分硬件初始化  准备引导操作系统需要的环境 
              2, 若有按键输入  进入交互模式 
    arch/arm/lib/board.c 
board_init_f:  
核心代码:  遍历函数指针数组,依次调用其中的函数 

    for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
        if ((*init_fnc_ptr)() != 0) {
            hang ();
        }
    }
    
    循环调用初始化函数,  CPU特殊功能初始化、内存池、定时器、环境变量、串口、等设备初始化
    
    board_init_r: 进入交互模式 
    /* main_loop() can return to retry autoboot, if so just run it again. */
    for (;;) {
        main_loop();   // 主循环  
    }

uboot移植操作:  参考实验手册 

ifeq   (arm,$(ARCH))
   CROSS_COMPILE ?= arm-none-linux-gnueabi-
endif

#if 1
    ldr r0, =0x11000c40 @GPK2_7 led2
    ldr r1, [r0]
    bic r1, r1, #0xf0000000
    orr r1, r1, #0x10000000
    str r1, [r0]
 
    ldr r0, =0x11000c44
    mov r1,#0xff
    str r1, [r0]
#endif    


    @#./mkuboot
    @split -b 14336 u-boot.bin bl2
    @+make -C sdfuse_q/
    @#cp u-boot.bin u-boot-4212.bin
    @#./sdfuse_q/add_sign
    @./sdfuse_q/chksum
    @./sdfuse_q/add_padding
    @rm bl2a*
    @echo

    cat E4412_N.bl1.SCP2G.bin bl2.bin all00_padding.bin u-boot.bin tzsw_SMDK4412_SCP_2GB.bin > u-boot-fs4412.bin

烧写uboot 到SD卡:
    1) 将要烧写的 u-boot-4212.bin 文件 复制到  sdfuse_q 目录中 
    2) 将 sd连接到 Ubuntu 系统中   
    3) 查看 连接成功否 
        sudo fdisk -l

Disk /dev/sda: 40 GiB, 42949672960 bytes, 83886080 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x0c1d422e

设备       启动    Start   末尾   扇区 Size Id 类型
/dev/sda1  *        2048 75493375 75491328  36G 83 Linux
/dev/sda2       75493376 83886079  8392704   4G  5 扩展
/dev/sda5       75495424 83884031  8388608   4G 83 Linux


Disk /dev/sdb: 7.4 GiB, 7948206080 bytes, 15523840 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x45db6c3e

设备       启动 Start   末尾   扇区  Size Id 类型
/dev/sdb1        2048 15523839 15521792  7.4G 83 Linux

    
    4) 使用工具 烧录 uboot到 sd卡  在sdfuse_q 中 
    sudo ./sd_fusing_exynos4x12.sh /dev/sdb ./u-boot-fs4412.bin 
            烧录脚本                 SD卡设备    要烧录的uboot文件
            
/dev/sdb reader is identified.
./u-boot-fs4412.bin fusing...
记录了1029+1 的读入
记录了1029+1 的写出
527104 bytes (527 kB, 515 KiB) copied, 2.48152 s, 212 kB/s
./u-boot-fs4412.bin image has been fused successfully.
Eject SD card
xwq@xwq-pc:~/sys_230901/u-boot-2013.01/sdfuse_q$ 

    5) 将sd卡插入开发板  将拨码开关拨动到  SD卡启动 

    上电: 可以看到 LED2 亮 了  串口没有反应(该实验的效果就这样)

串口输出: 

#if 1 /*for close watchdog */    
     /* PS-Hold high */
        ldr r0, =0x1002330c
        ldr r1, [r0]
        orr r1, r1, #0x300
        str r1, [r0]         
        ldr     r0, =0x11000c08
        ldr r1, =0x0
        str r1, [r0]
/* Clear  MASK_WDT_RESET_REQUEST  */
        ldr r0, =0x1002040c
        ldr r1, =0x00
        str r1, [r0]
#endif  

      ldr    r0, =0x10030000    
    ldr    r1, =0x666666  
    ldr    r2, =CLK_SRC_PERIL0_OFFSET
    str    r1, [r0, r2]
    ldr    r1, =0x777777 
    ldr    r2, =CLK_DIV_PERIL0_OFFSET
    str    r1, [r0, r2]

U-Boot 2013.01 (Dec 15 2023 - 16:09:18) for xwq fs4412

CPU:    Exynos4412@1000MHz

Board: ORIGEN
DRAM:  1 GiB
WARNING: Caches not enabled
MMC:   SAMSUNG SDHCI: 0
*** Warning - bad CRC, using default environment

In:    serial
Out:   serial
Err:   serial
Hit any key to stop autoboot:  0
XWQ #
XWQ #

Ubuntu网卡驱动移植: 
    参考实验手册 
    
    
#ifdef CONFIG_DRIVER_DM9000
#define EXYNOS4412_SROMC_BASE 0X12570000

#define DM9000_Tacs     (0x1) 
#define DM9000_Tcos     (0x1) 
#define DM9000_Tacc     (0x5) 
#define DM9000_Tcoh     (0x1) 
#define DM9000_Tah      (0xC) 
#define DM9000_Tacp     (0x9)   
#define DM9000_PMC      (0x1)  

struct exynos_sromc {
        unsigned int bw;
        unsigned int bc[6];
};

/*
 * s5p_config_sromc() - select the proper SROMC Bank and configure the
 * band width control and bank control registers
 * srom_bank    - SROM
 * srom_bw_conf  - SMC Band witdh reg configuration value
 * srom_bc_conf  - SMC Bank Control reg configuration value
 */
void exynos_config_sromc(u32 srom_bank, u32 srom_bw_conf, u32 srom_bc_conf)
{
        unsigned int tmp;
        struct exynos_sromc *srom = (struct exynos_sromc *)(EXYNOS4412_SROMC_BASE);

        /* Configure SMC_BW register to handle proper SROMC bank */
        tmp = srom->bw;
        tmp &= ~(0xF << (srom_bank * 4));
        tmp |= srom_bw_conf;
        srom->bw = tmp;

        /* Configure SMC_BC register */
        srom->bc[srom_bank] = srom_bc_conf;
}
static void dm9000aep_pre_init(void)
{
       unsigned int tmp;
       unsigned char smc_bank_num = 1;
       unsigned int     smc_bw_conf=0;
       unsigned int     smc_bc_conf=0;
       
       /* gpio configuration */
       writel(0x00220020, 0x11000000 + 0x120);
       writel(0x00002222, 0x11000000 + 0x140);
       /* 16 Bit bus width */
       writel(0x22222222, 0x11000000 + 0x180);
       writel(0x0000FFFF, 0x11000000 + 0x188);
       writel(0x22222222, 0x11000000 + 0x1C0);
       writel(0x0000FFFF, 0x11000000 + 0x1C8);
       writel(0x22222222, 0x11000000 + 0x1E0);
       writel(0x0000FFFF, 0x11000000 + 0x1E8);              
       smc_bw_conf &= ~(0xf<<4);
       smc_bw_conf |= (1<<7) | (1<<6) | (1<<5) | (1<<4);
          smc_bc_conf = ((DM9000_Tacs << 28)
                    | (DM9000_Tcos << 24)
                    | (DM9000_Tacc << 16)
                    | (DM9000_Tcoh << 12)
                    | (DM9000_Tah << 8)
                    | (DM9000_Tacp << 4)
                     | (DM9000_PMC));
       exynos_config_sromc(smc_bank_num,smc_bw_conf,smc_bc_conf);
}
#endif    


#ifdef CONFIG_CMD_NET
int board_eth_init(bd_t *bis)                                                  
{      
       int rc = 0;
#ifdef CONFIG_DRIVER_DM9000
       rc = dm9000_initialize(bis);                                            
#endif                                                                         
       return rc;                                                              
}  
#endif

#ifdef CONFIG_CMD_NET
#define CONFIG_NET_MULTI
#define CONFIG_DRIVER_DM9000  1
#define CONFIG_DM9000_BASE    0x05000000
#define DM9000_IO                  CONFIG_DM9000_BASE
#define DM9000_DATA                (CONFIG_DM9000_BASE + 4)
#define CONFIG_DM9000_USE_16BIT
#define CONFIG_DM9000_NO_SROM  1
#define CONFIG_ETHADDR         11:22:33:44:55:66
#define CONFIG_IPADDR              192.168.3.201
#define CONFIG_SERVERIP            192.168.3.200
#define CONFIG_GATEWAYIP          192.168.3.1
#define CONFIG_NETMASK         255.255.255.0
#endif

Linux内核移植: 
    1. Linux特性   非实时操作系统 
        开源,免费  
        可以裁剪 , 可以移植性强  
        需要的基本硬件资源很少    SRMA 8M  
    
    单片机使用较多: 
        RTOS  实时操作系统  :  对中断(异常) 响应时间快,稳定,可靠 
            多用于控制系统  
        FreeRTOS : 开源免费的     1K RAM   flash 16KB 
        UCos,..  : 开源收费的   
        VxWorks  : 完全收费的  
        
    伪操作系统:  事件驱动型  OSAL   ZigBee:    ble: 低功耗蓝牙  

Linux内核子系统:
    进程管理:  多进程  fork 
    内存管理:  堆内存malloc/free
    文件系统:  IO与文件
    网络系统:  网络编程  
    设备管理:  驱动开发 

Linux层次: 了解  
    应用层
    内核层

Linux内核编译步骤: 
    获取内核源码:   官网获取  www.kernel.org
    
    内核版本:   6.6.7 
                |  |====> 次版本号  是奇数: 过度版本 稳定性待验证   偶数: 较稳定的版本 
                |===> 主版本号

Linux源码包:    linux-3.14.tar.xz
    
Linux源码目录: 
    arch: 与体系架构相关的代码 

        以下与平台无关
    drivers     驱动相关,设备的相关驱动程序
        将硬件信息与驱动剥离,放到设备树文件,当设备变化时只需要修改设备树就可以,增强了代码的移植性,减轻维护成本。
    fs                文件系统相关代码
    init              系统初始化相关的
    include           头文件相关代码
    kernel          内核实现相关代码,调度算法等
    lib               系统相关库
    net              网络协议相关
    block           块设备相关的
    Document          帮助文档
    mm                 内存管理相关的
        
编译内核: 
    
    1. 指定交叉开发工具链  
        修改Makefile
        
    2. 导入默认配置     ./arch/arm/configs/exynos_defconfig
        make  exynos_defconfig

    3. 进行内核配置调整   一个字符型 的 窗口界面, 可以在其中进行配置  
        make menuconfig 
        
    4. 编译内核  
        make uImage  -j2 
        
Linux uImage 生成过程  以及 步骤: 
    通过编译打印 可得 
        
    源码链接  ----> vmlinux  ----->  Image -----> zImage ----> uImage 
                      elf             bin          压缩格式     uboot压缩格式
                      
    vmlinux:  60M  第一次链接生成的 内核的可执行文件 包含调试数据 符号链接等  源码根目录
    Image  :  5.2M 去除调试信息 以及符号链接等的 格式转换 可执行内核    arch/arm/boot/Image
    arch/arm/boot/compressed/vmlinux  二次链接    2.8M
            由 Image 压缩 以及 额外添加了 解压缩代码 
    zImage : 2756488 2.7M  有Image 压缩 以及添加了 解压缩代码的 内核压缩包      
    uImage : 2756552 2.7M  在zImage前面 添加的64字节的 特殊信息, 专门用于 uboot 引导 
        说明这个内核的版本、加载位置、生成时间、大小等信息;其0x40之后与zImage没区别。
        该步骤由mkimge工具完成的
    
内核启动 第一步: 自解压     
    
设备树编译:  存储着硬件的差异信息 特殊结构文件 目的 将驱动程序与硬件信息分离 

    1. 使用origen板子 的设备树 复制 
    cp arch/arm/boot/dts/exynos4412-origen.dts  arch/arm/boot/dts/exynos4412-fs4412.dts
    
    2. 编译设备树  exynos4412-fs4412.dtb
    make exynos4412-fs4412.dtb 
    
    或者使用 make dtbs  编译所有设备树 
    
设备树的结构:  在 arch/arm/boot/dts/ 中 
    文件后缀   .dtsi   .dts   .dtb  
       .dtsi  类似于 .h文件  主要描述 核心信息 通常由其他板子的 .dts文件 引用  
       .dts   类似于 .c文件  描述硬件信息, 以字符形式展示 
    结构类似一颗倒置的树  有点类似与 Linux目录结构  
        /  根节点
        {
            属性  以键值对形式表示 
            
            子节点1子节点名字 { 属性,  子节点 };
            子节点2 { 属性,  子节点 };
            // ,.....
        };
    
        .dtb  类似于 .o 文件  由 .dts 经过 DTC 工具  编译得到的 
                给内核使用的 二进制格式 人无法阅读 
    
    3. 验证 编译的 内核与设备树 
        复制 编译好的 设备树 与 内核镜像到  tftp工作目录 
        cp arch/arm/boot/dts/exynos4412-fs4412.dtb ~/tftpboot/
        cp arch/arm/boot/uImage ~/tftpboot/
    
    4. 开发板下载 并引导内核  uboot执行   配置开发板IP  设置bootargs 
        tftp 41000000 uImage 
        tftp 42000000 exynos4412-fs4412.dtb
        bootm 41000000 - 42000000 
        
Linux内核启动流程:  了解 
    
    Linux系统启动: 
        1. uboot 加载内核 
        2. linux 内核启动 
        3. 根文件系统 挂载, 应用程序运行  
        
    
    uboot: 
        tftp 41000000 uImage
    或 
        movi read kernel 41000000 
        
    Starting kernel ...    
linux 内核启动:        
    1. 内核自解压 
        由uImage 解压出来  Image
        运行zImage中自带的 解压缩程序 将 内核释放到指定位置  0x40008000
        
    uImage : 41000000 
    Image  : 40008000 
    
    完成自解压后 跳转到 入口地址 40008000 地址运行内核 Image 
    
    2. 内核启动 arch/arm/kernel/head.S 
        汇编阶段:   进行CPU 类型检查, 基本硬件初始化 
               __lookup_processor_type : CPU信息获取与检查
               __vet_atags   验证Uboot传入参数及设备树
               __create_page_tables :准备页表,为后续开启mmu(内存管理单元)做准备
            开启内存虚拟化:
            __mmap_switched:跳转到文件  arch/arm/kernel/head-common.S 
                拷贝data段 如果需要  清除bss段 
            b start_kernel   跳转C阶段  
          start_kernel:        进入到C阶段  
        C阶段: 
            init/main.c 文件中 
            定时器初始化, 关中断 , 内存虚拟化  ... 
            rest_init();  // 该函数不会返回 
                内核启动ok 
            内核线程 
            
    3.挂载根文件系统  运行第一个应用层程序  linuxrc
    
内核 驱动移植: 
    1. 网卡驱动   参考实验手册
    设备树 添加网卡节点 
srom-cs1@5000000 {    //bank1 物理设备 描述
        compatible = "simple-bus";
        #address-cells = <1>;
        #size-cells = <1>;
        reg = <0x5000000 0x1000000>;
        ranges;

        ethernet@5000000 {
            compatible = "davicom,dm9000";
            reg = <0x5000000 0x2         0x5000004 0x2>;
            interrupt-parent = <&gpx0>;   // 网卡的中断管脚 GPX0_6
            interrupts = <6 4>;
            davicom,no-eeprom;
            mac-address = [00 0a 2d a6 55 a2];
        };
    };
    
    网卡设备树 配置 参考 Documentation/devicetree/bindings/net/davicom-dm9000.txt

    2. 修改时钟使能 
    
    3. 配置内核   make menuconfig 
    
    4. 编译,在开发板上运行 
    
内核的配置过程以及原理: 
    
    .config : 源码根目录  存储 配置信息  定义宏以及其值 
    Kconfig : 在每个目录中都有, 用于提供界面选项(在make menuconfig)时
    Makefile: 在每个目录中都有, 用于在编译时 根据.config定义的变量 进行选择编译 
    
实验第三方驱动移植:  参考实验手册 
    第三方驱动: 不是内核自带的驱动程序    LED驱动 
    
    1. 直接编译到内核  系统启动需要的一些驱动 
        内核污染:  第三方驱动 污染的内核  
    2. 编译为模块 
        将驱动程序 编译为 一个独立的文件 后缀.ko
        在程序需要使用的时候  动态添加模块, 使用完毕后 可以卸载 
        可以解决冲突问题   同时方便更新与维护 
        
Kconfig格式: 

    source "xxx/Kconfig"   引入 xxx/Kconfig 文件展开到这里 
    menu  " xxxx "         创建一个菜单(可以展开的)
        // 写一些选项 
        config   XXXXX      #表示要创建一个选项 该选项控制宏   XXXXX
            bool  选项名    #表示这是一个二选一的 选项  tristate 表示3选1 
            default  y      # 默认值 
            help
                xxxx 帮助信息 
    endmenu    
    
    编译测试 应用程序 : 
    arm-none-linux-gnueabi-gcc   fs4412_led_app.c -o led_app
    
    编译模块  make modules 
    
    xxx.ko   内核模块  
    
    手动添加 设备节点  
    mknod  /dev/led  c  501  0
        添加一个设备节点 c 字符型  501 主设备号 0 次设备号

    安装内核模块: insmod xxx.ko 
    卸载内核模块: rmmod  xxx 
    查看安装的模块:  lsmod  

内核调试: 
    打印法调试(内核中的打印)
    puts 内核解压前使用
    printascii  串口初始化前使用    输出到 缓存区 
    串口初始化后     
    printk:   与printf 非常详细  
    printk( "a=%d",a);
    
printk 带有输出等级  
#define KERN_EMERG        "<0>"   /* system is unusable           */
#define KERN_ALERT         "<1>”     /* action must be taken immediately */
#define KERN_CRIT           "<2>"   /* critical conditions          */
#define KERN_ERR            "<3>"   /* error conditions         */
#define KERN_WARNING      "<4>"   /* warning conditions           */
#define KERN_NOTICE       "<5>"     /* normal but significant condition */
#define KERN_INFO          "<6>"   /* informational            */
#define KERN_DEBUG        "<7>"   /* debug-level messages

    printk(KERN_WARNING "warning ...");
    
    方便调试, 可以宏观控制 高于某个等级的 打印可以输出  
    
    控制内核打印输出的等级  通过bootargs参数设定  增加选项 loglevel=输出等级 0-8
    set bootargs  root=/dev/nfs nfsroot=192.168.3.200:/home/xwq/nfshome/rootfs rw console=ttySAC2,115200 init=linuxrc ip=192.168.3.201 loglevel=8
    
内核OOP打印: 内核崩溃时的打印信息  
    回溯内核函数栈, 显示内核崩溃时调用了哪些函数 
    
根文件系统制作: 
    使用工具 busybox 工具来制作  https://busybox.net/
    将Linux 常用的命令 以及 linuxrc 都集成到一个程序中 busybox 
    业内称作 瑞士军刀
    
根文件系统主要有些啥? 
    1.目录结构 
    bin  dev  etc   lib  linuxrc  mnt  proc  root  sbin  sys  tmp  usr  var
    bin: 存储Linux的shell命令 
    etc: 存储系统配置 
    lib: 存储一些需要的库 
    linuxrc: 是一个软链接  挂载根文件系统后的第一个进行 0号进程
    
    2.使用    busybox 生成根文件系统 
    
为什么需要根文件系统?
    文件系统: 是数据的一系列抽象,标准化数据的一种方式
            不同系统,不同架构,不同体系间都可以通过文件的形式共享,交流数据

    根文件系统: Linux内核启动后  需要运行用户的应用程序
            方便用户应用程序的 移植  
            用户应用程序  
            elf格式的  有操作系统情况下运行的 可执行文件 
            bin格式    用于裸机运行 

    内核与用户的交互接口 根文件系统

    参考实验手册: 根文件系统的移植实验手册.doc 
    
    1. 解压源码busybox 
    
    2. 配置busybox 
    make menuconfig  
    配置  交叉编译工具链 
    使能  命令使用静态库 
    
    3. 编译  
    make 
    
    4.安装  
    make install
    
    5. 添加其他目录 到 _install 
    mkdir  dev  etc  mnt  proc  var  tmp  sys  root 
    
    6. 添加一些库  只要动态库  
    cp /opt/gcc-4.6.4/arm-arm1176jzfssf-linux-gnueabi/sysroot/lib ./lib -r
    
    7. 删除静态库 以及 不需要的库  
    sudo rm ./*.a ./*.la -rf
    
    8. 删除动态库的符号表  
    arm-none-linux-gnueabi-strip  lib/*
    
    9. 添加开机配置文件  
    etc/
    ├── fstab    :  系统挂载表  挂载一些系统目录   在开机启动脚本中 会访问该文件 
    ├── init.d
    │   └── rcS  :  开机启动脚本,在inittab文件中指定 系统启动时需要执行一次该脚本
    ├── inittab  :  指定系统 在一些情况下需要作的事
    └── profile  :  指定系统启动后的 环境变量,主机名,用户名等的 配置 
    
    10. 根文件系统 ok  测试  
    删除原有的 nfshome/rootfs 中的内容 
    复制 _install 中的所有内容  到  nfshome/rootfs 中  
    
产品阶段     
系统固化:   将已经 做好的 Uboot  uImage  dtb设备树  根文件系统   固化化到  开发板  
    Uboot:  烧录到 SD 卡    烧录到flash 
    uImage: 烧录到flash kernel分区  
        tftp 41000000 uImage
        movi write kernel 41000000

    dtb  :  烧录到flash  dtb分区 
        tftp 42000000 exynos4412-fs4412.dtb
        movi write dtb 42000000
    
根文件系统固化:
    2个方向:
    1) 内存镜像:  掉电后,(系统启动后新增的)存储的数据会丢失
                  根文件系统 不会损坏 
        将根文件系统 作为 内存镜像方式   如图所示 
        根文件系统本身 以镜像(压缩包)形式存储在 flash 
        使用时(Linux启动时)  将镜像 解压到 内存中  在内存中挂载根文件系统 
        需要配置 Linux内核  要支持 内存镜像 根文件系统 
            
    2) 直接使用 flash分区或 SD等 存储介质  
        根文件系统 直接复制到 flash分区或 SD 卡上 
                  系统数据 可以在掉电后存储 
                  不能意外断电  突然断电 可能导致 系统数据丢失或出错 
        需要 Linux内核 支持 SD卡或emmc

            
    3) 根文件系统  使用 内存镜像   通过 挂载的方式  将SD卡或 flash分区 挂载到 
            根文件系统  , 用于存储用户数据  
            
实验 根文件系统 镜像制作:
    1. 开辟一个 指定大小(10M)的 磁盘镜像空间   
    xwq@xwq-pc:~/tmp$   dd  if=/dev/zero  of=ramdisk  bs=1k  count=10240
        
    2. 格式化 磁盘镜像空间 
    xwq@xwq-pc:~/tmp$     mkfs.ext2  -F  ramdisk 
    
    3. 挂载 磁盘镜像空间
    xwq@xwq-pc:~/tmp$    sudo mount ramdisk /mnt/mdisk/
    
    4. 复制根文件系统到 磁盘镜像空间
    xwq@xwq-pc:~/nfshome/rootfs$    sudo cp ./* /mnt/mdisk/ -r
    
    5. 卸载 磁盘镜像空间
    xwq@xwq-pc:/mnt$     sudo umount mdisk/
    
    6. 压缩磁盘镜像  生成 ramdisk.gz 
    xwq@xwq-pc:~/tmp$    gzip  --best  -c  ramdisk  >  ramdisk.gz
    
    7. 格式化ramdisk.gz  生成 ramdisk.img 文件  
    xwq@xwq-pc:~/tmp$  mkimage -n "ramdisk" -A arm -O linux -T ramdisk -C gzip -d ramdisk.gz ramdisk.img

    ramdisk.img 文件就是 根文件系统的 内存镜像  
    
    如何固化 与 使用 内存镜像 ?
    
    1) 下载 ramdisk.img 到内存   ramdisk.img 需要先复制到 tftpboot目录中  
    tftp  43000000 ramdisk.img

FS4412[general] # tftp  43000000 ramdisk.img
dm9000 i/o: 0x5000000, id: 0x90000a46
DM9000: running in 16 bit mode
MAC: 11:22:33:44:55:66
operating at 100M full duplex mode
Using dm9000 device
TFTP from server 192.168.3.200; our IP address is 192.168.3.201
Filename 'ramdisk.img'.
Load address: 0x43000000
Loading: #################################################################
         #################################################################
         #################################################################
         #################################################################
         #########
         897.5 KiB/s
done
Bytes transferred = 3943857 (3c2db1 hex)    
    
3c2db1: img磁盘镜像的大小 (16进制)

    2) 烧录 ramdisk.img 到 rootfs分区 
    movi write rootfs 43000000 3c2db1

使用固化的镜像 启动Linux系统:
    
    设置uboot环境变量:
    set bootcmd movi read kernel 41000000\;movi read dtb 42000000\;movi read rootfs 43000000 3c2db1\;bootm 41000000 43000000 42000000 
    set bootargs  root=/dev/ram0  rw console=ttySAC2,115200 init=linuxrc ip=192.168.3.201 loglevel=8

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值