青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

天衣有縫

冠蓋滿京華,斯人獨憔悴~
posts - 35, comments - 115, trackbacks - 0, articles - 0
   :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理

3課:輔助函數(shù)


聲明:轉(zhuǎn)載請保留

譯者http://m.shnenglu.com/jinglexy

原作者:xiaoming.mo at skelix dot org

MSN & Email: jinglexy at yahoo dot com dot cn

目標            下載源程序

 

這節(jié)課我們講述的內(nèi)容與操作系統(tǒng)暫無太大關(guān)系,但是這些基礎(chǔ)函數(shù)非常重要,并且在后面的課程中經(jīng)常用到。這就是我們經(jīng)常聽到的內(nèi)核庫。如果你對這些不是很感興趣,知道kprintfc語言里面的print一樣工作就行了。簡單掠過即可。


C用戶庫里面的printf具有高度可伸縮性,也很容易理解,相比之下C++中的IO運算符就比較難了。為了在屏幕上顯示字符串或數(shù)據(jù),我們現(xiàn)在需要實現(xiàn)類似C庫中的printf,顯示字符在B8000開始的顯存處。我并不像完全實現(xiàn)printf的所有功能,因為skelix內(nèi)核只需要顯示字符串,十進制和十六進制或二進制,正整數(shù),字符就行了,并且需要支持可變參數(shù)。其他更高級的功能我們不會用到。

這里有一種方法來實現(xiàn),我們直到象func(int arg1, int arg2, int arg3)這樣一個函數(shù)被調(diào)用時,它匯編后的指令應該如下(所有從左向右入棧的編譯器應該從地球上徹底消失):
pushl   arg3
pushl   arg2
pushl   arg1
call    func

 

我們看到,參數(shù)從右向左一個個入棧,參數(shù)越多,入棧越深。如果是可變參數(shù)那我們怎么知道有多少個參數(shù)呢?答案是printf格式化字符串中參數(shù)判斷:有多少個%X,就有多少個參數(shù)要解析。在32位模式下,所有小于4字節(jié)的參數(shù)都被當作4字節(jié)處理。例如一個char型參數(shù),入棧時就是int型了,所以在解析參數(shù)時務必保證正確。

我們這樣設計kprintf參數(shù):kprintf(color, format string, arguments...)

第一個參數(shù)定義輸出的前景/背景顏色。我們定義了很多宏來解析棧,如果你熟悉C語言應該很容易理解它們。


03/kprintf.c

#define args_list char *            // 這個宏用例轉(zhuǎn)換棧空間為字符串指針
#define _arg_stack_size(type)    (((sizeof(type)-1)/sizeof(int)+1)*sizeof(int))

                                    // 這個宏四舍五入?yún)?shù)大小為4字節(jié)的倍數(shù)
#define args_start(ap, fmt) do {    \
ap = (char *)((unsigned int)&fmt + _arg_stack_size(&fmt));   \
} while (0)

                                    // 參數(shù)將從格式化字符串后面開始解析,即fmt就是棧頂,上面這個宏就是取參數(shù)的首地址


#define args_end(ap)                //
到現(xiàn)在為止,什么也不做
#define args_next(ap, type) (((type *)(ap+=_arg_stack_size(type)))[-1])

                                    // 當前參數(shù)地址,然后設置指針為下一個參數(shù)地址,曖昧的函數(shù)名!

03/kprintf.c

static char buf[1024] = {-1};       // 注意沒有鎖保護,引用該變量的函數(shù)不可重入!
static int ptr = -1;

 

下面兩個函數(shù)解析值為指定的進制數(shù):
static void
parse_num(unsigned int value, unsigned int base) {            //
可以打印小于等于10進制的數(shù)
    unsigned int n = value / base;
    int r = value % base;
    if (r < 0) {
        r += base;
        --n;
    }
    if (value >= base)
        parse_num(n, base);
    buf[ptr++] = (r+'0');
}

static void                                                   //
打印16進制數(shù)
parse_hex(unsigned int value) {
    int i = 8;
    while (i-- > 0) {
        buf[ptr++] = "0123456789abcdef"[(value>>(i*4))&0xf];
    }
}

 

現(xiàn)在我們來看一下 kprintf這個函數(shù),它支持的格式:%s, %c, %x, %d, %%
void
kprintf(enum KP_LEVEL kl, const char *fmt, ...) {
    int i = 0;
    char *s;
    /* must be the same size as enum KP_LEVEL */
    struct KPC_STRUCT {
        COLOUR fg;
        COLOUR bg;
    } KPL[] = {
        {BRIGHT_WHITE, BLACK},
        {YELLOW, RED},
    };


enum KP_LEVEL {KPL_DUMP, KPL_PANIC} 
定義在 include/kprintf.h, 它表示兩種輸出方案, KPL_DUMP 使用黑色背景白色前景顯示字符,KPL_PANIC 使用黃色前景和紅色背景。顏色常量定義在 include/scr.h, 后面會介紹到.

 

    args_list args;
    args_start(args, fmt);

    ptr = 0;

    for (; fmt[i]; ++i) {
        if ((fmt[i]!='%') && (fmt[i]!='\\')) {
            buf[ptr++] = fmt[i];
            continue;
        } else if (fmt[i] == '\\') {
            /* \a \b \t \n \v \f \r \\ */
            switch (fmt[++i]) {
            case 'a': buf[ptr++] = '\a'; break;
            case 'b': buf[ptr++] = '\b'; break;
            case 't': buf[ptr++] = '\t'; break;
            case 'n': buf[ptr++] = '\n'; break;
            case 'r': buf[ptr++] = '\r'; break;
            case '\\':buf[ptr++] = '\\'; break;
            }
            continue;
        }

        /* 下面是支持的打印格式 */
        switch (fmt[++i]) {
        case 's':
            s = (char *)args_next(args, char *);
            while (*s)
                buf[ptr++] = *s++;
            break;
        case 'c':
            buf[ptr++] = (char)args_next(args, int);
            break;
        case 'x':
            parse_hex((unsigned long)args_next(args, unsigned long));
            break;
        case 'd':
            parse_num((unsigned long)args_next(args, unsigned long), 10);
            break;
        case '%':
            buf[ptr++] = '%';
            break;
        default:
            buf[ptr++] = fmt[i];
            break;
        }
    }
    buf[ptr] = '\0';
    args_end(args);
    for (i=0; i<ptr; ++i)
        print_c(buf[i], KPL[kl].fg, KPL[kl].bg);            /* print_c()
是下層的顯示函數(shù),本文后面會有講解 */

}


 

由于是內(nèi)核程序,我們無法使用C用戶庫。所以一下memcpymemsetmemcpy函數(shù)需要自己實現(xiàn),但是需要注意的是在BSD系統(tǒng)中,即便使用了-nostdlib,編譯器仍然會產(chǎn)生System V中相關(guān)的memcpy等代碼,具體情況我也不是很清除。這些函數(shù)的效率當然無法和linux內(nèi)核中的內(nèi)嵌匯編相比!我們暫時這樣實現(xiàn)它們吧。
03/libcc.c

 

 

/* 下面函數(shù)對重疊區(qū)域也進行了處理 */
void
bcopy(const void *src, void *dest, unsigned int n) {
    const char *s = (const char *)src;
    char *d = (char *)dest;
    if (s <= d)
        for (; n>0; --n)
            d[n-1] = s[n-1];
    else
        for (; n>0; --n)
            *d++ = *s++;
}

void
bzero(void *dest, unsigned int n) {
    memset(dest, 0, n);
}

void *
memcpy(void *dest, const void *src, unsigned int n) {
    bcopy(src, dest, n);
    return dest;
}

void *
memset(void *dest, int c, unsigned int n) {
    char *d = (char *)dest;
    for (; n>0; --n)
        *d++ = (char)c;
    return dest;
}

int
memcmp(const void *s1, const void *s2, unsigned int n) {
    const char *s3 = (const char *)s1;
    const char *s4 = (const char *)s2;
    for (; n>0; --n) {
        if (*s3 > *s4)
            return 1;
        else if (*s3 < *s4)
            return -1;
        ++s3;
        ++s4;
    }
    return 0;
}

int
strcmp(const char *s1, const char *s2) {
    while (*s1 && *s2) {
        int r = *s1++ - *s2++;
        if (r)
            return r;
    }
    if (*s1 == *s2)
        return 0
    else
        return (*s1)?1:-1;
}

char *
strcpy(char *dest, const char *src) {
    char *p = dest;
    while ( (*dest++ = *src++))
        ;
    *dest = 0;
    return p;
}

unsigned int
strlen(const char *s) {
    unsigned int n = 0;
    while (*s++)
        ++n;
    return n;
}

print_c
函數(shù)
直接操作顯存區(qū)域一點也不方便,所以我們需要一個顯示模塊。這個就是我們的顯卡驅(qū)動了,是不是不敢相信驅(qū)動是這么簡單的事情?我們先來看一下一些常量定義:
03/include/scr.h

 

#define MAX_LINES    25                // bios默認設置屏幕為 80x25大小,彩色字符模式
#define MAX_COLUMNS  80
#define TAB_WIDTH    8                 //
必須是:2^n
#define VIDEO_RAM    0xb8000           //
顯存地址

 

我們曾簡要提到過這個地址,在字符模式下,適配器使用0xB8000-0xBF000作為視頻內(nèi)存。通常我們處于80x25大小屏幕,有16種顏色。由于一個屏幕只需要80x25x2個字節(jié),即4k,所以該視頻內(nèi)存可以分為多個頁。我們使用所有的頁,但是當前只能有一個頁面可見。為了顯示一個字符,將用到2個字節(jié),一個字節(jié)是字符值,另一個字節(jié)是字符屬性(即顏色)。屬性字節(jié)定義如下:

To display a single character, two bytes are being used which called the character byte and the attribute byte. The character byte contains the value of the character. The attribute byte is defined like this:

Bit 7

閃爍

Bits 6-4

背景色

Bit 3

明亮模式

Bit3 2-0

前景色

 

#define LINE_RAM    (MAX_COLUMNS*2)
#define PAGE_RAM    (MAX_LINE*MAX_COLUMNS)

#define BLANK_CHAR    (' ')
#define BLANK_ATTR    (0x70)        /*
白色前景,黑色背景 */

#define CHAR_OFF(x,y)    (LINE_RAM*(y)+2*(x))        /*
計算給定坐標xy的偏移地址(相對0xB8000 */
Calculates the offset of a given ordinary x, y from 0xB8000

 

typedef enum COLOUR_TAG {                            /* 顏色表 */
    BLACK, BLUE, GREEN, CYAN, RED, MAGENTA, BROWN, WHITE,
    GRAY, LIGHT_BLUE, LIGHT_GREEN, LIGHT_CYAN,
    LIGHT_RED, LIGHT_MAGENTA, YELLOW, BRIGHT_WHITE
} COLOUR;

 

坐標系如下:

  ___________________\

 | 00          /

 |

\|/



03/scr.c

 

static int csr_x = 0;
static int csr_y = 0;

由于我們只用到了一個視頻頁,所以上面兩個變量就可以存儲坐標了。關(guān)于多頁顯示可以在網(wǎng)絡上查找相關(guān)資料。


static void
scroll(int lines) {        
向上滾動屏幕多少行,就是一些內(nèi)存復寫。
    short *p = (short *)(VIDEO_RAM+CHAR_OFF(MAX_COLUMNS-1, MAX_LINES-1));
    int i = MAX_COLUMNS-1;
    memcpy((void *)VIDEO_RAM, (void *)(VIDEO_RAM+LINE_RAM*lines),
           LINE_RAM*(MAX_LINES-lines));


    for (; i>=0; --i)            //
說明這個for循環(huán)有問題,覺得應該改成下面這樣:

    // for (i = i * lines; i>=0; --i)

        *p-- = (short)((BLANK_ATTR<<4)|BLANK_CHAR);

}

 

下面函數(shù)設置光標可能會引發(fā)競態(tài)條件,但是print_c只準備在內(nèi)核中使用,所以沒有關(guān)中斷。它可能會引起一些bug,但是我沒有找到。譯注:全局變量沒有鎖保護在設計上就是一種錯誤。這里的代碼保護確實是沒有做!讀者應用到自己的內(nèi)核時要小心了。

void
set_cursor(int x, int y) {

    csr_x = x;

    csr_y = y;

 

    outb(0x0e, 0x3d4);                                   設置光標高8位的準備工作

    outb(((csr_x+csr_y*MAX_COLUMNS)>>8)&0xff, 0x3d5);    設置光標高8

    outb(0x0f, 0x3d4);                                   設置光標低8位的準備工作
    outb(((csr_x+csr_y*MAX_COLUMNS))&0xff, 0x3d5);      
設置光標低8   
}

void
get_cursor(int *x, int *y) {
    *x = csr_x;
    *y = csr_y;
}

void
print_c(char c, COLOUR fg, COLOUR bg) {

// 用這個函數(shù)來顯示一個具體的字符到屏幕,我們可以把它看作顯卡驅(qū)動
    char *p;
    char attr;


    p = (char *)VIDEO_RAM+CHAR_OFF(csr_x, csr_y);        //
取光標位置
    attr = (char)(bg<<4|fg);                             //
屬性

 

    switch (c) {
    case '\r':
        csr_x = 0;
        break;
    case '\n':
        for (; csr_x<MAX_COLUMNS; ++csr_x) {
            *p++ = BLANK_CHAR;
            *p++ = attr;
        }
        break;
    case '\t':
        c = csr_x+TAB_WIDTH-(csr_x&(TAB_WIDTH-1));
        c = c<MAX_COLUMNS?c:MAX_COLUMNS;
        for (; csr_x<c; ++csr_x) {
            *p++ = BLANK_CHAR;
            *p++ = attr;
        }
        break;
    case '\b':
        if ((! csr_x) && (! csr_y))
            return;
        if (! csr_x) {
            csr_x = MAX_COLUMNS - 1;
            --csr_y;
        } else
            --csr_x;
        ((short *)p)[-1] = (short)((BLANK_ATTR<<4)|BLANK_CHAR);
        break;
    default:
        *p++ = c;
        *p++ = attr;
        ++csr_x;
        break;
    }
    if (csr_x >= MAX_COLUMNS) {
        csr_x = 0;
        if (csr_y < MAX_LINES-1)
            ++csr_y;
        else
            scroll(1);
    }
    set_cursor(csr_x, csr_y);        //
設置光標位置
}

函數(shù)比較簡單,沒有分析的必要了,大家自己琢磨吧。

 

 

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            99国产精品久久久久久久久久| 欧美日韩一区综合| 免费不卡在线视频| 亚洲一区影音先锋| 91久久久久久国产精品| 国产精品网站在线播放| 欧美日韩国产综合网| 美女精品网站| 久久在线精品| 久久久精品动漫| 亚洲在线成人精品| 亚洲午夜激情网页| 亚洲欧美精品一区| 亚洲影院在线观看| 欧美亚洲一区二区在线| 久久超碰97人人做人人爱| 美女网站在线免费欧美精品| 久久亚洲精品一区二区| 久久综合影视| 欧美jjzz| 亚洲欧洲偷拍精品| 老司机午夜精品视频在线观看| 久久久国产成人精品| 久久久久久有精品国产| 久久午夜视频| 欧美激情一区二区三区成人 | 久久久99国产精品免费| 亚洲一级片在线观看| 欧美精品一区二区三区蜜臀| 一区二区精品| 亚洲精品免费网站| 正在播放欧美视频| 先锋亚洲精品| 免费观看成人| 亚洲欧洲视频| 亚洲小说春色综合另类电影| 亚洲欧美综合| 久久国产精品黑丝| 欧美激情在线播放| 国产精品一二一区| 国模精品一区二区三区| 亚洲人成网站精品片在线观看| 一本色道久久88精品综合| 国内精品久久久久国产盗摄免费观看完整版 | 久久成人羞羞网站| 久久免费国产精品1| 久久天堂av综合合色| 亚洲精品一区二区三区99| 亚洲影院高清在线| 99视频精品免费观看| 久久成人羞羞网站| 欧美日韩亚洲激情| 一区二区三区在线高清| 亚洲夜晚福利在线观看| 久久精品国产亚洲精品| 亚洲免费影院| 国产私拍一区| 蜜臀久久久99精品久久久久久| 欧美日韩亚洲一区二区三区在线| 国产亚洲欧美日韩一区二区| 在线视频一区观看| 亚洲国产精品成人va在线观看| 久久国产欧美日韩精品| 99视频国产精品免费观看| 美女露胸一区二区三区| 国产一区二区久久| 午夜久久久久久| 久久综合给合久久狠狠色| 9久草视频在线视频精品| 欧美成人精品在线播放| 在线免费精品视频| 久久久免费精品视频| 亚洲欧美日韩中文视频| 欧美日韩中文字幕| 日韩一级精品| 亚洲黄色在线看| 老司机午夜精品视频在线观看| 欧美日韩三级| 一区二区欧美亚洲| 日韩视频精品在线观看| 欧美母乳在线| 欧美14一18处毛片| 欧美日韩亚洲成人| 国产亚洲精品激情久久| 亚洲欧美不卡| 一本一本久久a久久精品综合麻豆 一本一本久久a久久精品牛牛影视 | 久久五月激情| 久久综合成人精品亚洲另类欧美| 国产女主播视频一区二区| 亚洲欧美日韩国产一区| 亚洲尤物影院| 永久免费毛片在线播放不卡| 欧美大片第1页| 欧美国产综合| 亚洲综合另类| 欧美在线你懂的| 91久久极品少妇xxxxⅹ软件| 亚洲一区二区视频在线观看| 亚洲视屏在线播放| 激情久久久久久久| 亚洲理论在线观看| 国产亚洲在线观看| 亚洲国产一区二区三区在线播| 欧美激情视频网站| 欧美中文字幕第一页| 美女91精品| 久久岛国电影| 欧美黄在线观看| 久久狠狠一本精品综合网| 欧美ed2k| 久久综合中文字幕| 国产精品美女久久| 亚洲成色777777在线观看影院| 国产精品乱子乱xxxx| 亚洲国产1区| 国产一区二区你懂的| 亚洲欧洲久久| 亚洲电影在线观看| 亚洲自拍都市欧美小说| 亚洲精品一区在线观看| 欧美一区二区日韩| 亚洲男人的天堂在线观看| 麻豆精品在线视频| 久久久久久高潮国产精品视| 欧美四级伦理在线| 91久久精品视频| 在线日韩中文字幕| 欧美在线欧美在线| 久久岛国电影| 亚洲女女女同性video| 夜夜爽av福利精品导航| 麻豆精品91| 亚洲午夜久久久久久久久电影院| 欧美经典一区二区三区| 一区二区三区福利| 亚洲一区二区三区四区五区午夜| 亚洲精品影视在线观看| 欧美一区二区三区四区在线观看地址 | 欧美激情在线观看| 欧美激情小视频| 一区精品在线播放| 久久成人精品| 久久久噜久噜久久综合| 国产日韩欧美亚洲一区| 欧美一区二区精品久久911| 欧美怡红院视频| 国产精品一区二区久久国产| 一区二区三区.www| 亚洲综合大片69999| 欧美婷婷在线| 亚洲专区欧美专区| 久久国产综合精品| 一区二区三区中文在线观看| 久久久久国内| 欧美激情精品| 亚洲天堂免费在线观看视频| 欧美日韩爆操| 亚洲一二三四区| 欧美自拍丝袜亚洲| 黄色小说综合网站| 久久综合国产精品| 亚洲国内在线| 亚洲一区区二区| 国产日韩精品视频一区| 久久久av网站| 亚洲国产精品一区二区久| 99re6这里只有精品视频在线观看| 欧美日韩精品免费观看视一区二区| 99视频在线精品国自产拍免费观看| 亚洲欧洲av一区二区| 黄网站免费久久| 欧美精品久久久久久| 亚洲先锋成人| 欧美mv日韩mv国产网站app| a91a精品视频在线观看| 国产伦精品一区二区三区四区免费| 久久av一区二区三区| 亚洲精品国产欧美| 久久精品国产77777蜜臀| 最新精品在线| 国产日韩欧美黄色| 欧美黄色视屏| 久久国产精品网站| 99在线热播精品免费| 久久亚洲综合色一区二区三区| 亚洲精品视频在线观看网站| 国产欧美日韩麻豆91| 男人的天堂亚洲在线| 亚洲欧美伊人| 亚洲美女视频网| 麻豆91精品91久久久的内涵| 亚洲午夜性刺激影院| 亚洲电影一级黄| 国产亚洲一区在线播放| 欧美亚州在线观看| 久久天堂成人| 亚洲第一福利社区| 欧美极品欧美精品欧美视频| 亚洲一本大道在线| 亚洲国产精品成人一区二区|