zoukankan      html  css  js  c++  java
  • linux内核驱动的知识要点

    IT的本质
    信息技术
    研究0和1的行业

    计算机:数字计算

    数字描述万事万物

    数字的进制:10 24 12 7 60 16 2

    0和1可以描述万事万物

    内存的作用:
    1. 存指令
    2. 存数据

    CPU的组成:ALU(运算器) 控制器 寄存器
    ALU中包含很多个运算电路:每个电路对应一条指令


    CPU分为:
    RISC(精简指令集):易 慢 功耗低
    CISC(复杂指令集):难 快 高


    CPU——奴隶 内存——抽屉
    执行一条指令的过程:
    1. 取值(从内存中读取指令:打开抽屉取出写着指令的纸条)
    2. 译码(从二进制指令中解析出操作码以决定后面使用哪条运算电路:读懂纸条上的指令以便知道后面要做什么)
    3. [取数据](从内存中读取数据:打开抽屉取出后面所做事情所需的原材料)
    4. 执行(执行运算电路:完成所要做的事情)
    5. [存数据](运算电路产生的结果存储到内存:所做动作产生的结果存放到抽屉)

    老冯的精髓贡献:
    1. 二进制思想
    计算机世界里的一切信息 = 二进制位 + 上下文

    数据类型:
    1. sizeof
    2. 变量定义语句的作用
    3. 相关的运算
    4. 作为函数形参类型
    5. 作为函数返回值类型
    数据类型就是对内存中二进制位的上下文描述
    文件格式就是对外存中二进制位的上下文描述
    网络协议就是对网络中传输的二进制位的上下文描述

    2. 程序存储思想
    程序在执行之前先将指令存放到内存
    函数指针
    进程的内存布局:
    a. 栈区:非static的局部变量 函数形参
    b. 堆区:动态分配
    c. 数据区:static的局部变量 全局变量 字符串常量
    d. 代码区:二进制指令


    多核:
    并行编程:多任务编程
    伪并行:分时
    真并行:


    ARM:
    1. 公司名
    2. 技术专利名称
    3. 一系列CPU的统称

    寻址空间:26位
    两种指令集:ARM指令集 Thumb指令集
    Cortex A(应用) R(实时性) M(单片机)

    Cache高速缓存
    MPU:内存保护单元
    MMU:内存管理单元
    虚拟内存

    虚拟地址&物理地址


    汇编:
    1. 寄存器
    2. 寻址方式

    r0~r12

    r13(SP):堆栈寄存器
    r14(LR):链接寄存器
    r15(PC程序计数器):指向空间存放的是要被取指的指令
    C-PSR:当前程序状态寄存器
    S-PSR:备份CPSR内容


    执行流:
    1. 任务流(进程、线程)
    2. 异常流


    编译过程: 预处理 编译 汇编 链接


    ST:写内存
    LD:读内存
    SWP:交换


    数据结构:研究如何组织、管理、存储多个同类型数据以及相关操作的学科

    1. 逻辑关系
    集合
    线性关系:一对一 线性表 栈 队列
    树形关系:一对多
    图形关系:多对多
    2. 存储方式
    顺序存储
    链式存储


    执行流
    顺序执行
    跳转执行:
    选择
    分支
    循环
    函数调用
    break
    continue
    return
    goto


    test.S:
    AREA ttt,CODE,READONLY
    ENTRY
    MOV r0,#1
    MOV r1,#2
    ADD r2,r0,r1
    END

    64位linux编译运行32位app的支持:
    sudo apt-get install build-essential module-assistant
    sudo apt-get install gcc-multilib g++-multilib
    sudo apt-get install lib32ncurses5 lib32z1
    验证:
    gcc hello.c -o hello -Wall -m32

    RS232
    启动模式选择开关:
    1. SD卡
    2. NandFlash启动(靠铜柱)

    开发板的名字:Tiny210
    CPU:S5PV210(SOC)三星
    ARM核:Cortex-A8
    RAM:512M
    NandFlash:512M


    格式化:给分区指定文件系统
    文件系统:FAT32 NTFS ext4 yaffs2
    文件内容
    文件名
    元信息

    bootloader:一类裸机程序
    1. 启动操作系统
    2. 安装操作系统

    Superboot


    安装系统需要安装:
    1. bootloader
    2. OS
    3. 根文件系统rootfs

    1. cd
    2. mkdir arm210
    3. cd arm210
    4. mkdir bin src
    5. cp ???/src/tiny210...tgz ./src
    6. cd src
    7. tar zxvf tiny210...tgz
    8. mv tiny210... u-boot

    9. 安装交叉编译器
    a. sudo cp ???/tools/arm-linux-gcc-4.5.1-v6-vfp-20120301.tgz /opt
    b. cd /opt
    c. sudo tar zxvf arm-linux...tgz
    d. cd opt/FriendlyARM/toolschain/4.5.1/bin/
    e. pwd后拷贝路径
    f. cd
    g. 修改~/.bashrc
    最后添加两行:
    export ARM_GCC_BIN=粘贴拷贝的路径
    export PATH=$PATH:$ARM_GCC_BIN
    保存退出
    h. 关闭控制台,重启控制台
    i. 命令行敲arm加两次Tab键,出现一堆arm开头的信息说明安装OK

    u-boot:
    1. 如何编译uboot
    cd ~/arm210/src/u-boot
    make distclean
    make tiny210_config
    make all
    cp ./tools/mkimage ../../bin/
    cp tiny210-uboot.bin ../../bin/
    2. 如何安装uboot
    A. 用SD卡第一分区中的Superboot安装
    1) 拷贝 ~/arm210/bin/tiny210-uboot.bin 到 sd卡/images目录中
    2) 修改FriendlyARM.ini文件,注释掉安装zImage、内核参数、rootfs的三行
    3) 模式开关置于SD卡启动一侧
    4) 开发板加电,自动完成uboot的安装
    5) 安装成功后关闭电源,模式开关置于Nandflash启动一侧
    6) 重新加电,在SecureCRT中看到uboot命令行说明OK
    B. 用Nandflash第一分区安装好的uboot安装
    一、下载tiny210-uboot.bin到内存
    a. 方法1:串口下载
    1) 将编译好的tiny210-uboot.bin拷贝到windows
    2)【uboot命令行】loady 21000000
    3) SecureCRT菜单Transfer中选Send Ymodem
    4) 点击Send Ymodem出现的界面中选中tiny210-uboot.bin
    5) 点击ADD按钮然后点击OK按钮开始传送
    b. 方法2:SD卡下载
    1)将要下载的文件copy到sd卡根目录
    2)将sd插入开发板
    3)【uboot命令行】mmc part
    命令查看是第几个sd卡(一般为0),和该SD卡的FAT分区是第几个分区(一般为1)
    4)【uboot命令行】fatload mmc 0:1 21000000 sd卡中要下载的文件名
    二、擦除NandFlash第一分区
    【uboot命令行】nand erase 0 0x600000
    三、将内存中的tiny210-uboot.bin写到NandFlash第一分区
    【uboot命令行】nand write 0x21000000 0 0x600000
    3. 如何使用uboot
    两种工作模式:
    boot:默认模式
    loader:加电时SecureCRT界面敲空格进入uboot命令行
    4. uboot源码的两个阶段:
    汇编阶段
    C阶段


    Linux内核:
    1. 如何编译Linux内核
    sudo apt-get install libncurses5-dev
    cp ???/src/linux-3.0.8-20130327.tgz ~/arm210/src
    cd ~/arm210/src
    tar zxvf linux-3.0.8-20130327.tgz
    cd linux-3.0.8

    make distclean
    cp mini210_linux_defconfig .config
    make menuconfig
    界面中去掉:
    Device Drivers --->
    <*> Memory Technology Device (MTD) support --->
    <*>NAND Device Support --->
    [ ]S3C NAND Hardware ECC
    界面中选中:
    File systems --->
    [*] Miscellaneous filesystems --->
    [*] Lets Yaffs do its own ECC
    修改源码:
    drivers/mtd/nand/s3c_nand.c:1194行,_SOFT为_NONE

    make 开始编译
    cp arch/arm/boot/zImage ../../bin
    cd ../../bin
    ./mkimage -n 'Hiro' -A arm -O linux -T kernel -C none -a 0x21000000 -e 0x21000040 -d ./zImage ./uImage

    2. 如何安装Linux内核
    串口或SD卡下载uImage到内存(步骤同uboot下载)
    擦除第二分区:
    【uboot命令行】nand erase 0x600000 0x500000
    将内存中的uImage写到Nandflash第二分区
    【uboot命令行】nand write 0x21000000 0x600000 0x500000

    如果无法启动Linux内核,请设置uboot的启动命令:
    【uboot命令行】setenv bootcmd "nand read 21000000 600000 500000;bootm 21000000"
    【uboot命令行】saveenv
    3. uImage的组合过程
    4. Linux内核源码结构解析
    任务管理 内存管理 设备管理
    网络管理 文件管理 启动管理

    根文件系统:
    1. 如何制作根文件系统的img文件(镜像文件)
    cd ~/arm210/bin
    cp ???/tools/rootfs_qtopia_qt4-20130222.tar.gz ./
    cp ???/tools/mkyaffs2image-128M ./
    chmod +x ./mkyaffs2image-128M
    sudo tar zxvf rootfs_qtopia_qt4-20130222.tar.gz
    sudo mv rootfs_qtopia_qt4 rootfs
    cd rootfs/opt
    sudo rm * -rf
    cd ../usr/local
    sudo rm *.gz Trolltech/ -rf
    cd ~/arm210/bin
    sudo ./mkyaffs2image-128M ./rootfs rootfs.img

    2. 如何安装根文件系统
    SD卡下载rootfs.img到内存(步骤同uboot或uImage下载)
    擦除第四分区:
    【uboot命令行】nand erase 0xe00000 0xf200000
    将内存中的rootfs.img写到Nandflash第四分区
    【uboot命令行】nand write.yaffs 0x21000000 0xe00000 0x5BEB100 (rootfs.img文件大小的十六进制)

    需求分析
    设计
    编码:20%
    测试

    维护

    编程思想体现解决问题的第一思维:
    面向过程:步骤化
    结构化:模块化
    面向对象:对象化


    SE:
    TE:
    SPM:
    SQA:
    SCM:软件配置管理


    ARM-Linux App:
    1. 编译app:
    arm-linux-gcc ???.c -o 可执行文件名 -Wall
    2. 下载并执行app:
    a. 串口下载
    将编译好的可执行文件拷贝到windows文件系统
    【开发板Linux命令行】cd /opt
    【开发板Linux命令行】rx 可执行文件名
    SecureCRT界面中点菜单Transfer,再选Send Xmodem
    点Send Xmodem后的界面中选中要下载的文件,点击Add按钮,再点击OK按钮开始传送直到结束
    【开发板Linux命令行】chmod +x 可执行文件名
    【开发板Linux命令行】./可执行文件名
    b. SD卡下载
    将编译好的可执行文件拷贝到windows文件系统
    自己电脑上插入SD卡
    将已拷贝到windows文件系统的可执行文件拷贝到SD卡
    将SD卡插入开发板
    【开发板Linux命令行】cd /sdcard (该目录即为SD卡中的内容)

    UNIX家族的三大分支:
    1. System 5:AIX HPUX
    2. BSD:FreeBSD NetBSD OpenBSD
    3. 类UNIX:Linux、Minix


    if(likely(x > y))
    {
    ....
    }


    执行流:
    1. 任务流(任务上下文)
    a. 进程上下文
    b. 应用线程上下文
    c. 内核线程上下文
    2. 异常流(异常上下文)


    Linux命令:
    1. 外部命令
    2. 内部命令


    switch()
    {
    case 1:
    /*fall though*/
    case 2:
    }

    函数定义的作用:
    1. 代码复用
    2. 简化逻辑
    3. 拼装

    语句:
    1. 执行语句
    独立语句
    复合语句

    2. 非执行语句


    #define SWAP x=y;y=2;

    if(a>b)
    SWAP

    int i
    char c
    long l
    short s
    float f
    double d
    T * p
    struct st
    union un
    enum e
    array a

    double *T

    typedef int INTARR5[5];

    INTARR5 arr1;

    typedef signed char INT8;
    typedef short INT16;
    typedef int INT32;
    typedef long INT64;

    x += 2;


    #pragma pack(n)


    int *(*a[5])(int,char *);

    void (*b[10])(void (*)());

    double(*)() (*e)[9];


    int a;
    int *pa;
    int (*pa)[5];


    向linux源码driver/char/目录里添加自己的代码并编译到zImage中:
    1. 编写好代码
    2. 在同级目录下Kconfig文件中找到雷同内容进行修改:
    1)修改config 后的名字(将用在下面的Makefile文件中)
    2) 修改config下一行“”中的内容(将被显示在make menuconfig界面)
    3)help下一行内容,选择性修改
    3. 在同级目录下Makefile文件中找到雷同内容行进行修改:
    obj-$(CONFIG_XXX) += YYY.o
    (XXX为Kconfig文件对应内容第一行config后面的名字)
    (YYY为新增.c文件的文件名,注意不含.c扩展名)
    4. 执行make menuconfig进入:
    Device Drivers----->
    Character devices------>
    找到有(new)的哪一行,敲空格键将该项的值选为<*>或[*]
    退出make menuconfig界面时记得选择Yes进行保存修改
    5. 重新编译zImage:make
    6. cp arch/arm/boot/zImage ../../bin
    7. 将zImage制作成uImage:(下面的命令是在同一行)
    ./mkimage -n 'Hiro' -A arm -O linux -T kernel -C none -a 0x21000000 -e 0x21000040 -d ./zImage ./uImage
    8. 将uImage下载安装Nandflash的第二分区

    内核模块基础源码解析
    内核模块代码编译
    cd ~/arm210/src/linux3.0.8/
    cp drivers/char/myhello.c ~/arm210/src/mydriver/hello/
    cd ~/arm210/src/mydriver/hello/
    编写或修改Makefile
    make (有???.ko文件生成说明编译OK,否则要么Makefile有问题,要么C语言源码有问题)

    插入、查询和移除内核模块
    1. 开发板进入Linux命令行
    2. 下载???.ko文件到开发板Linux的/opt目录下(下载方法同app可执行文件)
    3. 插入、查询和移除内核模块的命令:
    插入内核模块:insmod ???.ko
    查询已被插入到内核的模块名:lsmod
    移除已被插入到内核的模块:rmmod 模块名(lsmod显示的模块名,不是???.ko文件名)


    内核模块参数
    模块间的依赖


    GPL
    LGPL

    开源软件 免费


    make:制作
    Makefile makefile

    1. 编译命令过长
    2. 编译时间过长

    主体:规则
    规则的组成:
    目标:依赖列表
    [Tab]怎么样用依赖产生目标的命令


    .c源码编译可以生成:
    1. app可执行文件
    2. 库文件
    静态库:windows下.lib UNIX家族OS下:.a
    动态库:windows下.dll UNIX家族OS下:.so (共享库)
    3. 裸机可执行文件
    4. Linux内核模块文件:.ko

    设备驱动程序:
    外设:(辅助设备)按设备功能来分
    1. 输入设备
    2. 输出设备
    3. 存储设备(外存)
    4. 控制设备

    外设:数据交互方式来分
    1. 字符设备:按字节顺序存取
    2. 块设备:按扇区(512字节)随机存取
    3. 网络设备

    linux下文件种类:
    1. -:普通文件
    2. d: 目录
    3. l: link文件
    4. p: 命名管道
    5. s: 本地socket
    6. c:字符设备 /dev
    7. b:块设备 /dev

    struct MyDev
    {
    struct cdev t;
    ....
    }

    内核里用链表将所有字符设备管理起来

    每个设备在内核里都有唯一的身份标识:
    1. 主设备号:哪一类设备
    2. 次设备号:哪一个设备


    globalmem:用内核空间中一块内存模拟一个简单的字符设备


    指针类型的形参:
    1. 值参数 (只读指向空间)
    2. 结果参数(只向指向空间写结果)
    3. 值-结果参数 (既从指向空间读数据又向指向空间写结果)


    内存操作错误:
    1. 野值(不确定值)
    2. 野指针(不确定地址值)
    3. 内存泄漏
    4. 重复释放
    5. 越界
    6. 修改了只读数据区

    C语言编程的最基本原则:
    1. 类型一致化
    2. 所有内存空间必须是已知可控的

    描述符
    标识符

    int型的函数返回值:
    1. 0表示调用正常,非0(负数更常用)表示发生了某种错误
    2. 表示是或不是什么东东(bool)
    3. 表示某个实际意义的整型数

    C库函数:fopen ----->open
    fclose ----->close
    fprintf fputs fputc fwrite --->write
    fscanf fgets fgetc fread --->read
    fseek ftell ----->lseek
    系统调用: open close read write lseek


    arm210/src/mydriver/globalmem/globalmem.c
    验证globalmem驱动程序:
    1. 编译成ko文件
    2. ko下载到开发板linux系统下的/opt目录里
    3. 插入内核模块
    4. 获取主设备号
    cat /proc/devices | grep globalmem
    5. 创建设备文件
    mknod /dev/globalmem c 主设备 0
    6. 编写App来验证驱动程序中各个函数

    int main()
    {
    int fd = -1;
    char buf[16] = "";
    fd = open("/dev/globalmem",O_RDWR);
    if(fd < 0)
    {
    printf("OPen failed ");
    return 1;
    }
    write(fd,"hello",5);
    lseek(fd,0,SEEK_SET);
    read(fd,buf,5);
    printf("buf=%s ",buf);

    ioctl(fd,1,0);
    memset(buf,0,16);
    read(fd,buf,5);
    printf("buf=%s ",buf);

    close(fd);
    return 0;
    }


    globalmem的缺陷:
    1. 读写操作不支持阻塞
    2. 不支持多任务共同使用

    链表分类:
    1. 指针域成员的个数
    2. 有没有首尾相接
    3. 有头结点的链表和无头结点的链表

    头指针:


    select:多路复用

    int ret = -1;
    fd_set rfds;
    struct timeval tout = {0};
    while(1)
    {
    求最大的文件描述符maxfd
    FD_ZERO(&rfds);
    FD_SET(fd1,&rfds);
    FD_SET(fd2,&rfds);
    .....
    FD_SET(fdn,&rfds);
    tout.tv_sec = 10;
    ret = select(maxfd+1,&rfds,NULL,NULL,&tout);
    if(ret < 0)
    {
    出错处理
    }
    if(FD_ISSET(fd1,&rfds))
    {
    从fd1中读数据
    处理数据
    }
    if(FD_ISSET(fd2,&rfds))
    {
    从fd2中读数据
    处理数据
    }
    ........
    if(FD_ISSET(fdn,&rfds))
    {
    从fd1中读数据
    处理数据
    }
    }

  • 相关阅读:
    JS 知识点补充
    JS 数据之间类型的转化
    JS 数据的类型
    数据结构--数组、单链表和双链表介绍 以及 双向链表
    数据结构--队列
    数据结构--栈
    24. 两两交换链表中的节点
    23. 合并K个排序链表
    22. 括号生成
    21. 合并两个有序链表
  • 原文地址:https://www.cnblogs.com/qiny1012/p/8603994.html
Copyright © 2011-2022 走看看