2009年10月9日 星期五

ubuntu9.04 install svnserver


 使用方式

 Subversion完整的參考文件
 

     (英) http://svnbook.red-bean.com/
     (中) http://svn.stu.edu.tw/svnbook/
 (Q&A) http://subversion.tigris.org/faq.html

  如何安裝 svn server 端
 #apt-get install subversion

 與Apache 結合的套件
 #apt-get install libapache2-svn

  如何使用 svn server 端
 

 建立起 svn 的 repository 的 tree

 其主要有三種類型的指令
 1. 管理 (svnadmin) : 主要是控制及管理project版本的整體的架構
 2. 查詢 (svnlook) : 主要是查詢關於版本的相關資訊
 3. 服務 (svnserve) : 處理其對外的服務設定

 使用最基本的架設....
 建立使用群組
 #groupadd  svnbrook
 將自己(brook)及www-data(apapch2帳戶)添加至該群組 #vi /etc/group
 最後一行就改成 svnbrook:x:1001:brook,www-data #mkdir /home/svn      #建立svn資料庫的父路徑 #cd /home/svn
 #mkdir myproject01   #建立svn資料庫的專案目錄
 #svnadmin create /home/svn/myproject01 #使用svn命令,建立svn資料庫
 
此時你可以在 myproject01 下看到
 conf dav db format hooks locks README.txt
 
#chown -R root:subversion myproject         #更改目錄群組
 
#chmod -R g+rws myproject   #增加群組用戶讀寫及新增目錄權限

 若要用 apache 做為連結管道再設定下述 (在此我們用 ssh 做為連結管道)
 

 #vi /etc/apach2/mods-available/dav_svn.conf

 加入
 
<Location /svn/myproject01>
    DAV svn
    SVNPath /home/svn/myproject01
    AuthType Basic
    AuthName "myproject subversion repository"
   AuthUserFile /etc/subversion/passwd
  <LimitExcept GET PROPFIND OPTIONS REPORT>
     Require valid-user
  </LimitExcept>
 </Location>

 再增加使用者及密碼
 
#cd /etc/subversion
 #touch passwd
 #htpasswd -c passwd brook
 New password:
 Re-type new password:
 Adding passwd for user brook

 重新啟動  apache2
 

 #/etc/init.d/apache2 restart

 你就可以在網頁上看到資訊

  如何使用 svn client 端
 

 其主要指令是 svn 來處理..基本的資料夾加刪...

 當我們是用 ssh 連入 svn server 時
 svn co svn+ssh://使用者id@hostname或hostip/home/svn/myproject
 連續輸入兩次使用者密碼即可進入

 先使用 svn update 更新至最新版本  以避免  conflict
 再使用 svn commit
 要將資料上傳時   再使用 svn add + 增加的資料夾及檔案
 這時會有設定...將要上傳的資料加入 設定中即可

  如何使用 svn 更新檔案

 在 svn server 端  是記載版本的變更

 故..................看不到修定的版本結果

 在 svn server 須使用 checkout 將 更新的資訊取出
 在本機新開的資料夾  brooktmp
 #mkdir brooktmp
 #cd brooktmp
 #svn co file:///home/svn/myproject01
 在 brooktmp 的資料夾中  即有最新版本的  myproject01 的資料夾

  將 svn server 連上網路使用

 你可以使用 Apache2 的 http 網頁設定  或 其 SSL 的 https 設定
 在此我們是使用 ssh 連入

 先用  WINSCP 將新更改的版本  Copy (F5) 置入  電腦 (Server 或另一台電腦)

 再用  svn 更新之   (另一台電腦需再用 ssh+svn 連入 Server)


 reference:
 http://svn.stu.edu.tw/svnbook/book.html#svn-ch-5-sect-4.2.1
 http://www.duduwolf.com/post/setting_up_subversion.asp
 http://www.blogjava.net/pandawang/archive/2006/09/05/67844.html

2009年10月6日 星期二

U-Boot的移植



U-Boot Practically Porting Guide



Author: Aaron Wong aaronwong@engineer.com




U-Boot的移植之()進階篇:從源代碼看系統啟動過程



為什麼要分析源代碼?分析優秀的源代碼本身就是一個學習的過程,也是進行深入研究的必經之路。不過在此我們的主要目的並非要研究U-bootBootloader技術本身,而僅僅是為了成功的並且恰當的將U-Boot移植到我們的開發板上。只有結合源代碼瞭解了U-boot的系統引導過程,才能在移植和調試過程中保持清晰的思路,才能在碰到困難和問題時從根本上加以解決。



在動手分析之前,至少應該對U-Boot的源代碼結構有基本的瞭解,很多參考書都有這方面的介紹,華清遠見的《嵌入式Linux系統開發技術詳解——基於ARM》的講解就比較清晰。



本文以lubbock開發板為例,以系統啟動的流程為線索進行縱向分析:後續的移植工作也將以此開發板為模板。Lubbock使用PXA255處理器。



首先要找到程序入口點。從board/lubbock/u-boot.lds可以發現,u-boot的程序入口為_start,在cpu/pxa/start.o當中。因此首先要分析start.S程序,U-Boot中所有的PXA系列的處理器都從這裡開始執行第一條語句。






.globl _start




_start: b reset




ldr pc, _undefined_instruction




ldr pc, _software_interrupt




ldr pc, _prefetch_abort




ldr pc, _data_abort




ldr pc, _not_used




ldr pc, _irq




ldr pc, _fiq




0x0地址開始是ARM異常向量表,學過ARM體系結構與編程的都明白,非常簡單,不多廢話。一上電的第一條指令是跳轉到reset復位處理程序:






reset:




/* 進入SVC模式 */




#ifndef CONFIG_SKIP_LOWLEVEL_INIT




bl cpu_init_crit /* we do sys-critical inits */




#endif




#ifndef CONFIG_SKIP_RELOCATE_UBOOT




relocate:




......




一般不要定義CONFIG_SKIP_LOWLEVEL_INIT,因此,接下來跳轉到cpu_init_crit處開始執行:






cpu_init_crit:




/* 屏蔽所有中斷 */




/* 設置時鍾源,關閉除FFUART,SRAM,SDRAM,FLASH以外的外設時鍾 */




......




#ifdef CFG_CPUSPEED




ldr r0, CC_BASE /* 時鍾控制寄存器基址 */




ldr r1, cpuspeed




/* cpuspeed: .word CFG_CPUSPEED */




str r1, [r0, #CCCR]




mov r0, #2




mcr p14, 0, r0, c6, c0, 0









setspeed_done:




#endif /* CFG_CPUSPEED */




/* 跳轉到lowlevel_init,這裡ipr12,用作暫存寄存器 */




mov ip, lr




bl lowlevel_init




mov lr, ip




/* Memory interfaces are working. Disable MMU and enable I-cache. */




ldr r0, =0x2001




......




/* 關閉MMU,使能I-Cache(可選) */




mov pc, lr /* 這裡是從cpu_init_crit返回到relocate標號 */









可見,在cpu_init_crit中的主要工作是設置時鍾,配置處理器主頻(這時CPU的工作頻率還沒有改變),調用lowlevel_init函數進行底層初始化(包括調整處理器工作頻率、系統總線頻率、存儲器時鍾頻率以及存儲系統的初始化等工作),隨後關閉MMU並使能I-Cache,再返回。



lowlevel_init函數在board/lubbock/lowlevel_init.S中定義,其流程都是按照PXA27X的開發手冊來的,所以不再贅述。僅指出,其中的寄存器在include/asm-arm/arch-pxa/pxa-regs.h頭文件中定義,寄存器初始化值在include/configs/lubbock.h中定義。另外,在後面的實際移植工作中,由於目標板XSBASE270使用的PXA270處理器,可使用adsvix開發板的lowlevel_init.S文件(lubbock中沒有開啟turbo模式)



接著程序的執行線索進行分析。從cpu_init_crit返回後就開始relocate(重定位),即將U-bootFLASH存儲器搬運到SDRAMTEXT_BASE開始的存儲空間(TEXT_BASEboard/lubbock/config.mk中定義),並初始化堆棧(清零.bss),以在SDRAM中開始進入到Bootloader stage 2C程序入口。Relocate部分開始的代碼如下:






/* 之前已定義的部分變量有:




_TEXT_BASE: .word TEXT_BASE




_armboot_start: .word _start




_bss_start: .word __bss_start




_bss_end: .word _end */




relocate: /* relocate U-Boot to RAM */




adr r0, _start /* r0 <- current position of code */




ldr r1, _TEXT_BASE /* test if we run from flash or RAM */




cmp r0, r1 /* don't reloc during debug */




beq stack_setup









ldr r2, _armboot_start /* 讀入_startr2 */




ldr r3, _bss_start /* 讀入__bss_startr3 */




sub r2, r3, r2 /* r2 <- size of armboot */




add r2, r0, r2 /* r2 <- source end address */









copy_loop:




ldmia r0!, {r3-r10} /* copy from source address [r0] */




stmia r1!, {r3-r10} /* copy to target address [r1] */




cmp r0, r2 /* until source end addreee [r2] */




ble copy_loop









/* Set up the stack */




stack_setup:




ldr r0, _TEXT_BASE /* upper 128 KiB: relocated uboot */




sub r0, r0, #CFG_MALLOC_LEN /* malloc area */




sub r0, r0, #CFG_GBL_DATA_SIZE /* bdinfo */




#ifdef CONFIG_USE_IRQ




sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)




#endif




sub sp, r0, #12 /* leave 3 words for abort-stack */









clear_bss:




ldr r0, _bss_start /* find start of bss segment */




ldr r1, _bss_end /* stop here */




mov r2, #0x00000000 /* clear */









clbss_l:str r2, [r0] /* clear loop... */




add r0, r0, #4




cmp r0, r1




ble clbss_l









ldr pc, _start_armboot









_start_armboot: .word start_armboot




這是很經典的一段代碼,相信學習凡是過ARM編程的,都分析過這段代碼,所以也不再贅述。之所以列出這段代碼,一是為了找到C程序入口start_armboot,二是為了給出U-Boot的一個存儲器映射圖:







這個圖可以幫助我們更好地理解後續的C語言代碼以及U-Boot對內存的分配與使用情況。



接下來進入到Bootloader Stage 2C語言代碼部分,入口是start_armboot,對應的源文件是lib_arm/board.c,這一文件對所有的ARM處理器都是通用的,因此在移植的時候不用修改。相關源代碼如下:






DECLARE_GLOBAL_DATA_PTR




/* include/asm-arm/global_data.h中定義的一個全局寄存器變量的聲明:




* #define DECLARE_GLOBAL_DATA_PTR register volatile gd_t *gd asm ("r8")




* 用於存放全局數據結構體gd_t的地址。




*/




void start_armboot (void)




{




init_fnc_t **init_fnc_ptr;




char *s;




#ifndef CFG_NO_FLASH




ulong size;




#endif




#if defined(CONFIG_VFD) || defined(CONFIG_LCD)




/* 本次移植暫不配置VFDLCD,後面也將不考慮的部分略去 */




/* 初始化全局數據結構體指針gd */




gd = (gd_t*)(_armboot_start - CFG_MALLOC_LEN - sizeof(gd_t));




....../* memsetlib_generic/string.c中定義*/




memset ((void*)gd, 0, sizeof (gd_t)); /*0填充全局數據表*gd */




gd->bd = (bd_t*)((char*)gd - sizeof(bd_t));




memset (gd->bd, 0, sizeof (bd_t)); /*0填充(初始化) *gd->bd */









monitor_flash_len = _bss_start - _armboot_start;









for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {




if ((*init_fnc_ptr)() != 0) {




hang (); /* 打印錯誤信息並死鎖 */




}




}









#ifndef CFG_NO_FLASH




/* configure available FLASH banks */




size = flash_init (); /* drivers/cfi_flash.c或自定義 */




display_flash_config (size);




#endif /* CFG_NO_FLASH */









/*armboot_start is defined in the board-specific linker script*/




mem_malloc_init (_armboot_start - CFG_MALLOC_LEN);




......




/* initialize environment */




env_relocate ();









/* IP Address */




gd->bd->bi_ip_addr = getenv_IPaddr ("ipaddr");




/* MAC Address */




{




int i;




ulong reg;




char *s, *e;




char tmp[64];









i = getenv_r ("ethaddr", tmp, sizeof (tmp));




s = (i > 0) ? tmp : NULL;









for (reg = 0; reg < 6; ++reg) {




gd->bd->bi_enetaddr[reg] = s ? simple_strtoul (s, &e, 16) : 0;




if (s)




s = (*e) ? e + 1 : e;




}




}









devices_init (); /* get the devices list going. */




.......




jumptable_init ();




console_init_r (); /* fully init console as a device */




enable_interrupts (); /* enable exceptions */









/* Perform network card initialisation if necessary */




#if defined(CONFIG_DRIVER_SMC91111)| |defined (CONFIG_DRIVER_LAN91C96)




if (getenv ("ethaddr"))




smc_set_mac_addr(gd->bd->bi_enetaddr);




#endif /* CONFIG_DRIVER_SMC91111 || CONFIG_DRIVER_LAN91C96 */









/* Initialize from environment */




if ((s = getenv ("loadaddr")) != NULL) {




load_addr = simple_strtoul (s, NULL, 16);




}









#if defined(CONFIG_CMD_NET)




if ((s = getenv ("bootfile")) != NULL)




copy_filename (BootFile, s, sizeof (BootFile));




#endif




#ifdef BOARD_LATE_INIT




board_late_init ();




#endif




......




/*main_loop() can return to retry autoboot, if so just run it again.*/




for (;;) {




main_loop ();




}




}




gd_t是全局數據表類型,在include/asm-arm/global_data.h中定義如下:






/*




Keep it *SMALL* and remember to set CFG_GBL_DATA_SIZE > sizeof(gd_t)




*/




typedef struct global_data {




bd_t *bd;




unsigned long flags;




unsigned long baudrate;




unsigned long have_console; /* serial_init() was called */




unsigned long reloc_off; /* Relocation Offset */




unsigned long env_addr; /* Address of Environment struct */




unsigned long env_valid; /*Checksum of Environment valid?*/




unsigned long fb_base; /* base address of frame buffer */




.......




void **jt; /* jump table */




} gd_t;




其中,bd_tinclude/asm-arm/u-boot.h中定義如下:






typedef struct bd_info {




int bi_baudrate; /* serial console baudrate */




unsigned long bi_ip_addr; /* IP Address */




unsigned char bi_enetaddr[6]; /* Ethernet adress */




struct environment_s *bi_env;




ulong bi_arch_number; /* unique id for this board */




ulong bi_boot_params; /* where this board expects params*/




struct /* RAM configuration */




{




ulong start;




ulong size;




}bi_dram[CONFIG_NR_DRAM_BANKS];




} bd_t;




jt是函數數組指針,隨後將在jumptable_init()函數中初始化。



lib_arm/board.c的源碼不難分析出系統的啟動流程:首先初始化全局數據表,然後順序執行函數指針數組init_sequence中的一系列初始化函數——由其在本文件中的相關定義可得知初始化流程:






typedef int (init_fnc_t) (void);




init_fnc_t *init_sequence[] = {




cpu_init, /* basic cpu dependent setup -- cpu/pxa/cpu.c */




board_init, /* basic board setup --board/lubbock/lubbock.c */




interrupt_init, /* set up exceptions -- cpu/pxa/interrupts.c */




env_init, /* initialize environment -- common/env_flash.c */




init_baudrate, /* initialze baudrate settings--lib_arm/board.c */




serial_init, /* serial communications setup--cpu/pxa/serial.c */




console_init_f, /* stage 1 init of console -- common/console.c */




display_banner, /* say that we are here -- lib_arm/board.c */




#if defined(CONFIG_DISPLAY_BOARDINFO)




checkboard, /* display board info */




#endif




dram_init, /* configure available RAM banks --board/lubbock/lubbock.c */




display_dram_config, /* lib_arm/board.c */




NULL,




};




在執行這個函數序列的過程中,任何一個函數異常返回都會導致u-boot「死鎖」或說「掛起」在hang()函數的死循環當中。



若一切順利,接下來就調用flash_init()函數初始化CFI FLASH(針對NOR型閃存而言),該函數在drivers/cfi_flash.c中定義,不過,只有在目標板頭文件中」#define CFG_FLASH_CFI_DRIVER」之後該驅動才會被編譯;在lubbocku-boot實現當中,include/configs/lubbock.h中沒有定義CFG_FLASH_CFI_DRIVER,而是在board/lubbock/ flash.c中實現了自己的FLASH驅動,包括flash_init()在內。在移植U-Boot時,可以根據實際情況選擇使用U-Boot自帶的FLASH驅動還是自己編寫新的驅動。如果配置了NAND閃存,還會對其進行初始化;筆者的XSABSE270板沒有銲接NAND FLASH,故對此不作討論。



接下來調用env_relocate()函數初始化環境變量,該函數在common/env_common.c文件中定義。在同一文件中可以發現還定義了一個字符數組default_environment[],用於描述缺省的環境變量,這些都要在include/configs/lubbock.h頭文件中進行設置,包括啟動命令CONFIG_BOOTCOMMAND,波特率CONFIG_BAUDRATEIP地址CONFIG_IPADDR等等。



然後是獲取自設置的目標板的網絡地址,包括IP地址和MAC地址。



再然後是調用common/devices.c中定義的devices_init()函數來創建設備列表,並初始化相應的設備,主要是」stdin」,」stdout」,」stderr」以及自定義的設備如I2CLCD等。這些相關代碼是與平台無關的,因此從移植的角度考慮,不必作細緻的研究與分析。



接著調用common/exports.c中定義的jumptable_init()函數,初始化全局數據表中的跳轉表gd->jt,跳轉表是一個函數指針數組,定義了u-boot中基本的常用的函數庫;而gd->jt是這個函數指針數組的首指針。部分代碼如下:






void jumptable_init (void) {




int i;




gd->jt = (void **) malloc (XF_MAX * sizeof (void *));




for (i = 0; i < XF_MAX; i++)




gd->jt[i] = (void *) dummy;




gd->jt[XF_get_version] = (void *) get_version;




gd->jt[XF_malloc] = (void *) malloc;




gd->jt[XF_free] = (void *) free;




gd->jt[XF_getenv] = (void *) getenv;




gd->jt[XF_setenv] = (void *) setenv;




......




}




上面的XF_get_versionXF_mallocXF_free等在include/exports.h的枚舉變量中定義,因此,實際上是作為」Label式整型序號」使用,即XF_get_version=1, XF_malloc=2, XF_free=3 ...,相關代碼如下:






enum { /* include/exports.h */




#define EXPORT_FUNC(x) XF_ ## x ,




#include <_exports.h>




#undef EXPORT_FUNC




XF_MAX



};




EXPORT_FUNC(get_version)




EXPORT_FUNC(getc)




EXPORT_FUNC(tstc)




EXPORT_FUNC(putc)




EXPORT_FUNC(puts)




EXPORT_FUNC(printf)




......... /* include/_exports.h */




由於這些也是平台無關的代碼,因此在移植過程中也不必深究。



然後是調用common/console.c中定義的函數console_init_r()初始化串口控制台,這同樣是平台無關的代碼,所以不必關心。



這時U-Boot的基本功能已經初始化完畢,便可開中斷,並進行附加功能的配置與初始化,包括網卡驅動配置,目標板使用LAN91C1111網卡,對應SMC91111網卡驅動,可以根據需要配置其他的網卡驅動如CS8900等,這些都在include/configs/lubbock.h中定義。



然後是調用board/lubbock/lubbock.c中定義的board_late_init()函數進行板級的後期初始化,實際上是配置stdoutstderr的硬件設備。相關源代碼如下:






int board_late_init(void)




{




setenv("stdout", "serial");




setenv("stderr", "serial");




return 0;




}








最後需要注意的一個很重要的文件是lib_arm/armlinux.c,它實現的功能包括設置內核啟動參數,並負責將這些參數傳遞給內核,最後跳轉到Linux內核入口函數,將控制權交給內核。



具體傳遞哪些參數,是通過在include/configs/lubbock.c中指定條件編譯選項來控制的,對應於lib_arm/armlinux.c中的部分源代碼形式如下:






#if defined (CONFIG_SETUP_MEMORY_TAGS) || \




defined (CONFIG_CMDLINE_TAG) || \




defined (CONFIG_INITRD_TAG) || \




defined (CONFIG_SERIAL_TAG) || \




defined (CONFIG_REVISION_TAG)




static void setup_start_tag (bd_t *bd);









# ifdef CONFIG_SETUP_MEMORY_TAGS




static void setup_memory_tags (bd_t *bd);




# endif




static void setup_commandline_tag (bd_t *bd, char *commandline);









# ifdef CONFIG_INITRD_TAG




static void setup_initrd_tag (bd_t *bd, ulong initrd_start,




ulong initrd_end);




# endif




static void setup_end_tag (bd_t *bd);




static struct tag *params;




#endif




......




void do_bootm_linux (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[],




ulong addr, ulong *len_ptr, int verify)




{




......




void (*theKernel)(int zero, int arch, uint params);




......




#ifdef CONFIG_CMDLINE_TAG




char *commandline = getenv ("bootargs");




#endif




theKernel = (void (*)(int, int, uint))ntohl(hdr->ih_ep);




......




theKernel (0, bd->bi_arch_number, bd->bi_boot_params);




}




關於這個參數列表中各個參數的定義及含義,以及參數列表的初始化過程,可以參考Booting ARM Linux一文。內核是如何找到這個參數列表在內存中的位置,以接收這些參數的呢?實際上,參數列表(tag list)在內存中的起始地址會保存在通用寄存器