打印
[嵌入式linux]

开始学linux驱动,三个月熟悉,立帖为证!每日汇报进展

[复制链接]
楼主: tiger84
手机看帖
扫描二维码
随时随地手机跟帖
141
tiger84|  楼主 | 2010-1-24 12:01 | 只看该作者 回帖奖励 |倒序浏览
以前的根文件是厂家自带的,用的是ramdisk。ramdisk是在启动时把一部分内存虚拟成磁盘,它有2个缺点:
(1)同时占用ram和flash;
(2)掉电不能保存数据。

于是想重新制作根文件系统,研究之后,初步打算使用cramfs+yaffs2的文件系统。
cramfs用来作根文件系统,充分利用系统资源,yaffs2用来存储一些配置参数。

cramfs优点:
(1)压缩比高
(2)占用内存少
缺点:只读。

于是加上yaffs2文件系统
优点:
(1)能更好的支持nand flash,延长nand flash寿命;
(2)资源占用少
(3)可读写
缺点:
(1)不提供日志机能,稳定性不如jffs
(2)不支持压缩,更适合存储容量大的系统

采用cramfs与yaffs2可以充分利用2者的优点,达到互补的效果。

使用特权

评论回复
142
tiger84|  楼主 | 2010-1-24 12:16 | 只看该作者
制作cramfs文件系统时,碰到一个主要问题就是cramfs是一个只读的文件系统,而在启动的过程中,我需要创建目录和文件,怎么办呢?

先不管,直接利用原理的根文件,只是简单的把它制作成了cramfs文件。

果然,启动过程中提示read only,不能创建文件。

上网查找,发现别人都利用到了tmpfs,把一些需要写的目录都挂载成tmpfs。

于是更改,然后成功启动。

接下来就是制作yaffs2文件系统,基本上没有遇到障碍。
以下是我的MTD分区
# cat /proc/mtd
dev:    size   erasesize  name
mtd0: 00400000 00020000 "u-boot"
mtd1: 00400000 00020000 "kernel-1"
mtd2: 00400000 00020000 "kernel-2"
mtd3: 00800000 00020000 "rootfs-1"
mtd4: 00800000 00020000 "rootfs-2"
mtd5: 00400000 00020000 "usr-config"
mtd6: 0e000000 00020000 "nandflash-store"

再rcS里添加了一句:
/bin/mount -t yaffs2 /dev/mtdblock5 /mnt/usr

然后就可以在/mnt/usr里面保存数据了。

唯一的疑惑是
我查看到的都是mtd0,mtd1,mtd2之类,使用的时候却需要使用mtdblock0,mtdblock1,mtdblock2.
还得再看看是怎么回事。

使用特权

评论回复
143
tiger84|  楼主 | 2010-1-24 12:32 | 只看该作者
本帖最后由 tiger84 于 2010-1-24 12:42 编辑

接下来的计划:
白天图生存,晚上求发展。
(1)把宋宝华的那本驱动及LDD3仔细研究一遍,试验可以试验的例程,做到一些简单的驱动没有任何问题且高质量,理论知识扎实。约2周,1月25日至2月6日的周末及晚上。
(2)研究u-boot,根据产品情况作出最符合的u-boot;约1周,2月6日至2月12日,这个貌似可以大大方方的放在工作日弄。
(3)启动时间优化;我手头Linux启动起来需要15S,可以优化的余地很大。现在对linux没有什么整体的把握,都是蜻蜓点水,仅能估计哪里可以优化,但是具体还无法去做。这个只能等年后了。

使用特权

评论回复
144
电子菜鸟435| | 2010-1-25 17:02 | 只看该作者
向你学习!

使用特权

评论回复
145
icecut| | 2010-1-25 18:03 | 只看该作者
加油.水平不错了.超过我了.

使用特权

评论回复
146
huangqi412| | 2010-1-25 19:12 | 只看该作者
厉害

使用特权

评论回复
147
icecut| | 2010-1-25 19:41 | 只看该作者
曲高和寡啊.

lz自己保重,我就不常来了

使用特权

评论回复
148
tiger84|  楼主 | 2010-1-25 21:21 | 只看该作者
icecut兄弟说笑了,我离你还远的很呢。
非常谢谢你这么多天的鼓励,真诚的说声谢谢。

使用特权

评论回复
149
tiger84|  楼主 | 2010-1-25 21:23 | 只看该作者
今天下午去了趟华强北,晚上才赶回来。
比较累,只是简单的看了下宋那本书的前5章,重新看过,很多东西果然很清晰了。

使用特权

评论回复
150
tiger84|  楼主 | 2010-1-25 21:34 | 只看该作者
手头的产品8月份需要出来,arm+dsp的,硬件上问题不大,主要还是软件。而软件的核心又集中在整个系统的框架和DSP那块。任务还是比较紧,需要付出更多的时间和高效率。一定要**住每天都学习linux!

使用特权

评论回复
151
tiger84|  楼主 | 2010-1-26 21:57 | 只看该作者
晚上仔细阅读了宋宝华老师的并发控制章节,简单摘录如下:
linux设备驱动中的并发控制
并发与竞态
解决方法:保证对共享资源的互斥访问!

访问共享资源的代码区称为临界区(critical sections),临界区需要以某种互斥机制加以保护。

linux设备驱动的互斥机制:中断屏蔽、原子操作、自旋锁、信号量。

中断屏蔽

使用方法:
---------------------------
local_irq_disable();     // 屏蔽中断
---------------------------
critical sections          // 临界区
---------------------------
local_irq_enable();     // 开中断
---------------------------

缺点:
(1)linux系统的异步I/O、进程调度等很多重要操作都依赖于中断,长时间屏蔽中断是不可取的;
(2)并不能解决SMP问题

因此单独使用中断屏蔽通常不是一种值得推荐的避免竞态的方法,它适宜与自旋锁联合使用。

原子操作
原子操作是指在执行过程中不会被别的代码路径所中断的操作。
原子操作分为:整型原子操作、位原子操作。

自旋锁
自旋锁(spin lock)是一种对临界资源进行互斥访问的典型手段,其名称来源于它的工作方式。
一般这样使用
spinlock_t lock;
spin_lock_init(&lock);

spin_lock(&lock);  //获取自旋锁,保护临界区
----// 临界区
spin_unlock(&lock); // 解锁

自旋锁主要针对SMP或者单CPU但内核可抢占的情况,对于单CPU且内核不支持抢占的系统,自旋锁退化为空操作。

应当谨慎使用自旋锁,使用中还要特别注意如下几个问题:
1,自旋锁实际上是忙等待,当锁不可用时,CPU一直循环执行“测试并设置”该锁直到可用而取得该锁。因此只有在占用锁的时间极

短的情况下,使用自旋锁才是合理的。
2,自旋锁可能导致系统死锁。引发这个问题最常见的情况就是递归使用一个自旋锁;此外,如果进程获得自旋锁之后再阻塞,也有

可能导致死锁的发生。copy_from_user()、copy_to_user()、kmalloc()等函数都有可能引起阻塞,因此在自旋锁的占用期间不能调

用这些函数。

读写自旋锁
自旋锁对读或者写一视同仁,不支持并发访问,于是出现了自旋锁的衍生锁读写自旋锁(rwlock)可允许读的并发,但是读和写也能同

时进行。

顺序锁
顺序锁(seqlock)是对读写锁的一种优化,若使用顺序锁,读执行单元绝不会被写执行单元阻塞。但是写执行单元与写执行单元之间

仍然是排斥的。
顺序锁有一个限制,它必须要求被保护的共享资源不含有指针,因为写执行单元可能使得指针失效,但读执行单元如果正要访问该指

针,将导致OOPS。


读--拷贝--更新
RCU(Read-Copy Update),它是基于其原理命名的。可看作读写锁的高性能版本,相比读写锁,RCU的优点在于既允许多个读执行单元

访问被保护的数据,又允许多个读执行单元与多个写执行单元同时访问被保护的数据。
但是RCU布恩那个替代读写锁,因为如果写比较多时,对读执行单元的性能提高不能弥补写执行单元导致的损失。因为使用RCU时,写

执行单元之间的同步开销会比较大,它需要延迟数据结构的释放,复制被修改的数据结构,它也必须使用某种锁机制同步并行的其他

写执行单元的修改操作。

信号量
信号量(semaphore)是用于保护临界区的一种常用方法,它的是用方式和自旋锁类似,与自旋锁不同的是当获取不到信号量时,进程

不会原地打转而是进入休眠等待状态。

如果信号量被初始化为0,则它可以用于同步。不过linux提供了一种比信号量更好的同步机制-----completion,它用于一个执行单

元等待另外一个执行单元完成某事。

自旋锁与信号量PK
        自旋锁与信号量都是解决互斥问题的基本手段,面对特定的情况,应该如何进行选择呢?选择的依据是临界区的性质和系统

的特点。
        从严格意义上来说,信号量和自旋锁属于不同层次的互斥手段,前者的实现依赖于后者。
        信号量是进程级的。因此只有当进程占用资源时间较长时,用信号量才是较好的选择。当所要保护的临界区访问时间比较短

时,使用自旋锁是非常方便的。

使用特权

评论回复
152
tiger84|  楼主 | 2010-1-26 21:59 | 只看该作者
明天又要跑华强北一趟,比较郁闷。

明晚仔细阅读阻塞与非阻塞I/O,异步通知与异步I/O。

使用特权

评论回复
153
tiger84|  楼主 | 2010-1-26 22:08 | 只看该作者
今天编译u-boot时,不知道怎么回事,出现了2个非常奇怪的问题:
(1)内存溢出错误,可以肯定源码和配置都没问题。
(2)连tar都出问题了
于是认为是系统出问题了,强行重启机器后,ssh一直连不上,由于只有1个主机,又手忙脚乱的去借了个显示器,启动,才发现系统挂了。
出现了“filesystem ----”,
具体忘记了。
吓我一大跳,来不及思考,就打算向同事去借DVD光驱,哪知道同事比较忙,光驱也不在,只好重新回到屏幕前。
屏幕上有很一些提示,手动用fsck来挂载,按照屏幕的提示,一步一步的来,reboot重启后,系统竟然恢复了,比较high。

使用特权

评论回复
154
gaoyucheng| | 2010-1-27 09:36 | 只看该作者
1# tiger84

使用特权

评论回复
155
gaoyucheng| | 2010-1-27 09:36 | 只看该作者
**

使用特权

评论回复
156
icecut| | 2010-1-27 12:49 | 只看该作者
慢慢找,还有更好玩的技术解决那些问题.只是宋的书,可能写的靠后,作为关键技术吧.有点书写的靠前.慢慢读

其实都不难.

使用特权

评论回复
157
tiger84|  楼主 | 2010-1-27 22:14 | 只看该作者
今天又浪费了1个下午在华强北,好在该办的事终于办了下来。晚上8点才回来,吃了个饭,就9点了,计划中的看书没有完成。

使用特权

评论回复
158
tiger84|  楼主 | 2010-1-27 22:33 | 只看该作者
以前用的u-boot是1.1.5的,为了熟悉u-boot,及更好的认识at91sam9260,下载了一个最新版本u-boot1.3.4,然后又在atmel的官方网站上下了个补丁,编译顺利通过。

刚开始我就想使用u-boot1.3.4,由于保存环境变量时出现问题,就又退回使用1.1.5了。下载到板子上,设置好几个参数。
saveenv

ok,没问题。

又写入了几个变量,
saveenv

出现
FAILED!

没保存成功。

多试验了几次,发现把u-boot烧进板子之后,就第一次设置环境变量会成功,后面的都会失败。

怎么出现失败的呢?

写的时候有个提示,在0x60000检测到了坏块。

读u-boot的README,发现1.3.4增加了坏块检测功能。并且它有2个保存环境变量的区域。
存的地址如下:
/* bootstrap + u-boot + env + linux in nandflash */
#define CFG_ENV_IS_IN_NAND        1
#define CFG_ENV_OFFSET                0x60000
#define CFG_ENV_OFFSET_REDUND        0x80000
#define CFG_ENV_SIZE                0x20000                /* 1 sector = 128 kB */
然后看程序
int writeenv(size_t offset, u_char *buf)
{
        size_t end = offset + CFG_ENV_RANGE;
        size_t amount_saved = 0;
        size_t blocksize;

        u_char *char_ptr;

        blocksize = nand_info[0].erasesize;

        while (amount_saved < CFG_ENV_SIZE && offset < end) {
                if (nand_block_isbad(&nand_info[0], offset)) {
                        offset += blocksize;                       
                }
else {
                        char_ptr = &buf[amount_saved];
                        if (nand_write(&nand_info[0], offset, &blocksize,
                                        char_ptr))
                                return 1;
                        offset += blocksize;
                        amount_saved += blocksize;                       
                }
        }
       
        if (amount_saved != CFG_ENV_SIZE)
    {
        return 1;
    }
               

        return 0;
}
见红色部分,由于我的坏区刚好在0x60000,所以u-boot1.3.4把这一块跳过去了,
offset 加上blocksize后就等于end了,也就跳出了循环,        然后就从蓝色部分跳出,写入失败!

我的u-boot是下载在0x20000,而且我给u-boot分配了2M的空间,资源应该足够了,既然0x60000有坏区,我就把他们的地址都加上0x20000,宏定义如下:
/* bootstrap + u-boot + env + linux in nandflash */
#define CFG_ENV_IS_IN_NAND        1
#define CFG_ENV_OFFSET                0x80000
#define CFG_ENV_OFFSET_REDUND        0xa0000
#define CFG_ENV_SIZE                0x20000                /* 1 sector = 128 kB */

改好之后,u-boot就可以正常保存变量了。
不知道这算不算u-boot1.3.4的一个BUG?或者说我的用法有问题?
这一块还得优化,万一坏块又出现在0x80000了,岂不又完了?今天没时间弄了,以后继续。

使用特权

评论回复
159
一朝成名| | 2010-1-27 22:48 | 只看该作者
注意身体,别累坏了~

使用特权

评论回复
160
tiger84|  楼主 | 2010-1-28 20:41 | 只看该作者
呵呵,谢谢成名的关心,俺身体吃得消,呵呵。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则