Wednesday, March 31, 2010
Linux and uClinux rc file and inittab file
There are system V and BSD styles to the arrangement of inittab, rc scripts and config files. And there are differences between Linux distributions. But the key point is, the system will startup at a predefined level most likely defined in inittab, and rc scripts will be run for that level to spawn all the necessary processes.
In uClinux there are inittab and rc file as well. But there are no run levels. An embedded system usually runs at just one level. So be carefull, uClinux inittab and rc are different from that of standard Linux.
In uClinux, rc is executed BEFORE inittab! rc file basically contains commands to prepare the system environment such mount /var, make directories, startup network etc. Inittab can be used to startup programs and services, such as serial terminals, IP servers, etc.
Something about the terminal. The line for terminal is usually like this:
ttyS0:vt100:/bin/agetty 9600 ttyS0
agetty is an excutable binary in /bin directory. It opens a tty port, prompt a login name and invokes /bin/login command. The above is the simplest format of an agetty command. It actually has quite a few options to change its behaviors. For example this one:
agetty -L 9600 ttyS1 vt100
This will force the line to be a local line with no need for carrier detect. This can be useful when you have a locally attached terminal where the serial line does not set the carrier detect signal. Try this if your terminal just sleeps instead of giving you a password: prompt.
Another thing is that agetty will optionally display the contents of /etc/issue. You can use a -f to display an alternative file, or you can use -i to ignore any issue file, not to display the contents of /etc/issue (or other) before writing the login prompt.
One more note, if there is no agetty in inittab, and you choose init with "enable console shell" when you configure core applications, then the uClinux will start without login at all.
Friday, March 26, 2010
MJPG-streamer, a light weight video streaming server for embedded system
mjpg-streamer looks like a good fit. It's an open source project at http://sourceforge.net/projects/mjpg-streamer/. And it's compiled for mini2440 at http://code.google.com/p/mjpg-streamer-mini2440/.
So I installed the binary for mini2440, it works pretty good. It works with a cheap USB camera, it works with a CMOS camera too. Only thing is, the frame rate is not high enough, 5 frames/sec, with 1-2 seconds delays. CMOS camera is obviously better than USB camera regarding to frames rate and delays. I haven't tried a camera with some compression capability yet, but it's supposed to have better result.
But it's pretty good overall. There are a few things I want to do with it (too busy now to do it now) in the near future:
1. A better camera
2. Make it part of the rootfs
3. Look into the code to see how it works with the camera driver.
4. Some modifications, such as embedded data within the pictures.
How come a ROM based ROMFS image can run from within RAM?
The image I built just works fine. But I decided to go a bit further. What's gonna happen if I run the image from within RAM? It's not supposed to be able to boot.
To my supprise, when I set uCbootloader environment varible "RAMIMAGE=yes" and type "go" command, the image get copied into ram, boot and run with staring address at 0x0020000, exactly as "RAMIMAGE=no"(which means boot from ROM at 0x10c20000).
Here is my explanation. For uCbootloader, when we type "go" to boot, the loader will fetch the first 32bytes of the image (the .bvec section of linux.bin) as the SP and IP content, and execute from the address pointed to by IP (the entry point of second bootloader). When the image get copied into RAM starting at 0x0020000, and when we "go" from there, the first 32 bytes starting from 0x0020000 are fetched into SP and IP. But, here is the point, the content of IP is still pointed to the entry address of second bootloader in ROM, so the execution is still go back to ROM.
To prove it I erase the Flash so there is no image in ROM at all. Then I download the ROM based image into RAM. Now I "goram" at 0x0020000, system just stop there without booting up, because the address pointed by IP is empty this time.
Conclusion, in a uClinux image, once generated, all the addresses of symbols (global varibles, functions, etc) are arranged and fixed. As long as the execution can jump to the right address, it will execute normally.
Wednesday, March 24, 2010
How to make putty private key authenticated
This is very insecure as everyone know, a username/passwd authentication in clear text is easy for attackers too. So I changed the authentication to RSA public/private key authentication. Here is a link that gives a pretty good explanation about how to do that. https://help.ubuntu.com/community/SSH/OpenSSH/Keys. But it's talking about clients running linux.
In order for the windows client putty to work, these extra steps are needed:
1. On ubuntu (the ssh server), copy the newly generated public key id_rsa.pub to authorized_keys, and uncomment the "AuthorizedKeysFile %h/.ssh/authorized_keys" in sshd_config. Of course restart sshd by "/etc/init.d/ssh restart"
2. Copy the private key, id_rsa to windows, load it into puttygen and save it as private key in .ppk format. (You need to download puttygen.exe from putty website)
3. Change your session to use private key authentication, by loading the private key into your session's configuration. Don't forget to save your session's configuration!
And the next time you login, you will be asked for a passphrase for your private key. After that, you're logged in private key authenticated. And you feel secured!!!
Friday, March 19, 2010
Linux zigbee checkout
Tuesday, March 2, 2010
How is romfs moved above .bss in uClinux?
Sunday, February 21, 2010
A Linux tool for downloading kernel and rootfs to mini2440
To compile: gcc dnw2.c -o dnw2 -lusb/* dnw2 linux main file. This depends on libusb.
*
* Author: Fox
* License: GPL
*
*/
#include <stdio.h>
#include <usb.h>
#include <errno.h>
#include <sys>
#include <fcntl.h>
#include <unistd.h>
#define QQ2440_SECBULK_IDVENDOR 0x5345
#define QQ2440_SECBULK_IDPRODUCT 0x1234
struct usb_dev_handle * open_port()
{
struct usb_bus *busses, *bus;
usb_init();
usb_find_busses();
usb_find_devices();
busses = usb_get_busses();
for(bus=busses;bus;bus=bus->next)
{
struct usb_device *dev;
for(dev=bus->devices;dev;dev=dev->next)
{
if( QQ2440_SECBULK_IDVENDOR==dev->descriptor.idVendor
&& QQ2440_SECBULK_IDPRODUCT==dev->descriptor.idProduct)
{
printf("Target usb device found!n");
struct usb_dev_handle *hdev = usb_open(dev);
if(!hdev)
{
perror("Cannot open device");
}
else
{
if(0!=usb_claim_interface(hdev, 0))
{
perror("Cannot claim interface");
usb_close(hdev);
hdev = NULL;
}
}
return hdev;
}
}
}
printf("Target usb device not found!n");
return NULL;
}
void usage()
{
printf("Usage: dnw2nn");
}
unsigned char* prepare_write_buf(char *filename, unsigned int *len)
{
unsigned char *write_buf = NULL;
struct stat fs;
int fd = open(filename, O_RDONLY);
if(-1==fd)
{
perror("Cannot open file");
return NULL;
}
if(-1==fstat(fd, &fs))
{
perror("Cannot get file size");
goto error;
}
write_buf = (unsigned char*)malloc(fs.st_size+10);
if(NULL==write_buf)
{
perror("malloc failed");
goto error;
}
if(fs.st_size != read(fd, write_buf+8, fs.st_size))
{
perror("Reading file failed");
goto error;
}
printf("Filename : %sn", filename);
printf("Filesize : %d bytesn", fs.st_size);
*((u_int32_t*)write_buf) = 0x30000000; //download address
*((u_int32_t*)write_buf+1) = fs.st_size + 10; //download size;
*len = fs.st_size + 10;
return write_buf;
error:
if(fd!=-1) close(fd);
if(NULL!=write_buf) free(write_buf);
fs.st_size = 0;
return NULL;
}
int main(int argc, char *argv[])
{
if(2!=argc)
{
usage();
return 1;
}
struct usb_dev_handle *hdev = open_port();
if(!hdev)
{
return 1;
}
unsigned int len = 0;
unsigned char* write_buf = prepare_write_buf(argv[1], &len);
if(NULL==write_buf) return 1;
unsigned int remain = len;
unsigned int towrite;
printf("Writing data ...n");
while(remain)
{
towrite = remain>512 ? 512 : remain;
if(towrite != usb_bulk_write(hdev, 0x03, write_buf+(len-remain), towrite, 3000))
{
perror("usb_bulk_write failed");
break;
}
remain-=towrite;
printf("r%d%t %d bytes ", (len-remain)*100/len, len-remain);
fflush(stdout);
}
if(0==remain) printf("Done!n");
return 0;
}