日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 运维知识 > linux >内容正文

linux

linux 0.11 内核学习 -- rs_io.s,串口汇编代码

發(fā)布時(shí)間:2025/3/15 linux 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 linux 0.11 内核学习 -- rs_io.s,串口汇编代码 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

/*

?* ?該文件實(shí)現(xiàn)rs232 串行通信中斷處理

?*/

/*

?* ?linux/kernel/rs_io.s

?*

?* ?(C) 1991 ?Linus Torvalds

?*/

/*

?* rs_io.s

?*

?* This module implements the rs232 io interrupts.

?*/

.text

.globl _rs1_interrupt,_rs2_interrupt

/* 讀寫隊(duì)列緩沖區(qū)的長(zhǎng)度 */

size = 1024 /* must be power of two !

? and must match the value

? in tty_io.c!!! */

/* these are the offsets into the read/write buffer structures */

/* 讀寫緩沖結(jié)構(gòu)中的偏移量tty_queue */

rs_addr = 0

head = 4

tail = 8

proc_list = 12

buf = 16

/* 當(dāng)寫隊(duì)列里還剩256 個(gè)字符空間(WAKEUP_CHARS)時(shí),我們就可以寫 */

startup = 256 /* chars left in write queue when we restart it */

/*

?* These are the actual interrupt routines. They look where

?* the interrupt is coming from, and take appropriate action.

?*/

.align 2

/* 串行端口1 中斷處理程序入口點(diǎn) */

_rs1_interrupt:

// tty 表中對(duì)應(yīng)串口1 的讀寫緩沖指針的地址入棧

pushl $_table_list+8 // table_list定義在文件tty_io.c文件中

jmp rs_int

/* 串行端口2 中斷處理程序入口點(diǎn) */

.align 2

_rs2_interrupt:

pushl $_table_list+16 // 同上

rs_int:

pushl %edx

pushl %ecx

pushl %ebx

pushl %eax

push %es

push %ds /* as this is an interrupt, we cannot */

/* 讓ds、es 指向內(nèi)核數(shù)據(jù)段 */

pushl $0x10 /* know that bs is ok. Load it */

pop %ds

pushl $0x10

pop %es

movl 24(%esp),%edx // 將緩沖隊(duì)列指針地址存入edx 寄存器

movl (%edx),%edx // 取讀隊(duì)列指針(地址)?-> edx

movl rs_addr(%edx),%edx // 取串口1 的端口號(hào)?-> edx

/* edx 指向中斷標(biāo)識(shí)寄存器 */

addl $2,%edx /* interrupt ident. reg */

rep_int:

xorl %eax,%eax // eax = 0

inb %dx,%al // 取中斷標(biāo)識(shí)字節(jié),用以判斷中斷來源

testb $1,%al // 有無(wú)待處理的中斷?

jne end // 沒有,則跳轉(zhuǎn)至退出處理處end

cmpb $6,%al /* this shouldn't happen, but ... */

ja end // al 值>6? 是則跳轉(zhuǎn)至end

movl 24(%esp),%ecx // 再取緩沖隊(duì)列指針地址?-> ecx

pushl %edx // 將端口號(hào)0x3fa(0x2fa)入棧

subl $2,%edx // 0x3f8(0x2f8)

/* jmp_table在下面定義 */

call jmp_table(,%eax,2) /* NOTE! not *4, bit0 is 0 already */

popl %edx // 彈出中斷標(biāo)識(shí)寄存器端口號(hào)0x3fa(或0x2fa)

jmp rep_int // 繼續(xù)處理

/* 向中斷控制器發(fā)送結(jié)束中斷指令EOI */

end: movb $0x20,%al

outb %al,$0x20 /* EOI */

pop %ds

pop %es

popl %eax

popl %ebx

popl %ecx

popl %edx

/* 丟棄緩沖隊(duì)列指針地址 */

addl $4,%esp # jump over _table_list entry

iret

/* 各中斷類型處理程序地址跳轉(zhuǎn)表 */

/* modem 狀態(tài)變化中斷,寫字符中斷,讀字符中斷,線路狀態(tài)有問題中斷 */

jmp_table:

.long modem_status,write_char,read_char,line_status

.align 2

/* 通過讀modem 狀態(tài)寄存器進(jìn)行復(fù)位(0x3fe) */

modem_status:

addl $6,%edx /* clear intr by reading modem status reg */

inb %dx,%al

ret

.align 2

/* 通過讀線路狀態(tài)寄存器進(jìn)行復(fù)位(0x3fd) */

line_status:

addl $5,%edx /* clear intr by reading line status reg. */

inb %dx,%al

ret

.align 2

/*

?* read_char實(shí)現(xiàn)的是從CPU讀取,將結(jié)果存儲(chǔ)到緩沖隊(duì)列中

?*/

read_char:

inb %dx,%al // 讀取字符?-> al

movl %ecx,%edx // 當(dāng)前串口緩沖隊(duì)列指針地址?-> edx

subl $_table_list,%edx // 當(dāng)前串口隊(duì)列指針地址?-> edx

shrl $3,%edx

movl (%ecx),%ecx # read-queue

// 取讀隊(duì)列中緩沖頭指針?-> ebx

movl head(%ecx),%ebx

// 將字符放在緩沖區(qū)中頭指針?biāo)傅奈恢?/p>

movb %al,buf(%ecx,%ebx)

incl %ebx // 將頭指針前移一字節(jié)

andl $size-1,%ebx // 緩沖區(qū)頭指針進(jìn)行模操作

cmpl tail(%ecx),%ebx // 緩沖區(qū)頭指針與尾指針比較

je 1f // 若相等,表示緩沖區(qū)滿,跳轉(zhuǎn)到標(biāo)號(hào)1 處

movl %ebx,head(%ecx) // 保存修改過的頭指針

1: pushl %edx // 將串口號(hào)壓入堆棧

call _do_tty_interrupt // 調(diào)用tty 中斷處理C 函數(shù)

addl $4,%esp // 丟棄入棧參數(shù),并返回

ret

.align 2

/*

?* write_char函數(shù)是將收到的數(shù)據(jù)傳送給CPU

?*/

write_char:

// 取寫緩沖隊(duì)列結(jié)構(gòu)地址?-> ecx

movl 4(%ecx),%ecx # write-queue

movl head(%ecx),%ebx // 取寫隊(duì)列頭指針?-> ebx

subl tail(%ecx),%ebx // 頭指針 - 尾指針 = 隊(duì)列中字符數(shù)

andl $size-1,%ebx # nr chars in queue

je write_buffer_empty // 如果頭指針 = 尾指針,說明寫隊(duì)列無(wú)字符,跳轉(zhuǎn)處理

cmpl $startup,%ebx // 隊(duì)列中字符數(shù)超過256 個(gè)?

ja 1f // 超過,則跳轉(zhuǎn)處理

// 取等待該隊(duì)列的進(jìn)程的指針,并判斷是否為空

movl proc_list(%ecx),%ebx # wake up sleeping process

testl %ebx,%ebx # is there any?

je 1f // 是空的,則向前跳轉(zhuǎn)到標(biāo)號(hào)1 處

movl $0,(%ebx) // 否則將進(jìn)程置為可運(yùn)行狀態(tài)(喚醒進(jìn)程)

/*

?* 緩沖區(qū)的長(zhǎng)度是1024,但是在緩沖區(qū)中含有256個(gè)字符時(shí),就開始

?* 進(jìn)行寫操作。下面的餓代碼首先將超過256的字節(jié)的后一個(gè)字節(jié)

?* 寫入端口中,然后該段代碼從尾部讀取一個(gè)字符,然后繼續(xù)rep_int

?* ,程序繼續(xù)判斷是那種的處理情況

?*

?* tail(low address) ---------------------> head(high address)

?*/

1: movl tail(%ecx),%ebx // 取尾指針

movb buf(%ecx,%ebx),%al // 從緩沖中尾指針處取一字符?-> al

outb %al,%dx // 將端口0x3f8(0x2f8)送出保存到寄存器中

incl %ebx // 尾指針前移

andl $size-1,%ebx // 尾指針若到緩沖區(qū)末端,則折回

movl %ebx,tail(%ecx) // // 保存已修改過的尾指針

cmpl head(%ecx),%ebx // 尾指針與頭指針比較

// 注意隊(duì)列數(shù)據(jù)結(jié)構(gòu)

je write_buffer_empty // // 若相等,表示隊(duì)列已空,則跳轉(zhuǎn)

ret

.align 2

/*

?* 喚醒進(jìn)程,改寫端口寄存器值

?*/

write_buffer_empty:

// 喚醒等待的進(jìn)程

movl proc_list(%ecx),%ebx # wake up sleeping process

// 有等待的進(jìn)程嗎?

testl %ebx,%ebx # is there any?

je 1f // 無(wú),則向前跳轉(zhuǎn)到標(biāo)號(hào)1 處

movl $0,(%ebx) // 喚醒進(jìn)程

1: incl %edx // 指向端口0x3f9(0x2f9)

inb %dx,%al // 讀取中斷允許寄存器

jmp 1f // 延遲

1: jmp 1f

/* disable transmit interrupt */

1: andb $0xd,%al

outb %al,%dx

ret

參考《linux內(nèi)核完全注釋》和網(wǎng)上相關(guān)文章

轉(zhuǎn)載于:https://www.cnblogs.com/xuqiang/archive/2010/02/01/1953773.html

總結(jié)

以上是生活随笔為你收集整理的linux 0.11 内核学习 -- rs_io.s,串口汇编代码的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。