星期五, 5月 02, 2008

To rebuild strace for ARM Platform


CC=arm-unknown-linux-gnu-gcc ./configure --target=arm-linux --host=arm-linux

,build就是你正在使用的机器,host就是你编译好的程序可以运行的平台,target就是你编译的程序可以处理的 平台.这个build和host比较好理解,但是target就不好办了,到底什么意思呢?一般来说,我们平时所说的交差编译用不到他target的,比 如./configure --build=i386-linux,--host=arm-linux就可以了,在386的平台上编译可以运行在arm板的程序.但是,一般我们都是 编译程序,而不是编译工具,如果我们编译工具,比如gcc,这个target就有用了.如果我们需要在一个我们的机器上为arm开发板编译

參考自: http://oss.lzu.edu.cn/blog/blog.php?/do_showone/tid_116.html


星期六, 4月 26, 2008

Dummy Block Driver for Linux

/*
* Sample disk driver, from the beginning.
*/

#include <linux/config.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>

#include <linux/sched.h>
#include <linux/kernel.h> /* printk() */
#include <linux/slab.h> /* kmalloc() */
#include <linux/fs.h> /* everything... */
#include <linux/errno.h> /* error codes */
#include <linux/timer.h>
#include <linux/types.h> /* size_t */
#include <linux/fcntl.h> /* O_ACCMODE */
#include <linux/hdreg.h> /* HDIO_GETGEO */
#include <linux/kdev_t.h>
#include <linux/vmalloc.h>
#include <linux/genhd.h>
#include <linux/blkdev.h>
#include <linux/buffer_head.h> /* invalidate_bdev */
#include <linux/bio.h>

MODULE_LICENSE("Dual BSD/GPL");

static int sbull_major = 0;
module_param(sbull_major, int, 0);
static int hardsect_size = 512;
module_param(hardsect_size, int, 0);
static int nsectors = 1024; /* How big the drive is */
module_param(nsectors, int, 0);
static int ndevices = 4;
module_param(ndevices, int, 0);

/*
* The different "request modes" we can use.
*/
enum {
RM_SIMPLE = 0, /* The extra-simple request function */
RM_FULL = 1, /* The full-blown version */
RM_NOQUEUE = 2, /* Use make_request */
};
static int request_mode = RM_SIMPLE;
module_param(request_mode, int, 0);

/*
* Minor number and partition management.
*/
#define SBULL_MINORS 16
#define MINOR_SHIFT 4
#define DEVNUM(kdevnum) (MINOR(kdev_t_to_nr(kdevnum)) >> MINOR_SHIFT

/*
* We can tweak our hardware sector size, but the kernel talks to us
* in terms of small sectors, always.
*/
#define KERNEL_SECTOR_SIZE 512

/*
* After this much idle time, the driver will simulate a media change.
*/
#define INVALIDATE_DELAY 30*HZ

/*
* The internal representation of our device.
*/
struct sbull_dev {
int size; /* Device size in sectors */
u8 *data; /* The data array */
short users; /* How many users */
short media_change; /* Flag a media change? */
spinlock_t lock; /* For mutual exclusion */
struct request_queue *queue; /* The device request queue */
struct gendisk *gd; /* The gendisk structure */
struct timer_list timer; /* For simulated media changes */
};

static struct sbull_dev *Devices = NULL;

/*
* Handle an I/O request.
*/
static void sbull_transfer(struct sbull_dev *dev, unsigned long sector,
unsigned long nsect, char *buffer, int write)
{
unsigned long offset = sector*KERNEL_SECTOR_SIZE;
unsigned long nbytes = nsect*KERNEL_SECTOR_SIZE;

if ((offset + nbytes) > dev->size) {
printk (KERN_NOTICE "Beyond-end write (%ld %ld)n", offset, nbytes);
return;
}
if (write)
memcpy(dev->data + offset, buffer, nbytes);
else
memcpy(buffer, dev->data + offset, nbytes);
}

/*
* The simple form of the request function.
*/
static void sbull_request(request_queue_t *q)
{
struct request *req;

while ((req = elv_next_request(q)) != NULL) {
struct sbull_dev *dev = req->rq_disk->private_data;
if (! blk_fs_request(req)) {
printk (KERN_NOTICE "Skip non-fs requestn");
end_request(req, 0);
continue;
}
// printk (KERN_NOTICE "Req dev %d dir %ld sec %ld, nr %d f %lxn",
// dev - Devices, rq_data_dir(req),
// req->sector, req->current_nr_sectors,
// req->flags);
sbull_transfer(dev, req->sector, req->current_nr_sectors,
req->buffer, rq_data_dir(req));
end_request(req, 1);
}
}


/*
* Transfer a single BIO.
*/
static int sbull_xfer_bio(struct sbull_dev *dev, struct bio *bio)
{
int i;
struct bio_vec *bvec;
sector_t sector = bio->bi_sector;

/* Do each segment independently. */
bio_for_each_segment(bvec, bio, i) {
char *buffer = __bio_kmap_atomic(bio, i, KM_USER0);
sbull_transfer(dev, sector, bio_cur_sectors(bio),
buffer, bio_data_dir(bio) == WRITE);
sector += bio_cur_sectors(bio);
__bio_kunmap_atomic(bio, KM_USER0);
}
return 0; /* Always "succeed" */
}

/*
* Transfer a full request.
*/
static int sbull_xfer_request(struct sbull_dev *dev, struct request *req)
{
struct bio *bio;
int nsect = 0;

rq_for_each_bio(bio, req) {
sbull_xfer_bio(dev, bio);
nsect += bio->bi_size/KERNEL_SECTOR_SIZE;
}
return nsect;
}

/*
* Smarter request function that "handles clustering".
*/
static void sbull_full_request(request_queue_t *q)
{
struct request *req;
int sectors_xferred;
struct sbull_dev *dev = q->queuedata;

while ((req = elv_next_request(q)) != NULL) {
if (! blk_fs_request(req)) {
printk (KERN_NOTICE "Skip non-fs requestn");
end_request(req, 0);
continue;
}
sectors_xferred = sbull_xfer_request(dev, req);
if (! end_that_request_first(req, 1, sectors_xferred)) {
blkdev_dequeue_request(req);
end_that_request_last(req);
}
}
}

/*
* The direct make request version.
*/
static int sbull_make_request(request_queue_t *q, struct bio *bio)
{
struct sbull_dev *dev = q->queuedata;
int status;

status = sbull_xfer_bio(dev, bio);
bio_endio(bio, bio->bi_size, status);
return 0;
}


/*
* Open and close.
*/

static int sbull_open(struct inode *inode, struct file *filp)
{
struct sbull_dev *dev = inode->i_bdev->bd_disk->private_data;

del_timer_sync(&dev->timer);
filp->private_data = dev;
spin_lock(&dev->lock);
if (! dev->users)
check_disk_change(inode->i_bdev);
dev->users++;
spin_unlock(&dev->lock);
return 0;
}

static int sbull_release(struct inode *inode, struct file *filp)
{
struct sbull_dev *dev = inode->i_bdev->bd_disk->private_data;

spin_lock(&dev->lock);
dev->users--;

if (!dev->users) {
dev->timer.expires = jiffies + INVALIDATE_DELAY;
add_timer(&dev->timer);
}
spin_unlock(&dev->lock);

return 0;
}

/*
* Look for a (simulated) media change.
*/
int sbull_media_changed(struct gendisk *gd)
{
struct sbull_dev *dev = gd->private_data;

return dev->media_change;
}

/*
* Revalidate. WE DO NOT TAKE THE LOCK HERE, for fear of deadlocking
* with open. That needs to be reevaluated.
*/
int sbull_revalidate(struct gendisk *gd)
{
struct sbull_dev *dev = gd->private_data;

if (dev->media_change) {
dev->media_change = 0;
memset (dev->data, 0, dev->size);
}
return 0;
}

/*
* The "invalidate" function runs out of the device timer; it sets
* a flag to simulate the removal of the media.
*/
void sbull_invalidate(unsigned long ldev)
{
struct sbull_dev *dev = (struct sbull_dev *) ldev;

spin_lock(&dev->lock);
if (dev->users || !dev->data)
printk (KERN_WARNING "sbull: timer sanity check failedn");
else
dev->media_change = 1;
spin_unlock(&dev->lock);
}

/*
* The ioctl() implementation
*/

int sbull_ioctl (struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
{
long size;
struct hd_geometry geo;
struct sbull_dev *dev = filp->private_data;

switch(cmd) {
case HDIO_GETGEO:
/*
* Get geometry: since we are a virtual device, we have to make
* up something plausible. So we claim 16 sectors, four heads,
* and calculate the corresponding number of cylinders. We set the
* start of data at sector four.
*/
size = dev->size*(hardsect_size/KERNEL_SECTOR_SIZE);
geo.cylinders = (size & ~0x3f) >> 6;
geo.heads = 4;
geo.sectors = 16;
geo.start = 4;
if (copy_to_user((void __user *) arg, &geo, sizeof(geo)))
return -EFAULT;
return 0;
}

return -ENOTTY; /* unknown command */
}

/*
* The device operations structure.
*/
static struct block_device_operations sbull_ops = {
.owner = THIS_MODULE,
.open = sbull_open,
.release = sbull_release,
.media_changed = sbull_media_changed,
.revalidate_disk = sbull_revalidate,
.ioctl = sbull_ioctl
};


/*
* Set up our internal device.
*/
static void setup_device(struct sbull_dev *dev, int which)
{
/*
* Get some memory.
*/
memset (dev, 0, sizeof (struct sbull_dev));
dev->size = nsectors*hardsect_size;
dev->data = vmalloc(dev->size);
if (dev->data == NULL) {
printk (KERN_NOTICE "vmalloc failure.n");
return;
}
spin_lock_init(&dev->lock);

/*
* The timer which "invalidates" the device.
*/
init_timer(&dev->timer);
dev->timer.data = (unsigned long) dev;
dev->timer.function = sbull_invalidate;

/*
* The I/O queue, depending on whether we are using our own
* make_request function or not.
*/
switch (request_mode) {
case RM_NOQUEUE:
dev->queue = blk_alloc_queue(GFP_KERNEL);
if (dev->queue == NULL)
goto out_vfree;
blk_queue_make_request(dev->queue, sbull_make_request);
break;

case RM_FULL:
dev->queue = blk_init_queue(sbull_full_request, &dev->lock);
if (dev->queue == NULL)
goto out_vfree;
break;

default:
printk(KERN_NOTICE "Bad request mode %d, using simplen", request_mode);
/* fall into.. */

case RM_SIMPLE:
dev->queue = blk_init_queue(sbull_request, &dev->lock);
if (dev->queue == NULL)
goto out_vfree;
break;
}
blk_queue_hardsect_size(dev->queue, hardsect_size);
dev->queue->queuedata = dev;
/*
* And the gendisk structure.
*/
dev->gd = alloc_disk(SBULL_MINORS);
if (! dev->gd) {
printk (KERN_NOTICE "alloc_disk failuren");
goto out_vfree;
}
dev->gd->major = sbull_major;
dev->gd->first_minor = which*SBULL_MINORS;
dev->gd->fops = &sbull_ops;
dev->gd->queue = dev->queue;
dev->gd->private_data = dev;
snprintf (dev->gd->disk_name, 32, "sbull%c", which + 'a');
set_capacity(dev->gd, nsectors*(hardsect_size/KERNEL_SECTOR_SIZE));
add_disk(dev->gd);
return;

out_vfree:
if (dev->data)
vfree(dev->data);
}

static int __init sbull_init(void)
{
int i;
/*
* Get registered.
*/
sbull_major = register_blkdev(sbull_major, "sbull");
if (sbull_major <= 0) {
printk(KERN_WARNING "sbull: unable to get major numbern");
return -EBUSY;
}
/*
* Allocate the device array, and initialize each one.
*/
Devices = kmalloc(ndevices*sizeof (struct sbull_dev), GFP_KERNEL);
if (Devices == NULL)
goto out_unregister;
for (i = 0; i < ndevices; i++)
setup_device(Devices + i, i);

return 0;

out_unregister:
unregister_blkdev(sbull_major, "sbd");
return -ENOMEM;
}

static void sbull_exit(void)
{
int i;

for (i = 0; i < ndevices; i++) {
struct sbull_dev *dev = Devices + i;

del_timer_sync(&dev->timer);
if (dev->gd) {
del_gendisk(dev->gd);
put_disk(dev->gd);
}
if (dev->queue) {
if (request_mode == RM_NOQUEUE)
blk_put_queue(dev->queue);
else
blk_cleanup_queue(dev->queue);
}
if (dev->data)
vfree(dev->data);
}
unregister_blkdev(sbull_major, "sbull");
kfree(Devices);
}

module_init(sbull_init);
module_exit(sbull_exit);

Dummy USB driver for Linux


/*
* USB Skeleton driver - 2.0
*
* Copyright (C) 2001-2004 Greg Kroah-Hartman (greg@kroah.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation, version 2.
*
* This driver is based on the 2.6.3 version of drivers/usb/usb-skeleton.c
* but has been rewritten to be easy to read and use, as no locks are now
* needed anymore.
*
*/

#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/kref.h>
#include <linux/smp_lock.h>
#include <linux/usb.h>
#include <asm/uaccess.h>


/* Define these values to match your devices */
#define USB_SKEL_VENDOR_ID 0xfff0
#define USB_SKEL_PRODUCT_ID 0xfff0

/* table of devices that work with this driver */
static struct usb_device_id skel_table [] = {
{ USB_DEVICE(USB_SKEL_VENDOR_ID, USB_SKEL_PRODUCT_ID) },
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE (usb, skel_table);


/* Get a minor range for your devices from the usb maintainer */
#define USB_SKEL_MINOR_BASE 192

/* Structure to hold all of our device specific stuff */
struct usb_skel {
struct usb_device * udev; /* the usb device for this device */
struct usb_interface * interface; /* the interface for this device */
unsigned char * bulk_in_buffer; /* the buffer to receive data */
size_t bulk_in_size; /* the size of the receive buffer */
__u8 bulk_in_endpointAddr; /* the address of the bulk in endpoint */
__u8 bulk_out_endpointAddr; /* the address of the bulk out endpoint */
struct kref kref;
};
#define to_skel_dev(d) container_of(d, struct usb_skel, kref)

static struct usb_driver skel_driver;

static void skel_delete(struct kref *kref)
{
struct usb_skel *dev = to_skel_dev(kref);

usb_put_dev(dev->udev);
kfree (dev->bulk_in_buffer);
kfree (dev);
}

static int skel_open(struct inode *inode, struct file *file)
{
struct usb_skel *dev;
struct usb_interface *interface;
int subminor;
int retval = 0;

subminor = iminor(inode);

interface = usb_find_interface(&skel_driver, subminor);
if (!interface) {
err ("%s - error, can't find device for minor %d",
__FUNCTION__, subminor);
retval = -ENODEV;
goto exit;
}

dev = usb_get_intfdata(interface);
if (!dev) {
retval = -ENODEV;
goto exit;
}

/* increment our usage count for the device */
kref_get(&dev->kref);

/* save our object in the file's private structure */
file->private_data = dev;

exit:
return retval;
}

static int skel_release(struct inode *inode, struct file *file)
{
struct usb_skel *dev;

dev = (struct usb_skel *)file->private_data;
if (dev == NULL)
return -ENODEV;

/* decrement the count on our device */
kref_put(&dev->kref, skel_delete);
return 0;
}

static ssize_t skel_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
{
struct usb_skel *dev;
int retval = 0;

dev = (struct usb_skel *)file->private_data;

/* do a blocking bulk read to get data from the device */
retval = usb_bulk_msg(dev->udev,
usb_rcvbulkpipe(dev->udev, dev->bulk_in_endpointAddr),
dev->bulk_in_buffer,
min(dev->bulk_in_size, count),
&count, HZ*10);

/* if the read was successful, copy the data to userspace */
if (!retval) {
if (copy_to_user(buffer, dev->bulk_in_buffer, count))
retval = -EFAULT;
else
retval = count;
}

return retval;
}

static void skel_write_bulk_callback(struct urb *urb, struct pt_regs *regs)
{
/* sync/async unlink faults aren't errors */
if (urb->status &&
!(urb->status == -ENOENT ||
urb->status == -ECONNRESET ||
urb->status == -ESHUTDOWN)) {
dbg("%s - nonzero write bulk status received: %d",
__FUNCTION__, urb->status);
}

/* free up our allocated buffer */
usb_buffer_free(urb->dev, urb->transfer_buffer_length,
urb->transfer_buffer, urb->transfer_dma);
}

static ssize_t skel_write(struct file *file, const char __user *user_buffer, size_t count, loff_t *ppos)
{
struct usb_skel *dev;
int retval = 0;
struct urb *urb = NULL;
char *buf = NULL;

dev = (struct usb_skel *)file->private_data;

/* verify that we actually have some data to write */
if (count == 0)
goto exit;

/* create a urb, and a buffer for it, and copy the data to the urb */
urb = usb_alloc_urb(0, GFP_KERNEL);
if (!urb) {
retval = -ENOMEM;
goto error;
}

buf = usb_buffer_alloc(dev->udev, count, GFP_KERNEL, &urb->transfer_dma);
if (!buf) {
retval = -ENOMEM;
goto error;
}
if (copy_from_user(buf, user_buffer, count)) {
retval = -EFAULT;
goto error;
}

/* initialize the urb properly */
usb_fill_bulk_urb(urb, dev->udev,
usb_sndbulkpipe(dev->udev, dev->bulk_out_endpointAddr),
buf, count, skel_write_bulk_callback, dev);
urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;

/* send the data out the bulk port */
retval = usb_submit_urb(urb, GFP_KERNEL);
if (retval) {
err("%s - failed submitting write urb, error %d", __FUNCTION__, retval);
goto error;
}

/* release our reference to this urb, the USB core will eventually free it entirely */
usb_free_urb(urb);

exit:
return count;

error:
usb_buffer_free(dev->udev, count, buf, urb->transfer_dma);
usb_free_urb(urb);
kfree(buf);
return retval;
}

static struct file_operations skel_fops = {
.owner = THIS_MODULE,
.read = skel_read,
.write = skel_write,
.open = skel_open,
.release = skel_release,
};

/*
* usb class driver info in order to get a minor number from the usb core,
* and to have the device registered with devfs and the driver core
*/
static struct usb_class_driver skel_class = {
.name = "usb/skel%d",
.fops = &skel_fops,
.mode = S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH,
.minor_base = USB_SKEL_MINOR_BASE,
};

static int skel_probe(struct usb_interface *interface, const struct usb_device_id *id)
{
struct usb_skel *dev = NULL;
struct usb_host_interface *iface_desc;
struct usb_endpoint_descriptor *endpoint;
size_t buffer_size;
int i;
int retval = -ENOMEM;

/* allocate memory for our device state and initialize it */
dev = kmalloc(sizeof(struct usb_skel), GFP_KERNEL);
if (dev == NULL) {
err("Out of memory");
goto error;
}
memset(dev, 0x00, sizeof (*dev));
kref_init(&dev->kref);

dev->udev = usb_get_dev(interface_to_usbdev(interface));
dev->interface = interface;

/* set up the endpoint information */
/* use only the first bulk-in and bulk-out endpoints */
iface_desc = interface->cur_altsetting;
for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
endpoint = &iface_desc->endpoint[i].desc;

if (!dev->bulk_in_endpointAddr &&
(endpoint->bEndpointAddress & USB_DIR_IN) &&
((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
== USB_ENDPOINT_XFER_BULK)) {
/* we found a bulk in endpoint */
buffer_size = endpoint->wMaxPacketSize;
dev->bulk_in_size = buffer_size;
dev->bulk_in_endpointAddr = endpoint->bEndpointAddress;
dev->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL);

if (!dev->bulk_in_buffer) {
err("Could not allocate bulk_in_buffer");
goto error;
}
}

if (!dev->bulk_out_endpointAddr &&
!(endpoint->bEndpointAddress & USB_DIR_IN) &&
((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
== USB_ENDPOINT_XFER_BULK)) {
/* we found a bulk out endpoint */
dev->bulk_out_endpointAddr = endpoint->bEndpointAddress;
}
}
if (!(dev->bulk_in_endpointAddr && dev->bulk_out_endpointAddr)) {
err("Could not find both bulk-in and bulk-out endpoints");
goto error;
}

/* save our data pointer in this interface device */
usb_set_intfdata(interface, dev);

/* we can register the device now, as it is ready */
retval = usb_register_dev(interface, &skel_class);
if (retval) {
/* something prevented us from registering this driver */
err("Not able to get a minor for this device.");
usb_set_intfdata(interface, NULL);
goto error;
}

/* let the user know what node this device is now attached to */
info("USB Skeleton device now attached to USBSkel-%d", interface->minor);
return 0;

error:
if (dev)
kref_put(&dev->kref, skel_delete);
return retval;
}

static void skel_disconnect(struct usb_interface *interface)
{
struct usb_skel *dev;
int minor = interface->minor;

/* prevent skel_open() from racing skel_disconnect() */
lock_kernel();

dev = usb_get_intfdata(interface);
usb_set_intfdata(interface, NULL);

/* give back our minor */
usb_deregister_dev(interface, &skel_class);

unlock_kernel();

/* decrement our usage count */
kref_put(&dev->kref, skel_delete);

info("USB Skeleton #%d now disconnected", minor);
}

static struct usb_driver skel_driver = {
.owner = THIS_MODULE,
.name = "skeleton",
.id_table = skel_table,
.probe = skel_probe,
.disconnect = skel_disconnect,
};

static int __init usb_skel_init(void)
{
int result;

/* register this driver with the USB subsystem */
result = usb_register(&skel_driver);
if (result)
err("usb_register failed. Error number %d", result);

return result;
}

static void __exit usb_skel_exit(void)
{
/* deregister this driver with the USB subsystem */
usb_deregister(&skel_driver);
}

module_init (usb_skel_init);
module_exit (usb_skel_exit);

MODULE_LICENSE("GPL");

Dummy PCI driver for Linux


#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/init.h>


static struct pci_device_id ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_3), },
{ 0, }
};
MODULE_DEVICE_TABLE(pci, ids);

static unsigned char skel_get_revision(struct pci_dev *dev)
{
u8 revision;

pci_read_config_byte(dev, PCI_REVISION_ID, &revision);
return revision;
}

static int probe(struct pci_dev *dev, const struct pci_device_id *id)
{
/* Do probing type stuff here.
* Like calling request_region();
*/
pci_enable_device(dev);

if (skel_get_revision(dev) == 0x42)
return -ENODEV;


return 0;
}

static void remove(struct pci_dev *dev)
{
/* clean up any allocated resources and stuff here.
* like call release_region();
*/
}

static struct pci_driver pci_driver = {
.name = "pci_skel",
.id_table = ids,
.probe = probe,
.remove = remove,
};

static int __init pci_skel_init(void)
{
return pci_register_driver(&pci_driver);
}

static void __exit pci_skel_exit(void)
{
pci_unregister_driver(&pci_driver);
}

MODULE_LICENSE("GPL");

module_init(pci_skel_init);
module_exit(pci_skel_exit);

星期六, 4月 19, 2008

Linux 2.6 驱动设计快速入门

引用自: http://dev.csdn.net/article/67/67489.shtm


Linux 2.6 和 2.4 的比较我不想废话,总体来说 2.6 功能更强,但是资源消耗更多。

由于 2.6 内核在驱动框架,底层调用上和 2.4 内核有很多差别,所以本文主要是为程序员提供 2.4 到 2.6 迁移的指导。

2.6 和 2.4 主要的不同在于

• 内核的 API 变化,增加了不少新功能(例如 mem pool )

• 提供 sysfs 用于描述设备树

• 驱动模块从 .o 变为 .ko

移植 hello word

下面是一个最简单的 2.4 驱动:

#define MODULE
#include <linux/module.h>
#include <linux/kernel.h>
int init_module(void)
{
printk(KERN_INFO "Hello, worldn");
return 0;
}
void cleanup_module(void)
{
printk(KERN_INFO "Goodbye cruel worldn");
}

2.6的hello world版本!

#include < linux/module.h>
#include < linux/config.h>
#include < linux/init.h>
MODULE_LICENSE("GPL");// 新,否则有 waring, 去掉了 #define MODULE, 自动定义
static int hello_init(void)
{
printk(KERN_ALERT "Hello, worldn");
return 0;
}
static void hello_exit(void)
{
printk(KERN_ALERT "Goodbye, cruel worldn");
}
module_init(hello_init);// 必须!!
module_exit(hello_exit); // 必须!!

注意,在 2.4 中 module_init 不是必须的,只要驱动的初始化函数以及析沟函数命名使用了缺省的 init_module 和 cleanup_module

编译生成:

2.4

gcc -D__KERNEL__ -DMODULE -I/usr/src/linux- 2.4.27 /include -O2 -c testmod.c

2.6

makefile 中要有 obj-m:= hello.o

然后:

make -C /usr/src/linux- 2.6.11 SUBDIRS=$PWD modules (当然简单的 make 也可以)

哈哈够简单!!

其他不同:

计数器:

以前 2.4 内核使用 MOD_INC_USE_COUNT 增加计数例如:

void

inc_mod(void)

{

MOD_INC_USE_COUNT;

} /* end inc_mod */

/************************************************************************

* Calculator DEC

************************************************************************/

void

dec_mod(void)

{

MOD_DEC_USE_COUNT;

} /* end dec_mod */

现在这个也过时了 !!

2.6 ,用户函数要加载模块,使用:

int try_module_get(&module);

函数卸载模块使用

module_put()

而驱动中不必显示定义 inc 和 dec

没有 kdev_t 了

现在都流行用 dev_t 了 , 而且是 32 位的

结构体初始化

老版本使用:

static struct some_structure = {

field1: value,

field2: value

};

现在流行用:

static struct some_structure = {

.field1 = value,

.field2 = value,

...

};

malloc.h

要用核态内存?用 <linux/slab.h> 好了,

内存池

内 存管理变化不大,添加了memory pool*(#include<linux/mempool.h> )。(现在什么都是pool,内存 线程 ....)这是为块设备提供的,使用mempool最大的优点是分配内存不会错,也不会等待(怎么这个也和RTEMS学)。对于embed的设备还是有些 用处的。标准调用方式:

mempool_t *mempool_create(int min_nr, mempool_alloc_t *alloc_fn, mempool_free_t *free_fn, void *pool_data);

使用mempool的函数 :

mempool_alloc_t / mempool_free_t

mempool_alloc_slab / mempool_free_slab

mempool_alloc / mempool_free

mempool_resize

结构体赋值

以前,驱动中结构体赋值使用:

static struct some_structure = {

field1: value,

field2: value

};

现在要用:

static struct some_structure = {

.field1 = value,

.field2 = value,

...

};

例如 :

static struct file_operations yourdev_file_ops = {

.open = yourdev_open,

.read = yourdev_read_file,

.write = yourdev_write_file,

};

min() , max()

不少程序员定义自己的 min 和 max 宏,大家也知道宏不安全, Linux 定义了 min 和 max 函数(注意不是模板函数,需要自己制定比较类型!)

原型变化

call_usermodehelper()

request_module()

函数原型变化了,用到的赶快查 !!!

Devfs

唉,还没怎么用,就过时了的技术,这就是 linux 。不是我们落伍,是世界变化快

字符设备

2.6 中主从设备编号不再局限于原来的 8bit

register_chrdev() 可以升级为:

int register_chrdev_region(dev_t from, // 设备号 unsigned count, // 注册号 char *name); // 名称

该函数的动态版本(不知道主设备号时使用)

int alloc_chrdev_region(dev_t *dev, unsigned baseminor,

unsigned count, char *name);

新的 file_operations

register_chrdev_region 没有使用 register_chrdev_region 参数,因为设备现在使用 struct cdev 来定义他在 <linux/cdev.h> 中定义。

struct cdev {

struct kobject kobj;

struct module *owner;

struct file_operations *ops;

struct list_head list;

dev_t dev;

unsigned int count;

};

使用时首先需要分配空间: struct cdev *cdev_alloc(void);

然后对其初始化:

void cdev_init(struct cdev *cdev, struct file_operations *fops);

cdev 使用 kobject_set_name 设置名称:例如:

struct cdev *my_cdev = cdev_alloc(); kobject_set_name(&cdev->kobj, "my_cdev%d", devnum);

此后就可以使用 int cdev_add(struct cdev *cdev, dev_t dev, unsigned count); 将 cdev 加入到系统中。

删除 cdev 使用

void cdev_del(struct cdev *cdev);

对 于没有使用 cdev_add 添加的 cdev 使用 kobject_put(&cdev->kobj); 删除 也就是使用: struct kobject *cdev_get(struct cdev *cdev); void cdev_put(struct cdev *cdev);

太极链;

struct inode -> i_cdev -> cdev

这样就从 inode 链接到 cdev

驱动体系:

/dev 到 /sys

/dev 也过时了,设备文件都跑到 /sys 里了!

# cd /sys

# ls

block bus class devices firmware


星期五, 4月 18, 2008

Build Kernel Module as KO files


Show build progress in verbose

make V=1

lib path for glibc

/opt/microtime/pro/devkit/arm/pxa270/gcc-4.0.2-glibc-2.3.3/arm-unknown-linux-gnu/arm-unknown-linux-gnu/lib

bin path of gcc

/opt/microtime/pro/devkit/arm/pxa270/gcc-4.0.2-glibc-2.3.3/arm-unknown-linux-gnu/bin

header file path of Linux Kernel

/usr/src/creator/pxa270/linux/include

obj-y

cmd_drivers/char/creator-pxa270-lcd.o := arm-unknown-linux-gnu-gcc -Wp,-MD,drivers/char/.creator-pxa270-lcd.o.d -nostdinc -isystem /opt/microtime/pro/devkit/arm/pxa270/gcc-4.0.2-glibc-2.3.3/arm-unknown-linux-gnu/bin/../lib/gcc/arm-unknown-linux-gnu/4.0.2/include -D__KERNEL__ -Iinclude -include include/linux/autoconf.h -mlittle-endian -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs -fno-strict-aliasing -fno-common -ffreestanding -fno-inline -Os -fno-omit-frame-pointer -fno-optimize-sibling-calls -g -fno-omit-frame-pointer -mapcs -mno-sched-prolog -mabi=apcs-gnu -mno-thumb-interwork -D__LINUX_ARM_ARCH__=5 -march=armv5te -mtune=xscale -Wa,-mcpu=xscale -msoft-float -Uarm -Wdeclaration-after-statement -Wno-pointer-sign -DKBUILD_BASENAME=creator_pxa270_lcd -DKBUILD_MODNAME=creator_pxa270_lcd -c -o drivers/char/creator-pxa270-lcd.o drivers/char/creator-pxa270-lcd.c

obj-m

step1:
cmd_drivers/char/creator-pxa270-lcd.o := arm-unknown-linux-gnu-gcc -Wp,-MD,drivers/char/.creator-pxa270-lcd.o.d -nostdinc -isystem /opt/microtime/pro/devkit/arm/pxa270/gcc-4.0.2-glibc-2.3.3/arm-unknown-linux-gnu/bin/../lib/gcc/arm-unknown-linux-gnu/4.0.2/include -D__KERNEL__ -Iinclude -include include/linux/autoconf.h -mlittle-endian -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs -fno-strict-aliasing -fno-common -ffreestanding -fno-inline -Os -fno-omit-frame-pointer -fno-optimize-sibling-calls -g -fno-omit-frame-pointer -mapcs -mno-sched-prolog -mabi=apcs-gnu -mno-thumb-interwork -D__LINUX_ARM_ARCH__=5 -march=armv5te -mtune=xscale -Wa,-mcpu=xscale -msoft-float -Uarm -Wdeclaration-after-statement -Wno-pointer-sign -DMODULE -DKBUILD_BASENAME=creator_pxa270_lcd -DKBUILD_MODNAME=creator_pxa270_lcd -c -o drivers/char/creator-pxa270-lcd.o drivers/char/creator-pxa270-lcd.c

step2:
scripts/mod/modpost -o /usr/src/creator/pxa270/pro/devkit/lsp/create-pxa270/linux-2.6.15.3/Module.symvers vmlinux drivers/char/creator-pxa270-lcd.o

step3:
arm-unknown-linux-gnu-gcc -Wp,-MD,drivers/char/.creator-pxa270-lcd.mod.o.d -nostdinc -isystem /opt/microtime/pro/devkit/arm/pxa270/gcc-4.0.2-glibc-2.3.3/arm-unknown-linux-gnu/bin/../lib/gcc/arm-unknown-linux-gnu/4.0.2/include -D__KERNEL__ -Iinclude -include include/linux/autoconf.h -mlittle-endian -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs -fno-strict-aliasing -fno-common -ffreestanding -fno-inline -Os -fno-omit-frame-pointer -fno-optimize-sibling-calls -g -fno-omit-frame-pointer -mapcs -mno-sched-prolog -mabi=apcs-gnu -mno-thumb-interwork -D__LINUX_ARM_ARCH__=5 -march=armv5te -mtune=xscale -Wa,-mcpu=xscale -msoft-float -Uarm -Wdeclaration-after-statement -Wno-pointer-sign -DKBUILD_BASENAME=creator_pxa270_lcd -DKBUILD_MODNAME=creator_pxa270_lcd -DMODULE -c -o drivers/char/creator-pxa270-lcd.mod.o drivers/char/creator-pxa270-lcd.mod.c

step4:
arm-unknown-linux-gnu-ld -EL -r -o drivers/char/creator-pxa270-lcd.ko drivers/char/creator-pxa270-lcd.o drivers/char/creator-pxa270-lcd.mod.o



星期六, 4月 12, 2008

arm linux 启动流程之 解压内核

引用自: http://blog.csdn.net/dansen_xu/archive/2007/08/13/1740738.aspx

Author-------Dansen-----xzd2734@163.com

从后往前看下编译生成zImage的过程,我们可以找到程序的入口还是那个很重要
链接文件,找到它,生成zImage所在的目录是kernelarcharmbootcompressed
Make过程为....ld -p -X -T vmlinux.lds head.o misc.o head-s3c2410.o piggy.o
libgcc.o -o vmlinux
然后是用二进制工具objcopy把vmlinux制作成可执行的二进制映像文件zImage
这样在我们就去kernelarcharmbootcompressed目录下去找到vmlinux.lds文件
如果没有编译就不会有这个文件,因为它也是在编译过程生成的,由同一目录下的
vmlinux.lds.in生成,打开这个文件
ENTRY(_start)
SECTIONS
{
. = LOAD_ADDR;
_load_addr = .;

. = TEXT_START;
_text = .;

.text : {
_start = .;
*(.start)
*(.text)
........
入口是_start,而且入口就直接定义在这个文件中了
入口直接接着.start段,所以程序开始是从.start段开始执行的
如果看看vmlinux.lds的生成过程就应该能找到LOAD_ADDR和TEXT_START的值
实际上这两个值是由其他两个变量赋给的 ZRELADDR 和 ZTEXTADDR
在kernelarcharmbootMakefile中我们可以找到这两个变量的值
ifeq ($(CONFIG_ARCH_S3C2410),y)
ZTEXTADDR = 0x30008000
ZRELADDR = 0x30008000
endif
所以
LOAD_ADDR = 0x30008000
TEXT_START = 0x30008000
看一下vmlinux.lds吧
ENTRY(_start)
SECTIONS
{
. = 0x30008000;
_load_addr = .;

. = 0;
_text = .;
显然LOAD_ADDR被赋值了0x30008000
看一下TEXT_START怎么成0了,我想这应该是一个偏移吧,偏移是0
所以它还是0x30008000
接着下来就从head.s来开始看代码吧
.section ".start", #alloc, #execinstr
/*
* sort out different calling conventions
*/
.align
start:
.type start,#function
.rept 8
mov r0, r0
.endr

b 1f
.word 0x016f2818 @ Magic numbers to help the loader
.word start @ absolute load/run zImage address
.word _edata @ zImage end address
1: mov r7, r1 @ save architecture ID
这里一定就是程序的入口了,一般汇编程序的含义就看看英文注释就是了
有一个要注意的地方,不是一个汇编文件就是属于一个段的,不是说先执行完了
head.s再去执行head-s3c2410.s,还是要注意链接的段,显然head.s
不一会就开始了另一个段.text
.text
adr r0, LC0
ldmia r0, {r1, r2, r3, r4, r5, r6, ip, sp}
subs r0, r0, r1 @ calculate the delta offset
而我们的head-s3c2410.s呢
.section ".start", #alloc, #execinstr
__S3C2410_start:
bic r2, pc, #0x1f
add r3, r2, #0x4000 @ 16 kb is quite enough...
还是属于.start段的,所以顺序执行下来时先执行head-s3c2410.s,然后再去执行
.text段。head-s3c2410.s主要是cpu的一些初始化工作。接着下来我们会需要把内核
接压缩,先说说为什么吧。还是注意到上面生成zImage的文件中有一个piggy.o,往上
追寻可以看到是piggy.o由那个真正的内核vmlinux生成的,这个vmlinux才是启动后一直在
运行的内核,原本很大,压缩以后可以方便地放在flash中,当然其实不压缩跳到它的
入口也就可以运行了。解压的内核是准备从LOAD_ADDR = 0x30008000开始的4M空间,会覆盖
我们的当前运行的代码,那样就先把内核解压到我们这个zImage+分配堆栈0x10000的最后
cmp r4, r2 //r4 是LOAD_ADDR=0x30008000
bhs wont_overwrite //r2 是当前代码的最底部 这里当然不会跳转
add r0, r4, #4096*1024 @ 4MB largest kernel size
cmp r0, r5 //r5 也是0x30008000
bls wont_overwrite //不会跳转

mov r5, r2 //r2是(user_stack+4096)在zImage的最后+0x10000
mov r0, r5
mov r3, r7 //machine type
bl decompress_kernel
有了r5,r0,r7作为参数,就可以调用misc.c中的decompress_kernel函数进行解压缩了
这个函数调用的gunzip函数时gcc的库函数,所以在源码中找不到的
解压在r5开始的地方,函数返回的是r0解压得到的长度。这时候我们需要对代码经行调整
add r1, r5, r0 @ end of decompressed kernel
adr r2, reloc_start
ldr r3, LC1 //LC1: .word reloc_end - reloc_start
add r3, r2, r3
1: ldmia r2!, {r8 - r13} @ copy relocation code
stmia r1!, {r8 - r13}
ldmia r2!, {r8 - r13}
stmia r1!, {r8 - r13}
cmp r2, r3 //这里就把从reloc_start到reloc_end这段我们需要的代码放到了
blo 1b //解压内核的最后,而在下面我们会将zImage都覆盖掉
bl cache_clean_flush
add pc, r5, r0 //调到调整后的reloc_start,在decompressed kernel后
reloc_start: add r8, r5, r0 //r5解压内核开始的地方 r0解压内核的长度
debug_reloc_start
mov r1, r4 //r4=0x30008000
1:
.rept 4
ldmia r5!, {r0, r2, r3, r9 - r13} @ relocate kernel
stmia r1!, {r0, r2, r3, r9 - r13}
.endr

cmp r5, r8

blo 1b //这样就又把解压的真正内核移到了0x30008000处

call_kernel: bl cache_clean_flush

bl cache_off

mov r0, #0

mov r1, r7 @ restore architecture number

mov pc, r4 @ call kernel

上面就是跳到0x30008000这里去执行真正的内核了吧


星期六, 3月 29, 2008

Linux 下透過 GPRS 上網


引用自: http://blog.linym.net/archives/171

基本需求:

  • 可連上 GPRS 的硬體設備
  • 編譯 Kernel 使其支援 PPP
  • 擁有 pppd、chat 兩個程式
  • PPP 連線的 script 檔案

1. 可連上 GPRS 的硬體設備
可以是專用的 GPRS Modem 或是手機,不過當然要先配置好相關設定及驅動,我是使用 Wavecom Q2403A 這個 GSM/GPRS 模組透過 com port 來實驗。

2. 編譯 Kernel 使其支援 PPP
# make menuconfig
選擇 Device Drivers —> Network device support —> PPP (point-to-point protocol) support,底下的子項目如果不確定就全選即可。
核心更新後請檢查 /dev/ppp 是否存在,若無可用 mknod /dev/ppp c 108 0 建立。

3. 擁有 pppd、chat 兩個程式
如果是一般 PC 版本應該都已經有內建了;Embedded 平台則可以考慮使用 busybox,裡面也有包含這兩個程式;再不然就自行下載 source code 來編譯。

4. PPP 連線的 script 檔案
建立 script 來做 PPP 連線,通常可以在 /usr/share/doc/ppp/examples/scripts 底下找到 ppp-on、ppp-off、ppp-on-dialer 三個範例檔案,不過用範例檔的設定不一定能成功,請參考我的檔案,已測試中華電信可以成功。

相關的設定及原理可以參考:



移植KVM到arm-linux


引用自: http://tech.jayya.com/2007/11/28/porting-kvm-to-armlinux.html

上午kvm能正常在板子上运行了,并且还解决了preverify的问题(感谢一下陶老师的帮助和提醒),今天一并完整的写出来整个过程吧

  1. 建立交叉编译环境:
    • 下载xscale-arm-linux-toolchain.tgz,tar zxfv xscale-arm-linux-toolchain.tgz,将解压后的文件在/usr/local/arm-linux下,将他击入当前的路径下, 比如修改你的.bash_profile,PATH=$PATH:/usr/local/arm-linux/bin,退出,在登陆使之生效,输入arm -linux-gcc -v可以查看gcc的版本;
    • 很抱歉,写得时候漏写了一个重要的设置步骤,多谢雨里来的提醒,现补充如下:我们还需要安装交叉编译环境的标准C函数库,进入系统的/usr/目录并解压库函数软件包
      [user@host]# cd /usr
      [user@host]# tar zvxf /root/gnupro-bin-glibc2.2.4.tgz
      上述命令会在系统目录/usr/cygnus/xscale-020726/H-i686-pc-linux-gnulibc2.4/目录下建立一系列的子目录和文件,它们是交叉编译时需要的标准C函数库和各种工具。
  2. 下载sun的cldc的src
  3. 解压,里面包含有相关的源码。我这里使用了j2me_cldc-1_0_4-src-winunix.zip,j2me_cldc-1_1-fcs -src-winunix.zip这两个都可以在sun的网站下载,不过推荐大家抓紧时间下载,因为今天去下载midp2.0就已经不能下载了(sun 阿,令人失望!)。

  4. 安装jdk并设置后相关路径
  5. 这里不推荐使用jdk1.5,因为他对中文的支持有问题,使用1.4或者更低的都可以(希望可以在sun的官方找到)
    我使用的是1.4.2_01。修改.bash_profile或者/etc/profile添加PATH或者CLASSPATH。这里说一些为什么要用到 jdk,主要是要编译api里面的java文件,当然我们只一致kvm就不需要这个了,详细地大家可以看看解开的文件cldc文件夹里面的make文件

  6. 修改make文件
  7. 进入j2me_cldc/kvm/VmUnix/build/,vi修改Makefile,主要修改将原来使用的x86的编译器GCC改为我们的 arm-linux-gcc,这样才能得到我们的所需,我主要是修改下面的句子:ifeq ($(GCC), true) CC =arm-linux-gcc,另外我又在文件的开始指定export PLATFORM=linux,当然你也可以在make的时候加参数PLATFORM=linux。

  8. 编译
  9. 先编译preverify,进入tools/preverfiyer/build/linux下,make,这里没有必要对这个makefile进 行修改,况且你的编译平台是x86,应该不能进行修改,否则编译出来的preverify是不运行的,那么kvm的编译也将会不能通过。
    编译kvm,进入kvm/VmUnix/build,make,就可以得到kvm,注意这个是在kvm的build目录下生成的,file kvm会的到以下信息:kvm: ELF 32-bit LSB executable, ARM, version 1 (ARM), for GNU/Linux 2.4.18, dynamically linked (uses shared libs), not stripped

  10. 在板子上运行并进行相应的测试
  11. 将得到的kvm,烧到板子上,x86下kvm运行所需文件: libm.so.6 => /lib/tls/libm.so.6 (0xb75c0000)
    libnsl.so.1 => /lib/libnsl.so.1 (0xb75ab000)
    libc.so.6 => /lib/tls/libc.so.6 (0xb7473000)
    /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0xb75eb000)
    大家可以参考以下,以便能使板子环境符合要求.更改属性为a+x,运行kvm,没有任何参数的情况下将会出现以下信息:ALERT: Must provide class name
    Usage: kvm < -options>
    Options:
    -version
    -classpath
    -heapsize (e.g. 65536 or 128k or 1M)

  12. 运行helloworld并正确使用preverify
  13. 这一步准确来说不是移植要做的事情,因为这是j2me开发者要注意的事情.我们先来看看kvm的执行.class 文件的机制:
    portingVerifiera.gif
    如图示:我们javac编译完的生成的.class文件必须经过preverify预验证后才能被kvm正确的执行,否则会出现 java/class/Verifyerror,为什么要采用预验证机制,是因为sun考虑到嵌入式设备资源有限,所以将jvm的庞大字节码验证机制进行 严重的”缩水”,也就用了一个轻量级机制
    来保证安全.说了这么多,讲讲具体怎么使用(这个流程开发j2me程序的人应该都知道点,虽然大家都不常用这个来开发).
    1编译javac -classpath kvm/classes hello.java 这里kvm/classes指你编译生成的classes文件夹
    2预验证preverify -classpath kvm/classes -d . mydir
    preverify有几个参数: -classpath 同上 -d 输出验证后的class文件,默认的是当前目录下的output文件夹下,还有检测是否使用了 finalizers ,float,native methods等
    将检验后的classs文件放到板子上,就可以执行了!


CLDC 1.0.4 Fix for Red_Hat

引用自: http://forum.java.sun.com/thread.jspa?threadID=468349


The following works for J2ME CLDC 1.1 (it may be the same for 1.0.4, I didn't try that).

If you don't care to verify that you are having the same problem, skip ahead a bit to what I did to fix the problem I was having.

Rebuild the kvm with debugging on. Goto the j2me_cldc/build/linux directory
edit Makefile around the 4th line add a line that says "export DEBUG=true"
If you have previously run make then do "make clean" then "make"

Im assuming your PATH and CLASSPATH are set appropriately so you can simply prevreify a class by typing "preverify HelloWorld" and you see "Segmentation fault"

At this point run "preverify -verbose HelloWorld" and you will see that it is indeed running and loading classes but it craps out after a few classes.

To run the debugger on this type "gdb --args preverify HelloWorld"
at the (gdb) prompt type "run". You will see
"Program received signal SIGSEGV, Segmentation fault."
Type bt (or backtrace) in the debuger. If you see something like this

#0 0x4207c1ac in memcpy () from /lib/tls/libc.so.6
#1 0x080520ef in utf2native ()
#2 0x0805b9ab in Locked_InitializeClass ()
...

then you either didn't get the "export DEBUG=true" part right or your didn't "make clean" or something else happened. You should see something more like this (more detail):

#0 0x4207c1ac in memcpy () from /lib/tls/libc.so.6
#1 0x080520ef in utf2native (from=0x8069740 "?_006b", to=0xbfff6ba0 "",
buflen=-1073779800) at ../../src/convert_md.c:100
#2 0x0805b9ab in Locked_InitializeClass (cb=0x8069740, detail=0xbfff6ba0)
at ../../src/classresolver.c:685
#3 0x0805b57a in InitializeClass (cb=0x8069740, detail=0xbfff6ba0)
at ../../src/classresolver.c:506
#4 0x0805c2af in InitializeAndResolveClass (cb=0x8069740, resolve=FALSE)
at ../../src/classresolver.c:991
...

what this is telling you is that the glibc memcpy function is where the segfault happened. memcpy is trying to copy memory but it looks like the buffer length (buflen) is bogus. memcpy is called from utf2native which is called by Locked_InitializerClass in classresolver.c

Quit the debugger (“quit”). Goto j2me_cldc/tools/preverifier/src/

Look at the file classresolver.c, at the Locked_InitializerClass function, around line 572. See the lines

char buff[BUFSIZ];
char *nativeName = &buff[0];

remember them. Look down to line 685, see the lines

utf2native(cbSuperName(cb), nativeName, BUFSIZ);
super = FindClassFromClass(ee, nativeName, FALSE, cb);

Nowehere else in classresolver.c is this buff or *nativeName used (so Im assuming we are free to mess with without significantly impacting anything else). What this is doing is creating a buffer on the stack that is BUFSIZ big (8192 bytes). utf2native gets the buffer and size and calls memcpy. Im guessing that because the preverifier seems to be loading classes recursively that there are lots of buffers like this on the stack hanging around and Im running out of stack space which results in a segmentation fault. I don’t know why EVERYONE running linux doesn’t have this problem.

How to fix this? We are now going to change the program to put the buffer in dynamic memory not on the stack.

In classresolver.c, around line 572, change the buff and nativeName declarations to this (comment out the old ones, put in new ones):

//char buff[BUFSIZ];
//char *nativeName = &buff[0];
char *buff;
char *nativeName;

The skip down to around line 685. Add a few lines around the call to utf2native to look like this:

buff = (char*)malloc(BUFSIZ);
if (buff == NULL)
fprintf( stderr, "Bogus, malloc failed." );
nativeName = buff;

utf2native(cbSuperName(cb), nativeName, BUFSIZ);
super = FindClassFromClass(ee, nativeName, FALSE, cb);

free(buff);

We added 4 lines before the utf2native call and the free(buff) after it. What we are doing is allocating dynamic memory for the buffer (not on the stack this time) and freeing it right after we are done with it.

Save your work. Now "make clean" and "make". When you try to run the preverifier, turn on -verbose. You will get the preverifier to run a little further but it may still die with a segmentation fault, this time in a different place, same problem. I found four c files that declare and use buff[BUFSIZ] (classloader.c, classresolver.c, file.c and jar_support.c). I also found that if you have your CLASSPATH is set to point to the j2me_cldc/api/classes directory or j2me_cldc/api/classes.zip file you will get the same error but different calling functions. My CLASSPATH originally pointed to the classes directory and the classloader.c and classresolver.c were crapping out. I switched to having the CLASSPATH point to the classes.zip file and then the jar_support.c functions were the problem. I fixed all 4 just to be sure. Im not guaranteeing this will solve your problem. But it solved mine.

Dan

星期二, 2月 12, 2008

ArmLinux 課程大綱 (PXA-270)


*新華電腦開課資訊: http://www.microtime.com.tw/training/ARM/9504/9604.htm



Linux 操作與系統建置篇(9:00~16:00;6 小時)
1. Linux 簡介

A. Linux 基本操作 (含實機操作)

2. Embedded Linux 系統架構
3. Embedded Linux
核心組態
4
. Embedded Linux 檔案系統規劃
A. Virtual PC
下建置 Embedded Linux(含實機操作)
B.
透過 Domingo debugger開發環境下載 Embedded Linux (含實機操作)

C. NFS (含實機操作)

D. MTD (含實機操作)

5. Linux 應用程式環境

A. Java Virtual Machine in Linux (含實機操作)

B. pppd (含實機操作)


Linux 程式開發篇(9:00~16:00;6小時)

1. Embedded Linux 開發環境

A. Kbuild System for Kernel

B. Auto Make System for Application

2. Embedded Linux 核心原始碼架構

3. Embedded Linux 核心初始化分析

A. 以 ICE 除錯核心(含實機操作)

4. Linux 應用程式設計

A. Memory Management (含實機操作)

B. File access (含實機操作)

B. Process (含實機操作)

C. Thread (含實機操作)

D. IPC (含實機操作)

5. 應用程式共享程式庫
A. 以MP3 Decoder程式庫為例 (含實機操作)
6. Linux 應用程式除錯工具

A. 以 GDB 除錯應用程式(含實機操作)
B. 記憶體配置除錯(memwatch/YAMD) ( 含實機操作)
C. 系統呼叫追蹤 (strace) (含實機操作)


基本驅動程式開發篇(9:00~16:00;6小時)
1. Linux
核心模組架構
A
. 建置與設定核心模組 (含實機操作)
2 Linux
驅動程式架構
A
. 建置與設定驅動程式( 含實機操作)
3. Linux 驅動程式除錯工具
A. 列印訊息法(printk) (含實機操作)
B. 訊息紀錄 (Klogd/syslogd) ( 含實機操作)
C
. 查詢除錯法(proc) ( 含實機操作)
4. Linux 字元類型驅動程式
A. 以LED & DIP Switch & Key 為例( 含實機操作)

B. Interrupt

C. Task Queue

D. Memory management


進階驅動程式開發篇(9:00~ 16:00;6小時)
1. LCD 驅動程式
A.
以LCD控制IC為例(含實機操作)

B. Frame Buffer 架構

2. Audio Driver 架構
3. 串列埠控制
A.
以Termios UART 控制為例
(含實機操作)

B. 控制台架構 (Console Architecture)

4. USB 驅動程式架構
5. PCI 驅動程式架構

6. Linux 區塊類型驅動程式
A. 以RAM Disk為例 (含實機操作)


網路應用開發篇(9:00~ 16:00;6小時)
1. Linux
網路類型驅動程式
2.
網路應用程式設計
A.
以聊天程式為例(含實機操作)
3.
利用 Embedded Linux 設置網路服務
A. Telnetd建置 (含實機操作)
B. Web Server 建置( 含實機操作)
4. CGI
程式設計
A.
以CGI 程式控制LED(含實機操作)

星期六, 1月 05, 2008

有趣的主題

Linux Package

Packman: http://packman.links2linux.org/ : 此網站存放 Suse Linux 軟體套件,讓使用者能很輕易地安裝與移除軟體。
LinuxToy: http://linuxtoy.org/

Ericsk 的 Ubuntu 筆記: http://blog.xuite.net/ericsk0313/ubuntu

Ericsk 的個人網站: http://blog.ericsk.org/

阿駕零零壹 © 學習筆記: http://twntwn.info/blog/ajer001

Linux 的粉絲衝上浪頭 2.0: http://blog.ilc.edu.tw/blog/blog/673/

Device Driver

The GNU/Linux "usbnet" Driver Framework: http://www.linux-usb.org/usbnet/

JVM

Java Midlets Tutorial (PocketPC): http://www.pocketpcmag.com/blogs/index.php?blog=3&p=644&more=1&c=1&tb=1&pb=1
JVMs, JDKs and JREs: http://java-virtual-machine.net/other.html

Network

Boa + PHP for uClinux: http://www.menie.org/georges/uClinux/boa-php.html

PHP for IIS: http://blog.raienet.com/188?TSSESSION=5d9fb85e5c0162885e12924128ef1838


Web Page Editor

AceHTML: http://software.visicommedia.com/en/products/acehtmlfreeware/
HomeSite: http://www.adobe.com/products/homesite/
NotePad++: http://notepad-plus.sourceforge.net/tw/site.htm
EditPlus: http://www.editplus.com/
Crimson: http://www.crimsoneditor.com/

Forum

大鳥的實驗室: http://www.armlabs.com/phpBB2/viewforum.php?f=7