2010年7月13日 星期二

關於linux/ctype.h

/include/linux/ctype.h此路徑為相對路徑,其絕對路徑依照linux源碼樹為參考:例如我的源碼樹存放在/opt/FriendlyARM/mini2440/linux-2.6.32.2;所以絕對路徑如下:/opt/FriendlyARM/mini2440/linux-2.6.32.2/include/linux/ctype.h
/include/linux/ctype.h代碼如下
#ifndef _LINUX_CTYPE_H
#define _LINUX_CTYPE_H
/*
* NOTE! This ctype does not handle EOF like the standard C
* library is required to.
*/
#define _U 0x01 /* upper */ /* 大寫字母A-Z*/
#define _L 0x02 /* lower */ /* 小寫字母a-z */
#define _D 0x04 /* digit */ /* 數字0-9 */
#define _C 0x08 /* cntrl */ /* 控制字元 */
#define _P 0x10 /* punct */ /* 標點符號*/
#define _S 0x20 /* white space (space/lf/tab) */ /* 空白字元:空格、\t、\n 等 */
#define _X 0x40 /* hex digit */ /* 十六進位數 */
#define _SP 0x80 /* hard space (0x20) */ /* 空格字元0x20 */
extern unsigned char _ctype[];
#define __ismask(x) (_ctype[(int)(unsigned char)(x)])

#define isalnum(c) ((__ismask(c)&(_U∣_L∣_D)) != 0)
#define isalpha(c) ((__ismask(c)&(_U∣_L)) != 0)
#define iscntrl(c) ((__ismask(c)&(_C)) != 0)
#define isdigit(c) ((__ismask(c)&(_D)) != 0)
#define isgraph(c) ((__ismask(c)&(_P∣_U∣_L∣_D)) != 0)
#define islower(c) ((__ismask(c)&(_L)) != 0)
#define isprint(c) ((__ismask(c)&(_P∣_U∣_L∣_D∣_SP)) != 0)
#define ispunct(c) ((__ismask(c)&(_P)) != 0)
#define isspace(c) ((__ismask(c)&(_S)) != 0)
#define isupper(c) ((__ismask(c)&(_U)) != 0)
#define isxdigit(c) ((__ismask(c)&(_D∣_X)) != 0)

#define isascii(c) (((unsigned char)(c))<=0x7f) #define toascii(c) (((unsigned char)(c))&0x7f)
static inline unsigned char __tolower(unsigned char c) { if (isupper(c)) c -= 'A'-'a'; return c; } static inline unsigned char __toupper(unsigned char c) { if (islower(c)) c -= 'a'-'A'; return c; } #define tolower(c) __tolower(c)
#define toupper(c) __toupper(c)
#endif

以下是/lib/ctype.c
#include
unsigned char _ctype[] = {
_C,_C,_C,_C,_C,_C,_C,_C, /* 0-7 */
_C,_C∣_S,_C∣_S,_C∣_S,_C∣_S,_C∣_S,_C,_C, /* 8-15 */
_C,_C,_C,_C,_C,_C,_C,_C, /* 16-23 */
_C,_C,_C,_C,_C,_C,_C,_C, /* 24-31 */
_S∣_SP,_P,_P,_P,_P,_P,_P,_P, /* 32-39 */
_P,_P,_P,_P,_P,_P,_P,_P, /* 40-47 */
_D,_D,_D,_D,_D,_D,_D,_D, /* 48-55 */
_D,_D,_P,_P,_P,_P,_P,_P, /* 56-63 */
_P,_U∣_X,_U∣_X,_U∣_X,_U∣_X,_U∣_X,_U∣_X,_U, /* 64-71 */
_U,_U,_U,_U,_U,_U,_U,_U, /* 72-79 */
_U,_U,_U,_U,_U,_U,_U,_U, /* 80-87 */
_U,_U,_U,_P,_P,_P,_P,_P, /* 88-95 */
_P,_L∣_X,_L∣_X,_L∣_X,_L∣_X,_L∣_X,_L∣_X,_L, /* 96-103 */
_L,_L,_L,_L,_L,_L,_L,_L, /* 104-111 */
_L,_L,_L,_L,_L,_L,_L,_L, /* 112-119 */
_L,_L,_L,_P,_P,_P,_P,_C, /* 120-127 */
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 128-143 */
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 144-159 */
_S∣_SP,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P, /* 160-175 */
_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P, /* 176-191 */
_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U, /* 192-207 */
_U,_U,_U,_U,_U,_U,_U,_P,_U,_U,_U,_U,_U,_U,_U,_L, /* 208-223 */
_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L, /* 224-239 */
_L,_L,_L,_L,_L,_L,_L,_P,_L,_L,_L,_L,_L,_L,_L,_L}; /* 240-255 */

所以由此我們可以來驗證:
大寫S=58h=88 查_ctype得到_U = 0x01
因此我們以以下幾個巨集來求證:
isalnum("S")=(0x01)& (ox01 ∣ 0x02 ∣ 0x04) =1,所以得到true
isalpha("S")=(0x01)& (ox01 ∣ 0x02) =1,所以得到true
iscntrl("S")=(0x01)& (ox08) =0,所以得到false
isdigit("S")=(0x01)& (ox04) =0,所以得到false

♫=0eh=14 查_ctype得到_C = 0x08
因此我們以以下幾個巨集來求證:
isalnum("S")=(0x08)& (ox01 ∣ 0x02 ∣ 0x04) =0,所以得到false
isalpha("S")=(0x08)& (ox01 ∣ 0x02) =0,所以得到false
iscntrl("S")=(0x08)& (ox08) =1,所以得到true
isdigit("S")=(0x08)& (ox04) =0,所以得到false
參考更多特殊字碼:http://cowwu.myweb.hinet.net/note/text/930421a.htm
ASCII code:http://home.educities.edu.tw/wanker742126/index.html
--> 閱讀更多...

2010年7月11日 星期日

如何在32bits保護模式下作debug

以下我所論及的主題並非是在os的保護模式底下的debug方式;而是當你有自己的執行系統,這個執行系統是從16bits模式執行後進入32bits保護模式,並且執行自己定義的ap。就類似memtest86這種從booting到run ap都能一手掌控的代碼。然而memtest在保護模式下都是C語言代碼,因此要debug相對容易,所以我們要討論的是以assembly為架構的debug方式。
首先我們知道frame buffer是以為址0xb8000~0xb8fff為vga顯示控制區域;當然其他模式mapping到的位址也不同;但我們討論的是前者。雖然在dos或16bits模式可以使用int 10h來讀寫螢幕,我們也知道int 10h的作法也是去控制frame buffer。然而進入保護模式下傳統的bios及dos中斷已不能調用。但是我們還是可以直接去存取frame buffer;所以我寫了比下代碼以assembly的方式來顯示一些除錯用途的資訊:
以下資訊為如何在保護模式下debug,並利用健盤做單步debug
;清除所有的輸出緩衝器資料
push ax
FlushOBF: in al,64h
test al,1
jz NotOBF
in al,60h
jmp short FlushOBF
NotOBF: pop ax


push ecx
push ebx
mov ecx,edi
POS_XY bx,20,23
call sub32_hexprint
pop ebx
pop ecx

;等待8042輸出緩衝器有資料送進來
push eax
WaitOBFLoop:
in al,64h
test al,1
jz WaitOBFLoop

pop eax
;以上這小段完成健盤單步執行判斷,做法是當無按鍵被按下時,便一直執行迴圈
;用法:
;先push ecx和ebx
;將要顯示的資料存到ecx
;POS_XY bx,__x,__y
;call sub32_hexprint
;pop ecx和ebx

sub32_hexprint proc
pushad
mov eax,160
mul bl
add eax,SCREEN_ADR
xchg eax,edx
mov eax,2
mul bh
add edx,eax
mov bx,8 ;count
xor edi,edi
NEXT:
call cl2digital
mov BPTR[edx+edi],al
shr ecx,4
add edi,2
dec bx
jnz NEXT
popad
ret
sub32_hexprint endp

cl2digital proc
xor eax,eax
push ecx
and ecx,0fh
cmp cl,10
jae isA2F
add cl,30h
jmp exit
isA2F:
sub cl,10
add cl,41h
exit:
mov al,cl
pop ecx
ret
cl2digital endp

下面是marco
SCREEN_ADR equ 0b8000h
POS_XY macro r_, x_, y_
mov r_, (((x_) SHL 8) + (y_))
endm


以下為鍵盤控制指令參考:
; ========================================================
; 以下為8042界面函數之內部呼叫函數
; ========================================================
;
Flush8042 PROC
; 清除所有的輸出緩衝器資料
push ax
FlushOBF: in al,64h
test al,1
jz NotOBF
in al,60h
jmp short FlushOBF
NotOBF: pop ax
retn
Flush8042 ENDP
;
WaitIBF PROC
; 等待8042輸入緩衝器有空
WaitIBFLoop: push ax
in al,64h
test al,2
pop ax
jnz WaitIBFLoop
retn
WaitIBF ENDP
;
WaitOBF PROC
; 等待8042輸出緩衝器有資料送來
WaitOBFLoop: push ax
in al,64h
test al,1
pop ax
jz WaitOBFLoop
retn
WaitOBF ENDP
;
Read8042Data PROC
; 讀取8042回應資料
; 傳回: AL = 回應資料
call WaitOBF ; 等待資料回庄
in al,60h
retn
Read8042Data ENDP
;
Write8042Data PROC
; 送出資料給8042
; 參數: AL = 8042系統命令或資料
; 備註: 本函數亦為送出系統命令或資料的函數
call WaitIBF ; 等待輸入緩衝區有空
out 60h,al ; 送出資料
call WaitIBF ; 確認8042收到
retn
Write8042Data ENDP
;
RealSend8042Cmd PROC
; 送出一般命令碼給8042
; 參數: AL = 8042一般控制命令
; 備註: 8042命令之參數或傳回值由外界處理
call WaitIBF ; 等待輸入緩衝區有空
out 64h,al ; 送出命令
call WaitIBF ; 確認8042收到
retn
RealSend8042Cmd ENDP
;
RealSend8042Sys PROC
; 送出系統命令碼或參數給8042
; 參數: AL = 8042系統控制命令或參數
; 傳回: AL = 8042回應值
; 備註: 除回音外,其餘命令或參數應檢查是否傳回ACK
call Flush8042
call Write8042Data
call Read8042Data
retn
RealSend8042Sys ENDP
;
; ========================================================
; 以下為8042界面函數,使用前必須使用CLI將岔斷禁能
; ========================================================
;
Send8042Cmd PROC
; 送出一般命令碼給8042
; 參數: AL = 8042一般控制命令
call RealSend8042Cmd
retn
Send8042Cmd ENDP
;
Read8042Cmd PROC
; 送出讀取命令給8042
; 參數: AL = 8042讀取命令
; 傳回: AL = 讀取值
call Flush8042
call RealSend8042Cmd
call Read8042Data
retn
Read8042Cmd ENDP
;
Write8042Cmd PROC
; 送出寫入命令給8042
; 參數: AL = 8042寫入命令
; AH = 寫入資料
; 備註: AX值會被破壞
call RealSend8042Cmd
xchg al,ah
call Write8042Data
retn
Write8042Cmd ENDP
;
Echo8042 PROC
; 送出8042回音命令
; 傳回: AL = EEh
mov al,0EEh ; 回音命令
call RealSend8042Sys
retn
Echo8042 ENDP
--> 閱讀更多...

2010年7月6日 星期二

u-boot 顯示logo,並說明其原理part1


jpegtopnm Benson.jpg l ppmquant 31 l ppmtobmp -bpp 8 > Benson-8bit.bmp
紅色l是管線符號,因無法正常顯示所以用小寫L取代
以上這個指令必須先安裝netpbm,其作用是將jpeg檔轉成特定格式的bmp檔。將Benson-8bit.bmp更改檔名為denx.bmp並存到tools\logos,重新compile u-boot,便可完成,如上圖。接著我們來說明其draw logo原理:
在/tools/Makefile:
LOGO_H = $(OBJTREE)/include/bmp_logo.h
ifeq ($(LOGO_BMP),)
LOGO_BMP= logos/denx.bmp
endif
ifeq ($(VENDOR),atmel)
LOGO_BMP= logos/atmel.bmp
endif
$(LOGO_H):$(obj)bmp_logo $(LOGO_BMP)
$(obj)./bmp_logo $(LOGO_BMP) >$@ 這個$@就是bmp_logo.h
也就是說$(LOGO_H)這個目標的必要條件是bmp_logo denx.bmp這兩個檔案,才能產生bmp_logo.h這個主角,它就是denx.bmp的位元圖陣列。
所以在uboot主目錄中的makefile中有這麼一行:@rm -f $(obj)include/bmp_logo.h。在clean 時會將其刪除。
以上資訊若使用Source Insight根本無法搜尋得到,終就還是得到linux使用gerp。像這次我的搜尋指令如下:grep -Hwn "bmp_logo.h" -r ./ 接著我們來了解一下bmp_logo.c:這是一支單一檔案所完成的獨立執行檔;我先把代碼列出;再來加入註解;另外也必須了解點陣圖的格式,請參考點陣圖(Bitmap)檔案格式
#include (stdio.h)
#include (stdlib.h)
#if defined(__linux__)
#include (stdint.h)
#else
#ifdef __CYGWIN__
#include "elf.h"
#else
#include (inttypes.h)
#endif
#endif

typedef struct bitmap_s { /* bitmap description */
uint16_t width;
uint16_t height;
uint8_t palette[256*3]; //調色盤資料
uint8_t *data; //圖的bit_map資料指標
} bitmap_t;

#define DEFAULT_CMAP_SIZE 16 /* size of default color map */

/* Neutralize little endians. */
uint16_t le_short(uint16_t x) //因為檔案格式是依照LITTLE ENDIAN排列,因此要找出實際數值必須作移位。
{
uint16_t val;
uint8_t *p = (uint8_t *)(&x);
val = (*p++ & 0xff) 左移 0;
val = (*p & 0xff) 左移 8;
return val;
}
void skip_bytes (FILE *fp, int n)
{
while (n-- > 0) fgetc (fp);
}

int main (int argc, char *argv[])
{
int i, x;
FILE *fp;
bitmap_t bmp;
bitmap_t *b = &bmp;
uint16_t data_offset, n_colors;

if (argc < color="#cc33cc">//判斷參數少於2便顯示fail
fprintf (stderr, "Usage: %s file\n", argv[0]);
exit (EXIT_FAILURE);
}
if ((fp = fopen (argv[1], "rb")) == NULL) {//開啟檔案,若失敗顯示fail
perror (argv[1]);
exit (EXIT_FAILURE);
}
if (fgetc (fp) != 'B' fgetc (fp) != 'M') { //判斷檔頭前2個byte是否為"BM",否則顯示錯誤
fprintf (stderr, "%s is not a bitmap file.\n", argv[1]);
exit (EXIT_FAILURE);
}
/*
* read width and height of the image, and the number of colors used;
* ignore the rest
*/
skip_bytes (fp, 8);
fread (&data_offset, sizeof (uint16_t), 1, fp);
skip_bytes (fp, 6);
fread (&b->width, sizeof (uint16_t), 1, fp);
skip_bytes (fp, 2);
fread (&b->height, sizeof (uint16_t), 1, fp);
skip_bytes (fp, 22);
fread (&n_colors, sizeof (uint16_t), 1, fp);
skip_bytes (fp, 6);
/*
* Repair endianess. 求出實際數值,包括data_offset b->width b->height n_colors
*/
data_offset = le_short(data_offset);
b->width = le_short(b->width);
b->height = le_short(b->height);
n_colors = le_short(n_colors);

/* assume we are working with an 8-bit file */
if ((n_colors == 0) or (n_colors > 256 - DEFAULT_CMAP_SIZE)) {
/* reserve DEFAULT_CMAP_SIZE color map entries for default map */
n_colors = 256 - DEFAULT_CMAP_SIZE;
}
//使用printf便可印到bmp_logo.h那是因為$(obj)./bmp_logo $(LOGO_BMP) >$@ 這個">"轉向指令
以下的代碼就不用再加註解,只要比對一下產生出來的bmp_logo.h,就知道了
printf ("/*\n"
" * Automatically generated by \"tools/bmp_logo\"\n"
" *\n"
" * DO NOT EDIT\n"
" *\n"
" */\n\n\n"
"#ifndef __BMP_LOGO_H__\n"
"#define __BMP_LOGO_H__\n\n"
"#define BMP_LOGO_WIDTH\t\t%d\n"
"#define BMP_LOGO_HEIGHT\t\t%d\n"
"#define BMP_LOGO_COLORS\t\t%d\n"
"#define BMP_LOGO_OFFSET\t\t%d\n"
"\n",
b->width, b->height, n_colors,
DEFAULT_CMAP_SIZE);

/* allocate memory */
if ((b->data = (uint8_t *)malloc(b->width * b->height)) == NULL) {
fclose (fp);
printf ("Error allocating memory for file %s.\n", argv[1]);
exit (EXIT_FAILURE);
}

/* read and print the palette information */
printf ("unsigned short bmp_logo_palette[] = {\n");

for (i=0; ipalette[(int)(i*3+2)] = fgetc(fp);
b->palette[(int)(i*3+1)] = fgetc(fp);
b->palette[(int)(i*3+0)] = fgetc(fp);
x=fgetc(fp);

printf ("%s0x0%X%X%X,%s",
((i%8) == 0) ? "\t" : " ",
(b->palette[(int)(i*3+0)] >> 4) & 0x0F,
(b->palette[(int)(i*3+1)] >> 4) & 0x0F,
(b->palette[(int)(i*3+2)] >> 4) & 0x0F,
((i%8) == 7) ? "\n" : ""
);
}

/* seek to offset indicated by file header */
fseek(fp, (long)data_offset, SEEK_SET);

/* read the bitmap; leave room for default color map */
printf ("\n");
printf ("};\n");
printf ("\n");
printf ("unsigned char bmp_logo_bitmap[] = {\n");
for (i=(b->height-1)*b->width; i>=0; i-=b->width) {
for (x = 0; x <>width; x++) {
b->data[(uint16_t) i + x] = (uint8_t) fgetc (fp) + DEFAULT_CMAP_SIZE;
}
}
fclose (fp);

for (i=0; i<(b->height*b->width); ++i) {
if ((i%8) == 0)
putchar ('\t');
printf ("0x%02X,%c", b->data[i], ((i%8) == 7) ? '\n' : ' ');
}
printf ("\n"
"};\n\n"
"#endif /* __BMP_LOGO_H__ */\n"
);

return (0);
}
--> 閱讀更多...