linux 0.11 内核学习 -- rs_io.s,串口汇编代码
/*
?* ?該文件實現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
/* 讀寫隊列緩沖區的長度 */
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 */
/* 讀寫緩沖結構中的偏移量tty_queue */
rs_addr = 0
head = 4
tail = 8
proc_list = 12
buf = 16
/* 當寫隊列里還剩256 個字符空間(WAKEUP_CHARS)時,我們就可以寫 */
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 中斷處理程序入口點 */
_rs1_interrupt:
// tty 表中對應串口1 的讀寫緩沖指針的地址入棧
pushl $_table_list+8 // table_list定義在文件tty_io.c文件中
jmp rs_int
/* 串行端口2 中斷處理程序入口點 */
.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 指向內核數據段 */
pushl $0x10 /* know that bs is ok. Load it */
pop %ds
pushl $0x10
pop %es
movl 24(%esp),%edx // 將緩沖隊列指針地址存入edx 寄存器
movl (%edx),%edx // 取讀隊列指針(地址)?-> edx
movl rs_addr(%edx),%edx // 取串口1 的端口號?-> edx
/* edx 指向中斷標識寄存器 */
addl $2,%edx /* interrupt ident. reg */
rep_int:
xorl %eax,%eax // eax = 0
inb %dx,%al // 取中斷標識字節,用以判斷中斷來源
testb $1,%al // 有無待處理的中斷?
jne end // 沒有,則跳轉至退出處理處end
cmpb $6,%al /* this shouldn't happen, but ... */
ja end // al 值>6? 是則跳轉至end
movl 24(%esp),%ecx // 再取緩沖隊列指針地址?-> ecx
pushl %edx // 將端口號0x3fa(0x2fa)入棧
subl $2,%edx // 0x3f8(0x2f8)
/* jmp_table在下面定義 */
call jmp_table(,%eax,2) /* NOTE! not *4, bit0 is 0 already */
popl %edx // 彈出中斷標識寄存器端口號0x3fa(或0x2fa)
jmp rep_int // 繼續處理
/* 向中斷控制器發送結束中斷指令EOI */
end: movb $0x20,%al
outb %al,$0x20 /* EOI */
pop %ds
pop %es
popl %eax
popl %ebx
popl %ecx
popl %edx
/* 丟棄緩沖隊列指針地址 */
addl $4,%esp # jump over _table_list entry
iret
/* 各中斷類型處理程序地址跳轉表 */
/* modem 狀態變化中斷,寫字符中斷,讀字符中斷,線路狀態有問題中斷 */
jmp_table:
.long modem_status,write_char,read_char,line_status
.align 2
/* 通過讀modem 狀態寄存器進行復位(0x3fe) */
modem_status:
addl $6,%edx /* clear intr by reading modem status reg */
inb %dx,%al
ret
.align 2
/* 通過讀線路狀態寄存器進行復位(0x3fd) */
line_status:
addl $5,%edx /* clear intr by reading line status reg. */
inb %dx,%al
ret
.align 2
/*
?* read_char實現的是從CPU讀取,將結果存儲到緩沖隊列中
?*/
read_char:
inb %dx,%al // 讀取字符?-> al
movl %ecx,%edx // 當前串口緩沖隊列指針地址?-> edx
subl $_table_list,%edx // 當前串口隊列指針地址?-> edx
shrl $3,%edx
movl (%ecx),%ecx # read-queue
// 取讀隊列中緩沖頭指針?-> ebx
movl head(%ecx),%ebx
// 將字符放在緩沖區中頭指針所指的位置
movb %al,buf(%ecx,%ebx)
incl %ebx // 將頭指針前移一字節
andl $size-1,%ebx // 緩沖區頭指針進行模操作
cmpl tail(%ecx),%ebx // 緩沖區頭指針與尾指針比較
je 1f // 若相等,表示緩沖區滿,跳轉到標號1 處
movl %ebx,head(%ecx) // 保存修改過的頭指針
1: pushl %edx // 將串口號壓入堆棧
call _do_tty_interrupt // 調用tty 中斷處理C 函數
addl $4,%esp // 丟棄入棧參數,并返回
ret
.align 2
/*
?* write_char函數是將收到的數據傳送給CPU
?*/
write_char:
// 取寫緩沖隊列結構地址?-> ecx
movl 4(%ecx),%ecx # write-queue
movl head(%ecx),%ebx // 取寫隊列頭指針?-> ebx
subl tail(%ecx),%ebx // 頭指針 - 尾指針 = 隊列中字符數
andl $size-1,%ebx # nr chars in queue
je write_buffer_empty // 如果頭指針 = 尾指針,說明寫隊列無字符,跳轉處理
cmpl $startup,%ebx // 隊列中字符數超過256 個?
ja 1f // 超過,則跳轉處理
// 取等待該隊列的進程的指針,并判斷是否為空
movl proc_list(%ecx),%ebx # wake up sleeping process
testl %ebx,%ebx # is there any?
je 1f // 是空的,則向前跳轉到標號1 處
movl $0,(%ebx) // 否則將進程置為可運行狀態(喚醒進程)
/*
?* 緩沖區的長度是1024,但是在緩沖區中含有256個字符時,就開始
?* 進行寫操作。下面的餓代碼首先將超過256的字節的后一個字節
?* 寫入端口中,然后該段代碼從尾部讀取一個字符,然后繼續rep_int
?* ,程序繼續判斷是那種的處理情況
?*
?* 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 // 尾指針若到緩沖區末端,則折回
movl %ebx,tail(%ecx) // // 保存已修改過的尾指針
cmpl head(%ecx),%ebx // 尾指針與頭指針比較
// 注意隊列數據結構
je write_buffer_empty // // 若相等,表示隊列已空,則跳轉
ret
.align 2
/*
?* 喚醒進程,改寫端口寄存器值
?*/
write_buffer_empty:
// 喚醒等待的進程
movl proc_list(%ecx),%ebx # wake up sleeping process
// 有等待的進程嗎?
testl %ebx,%ebx # is there any?
je 1f // 無,則向前跳轉到標號1 處
movl $0,(%ebx) // 喚醒進程
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內核完全注釋》和網上相關文章轉載于:https://www.cnblogs.com/xuqiang/archive/2010/02/01/1953773.html
總結
以上是生活随笔為你收集整理的linux 0.11 内核学习 -- rs_io.s,串口汇编代码的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 公司内部图书管理界面原型设计图
- 下一篇: rtklib 天线相位中心_(原文链接错