2011年11月6日 星期日

關於bridge中hard_header_len/needed_headroom的問題


我的interface在收送上本來沒有問題,但是當它和其他interface作bridge之後就發生crash了,後來才發現是head不夠大,於是參考這篇文章"关于bridge中hard_header_len值的问题",做了些修改,原因是因為我的device在預留head room時,是hard_header_len+needed_headroom。而且有些local generate的packet會使用LL_RESERVED_SPACE()這macro來保留head room,而LL_RESERVED_SPACE()也會使用到needed_headroom,所以最保險的作法就是同時設定bridge的hard_header_len和needed_headroom。
--- a/net/bridge/br_if.c
+++ b/net/bridge/br_if.c
@@ -369,6 +369,10 @@ void br_features_recompute(struct net_bridge *br)
 {
        struct net_bridge_port *p;
        unsigned long features, mask;
+#if 1 // Brook.
+    unsigned short max_hard_header_len = ETH_HLEN;
+    unsigned short max_needed_headroom = 0;
+#endif

        features = mask = br->feature_mask;
        if (list_empty(&br->port_list))
@@ -379,8 +383,22 @@ void br_features_recompute(struct net_bridge *br)
        list_for_each_entry(p, &br->port_list, list) {
                features = netdev_increment_features(features,
                                                     p->dev->features, mask);
+#if 1 // Brook.
+        if (p->dev->hard_header_len > max_hard_header_len) {
+            max_hard_header_len = p->dev->hard_header_len;
+        }
+
+        if (p->dev->needed_headroom > max_needed_headroom) {
+            max_needed_headroom = p->dev->needed_headroom;
+        }
+#endif
        }

+#if 1 // Brook.
+    br->dev->hard_header_len = max_hard_header_len;
+    br->dev->needed_headroom = max_needed_headroom;
+#endif
+
 done:
        br->dev->features = netdev_fix_features(features, NULL);
 }

    參考資料:
  1. 关于bridge中hard_header_len值的问题
  2. struct net_device结构中添加了needed_headroom/needed_tailroom成员



利用gen_init_cpio建立initrd的script


利用gen_init_cpio建立initrd的script
#!/bin/bash
#kernel的目錄
KERN_DIR=/usr/src/linux-kvm
#gen_initramfs_list.sh產生的暫存檔
INITRAMFS_LIST=/tmp/gen_initramfs_list
#initramfs的來源目錄, 為傳入該script的第一個參數
INITRAMFS_DIR=$1
#initrd的目的檔名, 為傳入該script的第二個參數
INITRD=$2
#給INITRAMFS_DIR default值
: ${INITRAMFS_DIR:="/home/brook/projects/rootfs"}
#給INITRD default值, 
: ${INITRD:="/home/brook/initrd"}

if [ ! -d $INITRAMFS_DIR ]; then
    echo "usage: $0 <initramfs_dir> <output_file>"
    exit 1
fi

sh $KERN_DIR/scripts/gen_initramfs_list.sh -d $INITRAMFS_DIR > $INITRAMFS_LIST
$KERN_DIR/usr/gen_init_cpio $INITRAMFS_LIST > $INITRD



2011年10月22日 星期六

javascript(6.1) - event, onkerpress


onkeypress當鍵盤被按下時觸發,這個event算蠻常用的,尤其是想要限制使用者的輸入範圍時。 其範例如下:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head>   <title></title> </head> <body>   <script type="text/javascript">     function noNumbers(e)     {        var keynum        var keychar        var numcheck        if (window.event) { // IE          keynum = window.event.keyCode        } else if(e.which) { // Netscape/Firefox/Opera          keynum = e.which        }        alert(keynum)        keychar = String.fromCharCode(keynum)        numcheck = /\d/        return !numcheck.test(keychar)     }   </script>   <form>     <input type="text" onkeypress="return noNumbers(event)">     <input type="text" id="k">   </form>   <script type="text/javascript">     document.getElementById("k").onkeypress = noNumbers;   </script> </body> </html>
這邊要注意的是,不同的瀏覽器會由不同的方式取得該event的值。


參考資料:W3schools, onkeypress Event


2011年9月29日 星期四

[讀書心得]大債時代(序)


「如果你欠銀行一百萬,你的命運掌握在銀行手中;如果你欠銀行一百億,銀行的命運掌握在你手中。」這一句開場白讓我印象深刻,台灣的茂德就是一個例子了,以股作債,金融遊戲沒有所謂的死巷,只有怎麼轉,讓錢轉進你的口袋。
「如果這個世界上,人人都擁有大量存款,沒有債務,那只會導致兩件事發生:第一,銀行倒閉,第二,存款變廢紙,擁有糧食的,才是真正富人。」第一件事情會不會發生我不確定,但是第二件事情肯定會發生,其實這世界最殘酷的事實就是不可能均富,一定要有人擁有大筆財富,而另一大群人缺錢,為錢賣命工作,這世界才可能進步,鄧小平說的最坦白了,先讓一部分的人富起來,沒有說要讓大家都富起來。
序的後面還有一段話讓我感受頗深,「我們希望自己的收入不斷成長,不斷的投入更多的時間與精力,追求下一份更高的薪水、更好的享受。快樂永遠是下一次加薪,下一次旅行,下一次購物。我們從不滿足於自己已經所有的。想像一下,有一個人在四、五十歲的年紀,有一天突然心臟病發作。雖然事後幸運地復原了,但發作那一霎那心痛如刀剮,讓他以為自己就要離開人世的瞬間,卻讓他看清了人生的目的。從此以後,他過著更健康的生活,更珍惜與家人與朋友相處的時光,更知道拿一些時間來做自己覺得真正重要的事。一次健康上的小打擊,卻讓他的人生之路走得更快樂踏實。」如果說,賺錢是要讓自己和家人過得更好,那麼在你追求財富的路途上,是不是真的有過得比較好,還是只看到帳面上的數字在增加,自己的身體或心理卻反其道而行,家人之間的感情是否更好,還是越來越疏遠了,我想都是值得我們去省思的。



2011年9月18日 星期日

[Lua Note] 2 - Types and Values


Types and Values

Lua的變數型態完全取決於assign的值,而Lua有8個基本資料型態nil、boolean、number、string、userdata、function、thread和 table等。
Lua 5.1.4  Copyright (C) 1994-2008 Lua.org, PUC-Rio
> print(type(a))
nil
> a="hello"
> print(type(a))
string
> a=3*5
> print(type(a))
number
> a=function() end
> print(type(a))
function
> a=true
> print(type(a))
boolean


nil

nil和C/Java Script的null意思差不多,當宣告一個變數還沒有給值,預設值就是nil,而當給變數nil就相當於delete這個變數。
> x = {}
> x["y"] = 1
> for k,v in pairs(x) do
>> print(k,v)
>> end
y       1
> x["y"] = nil -- 將y自x中移除
> for k,v in pairs(x) do
>> print(k,v)
>> end
> -- 沒有印出y了


booleans

說到boolean大家應該都知道boolean只有兩種值,true/false,在lua中,除了nil和false是false以外,其他都是true。not則是反轉boolean。
> print(x)
nil
> print(not not x)
false
> x=0
> print(not not x)
true -- 和C不同唷
> x=false
> print(not not x)
false
> x = function() end
> print(not not x)
true


numbers

Lua中沒有整數(integer),數值(numbers)是用雙精度儲存(double-precision floating-point)。


strings

Lua中的字串是儲存8-bit的字元,所以您可以儲存任何的資訊,和C不同的地方是C用null-terminated("\0"當結數符號),而Lua會用length紀錄字串長度。
當Lua中的字串是不能改變的,一旦改變就等同重新建立一個新字串,這點和C也不同。
Lua的字串除了可以用雙引號和單引號表示外,還可以用 [[...]]表示。
> s1="test1"
> s2='test2'
> s3=[[
>> test1
>> test2
>> ]]
> print(type(s3))
string
> print(s3)
test1
test2

Lua中字串可以用..串接在一起。
和JavaScript一樣,Lua在字串和數字之間的數學運算會試著將字串轉成數字,轉失敗就會出現error。
> print(10 .. "1")
101
> print(10 + "1")
11
> print(10 .. "x")
10x
> print(10 + "x")
stdin:1: attempt to perform arithmetic on a string value
stack traceback:
        stdin:1: in main chunk
        [C]: ?


table

table也稱為associative arrays,key可以是任何的資料型態,除了nil以外,都可以當key(或稱index),而任何其值可以是任何的資料型態,其表示法和一般C的array類似都是用"[]"來取值。
> x = {
[1] = "one",
["2"] = "two",
[3.0] = "three",
}
> print(x[1])
one
> print(x["2"]); print(x[3.0])
two
three



2011年9月17日 星期六

[Lua Note] 1 - Getting Started


Chunks

Lua就和一般的Script一樣,沒有所謂的main function,也不需要分號";"'當成一個statement的結束,分號可有可無,不過我還是習慣性的加上去,就像數學運算式的括號,很可能你想的和你寫出來的意思不同,導致錯誤,以下的範例都是一樣的意思
 
    a = 1
    b = a*2
    
    a = 1;
    b = a*2;
    
    a = 1 ; b = a*2
    
    -- "--"是註解的意思
    a = 1   b = a*2    -- 很醜,但還是合法

您可以在提示符號下執行lua,lua [ options ] [ script [ args ] ]
prompt> lua 會進入interactive 模式。
prompt> lua -la -lb會執行a.lua和b.lua,-l相當於require的意思,lua就像一般的computer language一樣,允許您寫自己的library,並且透過require載入。
lua也提供另外dofile這個function,讓您測試您寫的lua檔,dofile和require最大的不同是,require只會載入一次,而dofile可以重覆載入,所以拿來驗證lua檔就非常適合了。



Global Variables

在Lua中,沒有特別宣告local就是Global Variables,用到沒有宣告的變數,其值就是nil
 
function scope1()      -- step 4.
    function scope2()  -- step. 8
        print(A)               -- step. 9 印出A=20
        local A=30         -- step. 10又宣告一個變數A(範圍更小)
        print(A)               -- step. 11 印出該範圍的A, 即30
    end
    print(A)           -- step 5. 印出 10
    local A=20     -- step 6. 新的A=20, Global的A一樣不變
    scope2()        -- step 7.
     print(A)          -- step 12. 印出這個範圍的A = 20
end

print(A)                -- step 1. 印出 nil
A=10                   -- step 2. A=10
scope1()             -- step 3.
print(A)                -- step 13. 印出這個範圍的A = 10
os.exit()



Some Lexical Conventions

和一般的language一樣,會有所謂的key word,以下是lua的key word
while
and break do else elseif
end false for function if
in local nil not or
repeatreturn then true until

lua是case-sensitive就是有分大小寫的。 變數x和變數X是不同的。
在Lua中的註解 --是單行,像C中的//,而--[[ --]]就像C的/* */屬於多行註解。好用的地方是,只要在"--[["前面多一個"-"就等於取消整個註解,超好用。
 
--[[
    print(10)         -- no action (comment)
--]]

---[[
    print(10)         --> 10
--]]


The Stand-Alone Interpreter

lua會將command-line的參數存到陣列arg中,arg[0]存放執行的script,arg[-1]存放script檔名的前一個參數,arg[1]..arg[n]就是依序存放後面的參數。


參考資料:Programming in Lua (first edition)




2011年9月12日 星期一

Lua - Introduction


最近有幸開發新的Web Page,用的是LuCI(Lua Unified Configuration Interface),所以就得先學學Lua嚕,在這裡做些筆記,也和大家分享一下。
Lua是一種embedded language,就像Java Script一樣,通常會依附在host program底下(就像IE和Java script的關係一樣),而host program會執行Lua的程式碼,(就像網頁中參雜Java Script一樣)。不過,在寫LuCI的時候,感覺比較像在寫PHP或者ASP之類的。

Lua主用是用C寫的,原始的Lua非常的小,因為只有提供非常精簡的能力,但是可以透過擴充Library變得更強(更肥),因為精簡,所以適合在Embedded System上使用。

www.lua.org是Lua的官方網站,其中最重要的莫過於裡面的免費書籍,Programming in Lua (first edition),這本是必看的,後面的筆記應該都會是源自這邊,熟悉Lua之後,也可以看看Lua 5.1 Reference Manual
該網站還提供Web版的Lua,讓您沒有Lua也能學Lua。


如果您是在Windows環境底下,您可以安裝luaforwindows來練習,Practice Makes Perfect。


2011年8月6日 星期六

core dump and debug



看ulimit預設的一些參數,注意core file size若是0,就不會產生core文件了。

brook@vista:~$ cat -n foo.c 
     1  #include 
     2
     3  static void sub(void);
     4
     5  int main(void)
     6  {
     7      sub();
     8      return 0;
     9  }
    10
    11  static void sub(void)
    12  {
    13      int *p = NULL;
    14
    15      /* derefernce a null pointer, expect core dump. */
    16      printf("%d", *p);
    17  }
    18
    19
brook@vista:~$ gcc -g -Wall foo.c 
brook@vista:~$ ./a.out 
Segmentation fault
brook@vista:~$ ls core*
ls: cannot access core*: No such file or directory
brook@vista:~$ ulimit -c 1024
brook@vista:~$ ./a.out 
Segmentation fault (core dumped)
brook@vista:~$ ls core*
core
brook@vista:~$ gdb ./a.out core 
GNU gdb (Ubuntu/Linaro 7.2-1ubuntu11) 7.2
Copyright (C) 2010 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later
 
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
 Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
For bug reporting instructions, please see:
...
Reading symbols from /home/brook/a.out...done.
[New Thread 5382]

warning: Can't read pathname for load map: Input/output error.
Reading symbols from /lib/x86_64-linux-gnu/libc.so.6...
Reading symbols from /usr/lib/debug/lib/x86_64-linux-gnu/libc-2.13.so...done.
done.
Loaded symbols for /lib/x86_64-linux-gnu/libc.so.6
Reading symbols from /lib64/ld-linux-x86-64.so.2...
(no debugging symbols found)...done.
Loaded symbols for /lib64/ld-linux-x86-64.so.2
Core was generated by `./a.out'.
Program terminated with signal 11, Segmentation fault.
#0  0x0000000000400518 in sub () at foo.c:16
16          printf("%d", *p);
(gdb) 


    參考資料:
  1. http://blog.csdn.net/borefo/article/details/5029555, 在Linux下产生并调试core文件



2011年7月31日 星期日

台中 - 韓式料理 - 韓香 ☆☆☆


韓香位於居仁國中後面,就在中華電信旁,地理位置應該不難找,因為生意還算不錯,所以如果要吃,記得先預約唷,不然就得在外面慢慢排了,看到很多椅子了吧?就知道要等很久。


這是這家店的菜單,不過每次去都還是必點銅板烤肉+石鍋拌飯。




這家店最大的特色就是,小菜無限量供應,這邊的小菜大概有十多種吧,每次去每個人至少都可以吃掉10盤。



這邊有低消的限制唷。






地點:台中市市府路39號
價位:最低消費140元,另加收10%服務費



2011年7月9日 星期六

ELF之學習心得02 - ELF Header(e_ident篇)



這是ELF的layout,所謂的Linking View是指以檔案呈現之ELF(左圖),而Execution View則是指被載入到RAM上執行的ELF(右圖)。ELF header會包含整個檔案的"road map",我們可以利用readelf -h檢視elf header到底包含哪些東西?

由readelf -h可看出可看出ELF header包含了許多資訊,這些資訊都可以由定義在elf.h中的Elf32_Ehdr解讀出來。介紹ELF header之前,先介紹ELF的Data Types,這些資訊也都放置在elf.h檔中。

/* Standard ELF types.  */

#include <stdint.h>

/* Type for a 16-bit quantity.  */
typedef uint16_t Elf32_Half;
typedef uint16_t Elf64_Half;

/* Types for signed and unsigned 32-bit quantities.  */
typedef uint32_t Elf32_Word;
typedef int32_t  Elf32_Sword;
typedef uint32_t Elf64_Word;
typedef int32_t  Elf64_Sword;

/* Types for signed and unsigned 64-bit quantities.  */
typedef uint64_t Elf32_Xword;
typedef int64_t  Elf32_Sxword;
typedef uint64_t Elf64_Xword;
typedef int64_t  Elf64_Sxword;

/* Type of addresses.  */
typedef uint32_t Elf32_Addr;
typedef uint64_t Elf64_Addr;

/* Type of file offsets.  */
typedef uint32_t Elf32_Off;
typedef uint64_t Elf64_Off;

/* Type for section indices, which are 16-bit quantities.  */
typedef uint16_t Elf32_Section;
typedef uint16_t Elf64_Section;

/* Type for version symbol information.  */
typedef Elf32_Half Elf32_Versym;
typedef Elf64_Half Elf64_Versym;
Elf32和Elf64的data type只有在off和addr這兩種type的資料長度有不同,其餘都相同。您可以在下表中發現Elf32_Ehdr和Elf64_Ehdr的member資料長度只有差e_entry、e_phoff和e_shoff會不相同,其餘都相同,所以,Elf64_Ehdr比Elf32_Ehdr多了12byte。

ELF header如下
/* The ELF file header.  This appears at the start of every ELF file.  */

#define EI_NIDENT (16)

typedef struct
{
    unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */
    Elf32_Half  e_type;         /* Object file type */
    Elf32_Half    e_machine;      /* Architecture */
    Elf32_Word  e_version;      /* Object file version */
    Elf32_Addr    e_entry;        /* Entry point virtual address */
    Elf32_Off   e_phoff;        /* Program header table file offset */
    Elf32_Off e_shoff;        /* Section header table file offset */
    Elf32_Word  e_flags;        /* Processor-specific flags */
    Elf32_Half    e_ehsize;       /* ELF header size in bytes */
    Elf32_Half  e_phentsize;        /* Program header table entry size */
    Elf32_Half    e_phnum;        /* Program header table entry count */
    Elf32_Half  e_shentsize;        /* Section header table entry size */
    Elf32_Half    e_shnum;        /* Section header table entry count */
    Elf32_Half  e_shstrndx;     /* Section header string table index */
} Elf32_Ehdr;

typedef struct
{
    unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */
    Elf64_Half  e_type;         /* Object file type */
    Elf64_Half    e_machine;      /* Architecture */
    Elf64_Word  e_version;      /* Object file version */
    Elf64_Addr    e_entry;        /* Entry point virtual address */
    Elf64_Off   e_phoff;        /* Program header table file offset */
    Elf64_Off e_shoff;        /* Section header table file offset */
    Elf64_Word  e_flags;        /* Processor-specific flags */
    Elf64_Half    e_ehsize;       /* ELF header size in bytes */
    Elf64_Half  e_phentsize;        /* Program header table entry size */
    Elf64_Half    e_phnum;        /* Program header table entry count */
    Elf64_Half  e_shentsize;        /* Section header table entry size */
    Elf64_Half    e_shnum;        /* Section header table entry count */
    Elf64_Half  e_shstrndx;     /* Section header string table index */
} Elf64_Ehdr;

/* Fields in the e_ident array.  The EI_* macros are indices into the
 *    array.  The macros under each EI_* macro are the values the byte
 *       may have.  */

#define EI_MAG0     0       /* File identification byte 0 index */
#define ELFMAG0     0x7f        /* Magic number byte 0 */

#define EI_MAG1     1       /* File identification byte 1 index */
#define ELFMAG1     'E'     /* Magic number byte 1 */

#define EI_MAG2     2       /* File identification byte 2 index */
#define ELFMAG2     'L'     /* Magic number byte 2 */

#define EI_MAG3     3       /* File identification byte 3 index */
#define ELFMAG3     'F'     /* Magic number byte 3 */

/* Conglomeration of the identification bytes, for easy testing as a word.  */
#define ELFMAG      "\177ELF"
#define SELFMAG     4

#define EI_CLASS    4       /* File class byte index */
#define ELFCLASSNONE    0       /* Invalid class */
#define ELFCLASS32  1       /* 32-bit objects */
#define ELFCLASS64  2       /* 64-bit objects */
#define ELFCLASSNUM 3

#define EI_DATA     5       /* Data encoding byte index */
#define ELFDATANONE 0       /* Invalid data encoding */
#define ELFDATA2LSB 1       /* 2's complement, little endian */
#define ELFDATA2MSB 2       /* 2's complement, big endian */
#define ELFDATANUM  3

#define EI_VERSION  6       /* File version byte index */
                    /* Value must be EV_CURRENT */

#define EI_OSABI            7   /* OS ABI identification */
#define ELFOSABI_NONE       0   /* UNIX System V ABI */
#define ELFOSABI_SYSV       0   /* Alias.  */
#define ELFOSABI_HPUX       1   /* HP-UX */
#define ELFOSABI_NETBSD     2   /* NetBSD.  */
#define ELFOSABI_LINUX      3   /* Linux.  */
#define ELFOSABI_SOLARIS    6   /* Sun Solaris.  */
#define ELFOSABI_AIX        7   /* IBM AIX.  */
#define ELFOSABI_IRIX       8   /* SGI Irix.  */
#define ELFOSABI_FREEBSD    9   /* FreeBSD.  */
#define ELFOSABI_TRU64      10  /* Compaq TRU64 UNIX.  */
#define ELFOSABI_MODESTO    11  /* Novell Modesto.  */
#define ELFOSABI_OPENBSD    12  /* OpenBSD.  */
#define ELFOSABI_ARM_AEABI  64  /* ARM EABI */
#define ELFOSABI_ARM        97  /* ARM */
#define ELFOSABI_STANDALONE 255 /* Standalone (embedded) application */

#define EI_ABIVERSION       8   /* ABI version */

#define EI_PAD              9   /* Byte index of padding bytes */

資料結構大致介紹完畢,接著就可以透過實做readelf -h的程式來了解ELF header了,首先,所有的ELF開頭都會有16 bytes的ELF Identification,也是本章節所要介紹的部份。

EI_MAG0 ~ EI_MAG3

所有的ELF前面4byte為magic number,其內容為{0x7f, 'E', 'L', 'F'},用以判斷是否為ELF檔。

static int elf_header(int fd) 
{
    int sz; 
    unsigned char e_ident[EI_NIDENT];

    sz = read(fd, e_ident, sizeof(e_ident));
    if (sz < sizeof(e_ident)) {
        fprintf(stderr, "invalid elf file\n");
        return -1;
    }   

    // 判斷是否為ELF檔
    if (memcmp(ELFMAG, e_ident, SELFMAG)) {
        fprintf(stderr, "invalid elf file\n");
        return -1;
    }   
    elf_header_magic(e_ident);
}


/**
 * 印出ident(前面16byte)
 */
static int elf_header_magic(unsigned char *c)
{
    int i;
    printf("%-10s", "Magic: ");
    for (i = 0; i < EI_NIDENT; i++) {
        printf("%02X ", c[i]);
    }
    printf("\n");
    return 0;
}

EI_CLASS

EI_CLASS這個byte是用來判斷是32-bit或是64-bit的ELF檔,根據不同的Class就要選擇使用Elf32_Ehdr或是Elf64_Ehdr判讀後面的資料。

/**
 * 判斷是32-bit/64-bit architectures.
 */
static int elf_header_class(unsigned char c)
{
    printf("%-36s", "Class: ");
    switch(c) {
        case ELFCLASSNONE:
            fprintf(stderr, "Invalid class\n");
            return -1;

        case ELFCLASS32:
            printf("32-bit object\n");
            break;

        case ELFCLASS64:
            printf("64-bit object\n");
            break;

        default:
            fprintf(stderr, "unknow class\n");
            return -1;
    }
    return 0;
}


EI_DATA

EI_DATA這個byte是用來判斷ELF檔是LSB(Little-endian)還是MSB(Big-endian)。
/**
 * 判斷ELF檔是LSB(Little-endian)還是MSB(Big-endian)
 */
static int elf_header_data(unsigned char c)
{
    printf("%-36s", "Data: ");
    switch(c) {
        case ELFDATANONE:
            fprintf(stderr, "Invalid data encoding\n");
            return -1;

        case ELFDATA2LSB:
            printf("2's complement, little endian\n");
            break;

        case ELFDATA2MSB:
            printf("2's complement, big endian\n");
            break;

        default:
            fprintf(stderr, "unknow data\n");
            return -1;
    }
    return 0;
}


EI_VERSION

EI_VERSION這個byte是指出這個ELF檔的ELF header的版本是多少?目前這個值必須是EV_CURRENT。
static int elf_header_version(unsigned char c)
{
    printf("%-36s", "Version: ");
    switch(c) {
        case EV_CURRENT:
            printf("Current version");
            break;

        default:
        case EV_NONE:
            printf("Invalid ELF version");
            break;
    }
    printf("(%d)\n", c);
    return 0;
}


EI_OSABI

EI_OSABI這個byte是指出這個ELF檔會在那個OS上運行。
static int elf_header_osabi(unsigned char c)
{
    printf("%-36s", "OS/ABI: ");
    switch(c) {
        case ELFOSABI_SYSV:
            printf("UNIX System V ABI");
            break;

        case ELFOSABI_HPUX:
            printf("HP-UX");
            break;

        case ELFOSABI_NETBSD:
            printf("NetBSD.");
            break;

        case ELFOSABI_LINUX:
            printf("Linux.");
            break;

        case ELFOSABI_SOLARIS:
            printf("Sun Solaris.");
            break;

        case ELFOSABI_AIX:
            printf("IBM AIX.");
            break;

        case ELFOSABI_IRIX:
            printf("SGI Irix.");
            break;

        case ELFOSABI_FREEBSD:
            printf("FreeBSD.");
            break;

        case ELFOSABI_TRU64:
            printf("Compaq TRU64 UNIX.");
            break;

        case ELFOSABI_MODESTO:
            printf("Novell Modesto.");
            break;

        case ELFOSABI_OPENBSD:
            printf("OpenBSD.");
            break;

        case ELFOSABI_ARM_AEABI:
            printf("ARM EABI");
            break;

        case ELFOSABI_ARM:
            printf("ARM");
            break;

        case ELFOSABI_STANDALONE:
            printf("Standalone (embedded) application");
            break;

        default:
            fprintf(stderr, "unknow osabi\n");
            return -1;
    }
    printf("(%d)\n", c);
    return 0;
}


EI_ABIVERSION

EI_ABIVERSION這個byte是指出這個ELF檔會在那個API版本上運行。一個OS上可能有多個ABI的版本在運行的版本在運行,如SYSV至少就有SVR、Solaris、SCO等ABI。0代表不指定(unspecified)。
static int elf_header_abi_version(unsigned char c)
{
    printf("%-36s%d\n", "ABI Version: ", c);
    return 0;
}


EI_PAD

EI_PAD這個byte之後的都是padding。


到目前為止,僅有解釋ELF header中的e_ident,剩下的部份會在後面繼續探討與研究。


2011年6月19日 星期日

Introduction cpufreq


Linux Device Driver是架構在mechanism和policy之間,Mechanism定義了應該提供哪些功能(what capabilities are provided),而policy定義應該如何使用這些功能(how the capabilities are to be used),這樣的分層可以簡化設計,因為policy或mechanism的改變,另外一個可以不需要更動。一般而言,Linux Device Driver都是policy free,只提供Device本身的capabilities,而沒有policy,有時候會在上面再設計一個policy,比如這次的主題cpufreq就提供了一些governors(performance、powersave、userspace、conservative和ondemand) 提供了一些調動CPU頻率的policy,然而每個CPU的CPU frequence的設定方式都不同,所以,每個CPU都有自己的driver來達到CPU frequency scaling,比如Intel的Enhanced SpeedStep或AMD的PowerNow!。

在cpufreq這個sub-system中也提供了一些sys的interface可以操控policy,這邊大概提一下governors.txt中提到的幾個重點。
首先,CPU的frequency policy我們稱為governors,共有Performance、Powersave、Userspace、Ondemand和Conservative等五種。您可以透過讀取/sys/devices/system/cpu/cpu0/cpufreq/scaling_available_governors知道system提供了哪些的governors,也可以透過/sys/devices/system/cpu/cpu0/cpufreq/scaling_available_frequencies了解CPU提供了幾種CPU frequency。透過讀取/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor可以知道現在的governor為何?而要改變governor則是寫入到該檔案,藉由讀取/sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_frequencies可以讀取現在的CPU頻率。
    接下來介紹一下各個governor的規則,
  • Performance會always用最高的頻率執行,
  • Powersave會always用最低的頻率執行,
  • 當user使用Userspace時,可以讓user透過寫入/sys/devices/system/cpu/cpu0/cpufreq/scaling_setspeed改變CPU的頻率,
  • Ondemand則會根據系統的loading來調整頻率,當系統的loading高於/sys/devices/system/cpu/cpu0/cpufreq/ondemand/up_threshold時,就會立刻將CPU調到最高頻率運行,之後再慢慢的降下來,
  • conservative和Ondemand類似,conservative有/sys/devices/system/cpu/cpu0/cpufreq/conservative/up_threshold/sys/devices/system/cpu/cpu0/cpufreq/conservative/down_threshold當系統loading超過up_threshold時,就會調高CPU的頻率,當低於down_threshold就會調降CPU的頻率,
由於ondemand變換CPU頻率過大,所以使用ondemand的CPU必須有能力快速切換CPU的頻率,不然很容易當機。

您也可以透過一些utility如cpufreq-info讀取相關資訊,基本上都還是透過讀取上述的那些檔案內容列印出來而已。

由cpufreq-info可以知道目前是acpi-cpufreq這個driver(應該猜得出是Intel的CPU),還有其他資訊。
    參考資料:
  • Linux Documentation / cpu-freq / governors.txt
  • Linux Documentation / cpu-freq / user-guide.txt
  • https://wiki.archlinux.org/index.php/CPU_Frequency_Scaling
  • http://blog.csdn.net/guoshaobei/archive/2010/12/21/6090359.aspx
  • http://software.intel.com/en-us/articles/enhanced-intel-speedstepr-technology-and-demand-based-switching-on-linux/



2011年6月5日 星期日

ELF之學習心得01


目前Linux的主要的可執行檔格式是ELF(Executable and Linking Format),ELF為COFF格式的後繼者,主要特徵是可擁有多個section,並且有32-bit與64-bit的數值用以區別其格式屬於32-bit或是64-bit。主要缺點是ELF設計時有一個假設,每個系統只會有一個ABI(Application Binary Interface),但是事實上這是錯的,如SYSV至少就有SVR、Solaris、SCO等ABI。(詳細內容請閱讀參考資料)

    ELF主要有三種類型的object files:
  • A relocatable file holds code and data suitable for linking with other object files to create an executable or a shared object file.
  • An executable file holds a program suitable for execution.
  • A shared object file holds code and data suitable for linking in two contexts. First, the link editor may process it with other relocatable and shared object files to create another object file. Second, the dynamic linker combines it with an executable file and other shared objects to create a process image.


這是ELF的layout,所謂的Linking View是指以檔案呈現之ELF(左圖),而Execution View則是指被載入到RAM上執行的ELF(右圖)。

    主要的section包含
  1. .text,存放程式碼的區域。
  2. .data用於存放已經初始化的變數。
  3. .bss用於存放未初始化的變數或者內容初始化為0的,該區域不占檔案空間。
  4. .rodata用於存放read-only data。
  5. 其他section和使用者自訂section後面再慢慢介紹。
這些以"."開頭的section為系統保留之section,使用者可以自訂section,但是應該避免使用"."開頭。
#include <stdio.h>

int i0 = 0;
int i1 = 1;
static int si0 = 0;
static int si1 = 1;
const int ci0 = 0;
const int ci1 = 1;
const static int csi0 = 0;
const static int csi1 = 1;

int main(void)
{
    return 0;
}


objdump -x a.out 

SYMBOL TABLE:
0000000000601034 l   O .bss     0000000000000004  si0
000000000060101c l   O .data    0000000000000004  si1
00000000004005b4 l   O .rodata  0000000000000004  csi0
00000000004005b8 l   O .rodata  0000000000000004  csi1
00000000004005b0 g   O .rodata  0000000000000004  ci1
0000000000601030 g   O .bss     0000000000000004  i0
00000000004005ac g   O .rodata  0000000000000004  ci0
0000000000601018 g   O .data    0000000000000004  i1
根據前面的規則用const修飾的變數會被放置在.rodata中,有ci0、ci1、csi0、csi1。未初始化的變數或者內容初始化為0的都會被放置在.bss中,有i0、si0。已經初始化的變數則放在.data中,有i1、si1。



2011年5月21日 星期六

Android on OpenWrt


這篇要介紹openwrt上面的Andorid emulator,使用openwrt只有一個原因,因為內建android emulator,只要configure好,就可以執行。
步驟如下:
brook@vista:~/projects$ git git://nbd.name/openwrt.git
brook@vista:~/projects$ cd openwrt
brook@vista:~/projects/openwrt$ make menuconfig
    Target System選擇"Goldfish (Android Emulator)"
    Target Images選擇"jffs2"
    Emulators選擇"goldfish-qemu"
brook@vista:~/projects/openwrt$ make world




有相關的package沒裝好就會出現error,再依照指示逐一裝上即可。
最後執行內建的script就可以呼叫android模擬器出來了。
brook@vista:~/projects/openwrt/bin/goldfish$ sh run-emulator.sh



    參考資料:
  • http://lwn.net/Articles/332301/
  • http://nbd.name/blog/?p=36
  • http://nbd.name/blog/?p=48
  • https://forum.openwrt.org/viewtopic.php?id=15201



2011年5月7日 星期六

Linux Kernel(14)- Kernel Synchronization


這裡簡單介紹的介紹一下Kernel Synchronization的幾個觀念的幾個觀念。
  1. Race Condition
  2. 當多個process同時對同一個資料進行存取,且執行結果和其存取順序的不同而有所不同,稱為race condition。
  3. Critical Regions(或稱critical sections)
  4. 指的是一個存取共用資源的程式片斷。
  5. Kernel Synchronization
  6. 簡單說防止kernel發生race condition。保護的重點是shared data,而且保護的範圍和負擔越小越好。

Kernel Synchronization常見的作法就是locking,每次只允許一個process可以存取share data,就可以避免race condition了。

    在kernel中有幾種引發concurrency的可能
  1. Interrupt
  2. 當CPU收到interrupt會立刻中斷目前工作去執行interrupt handler。
  3. Softirq
  4. 當softirq被raise起來就會中斷目前工作去執行softirq。
  5. kernel preemption
  6. 如果kernel preemption被開啟,那麼task就可能被中斷。
  7. Sleeping
  8. 如果kernel執行到blocking code,就可能被schedule出去。
  9. SMP
  10. 同時間兩個以上的CPU存取相同的資料就會發生race condition。


在linunx kernel中,執行的context主要分成兩種interrupt context和process context,凡是只要in_interrupt()都是interrupt context,所以引起的原因包含Hardware interrupt和softirq兩種。以下就擷取片段程式碼說明。
// thread_info存放在task的stack裡面
# define task_thread_info(task)  ((struct thread_info *)(task)->stack)

// thread_info中的preempt_count分成幾個部份
// bits 0-7 are the preemption count (max preemption depth: 256)
// bits 8-15 are the softirq count (max # of softirqs: 256)
// bits 16-25 are the hardirq count (max # of nested hardirqs: 1024)
// bit 26 is the NMI_MASK
// bit 28 is the PREEMPT_ACTIVE flag
struct thread_info {
    struct task_struct *task;   /* main task structure */
    int    preempt_count;       /* 0 => preemptable */
};

# define preempt_count()        (current_thread_info()->preempt_count)
# define add_preempt_count(val) do { preempt_count() += (val); } while (0)
# define sub_preempt_count(val) do { preempt_count() -= (val); } while (0)

// 當每次呼叫irq_enter()就會將preempt_count屬於HARDIRQ的部份遞增
#define __irq_enter()                       \
    do {                                    \
        account_system_vtime(current);      \
        add_preempt_count(HARDIRQ_OFFSET);  \
        trace_hardirq_enter();              \
    } while (0)

# define invoke_softirq()   do_softirq()
# define IRQ_EXIT_OFFSET    HARDIRQ_OFFSET
/*
 * Exit an interrupt context. Process softirqs if needed and possible:
 */
void irq_exit(void)
{
    // 離開hard interrupt所以要減回去HARDIRQ_OFFSET
    sub_preempt_count(IRQ_EXIT_OFFSET);
    // 如果不在interrupt context(如softirq裡面),
    // 而且softirq有被raise就執行softirq
    if (!in_interrupt() && local_softirq_pending())
        invoke_softirq();
}

此圖出於http://blog.csdn.net/hero7935/archive/2011/05/07/6401522.aspx

    參考資料:
  • Linux Kernel Development 2nd, Novell Press



2011年4月16日 星期六

Adobe Flash “Square” on 64bit Linux for Firefox


安裝Adobe Flash到firefox事件小事,不過記一下免得以後還要再找一次,可以省事,
  1. http://labs.adobe.com/downloads/flashplayer10_square.html下載
  2. 解壓縮到/usr/lib64/mozilla/plugins
簡單結束。

現在可以看大盤的技術分析啦。


2011年3月19日 星期六

寫作小技巧in C


有些code寫的有些trick,不過常常因為太久沒用就忘記了,所以我決定特別留一篇,專門收集這種短小精幹的code。

判斷是不是2的n次方
if_power_of_2(n) (n != 0 && ((n & (n -1)) == 0))


XOR swap
void swap(int *x, int *y) {
    if (x != y) {
        *x ^= *y;
        *y ^= *x;
        *x ^= *y;
    }
}


Memory Alignment
作embedded常常會需要作一些Memory alignment的動作的動作,Linux的Netlink就有一小段macro可以拿來用。
#define NLMSG_ALIGNTO       4U // 作4byte alignment
#define NLMSG_ALIGN(len)    (((len)+NLMSG_ALIGNTO-1) & ~(NLMSG_ALIGNTO-1))
比如要讓NLMSG_HDRLEN能符合4byte-alignment就是定義如下的macro
#define NLMSG_HDRLEN        ((int) NLMSG_ALIGN(sizeof(struct nlmsghdr)))
陸續收集中...


2011年3月12日 星期六

GCC - Attributes - warn_unused_result


常常發現有些人對於funcion的return value都不太理會,所以後來我就在function上面加上warn_unused_result這個attribute,當programmer沒有使用這個function的return value時,就會跳出warning,嚴格一點再加上-Werror就可以讓這些warning變成error。



GCC VERSION:4.5之原文
The warn_unused_result attribute causes a warning to be emitted if a caller
of the function with this attribute does not use its return value.
This is useful for functions where not checking the result is either a
security problem or always a bug, such as realloc.



2011年2月27日 星期日

Linux Modules(14.1)- Read Copy Update


RCU (Read-Copy Update)是kernel同步機制之一,允許多個reader在writer更新資料的同時讀取資料,reader可能讀到更新前或更新後的,但是資料內容是一致的(不是新的就是舊的,這是因為RCU利用指標的dereference和assign達成的),另外,RCU也能確保資料在read-side使用時不會將之free(下一篇介紹RCU的原理在提吧)。


這裡有一張圖用來描述RCU再經典不過了。首先,藍色的reader的開始就是rcu_read_lock(),結束就是rcu_read_unlock(),下面的removal、grace period和reclamation代表著writer的狀態,這邊只要保證讀到舊資料的reader(就是開頭落在removal的reader),都能在grace period結束之前,離開read-side就可以了,聰明的你一定可以看出在grace period開始之後的reader都是讀到新資料,所以RCU就不管他想用多久。
    RCU的三個階段
  1. removal:更新指標。
  2. grace period:等待所有持有舊資料的reader都離開RCU read-side。
  3. reclamation:回收舊資料。

RCU本身就是read-write lock的一種,所以我們介紹一下RCU的reader和writer的形式。
struct foo {
    int x;
};

static struct foo *foo = NULL;

// Reader的形式
static int reader(void)
{
    int ret;

    rcu_read_lock();
    ret = rcu_dereference(foo)->x;
    rcu_read_unlock();

    return ret;
}

// Writer的形式
static void writer(int x)
{
    struct foo *new_foo, *old_foo = foo;

    // 建立新的資料內容new_foo
    new_foo = kmalloc(sizeof(struct foo), GFP_KERNEL);

    // 複製原本的內容
    *new_foo = *old_foo;

    // 修改內容
    new_foo->x = x;

    // removal
    rcu_assign_pointer(foo, new_foo);

    // grace period
    synchronize_rcu();

    // reclamation: 
    kfree(old_foo);

}

synchronize_rcu()就是在等待所謂的grace period,等所有持舊資料的reader都離開RCU read-side才會往下執行kfree(old_foo)。




2011年2月26日 星期六

Linux Kernel(8.1)- Notifier機制剖析


Linux Kernel(8)- Notification可以學會運用notifier,而這一篇會概述如何實現,基本上所謂的publish-and-subscribe pattern都是註冊callback function到某個list上去,某事件發生時,再將整個list的callback function執行過一次。


include/lunux/notifier.h
#define BLOCKING_NOTIFIER_HEAD(name)                \
        struct blocking_notifier_head name =            \
        BLOCKING_NOTIFIER_INIT(name)

struct blocking_notifier_head {
    // 用於blocking機制時使用
    // 可以於kernel/notifier.c看到以下註解
    /*
     * Blocking notifier chain routines.  All access to the chain is
     * synchronized by an rwsem.
     */
    struct rw_semaphore rwsem;
    // callback function之linking-list的頭
    struct notifier_block __rcu *head;
};

// linking-list之node結構
struct notifier_block {
    // callback function
    int (*notifier_call)(struct notifier_block *, unsigned long, void *);
    struct notifier_block __rcu *next;
    // 用於註冊到list之優先順序, 數字越大 priority越高
    int priority;
};


kernel/notifier.c
/**
 * blocking_notifier_chain_register - Add notifier to a blocking notifier chain
 * @nh: Pointer to head of the blocking notifier chain
 * @n: New entry in notifier chain
 *
 * Adds a notifier to a blocking notifier chain.
 * Must be called in process context.
 * // 因為semaphore只能用在process context
 *
 * Currently always returns zero.
 */
int blocking_notifier_chain_register(struct blocking_notifier_head *nh,
                struct notifier_block *n)
{
    int ret;

    /*
     * This code gets used during boot-up, when task switching is
     * not yet working and interrupts must remain disabled.  At
     * such times we must not call down_write().
     */
    if (unlikely(system_state == SYSTEM_BOOTING))
        return notifier_chain_register(&nh->head, n);

    // 使用writer semaphore保護, 確保kernel synchronization
    down_write(&nh->rwsem);

    // 真正掛callback function到list的function
    ret = notifier_chain_register(&nh->head, n);

    up_write(&nh->rwsem);
    return ret;
}


/*
 *  Notifier chain core routines.  The exported routines below
 *  are layered on top of these, with appropriate locking added.
 */

static int notifier_chain_register(struct notifier_block **nl,
                struct notifier_block *n)
{
    // nl指向list中的第一個node
    while ((*nl) != NULL) {
        // 比較list中的每一個node之priority,
        // 如果發現新的比較大, 就break準備插到這個(*nl)的前面
        if (n->priority > (*nl)->priority)
            break;
        nl = &((*nl)->next);
    }
    // 將(*nl)串到新的後面
    n->next = *nl;
    // 將(*nl)取代成n
    rcu_assign_pointer(*nl, n);
    return 0;
}

/**
 * blocking_notifier_chain_unregister - Remove notifier from a blocking notifier chain
 * @nh: Pointer to head of the blocking notifier chain
 * @n: Entry to remove from notifier chain
 *
 * Removes a notifier from a blocking notifier chain.
 * Must be called from process context.
 *
 * Returns zero on success or %-ENOENT on failure.
 */
int blocking_notifier_chain_unregister(struct blocking_notifier_head *nh,
                struct notifier_block *n)
{
    // 基本上這個function和blocking_notifier_chain_register()相同

    int ret;

    /*
     * This code gets used during boot-up, when task switching is
     * not yet working and interrupts must remain disabled.  At
     * such times we must not call down_write().
     */
    if (unlikely(system_state == SYSTEM_BOOTING))
        return notifier_chain_unregister(&nh->head, n);

    // 使用writer semaphore保護, 確保kernel synchronization
    down_write(&nh->rwsem);

    // 真正移除callback function
    ret = notifier_chain_unregister(&nh->head, n);

    up_write(&nh->rwsem);
    return ret;
}

static int notifier_chain_unregister(struct notifier_block **nl,
                struct notifier_block *n)
{
    while ((*nl) != NULL) {
        if ((*nl) == n) {
            // 找到n在list中的位置, 然後將之移除
            rcu_assign_pointer(*nl, n->next);
            return 0;
        }
        // 將nl往下一個移動
        nl = &((*nl)->next);
    }
    return -ENOENT;
}


int blocking_notifier_call_chain(struct blocking_notifier_head *nh,
                unsigned long val, void *v)
{
    return __blocking_notifier_call_chain(nh, val, v, -1, NULL);
}


/**
 *  __blocking_notifier_call_chain - Call functions in a blocking notifier chain
 *  @nh: Pointer to head of the blocking notifier chain
 *  @val: Value passed unmodified to notifier function
 *  @v: Pointer passed unmodified to notifier function
 *  @nr_to_call: See comment for notifier_call_chain.
 *  @nr_calls: See comment for notifier_call_chain.
 *
 *  Calls each function in a notifier chain in turn.  The functions
 *  run in a process context, so they are allowed to block.
 *
 *  If the return value of the notifier can be and'ed
 *  with %NOTIFY_STOP_MASK then blocking_notifier_call_chain()
 *  will return immediately, with the return value of
 *  the notifier function which halted execution.
 *  Otherwise the return value is the return value
 *  of the last notifier function called.
 */
int __blocking_notifier_call_chain(struct blocking_notifier_head *nh,
            unsigned long val, void *v, int nr_to_call, int *nr_calls)
{
    int ret = NOTIFY_DONE;

    /*
     * We check the head outside the lock, but if this access is
     * racy then it does not matter what the result of the test
     * is, we re-check the list after having taken the lock anyway:
     */
    if (rcu_dereference_raw(nh->head)) {
        down_read(&nh->rwsem);
        // 真正執行list中所有callback function的API
        ret = notifier_call_chain(&nh->head, val, v, nr_to_call,
                                nr_calls);
        up_read(&nh->rwsem);
    }
    return ret;
}

/**
 *  notifier_call_chain - Informs the registered notifiers about an event.
 *  @nl:        Pointer to head of the blocking notifier chain
 *  @val:       Value passed unmodified to notifier function
 *  @v:     Pointer passed unmodified to notifier function
 *  @nr_to_call:    Number of notifier functions to be called. Don't care
 *                  value of this parameter is -1.
 *  @nr_calls:  Records the number of notifications sent. Don't care
 *              value of this field is NULL.
 *  @returns:   notifier_call_chain returns the value returned by the
 *              last notifier function called.
 */
static int __kprobes notifier_call_chain(struct notifier_block **nl,
            unsigned long val, void *v, int nr_to_call, int *nr_calls)
{
    int ret = NOTIFY_DONE;
    struct notifier_block *nb, *next_nb;

    nb = rcu_dereference_raw(*nl);

    // 由blocking_notifier_call_chain傳進來的nr_to_call為-1, 
    // 由於nr_to_call只會--, 所以nr_to_call就是always成立
    // 於是停止的條件只剩下nb為NULL
    while (nb && nr_to_call) {
        // ??這段的用意就不是很明瞭了??
        // 為啥不在後面在nb = nb->next?
        next_nb = rcu_dereference_raw(nb->next);

#ifdef CONFIG_DEBUG_NOTIFIERS
        if (unlikely(!func_ptr_is_kernel_text(nb->notifier_call))) {
            WARN(1, "Invalid notifier called!");
            nb = next_nb;
            continue;
        }
#endif
        // 執行callback function
        ret = nb->notifier_call(nb, val, v);

        if (nr_calls)
            (*nr_calls)++;

        // 如果帶有 STOP的bit就停止執行後面的callback function
        if ((ret & NOTIFY_STOP_MASK) == NOTIFY_STOP_MASK)
            break;
        nb = next_nb;
        nr_to_call--;
    }
    return ret;
}

這篇文章還不算完成,後面在補充啦~~


熱門文章