Android2.3及Linux2.6.29内核模拟器版本编译与调试
一、前言
1.自旋锁与信号量
自旋锁:当不能获得自旋锁时一直忙等待,既不睡眠、也不执行调度;在SMP中使用自旋锁。
信号量:当不能获得信号量时,系统睡眠或执行调度(进程上下文中)。
2.自旋锁
在内核非抢占时,自旋锁相当于空操作、不起任何作用。
二、实例分析
1.Linux2.6.29内核开启内核抢占
make menuconfig
Kernel Features->Preemptible Kernel
如果不开启内核抢占,本试验将没有任何异常!
对比下开启前后内核模块的魔术字。
modinfo test_driver.ko
未开启内核抢占:
filename: test_driver.ko
license: GPL
author: tank
depends:
vermagic: 2.6.29-gb0d93fb-dirty mod_unload ARMv5
开启内核抢占:
filename: test_driver.ko
license: GPL
author: tank
depends:
vermagic: 2.6.29-gb0d93fb-dirty preempt mod_unload ARMv5
2.程序
内核模块:
test_driver.c
#include <linux/module.h>
#include <linux/types.h>
#include <linux/uaccess.h>
#include <linux/miscdevice.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/spinlock.h>
#include <linux/delay.h>
#define TEST_MAJOR 240
//static DEFINE_SPINLOCK(write_lock);
//static DEFINE_SPINLOCK(read_lock);
static spinlock_t write_lock;
static spinlock_t read_lock;
static DEFINE_MUTEX(write);
static DEFINE_MUTEX(read);
//动态设备节点
struct class *mymodule_class;
//结束
static int test_led_open(struct inode *inode, struct file *file)
{
printk("#########open######\n");
return 0;
}
static int test_led_close(struct inode *inode, struct file *file)
{
printk("#########release######\n");
return 0;
}
static int test_led_read(struct file *filp, char __user *buff, size_t count, loff_t *offp)
{
printk("############read##000000000####\n");
unsigned long flags;
down(&read);//spin_lock_init(&read_lock);
spin_lock(&read_lock);
spin_lock(&read_lock); //两次获得“自旋锁”,导致内核crash!!!!!!!!!
printk("#########read######\n");
//msleep(10000);
down(&write);//spin_lock(&write_lock);
printk("#########read#11111#####\n");
//msleep(10000);
up(&read);//spin_unlock_irqrestore(&read_lock,flags);
printk("#########read##22222####\n");
//msleep(10000);
up(&write);//spin_unlock(&write_lock);
printk("#########read##33333####\n");
return count;
}
static int test_led_write(struct file *filp, const char __user *buf, size_t count,loff_t *f_pos)
{
printk("########write#000000########\n");
unsigned long flags;
down(&write);//spin_lock(&write_lock);
printk("#########write######\n");
//msleep(10000);
down(&read);//spin_lock(&read_lock);
printk("#########write#11111#####\n");
//msleep(10000);
up(&write);//spin_unlock(&write_lock);
printk("#########write##22222####\n");
//msleep(10000);
up(&read);//spin_unlock(&read_lock);
printk("#########write##33333####\n");
return count;
}
static struct file_operations led_fops = {
.owner = THIS_MODULE,
.open = test_led_open,
.release = test_led_close,
.read = test_led_read,
.write = test_led_write,
};
static int __init test_drv_init(void)
{
int rc;
printk("test_driver dev\n");
//注册设备
rc = register_chrdev(TEST_MAJOR,"test_dev",&led_fops);
if (rc <0){
printk ("register %s char dev error\n","led");
return -1;
}
//实现动态创建
mymodule_class = class_create(THIS_MODULE, "test_dev");
device_create(mymodule_class, NULL, MKDEV(TEST_MAJOR, 0), NULL, "tankai_dev");
//结束
printk ("ok!\n");
return 0;
out_chrdev:
unregister_chrdev(TEST_MAJOR, "mymodule");
out:
return -1;
}
static void __exit test_drv_exit(void)
{ //动态设备节点
device_destroy(mymodule_class, MKDEV(TEST_MAJOR, 0));
class_destroy(mymodule_class);
//结束
unregister_chrdev(TEST_MAJOR, "test_dev");
}
module_init(test_drv_init);
module_exit(test_drv_exit);
MODULE_AUTHOR("tank");
MODULE_LICENSE("GPL");
Makefile
obj-m := test_driver.o
PWD := $(shell pwd)
#KERNELDIR := /usr/src/linux-headers-3.0.0-26-generic/
KERNELDIR := /home/android2.3/android2.3_kernel/
default:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
# cp -rf mini.ko ../module/
# cp -rf lddbus.ko ../module/
clean:
rm *.mod.c *.o *.ko *.bak modules.* Module.*
make生成test_driver.ko
用户测试程序:testread.c
#include <fcntl.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
int main(){
int fd = open("/dev/tankai_dev",O_RDWR,0);
if(fd < 0) perror("testdriver");
printf("TK------->>>fd is %d\n",fd);
char buf[20];
int result = read(fd,&buf,3);
printf("TK------->>>readresult is %d,buf is %s\n",result,buf);
strcpy(buf,"123");
//result = write(fd,&buf,3);
printf("TK------->>>writeresult is %d,buf is %s\n",result,buf);
close(fd);
return 0;
}
Android.mk
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
testread.c
LOCAL_SHARED_LIBRARIES := \
libutils
LOCAL_MODULE:= testread
LOCAL_MODULE_TAGS := optional
include $(BUILD_EXECUTABLE)
mm编译后生成testread
3.操作
insmod test_driver.ko
./testread
4.结果死锁
串口终端操作没有任何反映,手机界面也无法在操作;系统内核挂掉,死机。
#########open######
############read##000000000####
#########read######
#########read#11111#####
#########read##22222####
#########read##33333####
#########release######
Unable to handle kernel paging request at virtual address 40008084
pgd = c8e18000
[40008084] *pgd=0a685031, *pte=0bb1934f, *ppte=0bb19aae
Internal error: Oops: 81f [#1] PREEMPT
Modules linked in: test_driver
CPU: 0 Not tainted (2.6.29-gb0d93fb-dirty #93)
PC is at 0xafd1c9d2
LR is at 0xafd1c9cf
pc : [<afd1c9d2>] lr : [<afd1c9cf>] psr: 60000030
sp : beebebb8 ip : 00009118 fp : 00000000
r10: 00000000 r9 : 00000000 r8 : 00000000
r7 : beebebd4 r6 : afd424f8 r5 : 40008000 r4 : 40008084
r3 : 40008088 r2 : 00000003 r1 : 00001000 r0 : 00000000
Flags: nZCv IRQs on FIQs on Mode USER_32 ISA Thumb Segment user
Control: 00093177 Table: 08e18000 DAC: 00000015
Process testread (pid: 373, stack limit = 0xca5b2268)
Kernel panic - not syncing: Fatal exception