一、
基本概念
linux @ ubuntu :~$
用户名 类型:普通用户 系统名称 家目录
root
管理员用户
pwd 显示当前工作路径(绝对路径)
/home/linux 家目录 /$根目录下 /代表根目录
ls 列出文件状态 + 选项 (-l -i -h -1)
rwx r-x r--
文件所属用户对该文件执行权限 同组其他用户对该文件的执行权限 非同组其他用户对文件的执行权限
读 写 执行均可 可读 不可写 可执行 只可读 不可写 不可执行
文件类型 七种:
b block 块设备文件 例如:U盘 硬盘 按内存块读取
c char 字符设备文件 例如: 键盘 鼠标 按字符读写 先进先出原则
d 目录
- 普通文件
l 链接文件
s socket 套接字文件
p pipe 管道文件
cat +文件名 显示文件信息 rm +文件名 删除文件 cp +被复制的文件名+新文件名 复制文件
mv +被剪切的文件+新文件名 剪切文件 mkdir 创建文件夹 /目录 rmdir 删除空目录 touch 创建一个新文件
clear 或者 CTRL+l 可以清屏
rmdir 不能删除非空目录 rm + 文件名 + -rf 可以删除所有目录
cd 切换目录 cd + - 切换到上一次切换的目录
grep 查询关键字 + 关键字名称 + 路径名 + -rn 逐个目录查找/递归搜索
二、
vim编辑器
模式:1.底行模式 :wq 保存并退出 :q! 强制退出不保存 shift+zz 保存并退出
esc后 + yy 复制光标所在行 + p 复制 dd 剪切一行 按d剪切所有 按y复制所有 u 回复上一次状态
2.命令行模式/输入模式
vsp + 文件名 分屏 :wqa退出所有分屏
vi + -O + 文件名+ 文件名 直接打开分屏 大写O左右分屏 小写 上下分屏
CTRL+alt+T 重新打开一个家目录下的编辑界面
sudo su 进入root用户
sudo shutdown -h now 关机 -r now 重启 == sudo reboot now
三、
shell命令
head + 行数 + 显示文件开头
tail + 行数 + 显示文件结尾
diff 比较两个文件
file 查看文件类型
echo 显示文本信息 》代表输出 》》代表继续输出 在终端输入文件到设备中
+ 字符串 + 》(重定向) + 文件名 清空方式
+ 字符串 + 》》(重定向)+ +文件名 追加的方式
df + -TH 检查文件系统空间占用情况
du + -mh 查看文件大小
chmod 改变文件或目录的访问权限
sudo chmod 755 + 文件名
man linux官方文档
passwd 用户密码 sudo passwd +用户名(linux)
四、文件压缩以及解压
gzip + - 级别(1-9)+ 文件名 1-9为压缩级别 越大压缩越小
gunzip + -f + 压缩文件名 解压
gzip + -l + 压缩文件名 查看压缩比
tar 归档 压缩 解压
tar -c 创建一个归档文件
-f 指定归档文件名称
-x 释放归档文件
-v 显示归档以及释放过程
-j 由tar生成归档 由bzip2压缩
-z 由tar生成归档 由gzip压缩
归档并压缩
-cjf + 压缩文件名 + 需要压缩的文件夹
-czf + 压缩文件名 + 需要压缩的文件夹
解压
tar -xvf + 压缩文件名 便可直接解压
gcc 编译器
gcc + 文件名 编译文件
gcc + 文件名 + -o + 生成可执行程序名
执行: ./执行程序
五、编译器编译源码:
预处理(pre-processing) xxx.c---> (预处理文件)
编译(compiling) xxx.i---> (汇编文件)
汇编(assembling) xxx.s---> (可重定向文件)
链接(linking) xxx.o---> (可执行文件)
预处理:gcc -E test.c -o test.i
编译: gcc -s test.i -o test.s
汇编: gcc -c test.c -o test.o
链接: gcc test.o -o test
makefile
makefile格式
变量名称($)
$< 第一个依赖文件的名称
$^ 所有不重复的依赖文件 以空格分开
$@ 目标文件的完整名称
六、静态库、动态库
静态库:
1.将功能函数所在文件编译成可重定向文件
gcc -c func.c -o func.o
2.将可重定向文件制作成静态库
ar crs libfunc.a func.o
3.编译时,指定库的路径及库的名字
gcc main.c -o main -L. -lfunc
动态库:
1.将功能函数所在的文件编译成可重定向文件
gcc -fPIC -c func.c -o func.o
2.将可重定向文件制作成动态库
gcc -shared func.o -o libfunc.so
3.生效,将库文件存放到/lib
gcc main.c -o main -L. -lfunc 不可执行
sudo cp libfunc.so /lib/ 转移路径后
./main 便可执行
七、存储结构:
数组:
一维数组:数组名 《==》数组的首地址,数组的起始地址, 首元素地址
一维数组数组名:列性质地址
*(array+i)每次移动到下一位地址(列发生偏移)
* 代表解引用 ,根据数据所在地址,获取该地址上的内容
二维数组:数组名 《==》数组的起始地址 ,
二维数组数组名 :行性质地址
a[]: 列性质地址
&a[0][0]: 列性质地址
*(*(a+i)+j) 括号中*,表示降级处理,将a+i由行性质地址转换为列性质
结论:
a【i】 《=====》 *(a+i)
一维数组中* 代表解引用
二维数组中* 代表降级处理
指针:
指针变量在内存上占有四个字节,与其指向无关
普通指针是列指针, 保存的是指向的数据所在的内存的地址
数组指针:
指向数组的指针,不同于普通指针,数组指针是行指针
例如:int(*p)[4];
指针数组:
数组, 数组中的元素是指针(普通指针或函数指针),保存的是地址
结构体:
struct 结构体名
{
成员名:
成员名:
。。。。
};
结构体(初始化 赋值 获取结构体成员的值)
1.变量名:
变量名.成员名==值;
2.指针:
指针变量名指向成员名
p=&test;先指向结构体名
八、IO:
input output 输入 输出
文件IO: 采用系统调用的方式对文件进行读写
对文件进行读写的功能由内核完成--系统调用
操作方式:先打开(open),后读(read)写(write)
函数原型:int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
功能:打开一个文件或设备
参数:pathname 路径名(文件名)
flags 当前进程对该文件的操作权限
O_RDONLY 以只读的方式打开文件
O_WRONLY 以只写的方式打开文件
O_RDWR 以读写的方式打开文件
O_APPEND 以追加的方式打开文件
O_CREAT 如果文件不存在,自动创建
O_TRUNC 如果文件中有数据,清空数据
O_RDONLY 以只读的方式打开文件,文件必须存在,不存在,出错
O_RDWR 以读写的方式打开文件,文件必须存在,不存在,出错
O_WRONLY|O_CREAT|O_TRUNC 以只写的方式打开文件,如果文件不存在,自动创建,
如果文件已存在,清空文件原有的数据
O_RDWR|O_CREAT|O_TRUNC 以读写的方式打开文件,如果文件不存在,自动创建,
如果文件已存在,清空文件原有的数据
O_WRONLY|O_CREAT|O_APPEND 以只写的方式打开文件,如果文件不存在,自动创建,
如果文件已存在,已追加方式进行访问
O_RDWR|O_CREAT|O_APPEND 以读写的方式打开文件,如果文件不存在,自动创建,
如果文件已存在,已追加方式进行访问
mode 当flags指定O_CREAT,必须有第三个参数
mode:该文件所属用户对该文件的执行权限
例:0664
mode & ~umask(文件权限掩码)
返回值: 成功 文件描述符(非负数)
失败 -1
当程序打开文件,文件描述符的值从3开始,0,1,2系统默认自动打开
0:标准输入
1:标准输出
2:标准出错输出
#include
函数原型:ssize_t write(int fd, const void *buf, size_t count);
功能:向文件中写入count个字节的数据
参数:fd 文件描述符
buf 写入到文件的数据
count 需要写入到文件的字节数
返回值: 成功 实际写入的字节数
失败 -1
函数原型:ssize_t read(int fd, void *buf, size_t count);
功能: 期望读取count个字节的数据
参数:fd 文件描述符
buf 保存读取的数据
count 期望读取count个字节的数据
返回值: 成功 实际读取的字节数
失败 -1
九、进程
进程是一个程序的一次执行的过程
进程和程序的区别:
程序是静态的,它是一些保存在磁盘上的指令的有序的集合,没有任何执行的概念
进程是一个动态的概念,他是程序执行的过程,包括创建,调度,消亡
进程的创建:当程序开始执行时,系统会为每一个进程分配4G的虚拟地址空间,保存进程的资源
并且会为每一个进程创建task_struct,描述进程的状态信息,或者进程资源
调度: cpu的调度或者时间片轮转调度
时间片:进程在某一时刻获取cpu控制的时间
消亡(退出):进程退出,将该进程获取的有限资源全部释放
静态查看进程信息:ps + axj/(aux)
PPID(parent procss ID) PID (process ID) PGID(process croup ID) SID(session ID)
父进程ID号 进程ID号 进程组ID号 (组长ID号) 会话组ID(会话组组长ID号)
TTY TPGID STAT UID TIME COMMAND
终端 进程的状态 当前进程所属用户ID 进程获取CPU的控制总时间 进程名
CTRL + c 将进程退出 CTRL + z 将进程停止 bg 将进程放到后台执行(脱离终端控制) fg 将进程放到前台
十、系统
系统移植
Windows装机: BIOS界面----》引导界面----》烧写Windows镜像----》加载当前文件系统
bootloader(引导系统)----》linux镜像----》文件系统(运行应用程序)
uboot:
driver(驱动)
tftp服务器:(配置)
检测: sudo dpkg -s tftpd-hpa
在线安装:sudo apt-get install tftp-hpa tftp-hpa
失败的话更新数据源:sudo apt-get install update
配置服务器端: sudo vi /etc/default/tftpd-hpa 以管理员模式进入编辑
修改代码: TFTP_USERNAME="tftp"
TFTP_DIRECTORY="/tftpboot"
TFTP_ADDRESS="0.0.0.0:69"
TFTP_OPTIONS="-c -s -l"
改权限: sudo chmod 777 tftpboot 将tftpboot改成777最高权限 sudo mkdir tftpboot 在根目录下创建
配置参数:-c create 可上传新文件
-s server uboot默认tftpboot目录为传输目录
-l listen 监听
启动tftp服务器: sudo service tftpd-hpa restart
nfs服务器
配置nfs服务器端: sudo vi /etc/exports
在11行添加代码: /source/rootfs/ *(rw,sync,no_subtree_check,no_root_squash)
/source 共享目录 自行创建 sudo mkdir source--》创建目录 sudo chmod 777 source--》改权限
rw 读写 sync 文件系统中的文件可以同步到内存与硬盘
no_subtree_check 如果子目录可以被访问,就不检测父目录的权限了
no_root_squash 如果以root用户进入文件系统,将不会检测权限
启动nfs服务器: sudo /etc/init.d/nfs-kernel-server restart
联网:
重启网卡:sudo /etc/init.d/networking restart
十一、uboot
bootloader 操作模式:1.自启动模式 2.交互模式
setenv 设置新的环境变量
bootcmd 自启动命令、自启动模式、自动执行bootcmd后的参数
printenv 显示配置的环境变量
tftp 远程传输 tftp + address + file(二进制)
bootargs uboot设置好,给内核使用
bootm 解压并启动该地址上的内容 bootm + address
dmesg 查看内核打印缓冲区的内容 sudo insmod driver.ko 插入内核
lsmod 查看 sudo rmmod driver 卸载 modinfo driver.ko 查看
sudo dmesg -c 先查看,后刷新缓冲区
sudo dmesg -C 直接刷新缓冲区
sudo mknod /dev/led c 500 0 执行
十二、
字符设备驱动框架
1)设备号,驱动通过不同设备号区分不同的设备
申请注册设备号:1)用户自定义,向内核注册
2)系统分配,再注册
2)驱动需要实现对设备的控制(实现应用层对设备操作的函数接口)
3)设备节点(文件),给应用程序,应用程序视设备为文件
设备号
设备号(32bit)= 主设备号(高12bit) + 次设备号(低20bit)
#define MINORBITS 20
#define MINORMASK ((1U << MINORBITS) - 1)
#define MAJOR(dev设备号) ((unsigned int) ((dev) >> MINORBITS)) 根据设备号,得出主设备号
#define MINOR(dev设备号) ((unsigned int) ((dev) & MINORMASK)) 根据设备号,得出次设备号
#define MKDEV(ma主,mi次) (((ma) << MINORBITS) | (mi)) 根据主次设备号,生成设备号
申请注册:
1)静态注册(用户自定义设备号,向内核注册)
#define major 500
#define minor 0
dev_t devno = MKDEV(major, minor);
函数原型:int register_chrdev_region(dev_t from, unsigned count, const char *name)
功能:注册设备号
参数:from 设备号(用户自定义)
count 表示的是注册设备号的数量
name 名字 (描述设备号)
返回值:成功 0
失败 负数
2)动态注册(系统自动分配,向内核注册)
函数原型:int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count, const char *name)
功能:系统分配设备号,并且注册
参数:dev 系统自动分配设备号
baseminor 次设备号
count 注册设备号的数量
name 名字 描述设备号
返回值:成功 0
失败 负数
3)注销 void unregister_chrdev_region(dev_t from, unsigned count)
功能:注销设备号
参数:from 设备号
count 设备号的数量
如何实现对设备的控制
对于字符设备来讲,内核中提供结构体来描述一个设备strcut cdev
如何实现设备控制
对于字符设备,内核提供结构体来描述一个设备struct cdev
struct cdev {
struct module *owner; THIS_MODULE;
const struct file_operations *ops; 对设备进行操作的集合
dev_t dev; 设备号
unsigned int count;
};
1)初始化结构体
函数原型:void cdev_init(struct cdev *cdev, const struct file_operations *fops)
功能:初始化cdev结构体
参数:cdev cdev结构体
fops 对设备操作集合
2)将cdev结构体添加到内核链表
函数原型:int cdev_add(struct cdev *p, dev_t dev, unsigned count)
功能:将cdev结构体添加到内核链表
参数:p cdev结构体
dev 设备号
count cdev结构体的数量
返回值:成功 0
失败 负数
3)将cdev结构体从内核链表中移除
函数原型:void cdev_del(struct cdev *p)
参数:p cdev结构体
设备节点
手动创建: mknod /dev/xxx c 主设备号 次设备号
主、次设备号和驱动中的注册的设备号一致,将设备节点和设备关联
设备节点被创建在内存上,系统重启,节点删除
如何实现设备操作
应用程序:
int fd;
fd = open();
//操作代码
close(fd);
驱动:
int test_open(struct inode *, struct file *){
//实现硬件设备打开操作
return 0;
}
int test_close(struct inode *, struct file *){
//实现硬件设备关闭操作
return 0;
}
struct file_operations fops = {
.open = test_open,
.release = test_close,
};
十三、
驱动如何操作硬件设备
应用程序:int ioctl(int d, int request, ...);
功能:控制设备
参数:d 文件描述符
request 命令码
... 实现数据的传递
#define _IO(type幻数,nr编号)
#define _IOR(type,nr,size传输数据的大小)
#define _IOW(type,nr,size)
#define _IOWR(type,nr,size)
返回值:成功 0
失败 -1
驱动:long test_ioctl(struct file *filep, unsigned int cmd, unsigned long arg(地址)){
// 实现对设备的控制
}
struct file_operations fops = {
.unlocked_ioctl = test_ioctl,
}
硬件控制:
物理地址----------》虚拟地址
映射
函数原型: void *ioremap(unsigned long offset, unsigned long size)
功能:物理地址转换为虚拟地址
参数:offset 物理地址
size:范围
返回值: 成功 虚拟地址
失败 NULL
函数原型:void iounmap(volatile void_iomemd *adr)
参数: adr 虚拟地址
函数原型:u32 readl(const void *addr)
功能:读取寄存器保存的值
参数: addr 地址 (寄存器所在的地址) ---虚拟地址
返回值: 成功 寄存器的值
函数原型:void writel(u32 b, volatile void __iomem *addr)
功能:将修改之后的寄存器的值,写到寄存器
参数:b 修改之后的值
addr 寄存器所在的地址