国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

手寫簡易操作系統(tǒng)(十七)--編寫鍵盤驅(qū)動(dòng)

這篇具有很好參考價(jià)值的文章主要介紹了手寫簡易操作系統(tǒng)(十七)--編寫鍵盤驅(qū)動(dòng)。希望對大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

前情提要

上一節(jié)我們實(shí)現(xiàn)了鎖與信號量,這一節(jié)我們就可以實(shí)現(xiàn)鍵盤驅(qū)動(dòng)了,訪問鍵盤輸入的數(shù)據(jù)也屬于臨界區(qū)資源,所以需要鎖的存在。

一、鍵盤簡介

之前的 ps/2 鍵盤使用的是中斷驅(qū)動(dòng)的,在當(dāng)時(shí),按下鍵盤就會(huì)觸發(fā)中斷,引導(dǎo)操作系統(tǒng)去處理這個(gè)按鍵行文。但是當(dāng)今的usb鍵盤,使用的是輪詢機(jī)制,cpu會(huì)定時(shí)訪問鍵盤看有沒有按下鍵盤。

我個(gè)人認(rèn)為這是cpu技術(shù)的進(jìn)步導(dǎo)致的,在之前,cpu的頻率比較低,使用輪詢可能會(huì)導(dǎo)致漏掉用戶按鍵的行為。但是在今天,cpu的主頻已經(jīng)非常高了,處理一個(gè)按鍵行為就觸發(fā)中斷,這個(gè)開銷太大了,而且輪詢的頻率也上來了,現(xiàn)在每秒訪問幾千次對電腦一點(diǎn)影響都沒有,所以現(xiàn)在大多采用了輪詢機(jī)制。

不過據(jù)說中斷驅(qū)動(dòng)的還是比較快,現(xiàn)在一些電競主板還是支持ps/2的接口,這個(gè)未經(jīng)論證。

1.1、鍵盤的通碼與斷碼

鍵盤的狀態(tài)要么是按下,要么是彈起,因此一個(gè)鍵便有兩個(gè)編碼,按鍵按下時(shí)的編碼叫做通碼,鍵盤上的觸電接通了電路,使硬件產(chǎn)生了一個(gè)編碼,故此通碼叫makecode。按鍵在被按住不松手時(shí)會(huì)持續(xù)產(chǎn)生相同的碼,直到按鍵被松開時(shí)才終止,因此按鍵被松開彈起時(shí)產(chǎn)生的編碼叫斷碼,也就是電路被斷開了,不再持續(xù)產(chǎn)生碼了,故斷碼也稱為breakcode。

無論是按下鍵,或是松開鍵,當(dāng)鍵的狀態(tài)改變后,鍵盤中的8048芯片把按鍵對應(yīng)的掃描碼(通碼或斷碼)發(fā)送到主板上的8042芯片,由8042處理后保存在自己的寄存器中,然后向8259A發(fā)送中斷信號,這樣處理器便去執(zhí)行鍵盤中斷處理程序,將8042處理過的掃描碼從它的寄存器中讀取出來,繼續(xù)進(jìn)行下一步處理。

1.2、鍵盤掃描碼

鍵的掃描碼是由鍵盤中的鍵盤編碼器決定的,不同的編碼方案便是不同的鍵盤掃描碼,也就是說,相同的鍵在不同的編碼方案下產(chǎn)生的通碼和斷碼也是不同的。

根據(jù)不同的編碼方案,鍵盤掃描碼有三套,分別稱為scan code set 1、scan code set 2、scan code set 3。

其中scan code set 1是XT鍵盤用的掃描碼,這個(gè)歷史就比較久遠(yuǎn)了。scan code set 2是AT鍵盤的掃描碼,這個(gè)鍵盤和我們當(dāng)今的鍵盤也不是很一樣,但是已經(jīng)比較接近了。scan code set 3是IBM PS/2系列高端計(jì)算機(jī)所用的鍵盤上,IBM藍(lán)色巨人現(xiàn)在都涼了,這個(gè)鍵盤也就很少看到了。

第二套鍵盤掃描碼幾乎是目前所使用的鍵盤的標(biāo)準(zhǔn),因此大多數(shù)鍵盤向8042發(fā)送的掃描碼都是第二套掃描碼。但是難免有別的鍵盤,所以才會(huì)出現(xiàn)8042這個(gè)芯片,這個(gè)芯片做一個(gè)中間層,為了兼容第一套鍵盤掃描碼對應(yīng)的中斷處理程序,不管鍵盤用的是何種鍵盤掃描碼,當(dāng)鍵盤將掃描碼發(fā)送到8042后,都由8042轉(zhuǎn)換成第一套掃描碼,我們再從8042中讀取掃描碼。

這里我們給出常用鍵位的掃描碼(這里的掃描碼就是通碼,加0x80就是斷碼)

按鍵 掃描碼 按鍵 掃描碼 按鍵 掃描碼
Esc 0x01 F1 0x3B F2 0x3C
F3 0x3D F4 0x3E F5 0x3F
F6 0x40 F7 0x41 F8 0x42
F9 0x43 F10 0x44 F11 0x57
F12 0x58 PrintSc 0x37 ScrollLk 0x46
Pause/Brk 0x45 ` 0x29 1 0x02
2 0x03 3 0x04 4 0x05
5 0x06 6 0x07 7 0x08
8 0x09 9 0x0A 0 0x0B
- 0x0C = 0x0D Backspace 0x0E
Tab 0x0F Q 0x10 W 0x11
E 0x12 R 0x13 T 0x14
Y 0x15 U 0x16 I 0x17
O 0x18 P 0x19 [ 0x1A
] 0x1B | 0x2B CapsLock 0x3A
A 0x1E S 0x1F D 0x20
F 0x21 G 0x22 H 0x23
J 0x24 K 0x25 L 0x26
; 0x27 0x28 Enter 0x1C
Shift左 0x2A Z 0x2C X 0x2D
C 0x2E V 0x2F B 0x30
N 0x31 M 0x32 , 0x33
. 0x34 / 0x35 Shift右 0x36
Ctrl左 0x1D Win左 0xE0 Alt左 0x38
Space 0x39 Alt右 0xE038 Win右 0xE0
Menu 0xE0 Ctrl右 0xE01D

問:為什么會(huì)有通碼和斷碼,通碼不就夠了嘛

**答:**如果按一個(gè)組合鍵的話,比如ctrl+a,是先按下ctrl,再按a,再松開ctrl,再松開a。如果沒有斷碼,我們無法判斷ctrl是否松開。

1.3、鍵盤的芯片

和鍵盤相關(guān)的芯片只有8042和8048,它們都是獨(dú)立的處理器,都有自己的寄存器和內(nèi)存。Intel 8048芯片或兼容芯片位于鍵盤中,它是鍵盤編碼器,Intel 8042芯片或兼容芯片被集成在主板上的南橋芯片中,它是鍵盤控制器,也就是鍵盤的IO接口,因此它是8048的代理,也是前面所得到的處理器和鍵盤的“中間層”。我們只需要學(xué)習(xí)8042就夠了

他的端口如下

寄存器 端口 讀寫
Output Buffer(輸出緩沖區(qū)) 0x60
Input Buffer(輸入緩沖區(qū)) 0x60
Status Register(狀態(tài)寄存器) 0x64
Control Register(控制寄存器) 0x64

狀態(tài)寄存器8位寬度的寄存器,只讀,反映8048和8042的內(nèi)部工作狀態(tài)。各位意義如下。

(1)位0:置1時(shí)表示輸出緩沖區(qū)寄存器已滿,處理器通過in指令讀取后該位自動(dòng)置0。
(2)位1:置1時(shí)表示輸入緩沖區(qū)寄存器已滿,8042將值讀取后該位自動(dòng)置0。
(3)位2:系統(tǒng)標(biāo)志位,最初加電時(shí)為0,自檢通過后置為1。
(4)位3:置1時(shí),表示輸入緩沖區(qū)中的內(nèi)容是命令,置0時(shí),輸入緩沖區(qū)中的內(nèi)容是普通數(shù)據(jù)。
(5)位4:置1時(shí)表示鍵盤啟用,置0時(shí)表示鍵盤禁用。
(6)位5:置1時(shí)表示發(fā)送超時(shí)。
(7)位6:置1時(shí)表示接收超時(shí)。
(8)位7:來自8048的數(shù)據(jù)在奇偶校驗(yàn)時(shí)出錯(cuò)。

8位寬度的寄存器,只寫,用于寫入命令控制字。每個(gè)位都可以設(shè)置一種工作方式,意義如下。

(1)位0:置1時(shí)啟用鍵盤中斷。
(2)位1:置1時(shí)啟用鼠標(biāo)中斷。
(3)位2:設(shè)置狀態(tài)寄存器的位2。
(4)位3:置1時(shí),狀態(tài)寄存器的位4無效。
(5)位4:置1時(shí)禁止鍵盤。
(6)位5:置1時(shí)禁止鼠標(biāo)。
(7)位6:將第二套鍵盤掃描碼轉(zhuǎn)換為第一套鍵盤掃描碼。
(8)位7:保留位,默認(rèn)為0。

二、環(huán)形隊(duì)列

鍵盤中斷的數(shù)據(jù)是放在隊(duì)列中的,等待其他線程的讀取。如果我們之前做過關(guān)于軟件相關(guān)的工作,很容易理解這個(gè)概念,就是buffer,緩沖區(qū)。因?yàn)槲覀兪且恢痹谳斎氲?,所以這里設(shè)計(jì)成了環(huán)形隊(duì)列。

我們看一下環(huán)形隊(duì)列的數(shù)據(jù)結(jié)構(gòu)

#define bufsize 256

/* 環(huán)形隊(duì)列 */
struct ioqueue {
    // 生產(chǎn)者消費(fèi)者問題
    struct lock lock;
    // 生產(chǎn)者,緩沖區(qū)不滿時(shí)就繼續(xù)往里面放數(shù)據(jù)
    struct task_struct* producer;
    // 消費(fèi)者,緩沖區(qū)不空時(shí)就繼續(xù)從往里面拿數(shù)據(jù)
    struct task_struct* consumer;
    char buf[bufsize];			// 緩沖區(qū)大小
    int32_t head;			    // 隊(duì)首,數(shù)據(jù)往隊(duì)首處寫入
    int32_t tail;			    // 隊(duì)尾,數(shù)據(jù)從隊(duì)尾處讀出
};

這個(gè)就很明朗了。一個(gè)生產(chǎn)者一個(gè)消費(fèi)者,生產(chǎn)者向buf中添加數(shù)據(jù),消費(fèi)者從buf中取出數(shù)據(jù),為了防止buf中的數(shù)據(jù)出錯(cuò),生產(chǎn)者和消費(fèi)者同時(shí)只能有一個(gè)可以訪問到buf。如果buf中數(shù)據(jù)滿了,生產(chǎn)者就不能放了,此時(shí)阻塞生產(chǎn)者,如果buf中數(shù)據(jù)為空,消費(fèi)者就不能拿了,此時(shí)阻塞消費(fèi)者。

我們看一下具體的實(shí)現(xiàn)

/* 初始化io隊(duì)列ioq */
void ioqueue_init(struct ioqueue* ioq) {
    lock_init(&ioq->lock);                 // 初始化io隊(duì)列的鎖
    ioq->producer = ioq->consumer = NULL;  // 生產(chǎn)者和消費(fèi)者置空
    ioq->head = ioq->tail = 0;             // 隊(duì)列的首尾指針指向緩沖區(qū)數(shù)組第0個(gè)位置
}

/* 返回pos在緩沖區(qū)中的下一個(gè)位置值 */
static inline int32_t next_pos(int32_t pos) {
    return (pos + 1) % bufsize;
}

/* 判斷隊(duì)列是否已滿 */
bool ioq_full(struct ioqueue* ioq) {
    return next_pos(ioq->head) == ioq->tail;
}

/* 判斷隊(duì)列是否已空 */
bool ioq_empty(struct ioqueue* ioq) {
    return ioq->head == ioq->tail;
}

/* 使當(dāng)前生產(chǎn)者或消費(fèi)者在此緩沖區(qū)上等待 */
static void ioq_wait(struct task_struct** waiter) {
    // 二級指針不為空,指向的pcb指針地址為空
    ASSERT(*waiter == NULL && waiter != NULL);
    *waiter = running_thread();
    thread_block(TASK_BLOCKED);
}

/* 喚醒waiter */
static void wakeup(struct task_struct** waiter) {
    // 二級指針指向不為空
    ASSERT(*waiter != NULL);
    thread_unblock(*waiter);
    *waiter = NULL;
}

/* 消費(fèi)者從ioq隊(duì)列中獲取一個(gè)字符 */
char ioq_getchar(struct ioqueue* ioq) {
    // 若緩沖區(qū)(隊(duì)列)為空,把消費(fèi)者ioq->consumer記為當(dāng)前線程自己,等待生產(chǎn)者喚醒
    while (ioq_empty(ioq)) {
        lock_acquire(&ioq->lock);
        ioq_wait(&ioq->consumer);
        lock_release(&ioq->lock);
    }

    char byte = ioq->buf[ioq->tail];	  // 從緩沖區(qū)中取出
    ioq->tail = next_pos(ioq->tail);	  // 把讀游標(biāo)移到下一位置

    if (ioq->producer != NULL) {
        wakeup(&ioq->producer);		      // 喚醒生產(chǎn)者
    }

    return byte;
}

/* 生產(chǎn)者往ioq隊(duì)列中寫入一個(gè)字符byte */
void ioq_putchar(struct ioqueue* ioq, char byte) {
    // 若緩沖區(qū)(隊(duì)列)已經(jīng)滿了,把生產(chǎn)者ioq->producer記為自己,等待消費(fèi)者線程喚醒自己
    while (ioq_full(ioq)) {
        lock_acquire(&ioq->lock);
        ioq_wait(&ioq->producer);
        lock_release(&ioq->lock);
    }
    ioq->buf[ioq->head] = byte;      // 把字節(jié)放入緩沖區(qū)中
    ioq->head = next_pos(ioq->head); // 把寫游標(biāo)移到下一位置

    if (ioq->consumer != NULL) {
        wakeup(&ioq->consumer);      // 喚醒消費(fèi)者
    }
}

我們看一下后面兩個(gè)函數(shù),waitwakeup,這兩個(gè)函數(shù),這兩個(gè)函數(shù)傳入的是一個(gè)pcb指針的地址,所以這里是一個(gè)二級指針。所以無論是阻塞還是解除阻塞都是取這個(gè)二級指針的地址,也就得到了pcb指針。這里對于不熟悉指針的人來說可能會(huì)有點(diǎn)擾。

三、鍵盤驅(qū)動(dòng)

#define KBD_BUF_PORT 0x60	 // 鍵盤buffer寄存器端口號為0x60

/* 用轉(zhuǎn)義字符定義部分控制字符 */
#define esc		    '\033'	 // 八進(jìn)制表示字符,也可以用十六進(jìn)制'\x1b'
#define backspace	'\b'
#define tab		    '\t'
#define enter		'\r'
#define delete		'\177'	 // 八進(jìn)制表示字符,十六進(jìn)制為'\x7f'

/* 以上不可見字符一律定義為0 */
#define char_invisible	0
#define ctrl_l_char	    char_invisible
#define ctrl_r_char	    char_invisible
#define shift_l_char    char_invisible
#define shift_r_char	char_invisible
#define alt_l_char	    char_invisible
#define alt_r_char	    char_invisible
#define caps_lock_char	char_invisible

/* 定義控制字符的通碼和斷碼 */
#define shift_l_make	0x2a
#define shift_r_make 	0x36 
#define alt_l_make   	0x38
#define alt_r_make   	0xe038
#define alt_r_break   	0xe0b8
#define ctrl_l_make  	0x1d
#define ctrl_r_make  	0xe01d
#define ctrl_r_break 	0xe09d
#define caps_lock_make 	0x3a

struct ioqueue kbd_buf;	   // 定義鍵盤緩沖區(qū)

/* 定義以下變量記錄相應(yīng)鍵是否按下的狀態(tài),
 * ext_scancode用于記錄makecode是否以0xe0開頭 */
static bool ctrl_status, shift_status, alt_status, caps_lock_status, ext_scancode;

/* 以通碼make_code為索引的二維數(shù)組 */
static char keymap[][2] = {
    /* 掃描碼   未與shift組合  與shift組合*/
    /* ---------------------------------- */
    /* 0x00 */	{0,	0},
    /* 0x01 */	{esc,	esc},
    /* 0x02 */	{'1',	'!'},
    /* 0x03 */	{'2',	'@'},
    /* 0x04 */	{'3',	'#'},
    /* 0x05 */	{'4',	'$'},
    /* 0x06 */	{'5',	'%'},
    /* 0x07 */	{'6',	'^'},
    /* 0x08 */	{'7',	'&'},
    /* 0x09 */	{'8',	'*'},
    /* 0x0A */	{'9',	'('},
    /* 0x0B */	{'0',	')'},
    /* 0x0C */	{'-',	'_'},
    /* 0x0D */	{'=',	'+'},
    /* 0x0E */	{backspace, backspace},
    /* 0x0F */	{tab,	tab},
    /* 0x10 */	{'q',	'Q'},
    /* 0x11 */	{'w',	'W'},
    /* 0x12 */	{'e',	'E'},
    /* 0x13 */	{'r',	'R'},
    /* 0x14 */	{'t',	'T'},
    /* 0x15 */	{'y',	'Y'},
    /* 0x16 */	{'u',	'U'},
    /* 0x17 */	{'i',	'I'},
    /* 0x18 */	{'o',	'O'},
    /* 0x19 */	{'p',	'P'},
    /* 0x1A */	{'[',	'{'},
    /* 0x1B */	{']',	'}'},
    /* 0x1C */	{enter,  enter},
    /* 0x1D */	{ctrl_l_char, ctrl_l_char},
    /* 0x1E */	{'a',	'A'},
    /* 0x1F */	{'s',	'S'},
    /* 0x20 */	{'d',	'D'},
    /* 0x21 */	{'f',	'F'},
    /* 0x22 */	{'g',	'G'},
    /* 0x23 */	{'h',	'H'},
    /* 0x24 */	{'j',	'J'},
    /* 0x25 */	{'k',	'K'},
    /* 0x26 */	{'l',	'L'},
    /* 0x27 */	{';',	':'},
    /* 0x28 */	{'\'',	'"'},
    /* 0x29 */	{'`',	'~'},
    /* 0x2A */	{shift_l_char, shift_l_char},
    /* 0x2B */	{'\\',	'|'},
    /* 0x2C */	{'z',	'Z'},
    /* 0x2D */	{'x',	'X'},
    /* 0x2E */	{'c',	'C'},
    /* 0x2F */	{'v',	'V'},
    /* 0x30 */	{'b',	'B'},
    /* 0x31 */	{'n',	'N'},
    /* 0x32 */	{'m',	'M'},
    /* 0x33 */	{',',	'<'},
    /* 0x34 */	{'.',	'>'},
    /* 0x35 */	{'/',	'?'},
    /* 0x36	*/	{shift_r_char, shift_r_char},
    /* 0x37 */	{'*',	'*'},
    /* 0x38 */	{alt_l_char, alt_l_char},
    /* 0x39 */	{' ',	' '},
    /* 0x3A */	{caps_lock_char, caps_lock_char}
    /*其它按鍵暫不處理*/
};

/* 鍵盤中斷處理程序 */
static void intr_keyboard_handler(void) {

    /* 這次中斷發(fā)生前的上一次中斷,以下任意三個(gè)鍵是否有按下 */
    bool ctrl_down_last = ctrl_status;
    bool shift_down_last = shift_status;
    bool caps_lock_last = caps_lock_status;

    uint16_t scancode = inb(KBD_BUF_PORT);

    // 若掃描碼是e0開頭的, 結(jié)束此次中斷處理函數(shù),等待下一個(gè)掃描碼進(jìn)來
    if (scancode == 0xe0) {
        ext_scancode = true;    // 打開e0標(biāo)記
        return;
    }

    // 如果上次是以0xe0開頭,將掃描碼合并
    if (ext_scancode) {
        scancode = ((0xe000) | scancode);
        ext_scancode = false;   // 關(guān)閉e0標(biāo)記
    }

    // 若是斷碼(按鍵彈起時(shí)產(chǎn)生的掃描碼)
    if ((scancode & 0x0080) != 0) {
        // 獲得相應(yīng)的通碼
        uint16_t make_code = (scancode &= 0xff7f);
        // 若是任意以下三個(gè)鍵彈起了,將狀態(tài)置為false
        if (make_code == ctrl_l_make || make_code == ctrl_r_make) {
            ctrl_status = false;
        }
        else if (make_code == shift_l_make || make_code == shift_r_make) {
            shift_status = false;
        }
        else if (make_code == alt_l_make || make_code == alt_r_make) {
            alt_status = false;
        }
        // 若是其他非控制鍵位,不需要處理,那些鍵位我們只需要知道通碼
        return;

    }
    // 若是通碼,只處理數(shù)組中定義的鍵以及alt_right和ctrl鍵,全是make_code
    else if ((scancode > 0x00 && scancode < 0x3b) || (scancode == alt_r_make) || (scancode == ctrl_r_make)) {
        // keymap的二維索引
        bool shift = false;
        // 按下的鍵不是字母
        if ((scancode < 0x0e) || (scancode == 0x29) || \
            (scancode == 0x1a) || (scancode == 0x1b) || \
            (scancode == 0x2b) || (scancode == 0x27) || \
            (scancode == 0x28) || (scancode == 0x33) || \
            (scancode == 0x34) || (scancode == 0x35)) {  
            if (shift_down_last) {
                shift = true;
            }
        }
        // 如果按下的鍵是字母,需要和CapsLock配合
        else {
            if (shift_down_last && caps_lock_last) {      // 如果shift和capslock同時(shí)按下
                shift = false;
            }
            else if (shift_down_last || caps_lock_last) { // 如果shift和capslock任意被按下
                shift = true;
            }
            else {
                shift = false;
            }
        }

        // 將掃描碼的高字節(jié)置0,主要是針對高字節(jié)是e0的掃描碼.
        uint8_t index = (scancode &= 0x00ff);
        // 在數(shù)組中找到對應(yīng)的字符
        char cur_char = keymap[index][shift];

        // 如果cur_char不為0,也就是ascii碼為除'\0'外的字符就加入鍵盤緩沖區(qū)中
        if (cur_char) {
            // 如果ctrl按下,且輸入的字符為‘l’或者‘u’,那就保存為 cur_char-‘a(chǎn)’,主要是‘a(chǎn)’前面26位沒啥用
            if ((ctrl_down_last && cur_char == 'l') || (ctrl_down_last && cur_char == 'u')) {
                cur_char -= 'a';
            }

            // 如果緩沖區(qū)未滿,就將其加入緩沖區(qū)
            if (!ioq_full(&kbd_buf)) {
                ioq_putchar(&kbd_buf, cur_char);
            }
            return;
        }

        // 記錄本次是否按下了下面幾類控制鍵之一,供下次鍵入時(shí)判斷組合鍵
        if (scancode == ctrl_l_make || scancode == ctrl_r_make) {
            ctrl_status = true;
        }
        else if (scancode == shift_l_make || scancode == shift_r_make) {
            shift_status = true;
        }
        else if (scancode == alt_l_make || scancode == alt_r_make) {
            alt_status = true;
        }
        // 這里注意,大寫的鎖定鍵是取反
        else if (scancode == caps_lock_make) {
            caps_lock_status = !caps_lock_status;
        }
    }
    else {
        put_str("unknown key\n");
    }
}

/* 鍵盤初始化 */
void keyboard_init() {
    put_str("keyboard init start\n");
    ioqueue_init(&kbd_buf);
    register_handler(0x21, intr_keyboard_handler);
    put_str("keyboard init done\n");
}

鍵盤驅(qū)動(dòng)就稍顯復(fù)雜一點(diǎn),主要是涉及到了shiftctrl,alt,caplock這些個(gè)控制鍵,這些鍵位是否按下所表示的通碼斷碼是不一樣的。這里就是處理字符,相信大家看代碼就可以看明白。

四、仿真

我們創(chuàng)建一個(gè)線程,鍵盤輸入什么,打印什么

手寫簡易操作系統(tǒng)(十七)--編寫鍵盤驅(qū)動(dòng),手寫簡易操作系統(tǒng),計(jì)算機(jī)外設(shè),單片機(jī),嵌入式硬件,操作系統(tǒng),x86

結(jié)束語

本節(jié)我們編寫了鍵盤驅(qū)動(dòng)以及其使用的環(huán)形隊(duì)列數(shù)據(jù)結(jié)構(gòu)。下一節(jié)我們將實(shí)現(xiàn)一個(gè)用戶進(jìn)程,即特權(quán)級為3的進(jìn)程。

老規(guī)矩,代碼地址為 https://github.com/lyajpunov/os文章來源地址http://www.zghlxwxcb.cn/news/detail-858539.html

到了這里,關(guān)于手寫簡易操作系統(tǒng)(十七)--編寫鍵盤驅(qū)動(dòng)的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 如何編寫Windows操作系統(tǒng)

    編寫一個(gè)完整的操作系統(tǒng)是一項(xiàng)非常復(fù)雜的任務(wù),需要深入了解計(jì)算機(jī)體系結(jié)構(gòu)和操作系統(tǒng)的工作原理,還需要熟悉匯編語言和C/C++編程語言。在這里,我們簡單介紹一下編寫Windows操作系統(tǒng)的基本步驟。 Windows操作系統(tǒng)是由微軟公司開發(fā)的,因此微軟提供了一些用于Windows操作

    2024年02月07日
    瀏覽(18)
  • 【C語言】簡易登錄注冊系統(tǒng)(登錄、注冊、改密、文件操作)

    【C語言】簡易登錄注冊系統(tǒng)(登錄、注冊、改密、文件操作)

    ? ? ? ? 本登錄注冊系統(tǒng)通過使用C語言中的結(jié)構(gòu)體、函數(shù)、文件操作以及指針等,設(shè)計(jì)與實(shí)現(xiàn)了一個(gè)小型用戶登錄注冊系統(tǒng)的登錄、注冊、修改密碼等基本功能。 ? ? ? ? 本系統(tǒng)全部功能基本運(yùn)行良好、用戶界面友好、操作簡單、使用方便。但系統(tǒng)仍然有不完善之處。例如

    2024年02月03日
    瀏覽(16)
  • 簡易操作系統(tǒng):使用Python 做的圖形界面 C 做的內(nèi)核

    簡易操作系統(tǒng):使用Python 做的圖形界面 C 做的內(nèi)核

    目錄 實(shí)驗(yàn)要求 一、文件管理和用戶接口 ⑴文件的邏輯結(jié)構(gòu) ⑵磁盤模擬 ⑶目錄結(jié)構(gòu) ⑷磁盤分配 ⑸磁盤空閑存儲(chǔ)空間管理 ⑹用戶接口 ⑺屏幕顯示 ?代碼部分 ? ? ? ? python調(diào)用c的方法: ?編輯 c語言部分,文件名 Operating_System_C.c python語言部分 運(yùn)行實(shí)例: ?? 文件管理和用戶

    2024年02月08日
    瀏覽(15)
  • C# 編寫的 64位操作系統(tǒng) - MOOS

    C# 編寫的 64位操作系統(tǒng) - MOOS

    MOOS ( My Own Operating System )?是一個(gè)使用 .NET Native AOT 技術(shù)編譯的C# 64位操作系統(tǒng)。項(xiàng)目地址:https://github.com/nifanfa/MOOS。 微軟MVP實(shí)驗(yàn)室研究員 關(guān)于編譯 MOOS 的信息,請閱讀編譯維基頁面:https://github.com/nifanfa/MOOS/wiki/ VMware Workstation Player https://www.vmware.com/products/workstation-player.htm

    2024年02月05日
    瀏覽(15)
  • Linux下C程序的編寫(操作系統(tǒng)實(shí)驗(yàn))

    Linux下C程序的編寫(操作系統(tǒng)實(shí)驗(yàn))

    實(shí)驗(yàn)題目: ? Linux下C程序的編寫???????????????? ?????????? 實(shí)驗(yàn)?zāi)康模?? (1)掌握Linux下C程序的編寫、編譯與運(yùn)行方法; (2)掌握gcc編譯器的編譯過程,熟悉編譯的各個(gè)階段;??????? (3)熟悉Makefile文件的編寫格式和make編譯工具的使用方法。? ? ? ??

    2024年04月28日
    瀏覽(38)
  • 飛騰筆記本/銀河麒麟桌面操作系統(tǒng)鍵盤無法使用

    在安裝完銀河麒麟V10完成以后,進(jìn)入系統(tǒng)后無法使用鍵盤,外接鍵盤以及在安裝系統(tǒng)的過程中均可正常使用。 因?yàn)樵诎惭b過程中,以及外接鍵盤均可正常使用,所以初步懷疑是筆記本鍵盤與系統(tǒng)之間的不兼容導(dǎo)致 將/boot/grub.cfg配置文件中的drivicetree/dtb/u-boot-general.dtb修改為d

    2024年02月12日
    瀏覽(31)
  • 鍵盤敲入 A 字母時(shí),操作系統(tǒng)期間發(fā)生了什么?

    關(guān)于8.1 鍵盤敲入 A 字母時(shí),操作系統(tǒng)期間發(fā)生了什么?的總結(jié),前面都介紹了,但是在最后總結(jié)操作系統(tǒng)發(fā)生了什么的時(shí)候,我覺得有點(diǎn)不詳細(xì),于是寫一寫自己的補(bǔ)充和理解,不一定正確。 鍵盤敲擊之后, 鍵盤控制器根據(jù)敲擊的鍵生成掃描碼,寫入寄存器 。 同時(shí)通過中

    2024年02月11日
    瀏覽(14)
  • ubuntu版本Linux操作系統(tǒng)上安裝鍵盤中文輸入法

    ubuntu版本Linux操作系統(tǒng)上安裝鍵盤中文輸入法

    要在ubuntu版本Linux操作系統(tǒng)上安裝鍵盤中文輸入法 可以按照以下步驟進(jìn)行操作: 1、Linux終端輸入: sudo apt-get install ibus-pinyin 這將安裝一個(gè)常用的中文輸入法 “ ibus-pinyin ”。 2、重新啟動(dòng)系統(tǒng):為了使輸入法生效,需要重新啟動(dòng)您的系統(tǒng) Linux終端輸入: sudo reboot 3、在重啟后

    2024年02月16日
    瀏覽(31)
  • 基于JavaSE+JDBC使用控制臺操作的簡易購物系統(tǒng)【源碼+數(shù)據(jù)庫】

    基于JavaSE+JDBC使用控制臺操作的簡易購物系統(tǒng)【源碼+數(shù)據(jù)庫】

    本項(xiàng)目是一套基于JavaSE+JDBC使用控制臺操作的簡易購物系統(tǒng),主要針對計(jì)算機(jī)相關(guān)專業(yè)的正在做bishe的學(xué)生和需要項(xiàng)目實(shí)戰(zhàn)練習(xí)的Java學(xué)習(xí)者。 包含:項(xiàng)目源碼、數(shù)據(jù)庫腳本等,該項(xiàng)目可以直接作為bishe使用。 項(xiàng)目都經(jīng)過嚴(yán)格調(diào)試,確保可以運(yùn)行! JavaSE+JDBC+idea+mysql 用戶角色:

    2024年02月04日
    瀏覽(95)
  • 【linux深入剖析】操作系統(tǒng)與用戶之間的接口:自定義簡易shell制作全過程

    【linux深入剖析】操作系統(tǒng)與用戶之間的接口:自定義簡易shell制作全過程

    ??你好,我是 RO-BERRY ?? 致力于C、C++、數(shù)據(jù)結(jié)構(gòu)、TCP/IP、數(shù)據(jù)庫等等一系列知識 ??感謝你的陪伴與支持 ,故事既有了開頭,就要畫上一個(gè)完美的句號,讓我們一起加油 Linux的Shell是一種命令行解釋器,它是用戶與操作系統(tǒng)內(nèi)核之間的接口。 通過Shell,用戶可以輸入命令并與

    2024年03月18日
    瀏覽(32)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包