2013年7月21日 星期日

system call for arm platform (2)

from
[1]
http://opencsl.openfoundry.org/Lab06_interrupt_exception.rst.html
[2]
http://blog.csdn.net/wavemcu/article/details/8577058 
[3]
http://blog.xuite.net/ian11832/blogg/29210698-%E5%9C%A8+linux+%E4%B8%AD%E6%96%B0%E5%A2%9E%E8%87%AA%E5%B7%B1%E7%9A%84system+call+%28%E5%AF%A6%E5%81%9A%E5%9C%A8ARM+%E5%B9%B3%E5%8F%B0%E4%B8%8A%29
[4]
http://blog.csdn.net/adaptiver/article/details/7175165

3.1 system call 的撰寫方法

要新增 system call 除了撰寫程式本身之外,還需要向 Linux 註冊讓 kernel 知道它的存在 ,這樣 user program 才能夠透過 kernel 呼叫 system call。
註冊 system call 的步驟如下:
  1. 註冊 system call 的名字
  2. 定義新 system call 的代碼
  3. 調整 Makefile ,使 systam call 被包含在 kernel 中
  4. 增加 system call 的 header file ,讓 user program 能夠 include
另外在撰寫 system call 程式方面,因為程式是在 kernel space 執行, user program 和 system call 所使用的記憶體位置是無法直接互通的,所使用的函式也和一般的 user program 不同,使用上也必須特別小心,像是
  • 使用 printk 而不是 print
  • 使用 kmalloc、kfree 而不是 malloc、free

3.2 加入自己的 system call

在本節中,我們將透過 3.1 所敘述的步驟自己在系統中新增一個 system call ,這個 system call 將會顯示開機後它總共被呼叫了幾次。
  1. 撰寫 system call 的程式
    system call 的程式是放在 <linux>/arch/arm/kernel 中,檔名即為 system call 的名字。
    用編輯器打開 mysyscall.c 後,將以下內容複製進去:
    #include <linux/linkage.h>   // asmlinkage
    #include <linux/kernel.h>   // linux/printk.h
    #include <linux/types.h>   // atomic_t
    #include <linux/atomic.h>   // atomic_inc()
     
    asmlinkage void sys_mysyscall(void)
    {
       static atomic_t count = ATOMIC_INIT(0);
    
       atomic_inc(&count);
       printk("mysyscall has been called for %d time(s)\n", count);
    }
    
  2. header檔linux/kernel.h引用linux/printk.h中包含了printk的log層級:
    #define KERN_EMERG    "<0>"    /* system is unusable */
    #define KERN_ALERT    "<1>"    /* action must be taken immediately */
    #define KERN_CRIT     "<2>"    /* critical conditions */
    #define KERN_ERR      "<3>"    /* error conditions */
    #define KERN_WARNING  "<4>"    /* warning conditions */
    #define KERN_NOTICE   "<5>"    /* normal but significant */
    #define KERN_INFO     "<6>"    /* informational */
    #define KERN_DEBUG    "<7>"    /* debug-level messages */
    
    所以 printk() 可以這樣用:printk(KERN_INFO "Hello, world!\n");。
    log層級太低訊息只會顯示在dmesg指令執行時,在commandline不會顯示任何訊息
  3. 註冊 system call 的名字
    <linux>/arch/arm/kernel/call.S 定義了系統中 system call 的名字,我們要將新的 system call 紀錄在這個檔案中。請用編輯器打開 call.S 之後,找到目前的最後一個 system call,
    CALL(sys_get_mempolicy)
    CALL(sys_set_mempolicy)
    
    然後在後面加上
    CALL(sys_mysyscall)
    
    再存檔即可。
  4. 定義新 system call 的代碼
    <linux>/include/asm-arm/unistd.h 定義了系統中 system call 的代碼,我們也需要在這裡定義新的 system call 代碼。請用編輯器打開 unistd.h 後,找到目前的最後一個 system call(大約在350行),
    #define __NR_get_mempolicy              (__NR_SYSCALL_BASE+320)
    #define __NR_set_mempolicy              (__NR_SYSCALL_BASE+321)
    
    然後在後面加上
    #define __NR_mysyscall                  (__NR_SYSCALL_BASE+322)
    
  5. 調整 Makefile ,使 systam call 被包含在 kernel 中
    <linux>/arch/arm/kernel/Makefile 是該目錄的 makefile ,我們要將 mysyscall.c 加入編譯的範圍內。在檔案一開頭可以找到需要編譯的 object file 列表,
    obj-y := compat.o entry-armv.o .....
    
在此行的後面加上 mysyscall.o 即可。
  1. 增加 system call 的 header file ,讓 user program 能夠 include
    接著,我們要將 mysyscall 的 header 加入 linux 的 header 目錄中,它的位置是 <linux>/include/linux ,在該目錄裡新增 mysyscall.h 的檔案,並填入以下內容:
    #include <linux/unistd.h>
    
    #define __NR_mysyscall         (__NR_SYSCALL_BASE+322)
    #define mysyscall(void)        syscall(__NR_mysyscall);
    
    再存檔即可。
  2. 重新編譯 kernel
    最後,回到 <linux> 並鍵入
    make CROSS_COMPILE=arm-linux-uclibc- ARCH=arm
    
    重新編譯 kernel 後,就會產生新的 kernel image 了。

3.3 用 QEMU 測試

為了測試 system call 是否有成功加到 kernel 中,我們可以先用 QEMU 載入新的 kernel image ,並另外寫一個 user program 來呼叫 mysyscall 。
  1. 撰寫 user program
    若要呼叫 mysyscall ,要在程式中 include linux/mysyscall.h 。以下為使用 mysyscall 的範例:
    #include "linux/mysyscall.h"
    
    int main(){
    
       mysyscall();
    
       return 0;
    }
    
  2. 編譯程式
在寫好程式之後,我們可以用之前做好的 cross-compiler 來編譯程式,不過要注意的一點是,因為程式的內容牽涉到 kernel 的資訊( system call 是包含在 kernel 中的 ),因此我們也需要加入 kernel 的 include 檔。
假設要編譯的程式檔名為 test.c ,而要生成的執行檔為 test.out ,則在終端機下鍵入:
arm-linux-uclibc-gcc -I<linux>/include/ -static test.c -o test.out
即可。

2013年7月19日 星期五

system call for arm platform (1)

android的external/kernel-headers/original目錄
from:
https://github.com/billwangwl/android_linux_stuff/blob/master/android_bionic_kernel-headers-original_explanation_zh_CN.html

external folder中linux kernel header的作用

在Linux中,有一个external/kernel-headers/original,这个文件夹中有很多linux的头文件,与kernel/include/linux有很多重复的文件。

 1、Android external folder

  External refers to external open source libraries. That means libraries that the Android platform depend upon but that are not primarily developed and maintained by the Android open source project. Typical examples are webkit for the browser, FreeType for fonts, SqlLite for databases and so on. As more features are added to Android, more of these libraries are included in external.

 external folder是外部的open source lib,这些lib是android依赖的,但是主要的开发和维护又不是android来做

 http://stackoverflow.com/questions/10477565/android-external-folder-functionality

  2,external/kernel-headers/original 

 (external/kernel-headers/original/README.TXT)

 这个文件夹里的头文件是Bionic来用生成一个干净的user-land(user space)头文件。基于GPL2+。  

3、Bionic

 Bionic libc是BSD standard C library发展而来,最早是Google为Android开发。作用主要有三个: 

a) BSD license: 通过BSD license,Android程序就和GPL分隔开来。

b) Bionic比GNU C Library要小的多。

c) Bionic的速度更快。

 Bionic也缺少很多完整的libc的特性,比如宽字符和C++的异常处理。一些函数也没有实现。 

(http://discuz-android.blogspot.com/2008/10/google-android-native-libc-bionic.html

HAL层,以及除了kernel以外的任意用到的C头文件,都是bionic中的。

 ./core/pathmap.mk,pathmap_INCL := libc:bionic/libc/include (http://www.linuxidc.com/Linux/2011-03/33672.htm

Android编译环境所用的交叉编译工具链是prebuilt/linux-x86/toolchain/arm-eabi-4.2.1/bin /arm-eabi-gcc,-I和-L参数指定了所用的C库头文件和动态库文件路径分别是bionic/libc/include和out /target/product/generic/obj/lib

 (http://www.360doc.com/content/09/0624/17/36491_4018938.shtml )

 kernel中用的头文件在kernel/include中。user space用的头文件在bionic下。

 4,Bionic kernel header 

 (bionic/libc/kernel/README.TXT)

 Bionic有一套干净的Linux头文件,这些头文件是通过bionic/libc/kernel/tools解析一份原始的,没有修改过的linux头文件生成的,这份头文件就在external/kernel-headers/original

干净的头文件只包括类型和宏定义,不过处于效率的考虑,不会生成一些静态内联函数。 

这些生成的头文件可以用于编译C++,C,也能够按照ANSI模式编译(linux kernel中用到了大量GNU扩展)。

生成头文件的过程是:

 *external/kernel-headers/original 包含通常linux kernel source tree中的include目录。这里仅仅只应该包含android依赖的kernel头文件。

 *bionic/libc/kernel/common 包含平台无关的头文件。 

from:

 http://blog.csdn.net/muge0913/article/details/7518568

 About sys_ni_syscall in Kernel System Call Table

不是所有的系统调用都有实际内容,如sys_ni_syscll在kernel/sys_ni.c中定义:
asmlinkage long sys_ni_syscall(void)
{
    return -ENOSYS;
}

你会发现在sys_call_table中sys_ni_syscall占据了很多内容,其实它代表着已被淘汰的系统调用。其实只要是被内核淘汰的系统调用都会被sys_ni_systcall代替。之所以这样是为了老的程序在新的内核上运行时不至于出现大的问题。如不应调用这个系统调用却调用了那个系统调用了。

from:

http://bbs.csdn.net/topics/350141651

cond_syscall

#ifndef cond_syscall  
     #define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall")
#endif

告诉编译器,当在符号表中没有x时,就用sys_ni_syscall这个符号来代替。这样的话,一些在特殊系统中没有定义出的系统调用的函数,就被默认为是sys_ni_syscall了。

2013年7月9日 星期二

ubuntu super user

因為android下envsetup.sh中的mm指令權限不足無法編譯,
而直接下"sudo mm"又無法正確識別為mm指令,
只好成為root帳號來下指令。
要成為root要打指令"su  -",
可是在ubuntu下,一般操作都以sudo指令代替直接以root帳號執行指令,
因此不知道root密碼為何,無法進入root 帳號,
可以用"sudo passwd"修改root密碼再行登入。

2013年7月2日 星期二

oprofile

  • Oprofile 包含在 Linux 2.5 和更高版本的内核中
編譯kernel:
General setup
            Kernel Performance Events And Counters     --->
                          -> Kernel performance events and counters   # CONFIG_PERF_EVENTS
            -> Profiling support  [*]                             # CONFIG_PROFILING
            -> OProfile system profiling  <*>            # CONFIG_OPROFILE
Kernel Features
            -> Enable hardware performance counter support for perf events [*]
            # CONFIG_HW_PERF_EVENTS

在menuconfig模式中,可以用"shift + ?"查詢.config與make menuconfig所設定的對應關係,也可以用"/"查詢.config的選項名稱。

opcontrol  --setup

oprofiled  --session-dir=/data/oprofile  --vmlinux=/vmlinux   \

--kernel-range=c00xxxxx,c0xxxxxx  --events=CPU_CYCLES:255:0:10000:1:1:1   \

--separate-lib=1  --separate-kernel=1


opcontrol  --setup  --vmlinux=/vmlinux  -kernel-range=c00xxxxx,c0xxxxxx    \

--event=CPU_CYCLES:10000:1:1:1

opcontrol --timer