2012年12月30日 星期日

Cubieboard 耗電量實測





源起,最近在玩一個板子,Cubieboard (就一塊有帶SATA 的 A10 板子),心想到效能尚可,想拿來當多媒體播放中心,大家雖然知道它應該很省電,但耗電量多少也沒有看到測試報告,好奇想知道到底如何?於是有了本文。

測試一 (使用測電計, 藍光機殼溫度計)



執行環境

使用linaro desktop with sunxi-bsp


參考這一篇:Confirming that the Linaro Desktop build for the Hackberry works on CubieBoard

git clone https://github.com/linux-sunxi/sunxi-bsp/
cd sunxi-bsp
wget http://dl.linux-sunxi.org/amery/sunxi-3.0/20121109-1024/cubieboard_hwpack.tar.xz
wget http://releases.linaro.org/12.11/ubuntu/precise-images/alip/linaro-precise-alip-20121124-519.tar.gz
./scripts/sunxi-media-create.sh /dev/YOURSDCARD YOURHWPACK YOURROOTFS

製作了一個linaro desktop 的 SDCARD,試了這個版本總算 SATA 及2D 影片(RMVB 640x480 RV40 OK)播放功能都能正常支援。

測試時,硬體連接方式

測電計 --> 5v 變壓器(iphone 附)--> cubieboard → HDMI → HDMI-to-DVI 轉接頭 → CHIMEI LCD 22”

Part 1
初始耗電功率: 2.2w  (linaro 啟動到HDMI 輸出畫面)

Part 2
GNOME MPlayer 執行三個 (352x262 FFMPEG1, FFMP2FLOAT) 電影檔案 透過 samba intranet
CPU load: 86~92.7%





啟動時間 (分鐘後)A10 溫度: ℃耗電功率
2743.8℃3.6W
4346.4℃3.6W
4647.3℃3.6W
4947.9℃3.6W
5247.7℃3.6W
5647.8℃3.6W
6147.6℃3.6W
6447.4℃3.6W
7047.3℃3.6W


Part 3
將播放程式全部停止後,只有Linaro 桌面環境時



啟動時間 (分鐘後)A10 溫度: ℃耗電功率
9040.4℃2.2W
9238.5℃2.1W
9437.4℃2.2W


結論



Cubieboard 真是個省電好物,拿來當 media center (影音播放器)很適合。
linaro 桌面待機也不過2.2W而已。

接下來,目前有一點有待解決的問題如下:
* 就是youtube 在瀏覽器播放,會lag 的問題。
* 有啟動ibus時,會讓鍵盤輸入變得很卡,就算沒有有中文輸入也一樣。

附註:目前聲音用音源線接是OK的,從HDMI 還沒試過。

(如有同好使用的話,歡迎互相交流問題,把它弄得更好用吧。)


2013﹣01﹣01 更新:
中文輸入法部分改用 gcin 輸入子系統,調整一下 Locales 相關的設定後,中英文輸入得到不錯的速度。


2013﹣01﹣02 更新:
加入 ASUS N10 USB Wireless 支援 (patch sunxi-bsp),當無線網路啟用時,觀察CPU 使用約10~20﹪(@.@)。(更完整報告整理中。)

2012年12月27日 星期四

我們可能使用更高階的語言來寫OS嗎?


今天我看在 JuluOSDev 論壇上看到 

Descent 問道:寫 os 真的只有組合語言, c/c++ 可以完成嗎?別的語言無法用來寫 os 嗎?
(本文同步回覆於論壇)

以下是我參考一些文章翻譯及一點自已小心得總和而來。

其實是也不是,對所有語言來說最終會轉換machine code (大部分會產生中間的assembly)。
換個精確一點的問法:「我們可能使用更高階的語言來寫OS嗎?」

答案不是絕對的,因人而異。

排列比較答案後,大部分想使用高階語言來寫OS,是想簡化學習的曲線,避掉一些瑣碎細節,來享受快速開發的好處。

但憑心而論,學習沒有捷徑,天道酬勤;
還是需要大量的作業系統設計的基礎(如網路通信協定、記憶體管理、執行緒、驅動程式等等),
畢竟不會使用舊的方法的問題所在;無法創造新的路出來。

從技術的觀點來看,電腦其實並不知道你使用的是C#,還是JAVA;

首先你第一個要的是一個 bootloader, 
如果略過bootloader 的部分,你可以用任何語言來寫OS,

假設所使用的語言可以編譯出機器語言(而不是byte code,但有人可能反駁說硬體有JVM chip,可能也是成立的,視環境而定)。

另一方面,從效能的觀點,OS常需要精實而高效率的,
這部分高階語言無法為你做的,很有可能你會需要自行開適合的編譯器或其他的子系統來輔助,因為在和硬體溝通的部分若沒有低階語言存取能力,事情可能變得更複雜一些。

最後,就我個人而言,也夢想有一天,自已能用 python 或 nodejs 等語言來寫出OS來。

以下是大略列出(但不限),其他語言可用來寫OS:


* Forth -- http://www.forth.org/svfig/osf.html
ref: http://en.wikipedia.org/wiki/Forth_(programming_language)

* Lisp -- Genera is a commercial operating system
ref: http://en.wikipedia.org/wiki/Genera_(operating_system)

* JAVA: JNode
ref: http://www.jnode.org/
ref: http://www.jopdesign.com/ (Java Optimized Processor)

* C#: Singularity
ref: http://research.microsoft.com/en-us/projects/singularity/

* Ada: MaRTE OS
ref: MaRTE OS: An Ada Kernel for Real-Time Embedded ... - CiteSeerX
ref: http://marte.unican.es/


參考資料:
*stackoverflow - 627095/can a whole operating system be written without using even one line of c c code

*High level Languages and IO Access in Computer Interfacing﹣ osdever.net/tutorials/pdf/high_level_io.pdf

* System Programming in a High Level Language - Andrew D Birrell ﹣ http://birrell.org/andrew/papers/thesis.pdf

* wikipedia Operating system

* stackoverflow - 3317329/what language is used to write operating systems windows
* quora.com/What programming language are operating systems written in


以上寫了一堆,希望有所幫助。

2012年7月25日 星期三

F4OS與STM32F407的那些事兒?


源起,最近看到STM32F407這塊板子CPU 168MHz,性價比很高,手滑買了下來。


這塊板子上有個高手(Michael Pratt)正在認真地開發上面的作業系統,專案名為F4OS,源碼開放在GitHub。歷經三個多月,目前成品可直接在USART1跑一個只有一個uname 指令的shell。

在嵌入式無螢幕的裝置上,開發OS,最難的地方便是在沒有任何輸出之前的階段,把Terminal Console弄出來。

首先,Michael 開發是最先利用板子上的LED的明暗速度來進行偵錯。

筆者大約在6月份時,第一次用F4OS便是將LED 的明暗做調整,
接著用ARM的GDB來觀察暫存器值的變化,這真是黑暗前期。

直到最近,當看到Terminal輸出的畫面的一刻,真是令人十分感動。

USB2TTL

筆者使用的是  FT232 USB-Serial 的裝置
使用lsb 命令結果

~$ lsusb
Bus 002 Device 022: ID 0403:6001 Future Technology Devices International, Ltd FT232 USB-Serial (UART) IC
Bus 002 Device 021: ID 0483:3748 SGS Thomson Microelectronics
Bus 002 Device 002: ID 0e0f:0002 VMware, Inc. Virtual USB Hub
Bus 002 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub

STM32F407 + F4OS輸出畫面


執行uname -a 的輸出結果:

$ uname -a
F40S rev 143 Wed Jul 25 22:36:20 CST 2012

USB2TTL 與 STM32407 的連接

使用杜邦端子線來連接USB2TTL及STM32,之前一直卡在這裡;故特別對接法做個記錄。

STM32 Pin   ----    USB2TTL
PB6 (TX)  <------------> RX
PB7 (RX)  <------------> TX
GND  <-----------------> GND
(註:GND 線不接也可正常運作)

小結

有了Terminal 輸出的功能之後,開始進行其他實驗就十分的方便。
以上記錄目前的學習進度。


2012年5月21日 星期一

實作第一個BenOS 系統呼叫 puts

最近很久沒有更新BenOS的訊息,最近專注在研讀MIT-OSE 課程。

本次仿造 MIT-OSE JOS 中的系統呼叫,
筆者為自己小OS加新功能,算是對最近學習的一個驗證。

實作程式碼在 https://github.com/benwei/bos (develop branch)。

讓我們先來看JOS的系統呼叫的概念圖:
 可參考Lab3 JOS 實作程式碼在branch lab3 https://github.com/benwei/MIT-JOS

Lab3 JOS syscall calling sequence

執行步驟:
  1. lib/libmain.c:17 呼叫 sys_getenvid()
  2. lib/syscall.c:61 呼叫 syscall(SYS_getenvid)
  3. lib/syscall.c:23 呼叫48號中斷 帶入系統呼叫SYS_getenvid(2) 號
  4. 發生中斷 kern/trapentry.S:98, 將返回值0及 系統呼叫SYS_getenvid(2) 號放入堆疊,
  5. 跳至 kern/trapentry.S:312 _alltraps中,將相關的暫存器放入堆疊,接著執行332行trap(%esp), %esp == struct Trapframe *tf
  6. 為避免重覆執行中斷, kern/trap.c:200, eflags & FL_IF == 0 必須為真,204行檢查只否由使用者空間進入(tf->tf_cs & 3) == 3, 將tf 複製到核心空間保存;執行220行trap_dispatch()
  7. 執行trap.c:172 核心的syscall() 在 kern/syscall.c
  8. 跳至kern/syscall.c:87 執行 sys_getenvid(), 取得 curenv->env_id
  9. 返回trapdispatch, 執行kern/env.c:520 env_run 中 env_pop_tf()
  10. 呼叫kern/env.c:502 重新設置返回值及相關暫存器
  11. 於kern/env.c:507 執行iret 結束系統呼叫中斷
  12. 回到使用者空間,lib/syscall.c:34 檢查回傳值等等,完成一個呼叫流程
(注意:在lib/syscall.c:23及 TRAPHANDLER_NOEC&_alltrap 放入堆疊的數量與env_pop_tf 取回堆疊的數值必須一致,否則系統將發生不可預的行為。)

BenOS 實作


本次只先實作部分 kernel thread 間的系統呼叫,尚無ring3 至ring 0之間的權限切換。

詳見 user/libsyscall.c:10 系統呼叫:int TRAP_SYSCALL(68) , 其中 BSYS_PUTS(8)

1 #include "user/syscall.h"
2 #include "stdio.h"
3
4 /*
5  * num: BSYS_PUTS, a1 is string for display, a2 is undefined.
6  */
7 unsigned int syscall(int num, unsigned int a1, unsigned int a2)
8 {
9         unsigned int ret = 0;
10          __asm __volatile(
11                 "int %1\n"
12                 :"=a" (ret)
13                 :"i" (TRAP_SYSCALL),
14                  "a" (num),
15                  "d" (a1),
16                  "c" (a2)
17                 :"cc", "memory");
18         printf("syscall with ret=%d\n", ret);
19         return ret;
20 }
21
22 void uputs(const char *msg)
23 {
24         syscall(BSYS_PUTS, (unsigned int)msg, 202);
25 }

在kernel/osfunc.s:126 使用nasm 語法寫成,IDT 中斷呼叫256個函式庫。

其中osfunc.s:400 為減少堆疊使用,僅使用三個參數。
(註:將JOS 中的env_pop_tf 改寫成409~413,較易於理解)

400 _all_trap_handler:
401         push eax
402         push edx
403         push ecx
404
405         push esp
406         call trap_handler
407         add  esp, 4
408
409         pop ecx
410         pop edx
411         add esp, 4 ; no pop eax for return code
412         add esp, 8
413         iretd

kernel/trap.c
70 int trap_handler(struct trapframe *tf)
71 {
72         switch(tf->trapno) {
73         case TRAP_SYSCALL:
74                 print_tf(tf);
75
76                 return kern_syscall(tf->regs.eax,
77                              tf->regs.edx,
78                              tf->regs.ecx);
79                 break;
80         default:
81                 print_tf(tf);
82                 panic("panic: system halt\n");
83         }
84         return 0;
85 }

kernel/ksyscall.c
6 int kern_syscall(uint32_t num, uint32_t a1, uint32_t a2)
7 {
8         int ret = 0;
9         if (num == BSYS_PUTS) {
10                 do {
11                 struct task *t = get_now_task();
12                 printf("task_id(%d) syscall(BSYS_PUTS,a2=%d),a1: %s\n", t->pid, a2, a1);
13                 ret = strlen(a1);
14                 } while(0);
15         }
16         return ret;
17 }

執行結果:

開機完成至bos$ 下,執行run 來執行task 2 (events: hello_main)

0521_BOS


小結


本次的系統呼叫的基本框架,以最精簡的部分,實作出來。

筆者正在嘗試加入ring3 至 ring0 時,
在windows的qemu 0.13版,執行run 命令,qemu系統自動重新啟動bos;
但在MAC OS X 中使用qemu 0.12.5 執行同樣測試時,
qemu 會顯示正確存取權限失敗,
因為bos在ring3 中直接呼叫ring0函式。之後,會對使用者權限切換部分繼續實作。

有任何問題建議,歡迎至 http://www.juluos.org or http://julu.staros.mobi  中的Juluosdev google groups 參與討論。

2012年5月20日 星期日

python + shellcode 實測 64/32

0520-shellcode_py

最近看到Shellcode文章,手癢把它改相容64bit Ubuntu及32bit cygwin 了。

由此下載原始碼修改過smc.py


Ubuntu 11.10 (GNU/Linux 3.0.0-12-virtual x86_64)
使用Python 2.7.2+,進行測試

Linux pylab 3.0.0-12-virtual #20-Ubuntu SMP Fri Oct 7 18:19:02 UTC 2011 x86_64 x86_64 x86_64 GNU/Linux
# python smc.py
linux2_add64(99, 1) = 100


Linux xubuntu 2.6.35-32-generic #65-Ubuntu SMP i686 GNU/Linux
使用Python 2.6.6,進行測試

$ python smc.py
linux2_add32(99, 1) = 100


Windows XP+cygwin+gcc(4.5.3) + python 2.7.2
使用dump_machine_code.sh, ASM 的結果:

add.o:     file format pe-i386
Disassembly of section .text:
00000000 <_add>:
   0:   55                      push   %ebp
   1:   89 e5                   mov    %esp,%ebp
   3:   8b 45 0c                mov    0xc(%ebp),%eax
   6:   03 45 08                add    0x8(%ebp),%eax
   9:   5d                      pop    %ebp
   a:   c3                      ret
   b:   90                      nop
cygwin中,執行smc.py結果
$ python smc.py
cygwin_add32(99, 1) = 100


載入平台相依的libc

if sys.platform == "cygwin":
    libc = cdll.LoadLibrary("/bin/cygwin1.dll")
else:
    libc = CDLL('libc.so.6')


判斷32或64位元的方法之一


import sys
from math import log
def is64bit():
    return log(sys.maxsize, 2) == 63


小結


這技巧可以使用smc主程式,隨意在執行時修改程式碼的方法,也提供一條路讓python直接與硬體溝通。

如這是一個24小時不能停機的程式,意味著筆者可利用這方法做出不需要重新執行python主程式來動態載入修改過的函式庫。

當然這種方法也會影響Python 跨平台的可攜性,
解決方法只能為各種所需執行平台編繹對應的版本(若其平台安裝有gcc,則可以在執行檢查有無對應的platform_func.o 檔案,動態產生並載入它,類似pyc的做法)。

2012年3月31日 星期六

使用 array-label-goto 來模擬 while-switch-case 語法






最近看到在 Jserv 他的簡報中的某些Kernel原始碼,

使用 array+label + goto 來模擬while-switch-case的指令。

目的是讓整個程式片段能完整載入到CPU的L1快取中,

以提高程式效能。

以下是筆者所做的小實驗,程式碼可由此下載。

testla.c 用 array+label+goto 來實作


#include "testla.h"
#define dispatch(s, h)  { int n = (*++s) ? (s - h) % 3 : 3; \

                          goto *tdispatch_list[n]; }

int run(const char *s)
{
        const char *head = s;
        void *tdispatch_list[] = {&&la, &&lb, &&lc, &&ld};
        int a = 1;

        la:
               dmsg("a:%c\n", *s);
               a++;
               dispatch(s, head);
        lb:
               dmsg("b:%c\n", *s);
               a++;
               dispatch(s, head);
        lc:
               a-=2;
               dmsg("c:%c\n", *s);
               dispatch(s, head);

        ld:
        return a;
}

testsw.c 用while-switch-case 來實作

 #include "testla.h"

int run(const char *s)
{
        const char *h = s;
        int n = 0;
        int a = 1;
        do {

            switch(n) {
            case 0:
                   dmsg("a:%c\n", *s);
                   a++;
                    break;
            case 1:
                   dmsg("b:%c\n", *s);
                   a++;
                    break;
            case 2:
                   a-=2;
                   dmsg("c:%c\n", *s);
            };

            n = (*++s) ? (s - h) % 3 : 3;

        } while(n != 3);
        return a;
}


共用的主程式部分



#include "testshared.h"

int main(int argc, char **argv) {
        const char *s = "hello";
        long i;
        for (i = 0 ; i < 250000000; i++) {
                run(s);
        }
        return 0;
}


編譯及測試用Makefile

SHELL=bash

OS=$(shell uname -s)

ifeq ($(CROSS),1)
ifeq ($(OS),Darwin)
        CROSS_COMPILE=/usr/local/gcc-4.5.2-for-linux64/bin/x86_64-pc-linux-
        CC=$(CROSS_COMPILE)gcc
        AS=$(CROSS_COMPILE)as
        LD=$(CROSS_COMPILE)ld
        ifeq ($(DUMP_AD),1)
        CFLAGS = -Wa,-a,-ad
        endif
endif
endif


ifeq ($(NO_O2),1)
CFLAGS += --save-temps
else
CFLAGS += -O2 --save-temps
endif

all: testla testsw

.c.o:
        $(CC) -c $< -I. $(CFLAGS)

testla: main.o testla.o
        $(CC) -o $@ $^

testsw: main.o testsw.o
        $(CC) -o $@ $^


run: testla testsw
        time ./testla
        @echo
        time ./testsw

執行結果


(以執行環境:windows xp, cygwin 為例)
無最佳化 -O2參數,testla 檔案大小 20136 Bytes; testla 檔案大小 19624 Bytes

testlabelsw$ make run

time ./testla

real    0m5.596s
user    0m5.546s
sys     0m0.092s

time ./testsw

real    0m6.034s
user    0m5.968s
sys     0m0.077s

有最佳化 -O2 參數, 檔案大小 20136Bytes; testla 檔案大小 19624Bytes

testlabelsw$ make run
time ./testla


real    0m3.172s
user    0m3.077s
sys     0m0.061s

time ./testsw

real    0m3.219s
user    0m3.140s
sys     0m0.093s


結論

目前測試只在User Space中,執行函式2.5億次

無最佳化下,大約有 7.25 % 的效能提升。

有最佳化下,大約只有 1.46 % 的效能提升。

以目前的結果來看,若去除誤差值約0.2%,使用最佳化的情況下,

在user-space下,可能不太有價值去做這樣的更動;

但就系統Kernel來說,這個方法提供一種優化演算法的小技巧,值得玩玩。

更新04-19


根據Jserv的回覆:筆者添加到5個switch-case,在有最佳化的情況下,效能提升至 9~10% 之間(測試數據 ),所以在此更正結論。原始碼已更新,請由此下載。



2012年2月26日 星期日

用BeagleBone Rev.A3 打造簡易行動NAS系統

承上篇開發環境 BeagleBone A8 實測Linaro-nano, 筆者便想這塊Beaglebone 可以做什麼實際用途呢?

去年,曾寫過試用FreeNas 8.01一文,若能將常用的功能(rsync, ssh, cifs) 放到Beaglebone,則它便可成為一台行動網路NAS。

但FreeNas 還沒有ARM的版本,所以筆者用Linaro-nano 為基礎,作了簡單實做。

開發時,遇到網路卡會不定時自動斷掉,十分惱人。原本以為是Linaro 所用的kernel 不穩定;
後來找了很久,最後發現BeagleBone - Rev. A3上已知硬體問題。

Etherent Drop/Reset switch(A3 and A4 Only]
On some A3 and A4 boards, the reset switch can develop a low impedance path to ground creating a voltage divider making the reset line go to 1.5V to 1.8V. To determine this you can measure the voltage on pin 10 of P9. This issue can cause intermittent resets of the SMSC PHY, causing the link to drop. To fix this, just remove the reset switch. No, it will not void the warranty on the board if you remove the reset switch. You can request an RMA for a new switch and one will be sent to you. You can also request an RMA, return the board, and we will repair the switch for you.

remove_reset_button

依照說明(不會因此破壞保固),用尖嘴鉗把Reset 按鈕暴力拔除;斷電後,重新啟動執行,測試超過24小時,目前都運作正常。


簡易NAS移植

在Linaro 中,以apt-get 安裝下列套件
  • CIFS - Samba
  • Rsync -
  • FTP  - sftp
  • SSH - openssl-server
另外,使用者介面部分,暫時先以編輯設定檔方式來修改啟動必要之功能。

目前在開發板中,以Web方式來實作必要的管理介面。
Web 由將下列主要由 node.js+ python batchjob 組成。

利用node.js來實做web 介來顯示系統狀態:

使用arm gcc-4.6.1, 編譯node.js 0.6.9,並安裝npm套件: express, commander, nconf

NAS Web Prototype – Status

nas-web

小結:

經由上述實做,筆者將beaglebone Rev.A3 打造成為一個小型NAS 系統,
可利用 rsync , ssh/sftp , cifs 來經由網路存取其SD卡或姆指碟,
而系統記憶使用量約在80MB左右,應可進一步瘦身;
最後可依筆者需求來開發對應Restful API來進行管理作業。