linux 0.11 内核学习 -- rs_io.s,串口汇编代码
/*
?* ?該文件實(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)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 公司内部图书管理界面原型设计图
- 下一篇: rtklib 天线相位中心_(原文链接错