2012年3月28日 星期三

Linux驅動程式--chapter 5

這章的重點是concurrency的問題,介紹的工具是semaphore、mutexes、spinlock、atomic operations、seqlock、Read-Copy-Update(RCU)
基本上快都是作業系統(OS)介紹過的東西,如果上過這個課程,對這些東西應該不陌生。雖然很想這樣結束,但是我要說,書中介紹的原則往往比教科書來的多,也來的更貼近實際狀況;另外也讓我體驗到driver有時候設計真的充滿了trade off

一般而言,我們希望使用semaphore因為會比spinlock容易(因為高階),但是spinlock會比較有效率,但是spinlock又可能引起沒效率,這種弔詭的說法有舉例

一般而言,spinlock使用的時候會取消cpu preemption的功能,希望目前的task趕緊完成工作,儘快釋放lock,很不幸很多function call會引發目前的工作釋放cpu,比方說kmalloc,而且沒有完整的列表。其次中斷也會引發目前task帶著lock且釋放出cpu,這時候可能會有很不幸的事情發生,那就是如果該中斷要求同一個spinlock,這就好玩了,他會因為拿不到,重新觸發,然後就一直浪費cpu的時間在等待task釋放cpu,但是可能又因為cpu preemption功能被關閉,本來的task進不到cpu產生了dead lock,如果不會dead lock也有可能cpu空轉上好一段時間。這也是為何說spin lock可能引起效率低落的原因。

作者給spin lock幾個建議:

  • 使用spin lock不要有cpu preemption,這點kernel會處理,不至於太擔心
  • 使用spin lock不要讓task sleep,要非常小心,因為如上所說function call & interrupt
  • 使用spin lock要儘快釋放,免得schedule的功能"失去作用",因為spin lock取走了大部分cpu時間

對於種種同步的建議是:

  • 儘量事前規劃好,省得事後debug很困難
  • 對於鎖定的資源依序取得,可以避免一些dead lock的可能性
  • 不要呼叫交互取得lock或者資源的function,這樣也很容易dead lock


atomic operation則適用於int以及bit運算,因為有時候我們希望有些簡單但是重要的count功能或者加減的功能是使用atomic operations,但是有點要認知到,就是運算的串聯次序本身並沒有被保證,也就是兩個以上task執行了各十個atomic operations,你並不能知道他們之間的次序是如何排列的。
至於詳細的API使用方式,可以參考書本

2012年3月27日 星期二

Linux驅動程式--chapter 4

這一章已經超過了單純driver,還包含到了kerenel debug的技巧,首先介紹一些在kernel hacking裡面的選項,為了debug有時候是必須打開的,接著介紹不同的技巧以及他們應用的時機
printk() : 最簡單最直接的一種,大致上分成八個level只有當設定的訊息的level小於console_loglevel的時候,訊息才會直接被送到console,作者還介紹了一個小工具程式,讓我們可以設定輸出的console。接著printk的問題就是如果在code裡面埋了一堆debugger information,要如何在編譯階段可以清理掉,作者定義了幾個macro來處理這件事情

/proc : 從2.6開始procfs被引入作為顯示系統狀態的vfs,如果老是使用printk在動作很多的時候,訊息量可以淹沒整個console畫面,反過來如果可以在適當時機將需要的資料拿出來看,這樣除錯就可以輕鬆許多,要在/proc底下註冊建立/proc檔案需要用到
struct proc_dir_entry *create_proc_read_entery(const char *name, mode_t mode, struct proc_dir_entry *base, read_proc_t *read_proc, void *data)
這一個function,可以註冊需要的路徑跟虛擬裝置,同時要提供可以讀取資料的函數(跟自己寫的module在同一檔案/空間之中),將目前module的狀態讓使用者可以用類似cat /proc/scullmem的方式取出。這種方式有個限制就是基本上是以page size,在運作,操作複雜結構的資訊並不是很容易,另外就是/proc已經開始有濫用的趨勢,/proc已經不只是讀取,還可以寫入,有點跟/dev一樣的問題。linux已經開始引入sysfs來處理這樣的問題,他要求更有架構性的資料

ioctl() : 最靈活的方式,但是程式設計師必須自行處理,在此章節作者也還不打算詳細介紹,他另外有個好處就是code獨立,不是類似printk會"汙染"到原本的code,所以忘記把它拿掉只是佔據記憶體空間:P
strace : 用來追蹤一些system call的次序,但是可讀性低於printk,有許多參數,如-o表示將輸出轉移到檔案內
strace -o /tmp/x1 ls -R > /dev/scull0

Ooops information : 當系統fault的時候(不是panic/死當),會產生類似coredump檔案的輸出,包含了CPU register等等information(P.S>我不大清楚它會產生到哪裡去@@a)

magic SysRq key : 一些特殊的組合鍵,讓使用者可以做一些事情,請參考書內內容

debugger tools : gdb、kdb、kgdb、Linux Trace Toolkit (LTT)、Dynamic Probes

裡面有提到一個有趣的User-Mode Linux,這是一個虛擬機器的機構,但是她不能讓使用者直接存取硬體

最後,其實作者的sample code的scull包含了chapter 3跟4,所以如果光看了chapter 3就去看code會感到怎麼還有很多多出來的東西

參考資料:
http://zh.wikipedia.org/wiki/Sysfs
http://blog.linux.org.tw/~asho/archives/001816.html
http://184.82.2.112/wordpress/?p=505

system log

sysklogd套件主要包含兩個訊息紀錄程式,一個是klogd(Kernel Log Daemon),另一個為 syslogd(System Log Daemon),兩個工具主要的不同在於klogd是紀錄Linux 核心訊息與Linux核心模組訊息,每當核心程式呼叫printk時,就可以由這個User-Mode的klogd程式來負責把此時的核心訊息紀錄下來,而syslogd則是負責User-Mode程式所需紀錄的系統訊息(例如紀錄在/var/log/messages的系統訊息)。
syslogd的控制可以由/etc/syslog.conf來控制,其次klogd是記錄在一個環狀的紀錄中,當紀錄太多的時候,新來的紀錄會覆蓋掉舊有的紀錄

2012年3月24日 星期六

在ubuntu上面使用mspgcc編譯MSP430的code

只是記錄一下相關的連結,還沒有時間測試
http://hackaday.com/2010/08/11/how-to-launchpad-programming-with-linux/
http://blog.wikifotos.org/2010/11/15/msp430-launchpad-in-ubuntu/
http://mylightswitch.com/2010/06/21/installing-mpsgcc4-and-mspdebug-on-kubuntu-1004/

Linux驅動程式--chapter 3

對於新手還真的有點辛苦的一章,一邊念著一邊看著原始碼,這一章節作者寫了個scull的character device的module,先利用了一些script(mknod)將這些虛擬裝置建構出來

首先替module本身與裝置連結,所以要註冊裝置的編號,在linux 2.6中使用major number跟minor number組成一個獨一無二的編號
MKDEV(scull_major, scull_minor)
跟著使用register_chrdev_region註冊數個裝置(依序,如果之前minor number是2, count是3,就會註冊2~4這幾個裝置),或者使用alloc_chrdev_region動態配置

因為作者使用記憶體取代實際可能為磁碟或者其他硬體裝得部份,所以他有些結構需要初始化,scull_devices這個變數對應每個虛擬裝置的相關資料

接著填充一些必要得功能,其中最重要的是struct file_operations這個結構,他包含了許多character device應該具備有的功能,如果沒有的話則保持NULL,如果使用者使用了不再表格內的function call,就會回傳錯誤。底下是一個範例

struct file_operations scull_fops = {
.owner =    THIS_MODULE,
.llseek =   scull_llseek,
.read =     scull_read,
.write =    scull_write,
.ioctl =    scull_ioctl,
.open =     scull_open,
.release =  scull_release,
};

該結構內並不完全都是function pointer,其中.owner就是表示這個module本身,THIS_MODULE是一個macro
另外可以看到就是read/write、llseek跟open/release這幾個常見的操作,但是為何不是close而是release,這是因為linux一般會對裝置紀錄一個count,表示有多少人或者process這在使用這個資源,只有當count為0的時候才會真真的close

接著必須對每個device作file_operations跟device的對應,使用cdev_init輸入兩個參數,分別是該裝置所需用到的資料結構(struct scull_dev)以及file_operations這個結構,作者假設有四個裝置,就分配要配置四份,但是file_operations這些操作是共用的

這裡有點好玩的是,並沒有強制規定同樣的file device必須有同樣的,甚至因為傳入的是指標,表示可以在半路抽換介面@@a,真是一個好玩的狀況!!

仔細觀察file_operations就會發見到,很多地方需要使用到struct file以及struct inode這兩個參數(由kernel傳入),inode裡面有個成員i_cdev,這裡面包含之前用cdev_init配給某個device的資料結構,需要透過struct scull_dev *dev = container_of(inode->i_cdev, struct scull_dev, cdev);這個巨集取出,這樣就可以知道process正在存取哪個device,並且使用相對應的資料空間

另外討論到記憶體的管理,如作者之前提過得,在kernel space並不能使用一般的libc函數,也就是malloc/free之類的記憶體配置不能使用,這裡必須使用kmalloc/kfree。另外值得注意的一點是如何在user space以及kernel space之間傳遞資料,這裡使用
unsigned long copy_to_user(void __user *to, const void *from, unsigned long count)
unsigned long copy_from_user(void *to, const void __user*from, unsigned long count)
在這兩個呼叫,kernel還必須要檢查適當地存取權限,還有處理使用者指向的記憶體可能是page fault的問題

所以整體來說,簡化的架構就是

  • 註冊裝置
  • 初始化相對應裝置的資料
  • 完成file_operations表格
  • 完成相對應操作的函數 
  • 最後記得要清理資料

2012年3月23日 星期五

linux kernel的相關資料

這裡只是剛好爬文到網路上一個不錯的文庫,紀錄一下
驅動程序編寫基本流程              
Linux內核的ioctl函數學習
linux內核中struct file_operations結構體介紹
幾種設備的相關開發文件:
Linux音頻編程指南
嵌入式系統中LCD驅動的實現原理

因為linux驅動程式一書在這個部份寫得比較簡略的,直接翻code在對照文中所寫,就會有豁然開朗的感覺,畢竟第一次接觸linux較完整module(相對於第二章來說,第三章的範例也完整許多),其中也稍微解釋到我以前的疑惑,kernel space與user space的資料交換


有找到一些資料,但是比較無法分類,順便歸類在這裡好了
ARM MMU工作原理剖析
WIFI環境建構

2012年3月22日 星期四

LCD之framebuffer(4)

終於在網路上看到為何framebuffer會比實際上來的大,以前有人會解釋說是為了作double-buffer,但是有時候size又不是單純的一倍大小,這樣很難自圓其說,後來發現有另外一個原因,那就是為了smooth moving,如果有打過一些以前DOS小遊戲的人(有不小心透露出自己年紀不小嗎XD),遊戲主角移動單位是一格一格的,但是移動的時候卻是平滑移動的動畫,不是跳格的方式,這時候多出來的framebuffer空間就可以作為平滑移動,只要改變指標的位置,就不用會產生跳格的感覺

另外經由Linux驅動程式一書的解釋,framebuffer屬於user space的driver,所以效能會比kernel space來的差,所以表示,如果說要使用圖形顯示,但是又想繞過xwin,或許framebuffer是個不錯的選擇,但是想要在比desktop還要差的硬體下壓榨出更多的效能,可能就得自己對driver開刀了,這恐怕是個大工程,當然很多人會想要使用DSP硬體支援,這也是時下主流平板的選擇

pixel的color depth

其實本來不是很重視這個部份,只不過對名詞的精確性稍微作點筆記,對於每個像素(pixel)用多少bits來表示決定了他的色彩深度(color depth),對於不同的bits所決定出來的色彩(color),有不同的名詞描述
8bits
15/16bits : high color
24bits : true color
30/36/48bits : deep color

MSP430初探 (2)

MSP430有多種規格,以launch pad而言只有20個pin,但是有的卻多達40個以上,有的可憐到只有14個,不管如何,大多可以分為下面幾種,這些pin為IO接口,大致上可以分為幾種,且每一種都是可以作為他用(或者說重複使用,只要沒人用就可以用作其他用途)
PxIN: input register,x表示第幾個register
PxOUT: output register
PxDIR : register方向
PxSEL : 第二功能選項
PxIE : interrupt功能 enable
PxIES : interrupt edge trigger
PxIFG : interrupt flag

一般可以先用PxOUT規定pin的輸入輸出,如之前介紹,下面談談PxIE跟PxIFG如何使用來處理中斷

P1DIR=~BIT3; //讓PIN3為輸入
P1SEL=BIT3;  //讓該pin為interrupt,不是作為一般的IO pin
P1IE=BIT3;  //enable該pin的interrupt功能
_EINT();  //啟動interrupt

//下面一行是表示該函數為處理P1的所有pin的interrupt sub-routine
#pragma vector=PORT1_VECTOR
__interrupt void P1_ISR(void){
//前面有__intterupt告訴compiler將他編譯為ISR
  //...process
  P1IFG=0;
}
在launchpad中,BIT3為按鈕的pin。因為一個ISR function不只處理一個pin,所以有可能事件會同時發生,利用P1IFG可以看到哪些事件發生了,另外最後把P1IFG=0,這可以解除事件發生的狀態,不然事件可能會被辨識為一直發生

2012年3月21日 星期三

Linux驅動程式--chapter 2

這一章節簡單的給了個module的入門,一個只是用來insmod跟rmmod的moduule

#include <linux/init.h>
#include <linux/module.h>
MODULE_LICENSE("Dual BSD/GPL");
static int __init hello_init(void){
  printk(KERN_ALERT "Hello, world\n");
  return 0;
}
static void __exit hello exit(void){
  printk("KERN_ALERT "Goodbye, cruel world\n");
}
module_init(hello_init);
module_exit(hello_exit);
與一般user space不同,由於module運行於kernel space,所以並不連結一般的lib,所以類似printf就不能使用,只能使用printk,KERN_ALERT是一個macro,後面沒有逗點,module_init點出insmod module就運行的function,相對的module_exit則是rmmod的時候

設計module必須考量到

  • 是kernel space or user space(有些驅動程式是可以為user space,但是有好有壞)
  • module變數的race condition
  • module必須是reentrant
  • module的lifetime幾乎等同kernel,從insmod到rmmod(往往就是開機到關機),中間變數一直存在,並不隨著被服務的process結束而結束
  • module的記憶體有限,堆疊不可能配置太大的空間
  • module往往跟目前服務的process有很大的關係,可以使用struct task_struct中的current指向目前的process
  • module的相依性處理不完全在於程式,在於管理者必須知道使用modprobe來追蹤,但是這也表示module往往跟版本有很大的關係


在headers內定義了許多macro是供給modinfo用的

  • MODULE_LICENSE : 是使用GPL or BSD還是其他
  • MODULE_AUTHOR : 作者資訊
  • MODULE_VERSION : 版本,通常表示支援的kernel version等等
  • MODULE_DESCRIPTION : 描述
  • MODULE_ALIAS : alias name
  • MODULE_DEVICE_TABLE : 支援的device


有些關鍵字是C語言內沒有的,例如__init跟__exit,這是給compiler用的,分別表明該函數是初始化以及結束時該呼叫的,另外還有__initdata與__exitdata表示初始配置資料的函數跟離開時後歸還空間的函數,往往用於hotplug

其他關於編譯的細節以及一些版本號碼控管有空再說,本身這是一章節談論到很多關於kernel module的觀念

這本書每章節後面都會簡單的summary這章節的內容,蠻有幫助的


MSP430初探 (1)

P1OUT是一個register,代表在板子上的P0~P8的pin
P1DIR表示輸出、輸入方向,如果0表示輸入,1表示輸出
BIT0~BIT7分別表示第0~7個bit為1
另外可以看到P1.0寫著LED,所以只要把P1OUT=BIT0,就表示要將Red LED打開;同理P1OUT=BIT6就可以將Green LED打開,要同時打開就P1OUT=BIT0|BIT6

2012年3月20日 星期二

Linux驅動程式--chapter 1

玩嵌入式系統的人應該很難不動驅動程式有所牽連,不管是基於好奇也好,或者說萬般無奈為了某些功能也罷,驅動程式的確都是不可迴避的課題。講到這個,當然就屬於oreilly出版的linux驅動程式為一本入門的經典,接下來就是我拜讀的書本摘要,其實如果真的要鑽研linux驅動程式,這本書應該是放在你的架上的

驅動程式提供某些machanism,讓使用者依照某些policy來操作,所謂的machanism應該類似檔案操作的fopen, fwrite, fread, fclose,使用者要完成某項工作,例如讀取解析某些檔案,這些操作的程序比較類似policy。
linux將許多驅動程式變成了模組(module),好處是可以在隨時加入一些特性,主要依賴insmod與rmmod來引入與卸載模組。
模組大概可以依照硬體分成三類,character device、block device、queue,網路介面比較使用queue來對待
linux驅動程式強烈跟核心(kernel)相關,所以必須確定使用的核心版本,許多驅動程式在不同版本核心往往不保證相容性,因為kernel的API異動可能造成驅動程式的問題

因為現在已經新的開發大多已經使用linux 2.6以後的核心了,這也是這本書的第三版瞄準的目標,第二版是linux 2.4,2.4=>2.6架構上有很大的變動,所以舊版/二版的書基本上只能運作在2.4,要買書的讀者要注意

新玩意~MSP430

就跟圖片一樣,不是單單只有晶片,是TI的MSP430 LaunchPad,直接跟公司訂購為4.3USD,台灣有好心人士可以買得140NTD一片的價格(郵資另計),如果在台灣不想等的朋友可以直接訂購會稍微比較快一點

內容物如官方網站寫的,不過比較讓我訝異的是,電晶體竟然要自己焊接~TI打算讓我們重拾DIY的感動嗎?

另外讓我訝異的是IDE大到1.2G,原來其中很多是其他晶片的內容,其實並不需要

參考資料:
http://www.ti.com.tw/news/newsdetail.asp?scid=TIA-10030
http://processors.wiki.ti.com/index.php/MSP430_LaunchPad_%28MSP-EXP430G2%29?DCMP=launchpad&HQS=Other+PR+launchpadwiki-prtw

2012年3月18日 星期日

KConfig與Makefile

在編譯核心的時候,使用menuconfig,常常一閃而過而這個關鍵字,所以就google一下囉
在各個元件有自行的Kconfig檔案,主要的功能就是描述一些menuconfig上面的文字跟選項囉,還有跟parent以及child元件之間的關係,例如選了哪個選項,下面的子選項就要可見之類的
然後在該元件內設置一些Makefile,描述他跟Kconfig之間的關係,跟著大概就是kernel最外層的工具開始scan各個Kconfig,跟著把整個menu建構出來,當選擇完畢的時候,卻是把所有的資料寫入了.config這個file,作為Makefile的依據

參考資料:
http://huenlil.pixnet.net/blog/post/23493757-%5B%E8%BD%89%5Dkconfig-%26-makefile
http://smalldd.pixnet.net/blog/post/26192034-%E5%B0%87%E8%87%AA%E5%B7%B1%E5%AF%AB%E7%9A%84%E7%A8%8B%E5%BC%8F%E5%8A%A0%E5%85%A5-kernel-%E7%B7%A8%E8%AD%AF%E4%B8%AD-%E2%94%80%E2%94%80-%E7%B7%A8%E5%AF%AB-k
http://www.linuxidc.com/Linux/2009-11/23091.htm
http://edsionte.com/techblog/archives/1332

busybox內建的ftp server

先確定有/etc下的passwd、group、shadow檔案,如果沒有,可以新增檔案內容如下
passwd:
root:x:0:0:root:/root:/bin/sh
group:
root:x:0:
shadow:
root::12179:0:99999:7:::

使用inetd來管理server,所以在新增/etc/inetd.conf,內容新增
21 stream tcp nowait root ftpd ftpd -w /root
可以看到最後是指明anonymous登入的目錄,執行指令inetd即可,可以使用netstat -npl觀察ftp server有沒有啟動
如果沒看到可以檢查看看inetd是否有執行

OpenWrt這東西

之前就有在網路上論壇看到人家討論,還沒仔細看過,最近在網路上找問題的時候看到
https://openwrt.org/
似乎是一個為了wireless router作為設計基準的distribution,特色應該就是遷入系統,對於封包的管理,防火牆的設計等等作特殊設計的套件,不知道有沒有設計好的管理介面?有空的時候再來弄個硬體來體驗看看

2012年3月17日 星期六

編譯open ssl與wpa_supplicant(補)

本以為高高興興的編譯過之後,接下來就是完成無線網卡的module就可以快快樂樂得上網了,結果才知道自己天真了orz

首先是怎樣都無法wpa_supplicant成功,仔細看了許久的設定檔案,應該沒有錯誤(改過幾種),或者版本有問題(另外試驗0.61),再來懷疑是openssl沒有編譯好,找了幾個編譯版本,還修改了些參數(目前還是沒有編譯出.so,但是有編譯出.a),跟著甚至把ssl的lib用static link到wpa_supplicant裡面;又或者懷疑busybox是不是有問題,哪些tool沒裝?

最後才發現,原來要改kernel阿~~~囧~必須要打開CONFIG_PACKET選項阿~~~

好啦,打開之後,發現wpa_supplicant可以過了,想不到事情還沒結束,先看看需要dhcp,那表示我要編譯dhcpclient囉?嗯嗯~busybox有簡易的版本udhcpc,那就使用吧,用了之後竟然完全好似沒有作用!?去開AP的設定來看,有連上來阿~也分配了位置,又是上網爬文,發現原來udhcpc並不會自動更改設定,要透過script,在busybox解開的目錄內$(busybox)/examples/udhcp/simple.script,拷貝到機器上變成/usr/share/udhcpc/default.script,這樣一來只要使用updhcpc -i wlan0,ifconfig就可以看到系統自動幫我們設定好ip、netmask、nameserver...,應該可以上網了吧,ping又失敗了..............真的無力到了極點,我又開始"疑神疑鬼"了,最後答案是.....

原來的route路徑跟wlan衝突阿.....eth0跟wlan0兩者都是192.168.1.x的網域,所以系統大概先註冊先贏,率先去使用eth0的路徑吧orz,最後先把eth0關閉,終於可以上網了,真的是遠兜轉了

這只能說,desktop distribution還真的方便許多,嵌入式系統還真多東西自己要take care

2012年3月15日 星期四

編譯open ssl與wpa_supplicant

wpa_supplicant用以支援WPA等等的加密演算法的無線網路連線的工具,既然要提到加密,難免需要ssl支援,所以外加必須編譯open ssl,而且open ssl必須先使用wpa_supplicant裡面的patch檔案patch過,這裡我所使用的是wpa_supplicant 0.7.3與openssl 0.9.8i
先編譯open ssl

  • patch -p0<wpa_supplicant-0.7.3/patches/openssl-0.9.8i-tls-extensions.patch
  • ./Configure linux-elf-arm -DB_ENDIAN linux:'arm-linux-gcc' shared --prefix=$ROOTFS/openssl
  • make && make install

接著編譯wpa_supplicant

  • 找到Makefile將CC修改為arm-linux-gcc(依照你的toolchain)
  • cp defconfig .conf
  • 修改.conf中的參數
    • CC=arm-linux-gcc -L $(ROOTFS)/openssl/lib/
    • CFLAGS += -I$(ROOTFS)/openssl/include/
    • LIBS += -L$(ROOTFS)/openssl/lib/
  • make
另外中間發現,實在micro2440的光碟片有點太糟糕,竟然把不同cpu的toolchain放在一起,搞得我還拷貝錯lib跟ldconfig,試驗了老半天,怎麼都是Illegal instruction,因為根本無法載入library阿~天啊!!

2012年3月14日 星期三

micro2440編譯核心

只要使用廠商提供的核心設定檔案下去更改就簡單得多了,主要應該是卡在一個機器型號的設定上面,使得在super vivi還是uboot上面送出的參數會產生一些不匹配的問題,指令類似這樣
copy config_xxxx .config

不過只細看,設定檔案刪除了很多東西,比方一些檔案型態的支援,如果要支援fat跟ntfs記得要把他們編譯進去,另外就是編碼的選擇,記得在native language上選取要支援的編碼,免得有亂碼或者utf-8不支援的問題

可是我好像忘記把模組安裝上去XD另外順便在這裡筆記一下好了,下次要準備編譯一些wireless tools跟wpa_supplicant套件,那表示順便會編一到open ssl,這樣可能就順便編譯一下ssh好了,實在不大喜歡使用serial port,把網路弄起來用ssh連線會比較好一點

2012年3月13日 星期二

micro2440移植busybox 1.19.x


  • 基本上就跟前面busybox編譯差不多,比較困難的是設定的部份,還有一個選項,必須在Shell>內選擇choose which shell is ...都選擇ash,不然會有問題,這部份應該是被設定為default shell
  • 跟著我把所有toolchain內的libc/lib下的library跟link的檔案全部拷貝到<rootfs>/lib底下

另外兩個重要的設定檔案內容如下inittab
 第二行得加上去,如果部加上去的話你會看不到login shell,其他詳細的設定方式可以參考"建構嵌入式linux系統"一書

接著是/etc/rcS,這部份是借用了原來板子上的檔案,可是hotplug一直有問題,我直接把那行/bin/hotplug註解掉了,可是還是有點小問題
最後在用光碟內的工具用mkyaffs2image-128M _install yaffs_root.img,然後就可以下載到板子上
rootfs已經成功刷上去沒有問題,但是目前新編譯的kernel有問題~苦惱中,難道一個嵌入式系統就是編譯debug嗎:P

最後建議要刷板子的人先把nand flash的內容備份下來吧,雖然我覺得他好像有問題(不知道是賣我的人給我二手貨,還是出廠軟體就有問題)

[轉載]YAFFS檔案系統

來自http://jnds.yo2.cn/articles/%E5%9C%A8nand-flash%E4%B8%8A%E5%BB%BA%E7%AB%8Byaffs2%E6%96%87%E4%BB%B6%E7%B3%BB%E7%BB%9F%EF%BC%88%E4%B8%80%EF%BC%89.html

經過了半個多月的努力,終於搞定nandflash的mtd驅動和上層的yaffs2文件系統。這半個多月來幾乎每天都要和挫敗感鬥爭,每天都要忍 受這個方面,那個方面的bug。想想自己這半個多月來,也算看不少資料,得到不少人的幫助,總算是有點心得。鑑於國內搞yaffs2文件系統方面的資料還 是很少,就把自己的心得拿出來與大家共享。
      不說閒話了,先介紹一些背景資料    一. 閃存
我們常說的閃存其實只是一個籠統的稱呼,準確地說它是非易失隨機訪問存儲器(NVRAM)的俗稱,特點是斷電後數據不消失,因此可以作為外部存儲器使用。 而所謂的內存是揮發性存儲器,分為DRAM和SRAM兩大類,其中常說的內存主要指DRAM,也就是我們熟悉的DDR、DDR2、SDR、EDO等等。閃 存也有不同類型,其中主要分為NOR型和NAND型兩大類。
閃存的分類
NOR型與NAND型閃存的區別很大,打個比方說,NOR型閃存更像內存,有獨立的地址線和數據線,但價格比較貴,容量比較小;而NAND型更像硬 盤,地址線和數據線是共用的I/O線,類似硬盤的所有信息都通過一條硬盤線傳送一般,而且NAND型與NOR型閃存相比,成本要低一些,而容量大得多。因 此,NOR型閃存比較適合頻繁隨機讀寫的場合,通常用於存儲程序代碼並直接在閃存內運行,手機就是使用NOR型閃存的大戶,所以手機的「內存」容量通常不 大;NAND型閃存主要用來存儲資料,我們常用的閃存產品,如閃存盤、數碼存儲卡都是用NAND型閃存。
這裡我們還需要端正一個概念,那就是閃存的速度其實很有限,它本身操作速度、頻率就比內存低得多,而且NAND型閃存類似硬盤的操作方式效率也比內存 的直接訪問方式慢得多。因此,不要以為閃存盤的性能瓶頸是在接口,甚至想當然地認為閃存盤採用USB2.0接口之後會獲得巨大的性能提升。
前面提到NAND型閃存的操作方式效率低,這和它的架構設計和接口設計有關,它操作起來確實挺像硬盤(其實NAND型閃存在設計之初確實考慮了與硬盤 的兼容性),它的性能特點也很像硬盤:小數據塊操作速度很慢,而大數據塊速度就很快,這種差異遠比其他存儲介質大的多。這種性能特點非常值得我們留意。
NAND型閃存的技術特點
內存和NOR型閃存的基本存儲單元是bit,用戶可以隨機訪問任何一個bit的信息。而NAND型閃存的基本存儲單元是頁(Page)(可以看 到,NAND型閃存的頁就類似硬盤的扇區,硬盤的一個扇區也為512字節)。每一頁的有效容量是512字節的倍數。所謂的有效容量是指用於數據存儲的部 分,實際上還要加上16字節的校驗信息,因此我們可以在閃存廠商的技術資料當中看到「(512+16)Byte」的表示方式。目前2Gb以下容量的 NAND型閃存絕大多數是(512+16)字節的頁面容量,2Gb以上容量的NAND型閃存則將頁容量擴大到(2048+64)字節。
NAND型閃存以塊為單位進行擦除操作。閃存的寫入操作必須在空白區域進行,如果目標區域已經有數據,必須先擦除後寫入,因此擦除操作是閃存的基本操 作。一般每個塊包含32個512字節的頁,容量16KB;而大容量閃存採用2KB頁時,則每個塊包含64個頁,容量128KB。
每顆NAND型閃存的I/O接口一般是8條,每條數據線每次傳輸(512+16)bit信息,8條就是(512+16)×8bit,也就是前面說的 512字節。但較大容量的NAND型閃存也越來越多地採用16條I/O線的設計,如三星編號K9K1G16U0A的芯片就是64M×16bit的NAND 型閃存,容量1Gb,基本數據單位是(256+ 8) ×16bit,還是512字節。
尋址時,NAND型閃存通過8條I/O接口數據線傳輸地址信息包,每包傳送8位地址信息。由於閃存芯片容量比較大,一組8位地址只夠尋址256個頁, 顯然是不夠的,因此通常一次地址傳送需要分若干組,佔用若干個時鐘週期。NAND的地址信息包括列地址(頁面中的起始操作地址)、塊地址和相應的頁面地 址,傳送時分別分組,至少需要三次,佔用三個週期。隨著容量的增大,地址信息會更多,需要佔用更多的時鐘週期傳輸,因此NAND型閃存的一個重要特點就是 容量越大,尋址時間越長。而且,由於傳送地址週期比其他存儲介質長,因此NAND型閃存比其他存儲介質更不適合大量的小容量讀寫請求。
二.MTD
MTD是memory technology Device的縮寫。MTD支持類似於內存的存儲器,它是底層硬件和上層軟件之間的橋樑。對底層來說,它無論對nor型或是nandflash都有很好的 驅動支持,對上層來說,它抽象出文件系統所需要的接口函數。同時由於flash自身的特別之處(既有類似塊設備的特點,又有類似字符設備的特點),MTD 可以把flash同時為塊設備和字符設備。有了MTD,編寫flash的驅動變得十分輕鬆,因為上層的架構都已經做好,我們只用看看flash的 datasheet,寫最底層的控制時序即可。
以下內容為翻譯自mtd官方網站http://www.linux-mtd.infradead.org/archive/index.html
mtd致力於為存儲器,尤其是flash,設計一個通用的linux下的子系統。
設計這個系統的目標在於,通過這個系統所提供的硬件驅動和上層系統之間的接口,我們可以方便的為新的硬件編寫驅動。
對於底層的硬件驅動來說,它們所以提供是讀,寫,擦除的流程。而文件的存儲形式是和他們無關的(如FTL,FFS2等等),用恰當的形式存儲用戶的數據那時上層系統關注的事情。
MTD的用戶模塊
MTD為用戶提供五種可以直接在用戶空間使用的模塊
字符設備
塊設備
flash轉換層
nandflash轉換層
JFFS2文件系統
三.yaffs2文件系統
針對於flash的文件系統有很多,據我瞭解有jffs(1,2,3),yaffs(1,2)。還有商業的三星開發的RFS(健壯文件系統),專門針對三 星自己的nand和onenand,從底層驅動到上層文件系統一條龍服務,而且號稱和fat格式100%兼容。當時看得我直流口水,心裡把三星恨的咬牙切 齒。 下面主要介紹一下開源的yaffs文件系統。
Yaffs(Yet Another Flash File System)文件系統是專門針對NAND閃存設計的嵌入式文件系統,目前有YAFFS和YAFFS2兩個版本,一般說來,YAFFS對 512byte/page以下都有很好的支持,而更大的頁就需要YAFFS2了,如2K/page。
Yaffs文件系統有些類似於JFFS/JFFS2文件系統,與之不同的是JFFS1/2文件系統最初是針對NOR FLASH的應用場合設計的,而NOR FLASH和NAND FLASH本質上有較大的區別,所以儘管JFFS1/2 文件系統也能應用於NAND FLASH,但由於它在內存佔用和啟動時間方面針對NOR的特性做了一些取捨,所以對NAND來說通常並不是最優的方案。
Yaffs對文件系統上的所有內容(比如正常文件,目錄,鏈接,設備文件等等)都統一當作文件來處理,每個文件都有一個頁面專門存放文件頭,文件頭保存了 文件的模式、所有者id、組id、長度、文件名、Parent Object ID等信息。因為需要在一頁內放下這些內容,所以對文件名的長度,符號鏈接對象的路徑名等長度都有限制。
前面說到對於NAND FLASH上的每一頁數據,都有額外的空間用來存儲附加信息,通常NAND驅動只使用了這些空間的一部分,YAFFS正是利用了這部分空間中剩餘的部分來 存儲文件系統相關的內容。同時由於支持的page變大,YAFFS2使用更多的spare space來存儲這些信息。在結構上YAFFS和YAFFS2有一定的不同,具體結構可以去看一看這篇文檔http://www.aleph1.co.uk/node/38
那麼這個文件系統是如何運作起來呢。
操作文件系統的第一步自然是取得SuperBlock了,Yaffs文件系統本身在NAND Flash上並不存在所謂的SuperBlock塊,完全是在文件系統mount的過程中由read_super函數填充的,不過有意思的一點是,由於物 理上沒有存儲superblock塊,所以NAND Flash上的yaffs文件系統本身沒有存儲filesystem的魔數(MagicNum),在內存中superblock裡的s_magic參數也 是直接賦值的,所以存儲在NAND FLASH上的任何文件系統都能被當作yaffs文件系統mount上來,只是數據都會被當作錯誤數據放在lost+found目錄中,不知道這算不算 yaffs文件系統的一個bug。
通常一個具體的文件系統在VFS的Super_block結構中除了通用的數據外,還有自己專用的數據,Yaffs文件系統的專用數據是一個yaffs_DeviceStruct結構,主要用來存儲一些相關軟硬件配置信息,相關函數指針和統計信息等。
在mount過程執行read_super的過程中,Yaffs文件系統還需要將文件系統的目錄結構在內存中建立起來。由於沒有super塊,所以需要掃 瞄Yaffs分區,根據從OOB中讀取出的yaffs_tags信息判斷出是文件頭page還是數據page。再根據文件頭page中的內容以及數據 page中的ObjectID/ChunkID/serial Number等信息在內存中為每個文件(Object)建立一個對應的yaffs_object對象。
在yaffs_object結構中,主要包含了:
    如修改時間,用戶ID,組ID等文件屬性;
    用作yaffs文件系統維護用的各種標記位如髒(dirty)標記,刪除標記等等;
    用作組織結構的,如指向父目錄的Parent指針,指向同級目錄中其他對象鏈表的     siblings雙向鏈表頭結構
此外根據Object類型的不同(目錄,文件,鏈接),對應於某一具體類型的Object,在Yaffs_object中還有其各自專有的數據內容
       普通文件:文件尺寸,用於快速查找文件數據塊的yaffs_Tnode 樹的指針等
       目錄:目錄項內容雙向鏈表頭(children)
       鏈接:softlink的alias,hardlink對應的ObjectID
除了對應於存儲在NAND FLASH上的object而建立起來的yaffs_object以外,在read_super執行過程中還會建立一些虛擬對象(Fake Object),這些Fake Object在NAND FLASH上沒有對應的物理實體,比如在建立文件目錄結構的最初,yaffs會建立四個虛擬目錄(Fake Directory):rootDir, unlinkedDir, deleteDir, lostNfoundDir分別用作根目錄,unlinked對象掛接的目錄,delete對象掛接的目錄,無效或零時數據塊掛接的目錄。
通過創建這些yaffs_object,yaffs文件系統就能夠將存儲在NAND FLASH上數據系統的組織起來,在內存中維護一個完整的文件系統結構
另外,我在看YAFFS2的源代碼的時候發現,YAFFS2再mount和umount和YAFFS有所區別,增加一個checkpoint機制,每次在 umount的時候,YAFFS2會開闢專門幾個block用來存取一些信息,等待下次mount的時候就不需要掃瞄整個flash,而只有找出這幾個塊 就可以了,這樣可以大大加速mount的時間。不過仔細的原理我也沒有研究過。有興趣的話可以看一看這封郵件http://www.aleph1.co.uk/pipermail/yaffs/2006q2/002019.html



我們用的硬件是omap平台,跑得是linux-2.4.21。其實在這個版本的源代碼裡已經有了mtd的支持。不過看一下代碼可以發現,這個版本 mtd驅動對nandflash的支持並不好,而且支持的最大的page不過512byte,可能是代碼比較早的原因吧。因此移植的第一步是更新mtd驅 動。
首先從mtd官方網站下載最新的cvs(好像只有支持ipV6的,才可以直接要連到cvs庫。或者去ftp下載)。不過好像最新的cvs代碼有一點問題, 我用得是mtd-snapshot20050519。解壓這個snapshot,然後是打補丁。相信這一步應該都什麼問題。打完補丁後,可以去 drivers/mtd/nand/看一看,會發現多了好多文件,其中最最重要的是nand_base.c,關於讀寫擦的流程都是這裡實現的。
接下來的事情比較關鍵,就是定義底層的讀寫端口,讀寫控制。我們可以仿照驅動裡提供spia.c,針對自己的硬件寫一個XXX.C。上層的代碼都已經做 好,都是一些函數指針,我們只要把我們自己特定一些函數掛上去就可以了。這一步說難也難,說簡單也簡單。一開始可能覺得無從下手,其實只要多讀幾遍 nand目錄下提供的很多的例子程序,就會有些思路了。寫完這個,就修改一下nand目錄下的MakeFile.common,如果你懶一點,可以把 spia替換你的XXX.o,到時候記得配置內核在mtd的nand下選擇spia支持就行。你要想做得規範一點,其實也簡單,首先在MakeFile裡 加上obj-$(CONFIG_MTD_NAND_XXX) += XXX.o。然後修改Config.in,加上對XXX的配置支持就可以了。
接下來就是按部就班的配置內核,編譯。如果沒錯,那麼恭喜你。不過一般會有錯,我碰到的是提示少了幾個頭文件。我在snapshot裡可以找到,然後一一拷貝的include/linux下就可以了,^_^
開始測試:
首先在內核啟動的時候,mtd會檢測硬件系統中是否有flash存在,這一步是通過讀取flash的ID來判斷。如果這一步是正常的,那麼說明底層驅動的 流程和硬件上是沒有錯誤了。很不幸,我在這裡就掛了。系統提示can『t kernel paging request at virtual address 0x0c000000,顯示了一大堆寄存器和堆棧就死在那裡了。好不鬱悶。google了好久,發現這一個是一個地址映射的錯誤。因為linux是分為內 核空間和用戶空間的。對於arm來說,內核空間的地址應該是3G-4G處,3G以下是用戶空間。而我在寫我自己的xxx.c文件的時候,IO端口是這樣設 置的
this->IO_ADDR_R = 0x0c000000;
this->IO_ADDR_W = 0x0c000000;
顯然0x0c000000是不屬於內核空間的,因此造成了上述問題。
因此我們要把讀寫命令端口映射到內核空間去,這便是虛擬地址。
this->IO_ADDR_R = (unsigned long)ioremap(0x0c000000, SZ_1K);
this->IO_ADDR_W = (unsigned long)ioremap(0x0c000000, SZ_1K);
因此要用ioremap()函數。這些函數都定義在include/arch/asm-arm/io.h
至於物理地址和虛擬地址應是如何映射的,mm.c有定義
好了,現在內核可以順利啟動了,flash可以順利的認出來了。嘿嘿,掃瞄了一下,還找出了幾個壞塊。
現在flash現在已經成為linux一種設備了。下面這兩條命令
mknod /dev/mtd0 c 90 0
mknod /dev/mtdblock0 b 31 0
把flash的第一個分區映射為字符設備和塊設備。mtd/util/提供了許多有用的工具,比如nandwrite,flash_erase等等。交叉編譯後就可以使用了。
flash_eraseall /dev/mtd0 把分區零的內容全部刪除。
隨便新建一個文件xxx,然後nandwrite -p /dev/mtd0 xxx。其中參數p表示允許填充。因為文件的大小不一定是flash的page的整數倍。
如果提示寫進去了,那麼基本沒問題了。我不放心,又用自己的測試程序在ccs裡測了一下,果然寫進去了。那真叫一個開心啊。迫不及待的mount -t yaffs2 /dev/mtdblock0 /mnt
提示:NAND:geometry problem chunk size is 2048 type is yaffs2
然後退出了mount進程。一盤冷水澆了下來,告訴我苦難的里程剛剛開始咯……



過來好久,才想起要寫,後來發現關於YAFFS2的移植,一些網頁上已經寫的很詳細了,於是就懶得寫了,不如寫幾個自己碰到的問題吧,自己感覺還是挺關鍵的問題。
問題一:地址映射問題(MTD測試階段)
描述:在系統啟動的時候顯示can『t kernel paging request at virtual address 0x0c000000
同時系統 kill init進程。無法啟動
解決:發現是沒有進行地址映射的問題
linux把地址空間分為用戶空間和內核空間,內核空間從3G開始,而物理地址0x0c000000並不屬於內核空間,直接使用就造成了上述問題。
因此我們要把讀寫命令端口映射到內核空間去,這便是虛擬地址。
修改xxx.c:
this->IO_ADDR_R = (unsigned long)ioremap(0x0c000000, SZ_1K);
this->IO_ADDR_W = (unsigned long)ioremap(0x0c000000, SZ_1K);
因此要用ioremap()函數。這些函數都定義在include/arch/asm-arm/io.h
至於物理地址和虛擬地址應是如何映射的,mm.c有定義
問題二:mount問題(YAFFS2測試階段)
描述:mount錯誤,失敗,提示:
NAND:geometry problem chunk size is 2048 type is yaffs2
解決:追蹤代碼發現問題在yaffs_guts.c裡,從代碼可以發現,mount時要求的分區的block數目要大於
dev->internalStartBlock + dev->nReservedBlocks + 2。而我mount的分區大小為一個block,因此不滿足條件。後來mount一個為4095個block的分區,成功。
問題三:文件消失(YAFFS2測試階段)
描述:mount上分區後,可以向/mnt/flash1上寫文件,也可以讀取。
但是umount 後,再mount發現文件消失。  
解決:這個問題幾乎鬱悶了我半個月,幾乎每天都在網上看YAFFS的mail list。一堆一堆的英文,看得都想吐了。到最後快絕望時候,才查了出來,原來最新的mtd中的nand_base.c代碼有問題。在 nand_write_ecc()中,沒有寫oob的內容(如果你選擇NAND_ECC_NONE)。而在yaffs的接口函數中在既有數據又有oob信 息的時候,是直接調用mtd->write_ecc()的。由於nand_write_ecc()沒有寫oob的原因,導致yaffs從oob讀取 信息時,讀到的全是0xff,從而無法構建文件系統。這是最最主要的一個umount後文件消失的原因,其實文件信息全寫進去了,只是tag信息沒有寫進 去。
    後來我把mtd換成了mtd-sanpshot20050519,這裡的nand_write_ecc()是寫oob信息的。就解決的umount的問題。
    好了,終於寫完了。關於YAFFS2的記憶要告一段落了。很感謝YAFFS2給我帶來這個終身難忘的暑假,88吧。


只能感嘆說,遷入系統愈來愈完整,看到以前人的辛苦

2012年3月12日 星期一

busybox目錄與檔案補齊

busybox一般編譯出來,真的精簡到可以,很多檔案目錄都缺orz,製作這些目錄跟檔案要下一堆指令,乾脆寫成script,這裡紀錄一下
話說~micro2440還真比不上BB,不過這價格就將就吧

2012年3月9日 星期五

新玩具~對岸的友善之臂micro2440

剛剛到貨,一收到,哇~一大箱,心裡就涼了一半,不會是很大台吧@@a,拆開~果然是很大台,來跟beagleboard xm (BB)打個招呼吧
體積:
很明顯,BB不到micro2440的一辦大小,高度也是BB比較低
I/O port:
介面也不會比micro2440遜色(micro2440 com port倒是多了兩個)
CPU & memory:
可是BB可是雙核心阿A8(1G)+DSP,micro2440只有400MHz的A8還是A9,記憶體也比BB來的少
價格:
當然價格也差了許多,BB可以買兩台micro2440了,但是如果可以,我還是寧願使用BB

如果要學習,或許micro2440比較無所謂,玩壞了也不心疼,但是如果要當玩具,我想BB比較耐用。簡單的說,BB我會想要把它裝殼子(但是殼子好貴,國外的金屬外殼,快要可以再買一台BB),但是micro2440就讓它裸奔吧

2012年3月8日 星期四

Posix Message Queue (1)

Richard Steven的大作:

header file: mqueue.h
mqd_t mq_open(const char *name, int oflag, ...);
int mq_close(mqd_t mqdes);
int mq_unlink(const char *name);
回傳一個handler,型態為mqd_t,close表示關閉,unlink並不會真正刪除,而是隨著系統對close作count,直到count=0,也就是最後一個process使用close,才會刪除message queue

int mq_getattr(mqd_t mqdes, struct mq_attr *attr);
int mq_setattr(mqd_t mqdes, struct mq_attr *attr,mq_attr *oattr);
struct mq_attr{
long mq_flags;
long mq_maxmsg;
long mq_msgsize;
long mq_curmsgs;
};
可以取得各種屬性,其中mq_maxmsg跟mq_msgsize都只能在mq_open的時候設定,免得硬要把已經在msg queue內的message縮小,這樣的操作屬於不合理

message queue收送
int mq_send(mqd_t mqdes,const char *ptr, size_t len, unsigned int prio);
ssize_t mq_receive(mqd_t mqdes,const char *ptr, size_t len, unsigned int prio);

書中有提到一個問題就是message queue資料型態被定義為char*,其實建議應該定義為void*
另外就是在receive的時候必須先使用mq_getattr取得資料的大小,如果太小將會傳回錯誤,書中的程式figure 5.7就是這麼作,其實我認為應該是使用最大的msg size最為配置大小才不會產生錯誤,因為如果多人同時讀取message queue難保沒有race condition,不然就得加上file lock的機制

message queue跟FIFO一個很大的差異就是優先權以及個數,對FIFO來說,他就是一個stream,可是message是很多個package組成,再者FIFO並沒有優先權的概念,message queue有

另外必須注意到系統message queue的限制,書中提到可以使用sysconf來讀取

後面開始探討message非同步的問題,這就牽涉到system call以及非同步訊號安全函數的使用,等後面有空再寫

2012年3月7日 星期三

android開發的第一步

很單純(應該吧)使用android sdk加上eclipse

  • 先下載sun的java sdk,我使用的是之前的1.6版本
  • 先到http://developer.android.com/sdk/index.html下載SDK starter,我下載的是installer_r16-windows.exe,這個會從網路下載SDK完整的套件下來安裝到電腦,以windows來說,會安裝到c:/Programming Files/Android/android-sdk
  • 過程中可能會詢問啥htcPhone或者MotoDEV之類的,我一律按下取消,可能是HTC或者Moto開發者特有的API吧,但是需要帳號密碼,沒有這個需求,就把它關閉了
  • 過程會詢問要安裝哪個平台,我選擇的2.3的平台
  • 跟著下載eclipse for java(此時eclipse classic為3.7),執行後,選擇[Help]=>[Install New Software],在裡面新增來源http://dl-ssl.google.com/android/eclipse/site.xml,跟著安裝Android DDMS & Android Development Tools
  • 安裝完畢eclipse會詢問要不要重新開啟,重開啟之後,選擇android SDK路徑,就是前幾步安裝的路徑
  • 接下來就可以在New Project裡面選擇[Android Project],跟著填寫相關資訊,就完成了一個基本的Project
  • 在工具列上面會有個Icon,類似一個機器人貼在一個機器內,[Open Android Virtual Devices Management],在裡面新增一個device
接下來可以打開Project,可以在裡面輸入code了,類似底下

package firsttask.hello;

import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;

public class FirstSimpleActivity extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        TextView tv=new TextView(this);
        tv.setText("hello , world!");
        setContentView(R.layout.main);
    }
}

跟著按下[run],他會詢問要執行哪個,選擇[android application],因為模擬器的關係,模擬器模擬一個很慢速cpu的模擬器,跑得很慢orz,可以去上個廁所再回來,因為再好的機器也快不起來
接著就會看到

2012年3月6日 星期二

Pipe與FIFO

header file : unistd.h
int pipe(int fd[2]); 正確回傳0錯誤回傳-1
相當單純的一個函數,fd[0] 供 read,fd[1]提供write
使用於fork()的時候,通常provider關閉fd[0],只有使用fd[1],相反的comsumer則是關閉fd[1],使用fd[0],關閉pipe則是使用close()
pipe是半雙工的模式,如果要使用全雙工,richard steven建議使用兩組pipe來模擬

header file: stdio.h
FILE *popen(const char *cmd, const char *type);
int pclose(FILE *stream);
類似使用檔案一樣,只是執行一道command,然後由stdout讀入資料,或者使用寫入模式,經stdin將資料輸入command中

Pipe有兩個問題,第一個就因為file desriptor只有在程式執行間產生,也就是大致上只能適用於parent/child之間的關係,對於不相關的process就無法溝通,第二個問題是沒有權限的管理,因為設計的關係,本身不遭遇/提供這樣的情境


FIFO的設計就是用來解決這問題
header files: sys/types.h, sys/stat.h
int mkfifo(const char *pathname, mode_t mode);

由於是輸入路徑,所以只要知道檔案路徑就可以在process之間的做溝通,取得回傳值之後就可以使用open來開啟,但是FIFO不支援lseek操作,會回傳ESPIPE錯誤
關閉一樣使用close就可以,但是因為mkfifo會產生file,所以必須使用unlink()來刪除

至於FIFO還有其他的特性,如nonblock,晚點有時間再寫

beagleboard xm的輸出悲劇

話說~想要讓beagleboard xm輸出d-sub訊號,但是可能還是不可能呢?我不知道,但是.....至少就線材上就挑錯了,這樣就悲劇了
詳細情形請上wikipedia他就會告訴你哪種dvi接頭有可能可以輸出d-sub訊號,但是~但是~要從hdmi訊號轉成d-sub訊號,還是相當有可能失敗,我網路上看到一個可能性,等我試驗後再報告,最後一條路就是印象中網路上有看到人自已DIY d-sub輸出,最不得已的選項

IPC object的life time

IPC Objectlifetime
FIFOprocess
Posix mutexprocess
Posix conditional varprocess
Posix read/write lockprocess
fcntl recorder lockprocess
Posix message queuekernel
Posix named semaphorekernel
Posix memory semaphoreprocess
Posix shared memorykernel
System V message queuekernel
System V semaphorekernel
System V shared memorykernel
TCP socketprocess
UDP socketprocess
Unix domain socketprocess

明顯的kernel將會隨著有無釋放相關的IPC物件而影響lifetime,另外一個影響因素就是為是否為kernel等級,如果是kernel的lifetim,該物件如果沒有釋放,將會被保留到系統結束為止,換句話說,他會相當的佔用系統的資源

底下是兩大主流Posix與System V所支援的IPC的head file
IPC ObjectHeader filefunctions
Posix msg queuemqueue.hmq_open、mq_close、mq_closemq_getattr、mq_setattrmq_send、mq_receive、mq_notify
Posix semaphoresemaphore.hsem_open、sem_close、sem_unlinksem_init、sem_destroysem_wait、sem_trywait、sem_post、semgetvalue
Posix shared memorysys/mman.hshm_open、shm_unlinkftruncate、fstatmmap、munmap
System V msg queuesys/msg.hmsggetmsgctlmsgsndmsgrcv
System V semaphoresys/sem.hsemgetsemctlsemop
System V shared memorysys/shm.hshmgetshmctlshmatshmdt
在Posix系統,藍色為建立/開啟予刪除的function,而System V則是只有建立,同樣綠色都為屬性操作的函數,System V大多把刪除的部分交給綠色的function,最後紅色則是物件操作,看的出來system V大概應該是依賴輸入的flag/definition去作為辨識,雖然感覺function比posix少,但是操作起來語意可能反而不明顯,但是也換來了一個好處,Posix擴充可能必須新增function name,但是System V只要擴充參數的意義跟定義就好

2012年3月4日 星期日

toolchain安裝工具

http://elinux.org/Toolchains
建立toolchain有時候是浩大工程,或者說如果需要開發很多projects,如何建置適合的toolchain很花費功夫,有人開發出了buildroot之類的工具,但是版本也很多,特色各有差異,剛好爬文爬到,就記錄一下人家的說法

Shared Memory in C (2)

今天翻出了Unix Network Programming Vol. 2,看了shared memory
原來還有分posix跟跟system v阿,之前用的是system v的share memory,主要利用到幾個呼叫函數
#include<sys/shm.h>
shmget 建立一塊share memory
shmat 將share memory attached到某個process的空間內
shmdt 分離share memory與該行程
shmctl share meory的操作,包含刪除的部分

一直誤shared memory是parent/child或者child/child之間的資訊交換使用,事實上他可以超越許多process,也就是兩個processes之間沒有關係也可以使用shared memory做溝通,不過中間有個重點就是key的產生,在使用shmget的時候會需要用到一個唯一的key去產生,只要知道這個key value,就可以取得相對應的shared memory

在書中使用ftok這個function去產生唯一的key,其實有個小小的陷阱,ftok接受一個存在的檔案路徑,並且產生相對應的唯一key,也就是只要預期兩個相同的檔案路徑就會產生相同的key,但是事實上man page有提到,如果說該檔案路徑被刪除後就有可能不一樣,也就是說假設A, B兩個processes,A使用ftok(path1,1)取得key1,當path1重新被建立(如刪除後又重新新增),這時候B使用ftok(path1,1)可能會取得key2且key2!=key1

效能方面,書中也有所解說,shared memory與pipe/FIFO/message que這些空間主要都由kernel在維護,但是後者是由process A讀取檔案(system call 1)後寫入pipe/FIFO/message queue(system call 2),跟著再由process B取得(system call 3),最後再由process B輸出到(system call4)檔案,也就是後者進行了四次的system call。由於shared memory是直接對於kernel將共享的記憶體映射到process空間,也就是不用透過kernel來管理,這樣只要兩次(system call 1, 4),所以效能會比較好

雖然richard steven大師這樣的解釋讓人比較了解差別跟應用的情境,但是實際上實作的差異還是有分別,如shared memory屬於哪個process?還是屬於kernel?如果實際屬於kernel那就嚴重囉,表示使用者如果讓他產生溢位的話可能會危害到kernel,如果屬於process,那他應該屬於哪個process的?這些疑問等以後有時間再來trace code好了

2012年3月3日 星期六

[舊聞]Java 6上的swing framework擴展

http://java.sun.com/developer/technicalArticles/javase/swingappfr/#actions
有人問到我一些關於annotation的東西,讓我想到這個,已經有三四年沒看到了,竟然依時間找不到,找到就隨手做個筆記

新玩具完工~雲端投影片~

做了一個雲端投影的應用,弄了許久,終於搞定,這只是為了自己好玩開發出來的。也在網路程式上重新在上了一課,以前老是用高階的程式語言,開發的時候輕鬆許多,但很多時候也有許多限制,必須重新檢視網路的能力,再重新把Richard Steven的書翻出來,有了更深刻的體會,以前一些隱晦不明的地方,隨著對系統的了解也有比較深入的認知

比方以前很少去動到的socket option的設定,這次也用到了,因為在報告過程之中,一個socket可能會保留很久,預設的timeout時間太短了

setsockopt (sockfd, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout,sizeof(timeout))

另外很多高階的程式語言其實無法很貼近系統,對於一些IPC的操作之類顯得比較無法做細部的調整,畢竟高階語言大多要跨平台,只能就共同的特性做對應

最後就是有些陷阱的部分,比方說使用24bits顯示模式,用程式抓下來的圖片最多不會超過24bits(很多人心裡應該會這樣默認吧),很可惜有些程式很好心的幫我們轉成了32bits,結果在解析圖片過程就可能造成錯誤

也遇到了一個無法解決的問題,那就是開發過程中因為程式的不正確讓connection若入的LAST_ACK的模式,但是client一直沒有反應,這時候即使把server的process殺了,port #還是會被綁住5~6mins之久,而且我也沒有找到解決方式,網路上大多釋放port #的方式是使用kill process的方式,對這個問題是沒有幫助的

2012年3月1日 星期四

signal process、shared memory與IPC

shared memory這手法已經是常見的IPC手法,但是在開發期間往往程式會在無預期的地方出錯,或者是手動ctrl+c給予中斷,這時候必須加入signal process讓程式自行清理,或者類似socket的地方,不然會有port number或者shared memory繼續被占據,下次執行前必須手動清理

常見的signal有
SIGINT : 由ctrl+c產生
SIGTERM : 關機或者由其他方式送入
最後在IPC產生的時候,由child process可以要求系統對於parent process結束的時候送出一個signal給child process
prctl(PR_SET_PDEATHSIG, SIGHUP);
這個只適用於linux,屬於kernel額外提供的功能


但是一旦需要再signal process中回收資源的後,表示資源必須是global variable,因為我暫時想不到其他方式,這某種程度讓程式變得比較不穩定,當然可以想辦法寫入shared memory中,但是這樣一來就面臨shared memory規劃的問題(要小心不要輸入的資料蓋錯地方),還有race condition的議題

愈是深入IPC就愈覺得System Programming因作業系統而異的特色

參考資料:
http://www.win.tue.nl/~aeb/linux/lk/lk-5.html
http://www.cs.cf.ac.uk/Dave/C/node24.html
http://www.c.happycodings.com/Gnu-Linux/code18.html
http://hylcarson.blog.sohu.com/54735006.html