手把手教你在友善之臂tiny4412上用uboot启动Linux内核

来源:互联网 发布:垃圾处理器 知乎 编辑:程序博客网 时间:2024/05/21 21:35

要想用uboot启动内核,我推荐一种方法,用dnw下载内核到开发板上,然后用uboot命令启动:

首先我在网上随便下了一个dnw工具,经过移植修改后,代码如下:

/*YYX--->for tiny4412 dnwversion:20170423 v1*/#include <stdio.h>#include <stdlib.h>#include <string.h>#include <malloc.h>#include <errno.h>#include <sys/types.h>#include <sys/stat.h>#include <sys/time.h>#include <unistd.h>#include <fcntl.h>#include <stdint.h>const char* dev = "/dev/secbulk0";#define BLOCK_SIZE(1*1024*1024)struct download_buffer {uint32_tload_addr;  /* load address */uint32_tsize; /* data size */uint8_tdata[0];/* uint16_t checksum; */};static int _download_buffer(struct download_buffer *buf){int fd_dev = open(dev, O_WRONLY);if( -1 == fd_dev) {printf("Can not open %s: %s\n", dev, strerror(errno));return -1;}printf("Writing data...\n");size_t remain_size = buf->size;size_t block_size = BLOCK_SIZE;size_t writed = 0;while(remain_size>0) {size_t to_write = remain_size > block_size ? block_size : remain_size;if( to_write != write(fd_dev, (unsigned char*)buf + writed, to_write)) {perror("write failed");close(fd_dev);return -1;}remain_size -= to_write;writed += to_write;printf("\r%02zu%%\t0x%08zX bytes (%zu K)",(size_t)((uint64_t)writed*100/(buf->size)),writed,writed/1024);fflush(stdout);}printf("\n");close(fd_dev);return 0;}static inline void cal_and_set_checksum(struct download_buffer *buf){uint16_t sum = 0;int i;for(i = 0; i < buf->size; i++) {sum += buf->data[i];}*((uint16_t*)(&((uint8_t*)buf)[buf->size - 2])) = sum;}static struct download_buffer* alloc_buffer(size_t data_size){struct download_buffer*buffer = NULL;size_t total_size = data_size + sizeof(struct download_buffer) + 2;buffer = (typeof(buffer))malloc(total_size);if(NULL == buffer)return NULL;buffer->size = total_size;return buffer;}static void free_buffer(struct download_buffer *buf){free(buf);}static struct download_buffer *load_file(const char *path, unsigned long load_addr){struct statfile_stat;struct download_buffer*buffer = NULL;unsigned longtotal_size;intfd;fd = open(path, O_RDONLY);if(-1 == fd) {printf("Can not open file %s: %s\n", path, strerror(errno));return NULL;}if( -1 == fstat(fd, &file_stat) ) {perror("Get file size filed!\n");goto error;}buffer = alloc_buffer(file_stat.st_size);if(NULL == buffer) {perror("malloc failed!\n");goto error;}if( file_stat.st_size !=  read(fd, buffer->data, file_stat.st_size)) {perror("Read file failed!\n");goto error;}buffer->load_addr = load_addr;cal_and_set_checksum(buffer);return buffer;error:if(fd != -1)close(fd);if( NULL != buffer )free(buffer);return NULL;}static int download_file(const char *path, unsigned long load_addr){struct download_buffer *buffer;struct timeval __start, __end;long __time_val = 0;float speed = 0.0;buffer = load_file(path, load_addr);gettimeofday(&__start,NULL);if (buffer != NULL) {if (_download_buffer(buffer) == 0) {gettimeofday(&__end,NULL);__time_val = (long)(__end.tv_usec - __start.tv_usec)/1000 + \(long)(__end.tv_sec - __start.tv_sec) * 1000;speed = (float)buffer->size/__time_val/(1024*1024) * 1000;printf("speed: %fM/S\n",speed);free_buffer(buffer);} else {free_buffer(buffer);return -1;}} elsereturn -1;}int main(int argc, char* argv[]){unsigned load_addr = 0x57e00000;char* path = NULL;intc;while ((c = getopt (argc, argv, "a:h")) != EOF)switch (c) {case 'a':load_addr = strtol(optarg, NULL, 16);continue;case '?':case 'h':default:usage:printf("Usage: dwn [-a load_addr] <filename>\n");printf("Default load address: 0x57e00000\n");return 1;}if (optind < argc)path = argv[optind];elsegoto usage;printf("load address: 0x%08X\n", load_addr);if (download_file(path, load_addr) != 0) {return -1;}return 0;}
然后我们还要写一个Makefile,用来编译dnw这个工具:

如下:

dnw : dnw.c        gcc -g -o $@ $^        clean :        rm -rf dnw *.oinstall : dnw        cp $^ /usr/bin

然后make , 编译成功


在当前目录下可以看到生成了dnw这个二进制文件。

接下来,我们还需要一个驱动secbulk,于是再去网上下载:

源码如下:

在源码中,我们看到:{ USB_DEVICE(0x04e8, 0x1234) }, /* EZTIN4412 */

这一行是我自己添加的,该驱动要知道4412开发板USB的设备ID还有厂商ID,这个信息可以通过lsusb来获得,如下:

查看方法如下:

(1)先在minicom中敲一下dnw,会弹出这个界面等待PC文件传输过来。


(2)然后回到PC端,敲lsusb命令,如图:


从上图,我们看到Samsung Electiornics Co. , Ltd , 所以得知开发板的ID是04e8:1234

所以以下代码就要添加这么一个ID:{ USB_DEVICE(0x04e8, 0x1234) }, /* EZTIN4412 */

#include <linux/kernel.h>#include <linux/module.h>#include <linux/usb.h>#include <linux/fs.h>#include <linux/mutex.h>#include <linux/slab.h>#include <linux/uaccess.h>#define SECBULK_MAJOR102#define SECBULK_MINOR0#define DRIVER_NAME"secbulk"#define BULKOUT_BUFFER_SIZE(4*1024)struct secbulk_dev{struct usb_device *udev;struct mutex io_mutex;char*bulkout_buffer;__u8bulk_out_endpointAddr;};static struct usb_class_driver secbulk_class;static struct usb_device_id secbulk_table[]= {{ USB_DEVICE(0x5345, 0x1234) }, /* FS2410 */{ USB_DEVICE(0x04e8, 0x1234) }, /* TINY4412 */{ }};static struct usb_driver secbulk_driver;static void secbulk_disconnect(struct usb_interface *interface){struct secbulk_dev *dev = NULL;printk(KERN_INFO "secbulk:secbulk disconnected!\n");dev = usb_get_intfdata(interface);if( NULL != dev )kfree(dev);usb_deregister_dev(interface, &secbulk_class);return;}static ssize_t secbulk_read(struct file *file, char __user *buf, size_t len,loff_t *loff){return -EPERM;}static ssize_t secbulk_write(struct file *file, const char __user *buf,size_t len, loff_t *loff){size_t to_write;struct secbulk_dev *dev = file->private_data;int ret;int actual_length;size_t total_writed;total_writed = 0;while(len > 0) {to_write = min(len, BULKOUT_BUFFER_SIZE);if(copy_from_user(dev->bulkout_buffer, buf+total_writed,to_write)) {printk(KERN_ERR "secbulk:copy_from_user failed!\n");return -EFAULT;}ret = usb_bulk_msg(dev->udev,usb_sndbulkpipe(dev->udev, dev->bulk_out_endpointAddr),dev->bulkout_buffer,to_write,&actual_length,3*HZ);if(ret || actual_length!=to_write) {printk(KERN_ERR "secbulk:usb_bulk_msg failed!\n");return -EFAULT;}len -= to_write;total_writed += to_write;}return total_writed;}static int secbulk_open(struct inode *node, struct file *file){struct usb_interface *interface;struct secbulk_dev *dev;interface = usb_find_interface(&secbulk_driver, iminor(node));if(!interface)return -ENODEV;dev = usb_get_intfdata(interface);dev->bulkout_buffer = kzalloc(BULKOUT_BUFFER_SIZE, GFP_KERNEL);if(!(dev->bulkout_buffer))return -ENOMEM;if(!mutex_trylock(&dev->io_mutex))return -EBUSY;file->private_data = dev;return 0;}static int secbulk_release(struct inode *node, struct file *file){struct secbulk_dev *dev;dev = (struct secbulk_dev*)(file->private_data);kfree(dev->bulkout_buffer);mutex_unlock(&dev->io_mutex);return 0;}static struct file_operations secbulk_fops = {.owner =THIS_MODULE,.read =secbulk_read,.write=secbulk_write,.open   =secbulk_open,.release=secbulk_release,};static struct usb_class_driver secbulk_class = {.name = "secbulk%d",.fops =&secbulk_fops,.minor_base=100,};static int secbulk_probe(struct usb_interface *interface, const struct usb_device_id *id){int ret;struct secbulk_dev *dev;struct usb_host_interface *iface_desc;struct usb_endpoint_descriptor *endpoint;int i;printk(KERN_INFO "secbulk:secbulk probing...\n");dev = kzalloc(sizeof(*dev), GFP_KERNEL);if(!dev) {ret = -ENOMEM;goto error;}iface_desc = interface->cur_altsetting;for(i=0; i < iface_desc->desc.bNumEndpoints; i++) {endpoint = &(iface_desc->endpoint[i].desc);if(!dev->bulk_out_endpointAddr&& usb_endpoint_is_bulk_out(endpoint)) {printk(KERN_INFO "secbulk:bulk out endpoint found!\n");dev->bulk_out_endpointAddr = endpoint->bEndpointAddress;break;}}if(!(dev->bulk_out_endpointAddr)) {ret = -EBUSY;goto error;}ret = usb_register_dev(interface, &secbulk_class);if(ret) {printk(KERN_ERR "secbulk: usb_register_dev failed!\n");return ret;}dev->udev = usb_get_dev(interface_to_usbdev(interface));usb_set_intfdata(interface, dev);mutex_init(&dev->io_mutex);return 0;error:if(!dev)kfree(dev);return ret;}static struct usb_driver secbulk_driver= {.name="secbulk",.probe=secbulk_probe,.disconnect=secbulk_disconnect,.id_table=secbulk_table,};static int __init secbulk_init(void){int result;printk(KERN_INFO "secbulk:secbulk loaded\n");result = usb_register(&secbulk_driver);if(result) {printk(KERN_ERR "secbulk:usb_register failed: %d", result);return result;}return 0;}static void __exit secbulk_exit(void){usb_deregister(&secbulk_driver);printk(KERN_INFO "secbulk:secbulk unloaded\n");}module_init(secbulk_init);module_exit(secbulk_exit);MODULE_LICENSE("GPL");
接下来,我们来写一个Makefile:

#obj-m := secbulk.o#secbulk-m := secbulk.oobj-m := secbulk.oKDIR := /lib/modules/`uname -r`/buildPWD  := $(shell pwd)default:$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modulesclean:$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) cleanrm -rf *.order *.symvers
然后在当前目录下make

编译成功如下:


编译成功以后,需要执行

chmod 777 secbulk.ko

sudo insmod secbulk.ko将内核插入系统。

接下来,还要安装一个库,方法:

sudo apt-get install libusb-dev

万事具备,只欠东风,现在可以启动minicom来尝试下载内核了

方法如下:

(1)在minicom端执行dnw 0x40008000,如图:


(2)切换到另外一个终端

然后执行dnw arch/arm/boot/zImage


切换到minicom端看到下载成功如下图:


接下来,在uboot中敲击bootm 0x40008000,注意不要打tab按键,否则你回看到以下未识别的信息:

我们重新来一次:

成功启动内核!!!!





1 0
原创粉丝点击