久久精品国产精品国产精品污,男人扒开添女人下部免费视频,一级国产69式性姿势免费视频,夜鲁夜鲁很鲁在线视频 视频,欧美丰满少妇一区二区三区,国产偷国产偷亚洲高清人乐享,中文 在线 日韩 亚洲 欧美,熟妇人妻无乱码中文字幕真矢织江,一区二区三区人妻制服国产

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

Linux内核的中断机制

發布時間:2023/12/10 linux 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Linux内核的中断机制 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
§5.1?I386的中斷與異常?
中斷通常被分為“同步中斷”和異步中斷兩大類。同步中斷是指當指令執行時由CPU控制單元產生的中斷,之所以稱為“同步中斷”是因為只有在一條指令中止執行后CPU才會發出這類中斷信號。而異步中斷則是指由其他硬件設備依照CPU時鐘隨機產生的中斷信號。?
在Intel?80x86?CPU手冊中,同步中斷和異步中斷也被分別稱為“異常(Exception)”和“中斷(Interrupt)”。Intel又詳細地把中斷和異常細分為以下幾類:?
(1)中斷?
1.?可屏蔽中斷(Maskable?Interrupt):這類中斷被送到CPU的INTR引腳,通過清除eflag寄存器的IF標志可以關閉中斷。?
2.?不可屏蔽中斷(Nonmaskable?Interrupt):被送到CPU的NMI引腳,通常只有幾個危急的事件,如:硬件故障等,才產生不可屏蔽中斷信號。寄存器eflag中的IF標志對這類中斷不起作用。?
(2)異常?
1.?處理器探測異常(Processor-detected?exception):當CPU執行一條指令時所探測到的一個反常條件所產生的異常。依據CPU控制單元產生異常時保存在內核態堆棧eip寄存器的值,這類異常又可以細分為三種:?
n?故障(Fault):保存在eip中的值是引起故障的指令地址,因此但異常處理程序結束后,會重新執行那條指令?!叭表摴收稀笔沁@類異常的一個常見例子。?
n?陷阱(Trap):保存在eip中的值是一個指令地址,但該指令在引起陷阱的指令地址之后。只有當沒有必要重新執行已執行過的指令時,才會觸發trap,其主要用途是調試程序。?
n?異常中止(Abort):當發生了一個嚴重的錯誤,致使CPU控制單元除了麻煩而不能在eip寄存器中保存有意義的值。異常中止通常是由硬件故障或系統表中無效的值引起的。由CPU控制單元發生的這個中斷是一種緊急信號,用來把CPU的執行路徑切換到異常中止的處理程序,而相應的ISR通常除了迫使受到影響的進程中止外,別無選擇。?
2.?編程異常(Programmed?Exception):通常也稱為“軟中斷(software?interrupt)”,是由編程者發出中斷請求指令時發生的中斷,如:int指令和int3指令。當into(檢查溢出)和bound(檢查地址越界)指令檢查的條件不為真時,也引起編程異常。CPU控制單元把編程異常當作Trap來處理,這類異常有兩個典型的用途:一、執行系統調用;二、給調試程序通報一個特定條件。?
5.1.1?中斷向量?
每個中斷和異常都可以用一個0-255之間的無符號整數來標識,Intel稱之為“中斷向量(Interrupt?Vector)”。通常,不可屏蔽中斷和異常的中斷向量是固定的,而可屏蔽中斷的中斷向量則可以對中斷控制器進行編程來改變。I386?CPU的256個中斷向量是這樣分配的:?
1.?從0-31這一共32個向量用于異常和不可屏蔽中斷。?
2.?從32-47這一共16個向量用于可屏蔽中斷,分別對應于主、從8259A中斷控制器的IRQ輸入線。?
3.?剩余的48-255用于標識軟中斷。?
Linux全部使用了0-47之間的向量。但對于48-255之間的軟中斷向量,Linux只使用了其中的一個,即用于實現系統調用的中斷向量128(0x80)。當用戶態下的進程執行一條int?0x80匯編指令時,CPU切換到內核態,以服務于系統調用。?
Linux在頭文件include/asm-i386/hw_irq.h中定義了宏FIRST_EXTERNAL_VECTOR來表示第一個外設中斷(即8259A的IRQ0)所對應的中斷向量,此外還定義了SYSCALL_VECTOR來表示用于系統調用的中斷向量。如下所示:?
/*?
*?IDT?vectors?usable?for?external?interrupt?sources?start?
*?at?0x20:?
*/?
#define?FIRST_EXTERNAL_VECTOR?0x20?
#define?SYSCALL_VECTOR?0x80?
5.1.2?I386的IDT?
i386?CPU的IDT表一共有256項,分別對應每一個中斷向量。每一個表項就是一個中斷描述符,用以描述相對應的中斷向量,中斷向量就是該描述符在IDT中的索引,每一個中斷描述符的大小都是8個字節。根據INTEL的術語,中斷描述符也稱為“門(Gate)”。?
中斷描述符有下列4種類型:?
(1)任務們(Task?Gate):包含了一個進程的TSS段選擇符。每當中斷信號發生時,它被用來取代當前進程的那個TSS段選擇符。Linux并沒有使用任務們。任務們的格式如下:?
(2)中斷門(Interrupt?Gate):中斷門中包含了一個段選擇符和一個中斷處理程序的段內偏移。注意,當I386?CPU穿越一個中斷門進入相應的中斷處理程序時,它會清除eflag寄存器中的IF標志,從而屏蔽接下來可能發生的可屏蔽中斷。?
(3)陷阱門(Trap?Gate):與中斷門類似,不同之處在于CPU通過陷阱門轉入中斷處理程序時不會清除IF標志。?
(4)調用門(Call?Gate):Linux并沒有使用調用門。?
這三種門的格式如圖5-2所示。?
5.1.3?中斷控制器8259A?
我們都知道,PC機中都使用兩個級聯的8359A?PIC(Programmable?Interrupt?Controller,可編程中斷控制器,簡稱PIC)來管理來自系統外設的中斷信號。每個8259A?PIC提供8根IRQ(Interrupt?ReQuest,中斷請求,簡稱IRQ)輸入線。在級聯方式中,Master?8259A?PIC(第一個PIC)的中斷信號輸入線IR2用于級聯Slave?8259A?PIC(第二個PIC)的INT引腳,因此兩個8259A一共可以提供15根可用的IRQ輸入線。如下圖所示:?

圖5-3?主、從8259A中斷控制器的級聯?
5.1.3.1?8259A?PIC的基本原理?
8259A?PIC芯片的基本邏輯塊圖如下所示:?
“中斷屏蔽寄存器”(Interrupt?Mask?Register,簡稱IMR)用于屏蔽8259A的中斷信號輸入,每一位對應一個輸入。當IMR中的bit(0≤i≤7)位被置1時,相對應的中斷信號輸入線IRi上的中斷信號將被8259A所屏蔽,也即IRi被禁止。?
當外設產生中斷信號時(由低到高的跳變信號,80x86系統中的8259A是邊緣觸發的,Edge?Triggered),中斷信號被輸入到“中斷請求寄存器”(Interrupt?Request?Register,簡稱IRR),并同時看看IMR中的相應位是否已被設置。如果沒有被設置,則IRR中的相應位被設置為1,表示外設產生一個中斷請求,等待CPU服務。?
然后,8259A的優先級仲裁部分從IRR中選出一個優先級最高中斷請求。優先級仲裁之后,8259A就通過其INT引腳向CPU發出中斷信號,以通知CPU有外設請求中斷服務。CPU在其當前指令執行完后就通過他的INTA引腳給8259A發出中斷應答信號,以告訴8259A,CPU已經檢測到有中斷信號產生。?
8259A在收到CPU的INTA信號后,將優先級最高的那個中斷請求在ISR寄存器(In-Service?Register,簡稱ISR)中對應的bit置1,表示該中斷請求已得到CPU的服務,同時IRR寄存器中的相應位被清零重置。?
然后,CPU再向8259A發出一個INTA脈沖信號,8259A在收到CPU的第二個INTA信號后,將中斷請求對應的中斷向量放到數據總線上,以供CPU讀取。CPU讀到中斷向量后,就可以裝入執行相應的中斷處理程序。?
如果8259A工作在AEOI(Auto?End?Of?Interrupt,簡稱AEOI)模式下,則當他收到CPU的第二個INTA信號時,它就自動重置ISR寄存器中的相應位。否則,ISR寄存器中的相應位就一直保持為1,直到8259A顯示地收到來自于CPU的EOI命令。?
5.1.3.2?8259A的I/O端口?
Master?8259A的IO端口地址位0x20和0x21,Slave?8259A的IO端口地址為0xA0和0xA1。對這些IO端口進行讀寫操作時的功能如下表所示:?
I/O?Port?Addrss?Read/Write?Function?
Port?A(0x20/0xA0)?W?Initialization?Command?Word1(ICW1)?
W?Operation?Command?Word2(OCW2)?
W?Operation?Command?Word3(OCW3)?
R?Interrupt?Request?Register(IRR)?
R?In-Service?Register(ISR)?
Port?B(0x21/0xA1)?W?Initialization?Command?Word2(ICW2)?
W?Initialization?Command?Word3(ICW3)?
W?Initialization?Command?Word4(ICW4)?
W?Operation?Command?Word1(OCW1)?
R?Interrupt?Mask?Register(IMR)?
表5-1?8259A的I/O端口地址列表?
5.1.3.3?初始化8259A?
8259A?PIC的初始化是通過向其寫一系列“初始化命令字”(Initialization?Command?Word,簡稱ICW)來實現的。其中,ICW1必須寫到Port?A(0x20/0xA0)中,而ICW2、ICW3和ICW4則必須寫到Port?B(0x21/0xA1)中。此外,主、從8259A必須分別進行初始化。?
ICW1的格式如下圖5-5所示:?
ICW2的格式如下圖5-6所示:?
在MCS-80/85模式下,A15-A8指定中斷向量地址;而在80x86模式下,T7-T3用于指定中斷向量地址,而bit[2:0]則可被設置為0。?
ICW3(Master?Device)的格式如下:?
Si(0≤i≤7)為1則表示相應的IRi上級聯了一個Slave?8259A?PIC。?
ICW3(Slave?Device)的格式如下:?

Bit[7:3]總為0,而ID2、ID1、ID0(即bit[2:0])用于標識Slave?8259A連接在Master?8259A的哪一根IRQ線上。例如:010就表示Slave?8259A是連接在Master?8259A的IR2上。?
ICW4的格式如下:?
5.1.3.4?控制8259A?
可以向Port?A或Port?B寫入“控制命令字”(Control?Command?Word,簡稱OCW)來控制8259A?PIC。有三種類型的OCW,其中OCW1只能被寫入到Port?B中,OCW2和OCW3只能被寫到Port?A中。?
OCW1(Interrupt?Mask?Register)的格式如下:?
M7…M0就是IRQ7…IRQ0各自對應的屏蔽位。IMR寄存器可以通過向Port?B寫入OCW1來設置,它的當前值也可以通過讀取Port?B來得到。?
OCW2的格式如下:?
OCW3的格式如下:?

§5.2?Linux對IDT的初始化?
5.2.1?定義IDT的數據結構?
Linux在include/asm-i386/Desc.h頭文件中定義了數據結構desc_struct,用來描述i386?CPU中的各種描述符(均為8字節),如下:?
struct?desc_struct?{?
unsigned?long?a,b;?
};?
基于上述結構,Linux在arch/i386/kernel/traps.c文件中定義了數組idt_table[256],來表示中斷描述符表IDT,其定義如下:?
/*?
*?The?IDT?has?to?be?page-aligned?to?simplify?the?Pentium?
*?F0?0F?bug?workaround..?We?have?a?special?link?segment?
*?for?this.?
*/?
struct?desc_struct?idt_table[256]?__attribute__((__section__(".data.idt")))?=?{?{0,?0},?};?
5.2.2?對門的操作函數?
Linux在arch/i386/kernel/traps.c文件中定義了宏_set_gate(),用來設置一個描述符(即門)的具體值。由于Linux內核代碼均在段選擇子__KERNEL_CS所指向的內核段中,因此門中的Segment?Selector字段總是等于__KERNEL_CS。宏_set_gate()有四個參數:(1)gate_addr:描述符desc_struct結構類型的指針,指定待操作的描述符,通常指向數組idt_table中的某個項。(2)type:描述符類型,對應于門格式中的Type字段。(3)dpl:該描述符的權限級別;(4)addr:中斷處理程序入口地址的段內偏移量,由于內核段的起始地址總是為0,因此中斷處理程序在內核段中的段內偏移量也就是中斷處理程序的入口地址(即核心虛地址)。?
宏_set_gate()的源碼如下:?
#define?_set_gate(gate_addr,type,dpl,addr)?\?
do?{?\?
int?__d0,?__d1;?\?
__asm__?__volatile__?("movw?%%dx,%%ax\n\t"?\?
"movw?%4,%%dx\n\t"?\?
"movl?%%eax,%0\n\t"?\?
"movl?%%edx,%1"?\?
:"=m"?(*((long?*)?(gate_addr))),?\?
"=m"?(*(1+(long?*)?(gate_addr))),?"=&a"?(__d0),?"=&d"?(__d1)?\?
:"i"?((short)?(0x8000+(dpl<<13)+(type<<8))),?\?
"3"?((char?*)?(addr)),"2"?(__KERNEL_CS?<<?16));?\?
}?while?(0)?

由于不同的門其Type字段和DPL字段是固定的,因此Linux又在宏_set_gate()的基礎上為不同類型的門分別封裝了專用的操作宏,它們同樣也在traps.c文件中:?
(1)中斷門的操作宏set_intr_gate(),其源碼如下:?
void?set_intr_gate(unsigned?int?n,?void?*addr)?
{?
_set_gate(idt_table+n,14,0,addr);?/*?Type=1110(14),dpl=0(ring?0)*/?
}?
其中,參數n是中斷向量(被用作IDT表的索引)。參數addr是中斷處理程序的入口地址。?
(2)陷阱門的操作宏set_trap_gate()。其源碼如下:?
static?void?__init?set_trap_gate(unsigned?int?n,?void?*addr)?
{?
_set_gate(idt_table+n,15,0,addr);?/*?Type=1111(15),dpl=0(ring?0)*/?
}?
(3)系統門的操作宏set_system_gate()。Linux擴展了INTEL的術語,它將可編程異常所對應的中斷描述符稱為“系統門”。系統門的DPL字段為3(用戶態),因此使得用戶進程可以在用戶態下(I386運行在ring?3級別)通過int指令或其它指令穿越系統門而進入內核態。?
static?void?__init?set_system_gate(unsigned?int?n,?void?*addr)?
{?
_set_gate(idt_table+n,15,3,addr);?/*?Type=1111(15),dpl=3(ring?3)*/?
}?
(4)調用門的操作宏set_call_gate(),其源碼如下:?
static?void?__init?set_call_gate(void?*a,?void?*addr)?
{?
_set_gate(a,12,3,addr);?/*?Type=1100(12),dpl=3(ring?3)*/?
}?
從上述這四個專用的宏操作實現也可以看出,Linux并沒有使用i386?CPU的調用門和任務門,而是僅僅使用了中斷門和陷阱門(Linux又將它細分為陷阱門和系統門)兩種中斷描述符。?
5.2.3?對IDT表的初始化設置?
Linux內核在初始階段完成了對也是虛存管理機制的初始化后,便調用trap_init()函數和init_IRQ()函數對i386?CPU中斷機制的核心——IDT進行初始化設置。如下:?
asmlinkage?void?__init?start_kernel(void)?
{?
……?
trap_init();?
init_IRQ();?
……?
}?
其中,函數trap_init()用來對除外設中斷(32-47)以外的所有處理器保留的中斷向量進行初始化。而init_IRQ()函數則用來初始化對應于主、從8259A中斷控制器的可屏蔽外設中斷32-47。?
函數trap_init()定義在arch/i386/kernel/traps.c文件中,其源碼如下:?
void?__init?trap_init(void)?
{?
#ifdef?CONFIG_EISA?
if?(isa_readl(0x0FFFD9)?==?'E'+('I'<<8)+('S'<<16)+('A'<<24))?
EISA_bus?=?1;?
#endif?

set_trap_gate(0,&divide_error);?
set_trap_gate(1,&debug);?
set_intr_gate(2,&nmi);?
set_system_gate(3,&int3);?/*?int3-5?can?be?called?from?all?*/?
set_system_gate(4,&overflow);?
set_system_gate(5,&bounds);?
set_trap_gate(6,&invalid_op);?
set_trap_gate(7,&device_not_available);?
set_trap_gate(8,&double_fault);?
set_trap_gate(9,&coprocessor_segment_overrun);?
set_trap_gate(10,&invalid_TSS);?
set_trap_gate(11,&segment_not_present);?
set_trap_gate(12,&stack_segment);?
set_trap_gate(13,&general_protection);?
set_trap_gate(14,&page_fault);?
set_trap_gate(15,&spurious_interrupt_bug);?
set_trap_gate(16,&coprocessor_error);?
set_trap_gate(17,&alignment_check);?
set_trap_gate(18,&machine_check);?
set_trap_gate(19,&simd_coprocessor_error);?

set_system_gate(SYSCALL_VECTOR,&system_call);?

/*?
*?default?LDT?is?a?single-entry?callgate?to?lcall7?for?iBCS?
*?and?a?callgate?to?lcall27?for?Solaris/x86?binaries?
*/?
set_call_gate(&default_ldt[0],lcall7);?
set_call_gate(&default_ldt[4],lcall27);?

/*?
*?Should?be?a?barrier?for?any?external?CPU?state.?
*/?
cpu_init();?

#ifdef?CONFIG_X86_VISWS_APIC?
superio_init();?
lithium_init();?
cobalt_init();?
#endif?
}?
從上述代碼可以看出,trap_init()函數的核心就是做兩件事:(1)設置IDT的前20個表項,這是因為在0-31這32個CPU保留的異常中斷向量中,Intel僅定義了前20個(0-19)中斷向量,而中斷向量20-31這12個中斷向量則保留待以后擴展。(2)設置中斷向量SYSCALL_VECTOR(0x80),以用于系統調用的實現。?
函數init_IRQ()實現在arch/i386/kernel/i8259.c文件中。它負責初始化IDT表中的后224個中斷描述符即中斷向量32-256所對應的中斷描述符(除了用于syscall的中斷向量0x80)。其源碼如下:?
void?__init?init_IRQ(void)?
{?
int?i;?

#ifndef?CONFIG_X86_VISWS_APIC?
init_ISA_irqs();?
#else?
init_VISWS_APIC_irqs();?
#endif?
/*?
*?Cover?the?whole?vector?space,?no?vector?can?escape?
*?us.?(some?of?these?will?be?overridden?and?become?
*?'special'?SMP?interrupts)?
*/?
for?(i?=?0;?i?<?NR_IRQS;?i++)?{?
int?vector?=?FIRST_EXTERNAL_VECTOR?+?i;?
if?(vector?!=?SYSCALL_VECTOR)?
set_intr_gate(vector,?interrupt);?
}?

#ifdef?CONFIG_SMP?
/*?
*?IRQ0?must?be?given?a?fixed?assignment?and?initialized,?
*?because?it's?used?before?the?IO-APIC?is?set?up.?
*/?
set_intr_gate(FIRST_DEVICE_VECTOR,?interrupt[0]);?

/*?
*?The?reschedule?interrupt?is?a?CPU-to-CPU?reschedule-helper?
*?IPI,?driven?by?wakeup.?
*/?
set_intr_gate(RESCHEDULE_VECTOR,?reschedule_interrupt);?

/*?IPI?for?invalidation?*/?
set_intr_gate(INVALIDATE_TLB_VECTOR,?invalidate_interrupt);?

/*?IPI?for?generic?function?call?*/?
set_intr_gate(CALL_FUNCTION_VECTOR,?call_function_interrupt);?
#endif?

#ifdef?CONFIG_X86_LOCAL_APIC?
/*?self?generated?IPI?for?local?APIC?timer?*/?
set_intr_gate(LOCAL_TIMER_VECTOR,?apic_timer_interrupt);?

/*?IPI?vectors?for?APIC?spurious?and?error?interrupts?*/?
set_intr_gate(SPURIOUS_APIC_VECTOR,?spurious_interrupt);?
set_intr_gate(ERROR_APIC_VECTOR,?error_interrupt);?
#endif?

/*?
*?Set?the?clock?to?HZ?Hz,?we?already?have?a?valid?
*?vector?now:?
*/?
outb_p(0x34,0x43);?/*?binary,?mode?2,?LSB/MSB,?ch?0?*/?
outb_p(LATCH?&?0xff?,?0x40);?/*?LSB?*/?
outb(LATCH?>>?8?,?0x40);?/*?MSB?*/?

#ifndef?CONFIG_VISWS?
setup_irq(2,?&irq2);?
#endif?

/*?
*?External?FPU??Set?up?irq13?if?so,?for?
*?original?braindamaged?IBM?FERR?coupling.?
*/?
if?(boot_cpu_data.hard_math?&&?!cpu_has_fpu)?
setup_irq(13,?&irq13);?
}?
該函數主要執行以下幾個步驟:?
1.?在沒有配置80x86?APIC的情況下,調用init_ISA_irqs()函數來初始化中斷向量32-256這后224個中斷向量所對應的IRQ描述符。否則就調用init_VISWS_APIC_irqs()來完成這一點。PC體系結構中通常都沒有配置APIC,因此后面將詳細分析init_ISA_irqs()函數。?
2.?接下來,用一個簡單的for循環來初始化32-256這后224個中斷向量(除了用于syscall之外的0x80中斷向量)在IDT中對應的描述符。位于32-256之間的中斷向量i所對應的中斷處理程序入口地址由數組元素interrupt[i-32]。后面將會詳細介紹這個數組interrupt[224]——一個被內核用來保存中斷處理程序入口地址的數組。?
3.?初始化系統時鐘。?
4.?如果沒有定義CONFIG_VISWS配置選項,則調用setup_irq()函數將8259A中斷控制器的IRQ2設置為用于級聯。?
5.?如果使用了FPU,則將IRQ13分配用于數學協處理器的錯誤報告中斷。所以調用setup_irq()函數將IRQ13設置為用于FPU。?

接下來將討論內核對中斷處理程序的構建,也即數組interrupt[224]的構建。?

§5.3內核對中斷服務程序的構建?
由上一節對init_IRQ()函數的分析我們知道,函數指針數組interrupt[]中定義了中斷向量32-256所對應的中斷服務程序的入口地址。本節我們就來分析一下Linux內核是如何巧妙地為這224個中斷向量構建ISR的。?
函數指針數組interrupt[]定義在arch/i386/kernel/i8259.c文件中:?
#define?IRQ(x,y)?\?
IRQ##x##y##_interrupt?

#define?IRQLIST_16(x)?\?
IRQ(x,0),?IRQ(x,1),?IRQ(x,2),?IRQ(x,3),?\?
IRQ(x,4),?IRQ(x,5),?IRQ(x,6),?IRQ(x,7),?\?
IRQ(x,8),?IRQ(x,9),?IRQ(x,a),?IRQ(x,b),?\?
IRQ(x,c),?IRQ(x,d),?IRQ(x,e),?IRQ(x,f)?

void?(*interrupt[NR_IRQS])(void)?=?{?
IRQLIST_16(0x0),?

#ifdef?CONFIG_X86_IO_APIC?
IRQLIST_16(0x1),?IRQLIST_16(0x2),?IRQLIST_16(0x3),?
IRQLIST_16(0x4),?IRQLIST_16(0x5),?IRQLIST_16(0x6),?IRQLIST_16(0x7),?
IRQLIST_16(0x8),?IRQLIST_16(0x9),?IRQLIST_16(0xa),?IRQLIST_16(0xb),?
IRQLIST_16(0xc),?IRQLIST_16(0xd)?
#endif?
};?

#undef?IRQ?
#undef?IRQLIST_16?
從上述定義可以看出,在沒有定義CONFIG_X86_IO_APIC配置選項的單CPU體系結構中,interrupt[]數組中只有前16個數組元素中包含有有效的指針(也即對應于主、從8259A中斷控制器的中斷請求)。?
先看宏IRQ()的定義。我們知道GCC預編譯符號##的作用就是將字符串連接在一起。因此經過GCC的預編譯處理后,宏IRQ(x,y)實際上就是符號IRQxy_interrupt。?
在來看宏IRQLIST_16()。它的作用主要是為了避免重復的文字輸入。因此但在interrupt[]數組的初始化中以參數0x0來調用宏IRQLIST_16()時,我們所得到的就是16個宏定義:IRQ(0x0,0)?、…、IRQ(0x0,f),將IRQ()宏繼續展開,我們就可知道interrupt[]函數指針數組的前16項的值為:IRQ0x00_interrupt、…、IRQ0x0f_interrupt。而后208個數組元素則或者都是NULL指針(在沒有APIC的情況下),或者分別是IRQ0x10_interrupt…IRQ0xdf_interrupt。?
現在我們已經清楚地了解了interrupt[224]數組的定義以及它的初始值。很自然地我們會想到,函數IRQ0x00_interrupt到IRQ0xdf_interrupt這224個函數又是在哪定義的呢?請看i8259.c文件中另外幾行宏定義與宏引用:?
#define?BI(x,y)?\?
BUILD_IRQ(x##y)?

#define?BUILD_16_IRQS(x)?\?
BI(x,0)?BI(x,1)?BI(x,2)?BI(x,3)?\?
BI(x,4)?BI(x,5)?BI(x,6)?BI(x,7)?\?
BI(x,8)?BI(x,9)?BI(x,a)?BI(x,b)?\?
BI(x,c)?BI(x,d)?BI(x,e)?BI(x,f)?

/*?
*?ISA?PIC?or?low?IO-APIC?triggered?(INTA-cycle?or?APIC)?interrupts:?
*?(these?are?usually?mapped?to?vectors?0x20-0x2f)?
*/?
BUILD_16_IRQS(0x0)?
顯然,以參數0x0來引用BUILD_16_IRQ()宏在經過gcc預處理后,將展開成:BUILD_IRQ(0x00)、BUILD_IRQ(0x01)、…、BUILD_IRQ(0x0f)等共16個宏定義的引用。而宏BUILD_IRQ()則是定義在include/asm-i386/hw_irq.h頭文件中定義的:?
#define?BUILD_IRQ(nr)?\?
asmlinkage?void?IRQ_NAME(nr);?\?
__asm__(?\?
"\n"__ALIGN_STR"\n"?\?
SYMBOL_NAME_STR(IRQ)?#nr?"_interrupt:\n\t"?\?
"pushl?$"#nr"-256\n\t"?\?
"jmp?common_interrupt");?

上述代碼中的IRQ_NAME()宏也是定義在include/asm-i386/hw_irq.h中:?
#define?IRQ_NAME2(nr)?nr##_interrupt(void)?
#define?IRQ_NAME(nr)?IRQ_NAME2(IRQ##nr)?
所以,宏引用IRQ_NAME(nr)被展開后也就是一個類似于IRQ0x01_interrupt(void)這樣的函數名。?
因此,從BUILD_IRQ(0x00)到BUILD_IRQ(0x0f)這一共16個宏引用經過gcc預處理后,將展開成為一系列如下樣式的代碼:?
amslinkage?void?IRQ0x01_interrupt(void);?
__asm__(?\?
“\n”?\?
“IRQ0x01_interrupt:\n\t”?\?
“pushl?$0x01-256?\n\t”?\?
“jmp?common_interrupt”);?
可以看出,Linux內核正是通過gcc的預處理功能巧妙地定義了從IRQ0x00_interrupt()到IRQ0x0f_interrupt()這16個中斷處理函數。?

下面在來看看中斷處理函數IRQ0x00_interrupt()到IRQ0x0f_interrupt()本身的流程。這16個中斷處理函數的執行過程都是一樣的,它主要完成兩件事:(1)將立即數(IRQ號-256)這樣一個負數壓入內核堆棧,以供中斷處理流程中后面的函數獲取中斷號。比如對于中斷向量0x20,它對應于注8259A中斷控制器的IRQ0,因此其中斷服務程序的入口地址應該是interrupt[0],也即函數IRQ0x00_interrupt(),該函數所做的第一件事情就是把負數-256壓入內核堆棧中。這里之所以用復數來表示中斷號,是因為正數已被用于標識0x80中斷中的系統調用號。(2)所有的中斷服務函數所做的第二件事情都相同——即跳轉到一個公共的的程序common_interrupt中,并由該公共程序繼續對中斷請求進行服務。?
5.3.1?公共的中斷服務程序——common_interrupt?
在源文件arch/i386/kernel/i8259.c中一開始就引用了宏BUILD_COMMON_IRQ(),其作用就是構建面向所有中斷的公共服務程序common_interrup,如下所示:?
36:?BUILD_COMMON_IRQ()?

宏BUILD_COMMON_IRQ()定義在頭文件include/asm-i386/hw_irq.h中,如下所示:?
#define?BUILD_COMMON_IRQ()?\?
asmlinkage?void?call_do_IRQ(void);?\?
__asm__(?\?
"\n"?__ALIGN_STR"\n"?\?
"common_interrupt:\n\t"?\?
SAVE_ALL?\?
"pushl?$ret_from_intr\n\t"?\?
SYMBOL_NAME_STR(call_do_IRQ)":\n\t"?\?
"jmp?"SYMBOL_NAME_STR(do_IRQ));?

上述代碼經過展開后,就成為如下匯編代碼:?
common_interrupt:?
SAVE_ALL?
call?do_IRQ?
jmp?ret_from_intr?
可以看出,公共服務程序common_interrupt主要做三件事:(1)首先,調用宏SAVE_ALL來保存CPU的執行現場;(2)然后,調用總控函數do_IRQ()對中斷請求進行真正的服務;(3)當從do_IRQ()返回后,跳到函數ret_from_intr,進入中斷返回操作。?

用于保存現場的SAVE_ALL宏定義在arch/i386/kernel/entry.S文件中,如下所示:?
#define?SAVE_ALL?\?
cld;?\?
pushl?%es;?\?
pushl?%ds;?\?
pushl?%eax;?\?
pushl?%ebp;?\?
pushl?%edi;?\?
pushl?%esi;?\?
pushl?%edx;?\?
pushl?%ecx;?\?
pushl?%ebx;?\?
movl?$(__KERNEL_DS),%edx;?\?
movl?%edx,%ds;?\?
movl?%edx,%es;?
說明幾點:(1)用戶態堆棧SS寄存器和ESP寄存器是在切換到內核態堆棧被壓入的;(2)CPU在進入中斷服務程序之前已經把EFLAGS寄存器和返回地址壓入堆棧中;(3)段寄存器DS和ES被更改為內核態的段選擇符__KERNEL_DS。因此,在執行SAVE_ALL宏之后內核態堆棧的內容應為如下圖所示:?
而Linux也根據上圖中的關系在arch/i386/kernel/entry.S文件中定義了一些常數來表示個寄存器的內容相對于當前內核堆棧指針的偏移:?
EBX?=?0x00?
ECX?=?0x04?
EDX?=?0x08?
ESI?=?0x0C?
EDI?=?0x10?
EBP?=?0x14?
EAX?=?0x18?
DS?=?0x1C?
ES?=?0x20?
ORIG_EAX?=?0x24?
EIP?=?0x28?
CS?=?0x2C?
EFLAGS?=?0x30?
OLDESP?=?0x34?
OLDSS?=?0x38?

真正對中斷請求進行服務的do_IRQ()函數和中斷返回函數ret_from_intr()將在下面介紹。在分析總控函數do_IRQ()之前,先來討論一下中斷請求描述符和中斷服務隊列。?

§5.4?中斷請求描述符和中斷服務隊列?
我們都知道,在256個中斷向量中,i386?CPU保留了0~31這前32個中斷向量用于CPU異常,而剩余的224個中斷向量則是可用于外設中斷或軟中斷的可使用中斷向量。由于不同體系結構的CPU所保留的中斷向量不同,因此剩余的可使用中斷向量數目也不同。所以,Linux定義了宏NR_IRQS來表示這個值。對于i386而言,該宏定義在include/asm-i386/irq.h頭文件中:?
#define?TIME_IRQ?0?/*?for?i386,主8259A的IRQ0用于時鐘中斷?*/?
#define?NR_IRQS?224?

5.4.1?對中斷控制器的抽象描述?
在剩余的224個可用中斷向量中,各中斷向量所對應的中斷類型也是不同的。比如對于PC機,中斷向量0x20~0x2f則來自于主、從8259A?PIC,其余中斷向量則屬于軟中斷(Linux僅僅使用了其中的0x80)。因此有必要對這些不同類型的中斷向量進行區分。?
另外,從中斷控制器的角度看,盡管不同平臺使用不同的PIC,但幾乎所有的PIC都由相同的基本功能和工作方式。因此為了獲得更好的跨平臺兼容性,Linux對中斷控制器進行了抽象描述。定義在頭文件include/linux/irq.h頭文件中的數據結構hw_interrupt_type描述了一個標準的中斷控制器,如下所示:?
/*?
*?Interrupt?controller?descriptor.?This?is?all?we?need?
*?to?describe?about?the?low-level?hardware.?
*/?
struct?hw_interrupt_type?{?
const?char?*?typename;?
unsigned?int?(*startup)(unsigned?int?irq);?
void?(*shutdown)(unsigned?int?irq);?
void?(*enable)(unsigned?int?irq);?
void?(*disable)(unsigned?int?irq);?
void?(*ack)(unsigned?int?irq);?
void?(*end)(unsigned?int?irq);?
void?(*set_affinity)(unsigned?int?irq,?unsigned?long?mask);?
};?
typedef?struct?hw_interrupt_type?hw_irq_controller;?

在此基礎上,Linux又在arch/i386/kernel/i8259.c文件中定義了全局變量i82559_irq_type,以用于所有來自主、從8259A中斷控制器的中斷請求(對應的中斷向量為0x20~0x2f),如下:?
static?struct?hw_interrupt_type?i8259A_irq_type?=?{?
"XT-PIC",?
startup_8259A_irq,?
shutdown_8259A_irq,?
enable_8259A_irq,?
disable_8259A_irq,?
mask_and_ack_8259A,?
end_8259A_irq,?
NULL?
};?

而對于0x30~0xff子間的中斷向量,Linux也在arch/i386/kernel/irq.c文件中定義了全局變量no_irq_type——一個虛擬的中斷控制器,以表示這些中斷向量的中斷請求并不是來自于任何硬件PIC的中斷,而是由軟件編程指令產生的軟中斷。如下所示:?
/*?startup?is?the?same?as?"enable",?shutdown?is?same?as?"disable"?*/?
#define?shutdown_none?disable_none?
#define?end_none?enable_none?

struct?hw_interrupt_type?no_irq_type?=?{?
"none",?
startup_none,?
shutdown_none,?
enable_none,?
disable_none,?
ack_none,?
end_none?
};?

5.4.2?IRQ描述符?
由上面的討論可知,中斷向量0x20~0xff所對應的中斷請求是不同的,所以Linux在include/linux/irq.h頭文件中定義了數據結構irq_desc_t來描述一個中斷請求行為的屬性。如下所示:?
typedef?struct?{?
unsigned?int?status;?/*?IRQ?status?*/?
hw_irq_controller?*handler;?
struct?irqaction?*action;?/*?IRQ?action?list?*/?
unsigned?int?depth;?/*?nested?irq?disables?*/?
spinlock_t?lock;?
}?____cacheline_aligned?irq_desc_t;?
各成員的含義如下:?
(1)status:表示中斷請求的狀態。它可以是下列值:?
/*?
*?IRQ?line?status.?
*/?
#define?IRQ_INPROGRESS?1?/*?IRQ?handler?active?-?do?not?enter!?*/?
#define?IRQ_DISABLED?2?/*?IRQ?disabled?-?do?not?enter!?*/?
#define?IRQ_PENDING?4?/*?IRQ?pending?-?replay?on?enable?*/?
#define?IRQ_REPLAY?8?/*?IRQ?has?been?replayed?but?not?acked?yet?*/?
#define?IRQ_AUTODETECT?16?/*?IRQ?is?being?autodetected?*/?
#define?IRQ_WAITING?32?/*?IRQ?not?yet?seen?-?for?autodetection?*/?
#define?IRQ_LEVEL?64?/*?IRQ?level?triggered?*/?
#define?IRQ_MASKED?128?/*?IRQ?masked?-?shouldn't?be?seen?again?*/?
#define?IRQ_PER_CPU?256?/*?IRQ?is?per?CPU?*/?
上述這些狀態標志值也是定義在include/linux/irq.h頭文件中。?
(2)handler指針:指向這個中斷請求所來自的中斷控制器描述符。對于中斷向量0x20~0x2f上的中斷請求而言,該成員指針應該指向全局變量i8259_irq_type;而對于其余軟中斷的中斷請求,該指針因該指向no_irq_type。?
(3)action指針:指向服務這個中斷請求的、由設備驅動程序注冊的服務程序(ISR)隊列。?
(4)depth:表示action指針所指向的中斷請求服務隊列的長度。?
(5)lock:對irq_desc_t結構中其他成員進行訪問保護的自旋鎖。這是因為內核中irq_desc_t類型的變量(如下面的irq_desc[]數組)都是全局變量,因此對它們的訪問都必須是互斥地進行的。?

在上述結構的基礎上,Linux在arch/i386/kernel/irq.c文件中定義了數組irq_desc[224]來分別描述中斷向量0x20~0xff所對應的中斷請求:?
/*?
*?Controller?mappings?for?all?interrupt?sources:?
*/?
irq_desc_t?irq_desc[NR_IRQS]?__cacheline_aligned?=?
{?[0?...?NR_IRQS-1]?=?{?0,?&no_irq_type,?NULL,?0,?SPIN_LOCK_UNLOCKED}};?

5.4.3?中斷請求服務隊列?
現代外設總線(如PCI)通常都允許外設共享一個IRQ線,因此一個中斷向量可能會對應有多個由設備驅動程序提供的中斷請求服務例程(ISR),所以Linux內核必須有效地將這個多個來自不同的device?driver的ISR組織起來。為此,Linux通過數據結構irqaction來描述一個設備驅動程序對中斷請求的服務行為,其定義如下所示(include/linux/interrupt.h):?
struct?irqaction?{?
void?(*handler)(int,?void?*,?struct?pt_regs?*);?
unsigned?long?flags;?
unsigned?long?mask;?
const?char?*name;?
void?*dev_id;?
struct?irqaction?*next;?
};?
各成員的含義如下:?
(1)handler指針:指向驅動程序的ISR入口地址。?
(2)flags:描述中斷類型的屬性標志,它可以是下列三個值的“或”:?
l?SA_SHIRQ:表示中斷是共享的。?
l?SA_INTERRUPT:當執行handler函數時,屏蔽同級中斷。?
l?SA_SAPLE_RANDOM。?
(3)mask:屏蔽掩碼。?
(4)name指針:表示提供handler函數的設備名稱。?
(5)dev_id:一個唯一的設備標識符。注意!當flags屬性中設置了SA_SHIRQ屬性時,dev_id指針不能為NULL。?
(6)next指針:指向同屬于該中斷請求的下一個服務行為。Linux就是通過next指針把同一個中斷向量的中斷請求的多個服務行為組織成為一條中斷請求服務隊列的。?
下圖5-14清晰地描述了與中斷請求相關的幾個數據結構之間的關系:?

5.4.4?中斷請求描述符數組的初始化?
函數init_ISA_irqs()完成對中斷請求描述符數組irq_desc[]中各元素的初始化,該函數定義在arch/i386/kernel/i8259.c文件中,如下所示:?
void?__init?init_ISA_irqs?(void)?
{?
int?i;?

init_8259A(0);?

for?(i?=?0;?i?<?NR_IRQS;?i++)?{?
irq_desc.status?=?IRQ_DISABLED;?
irq_desc.action?=?0;?
irq_desc.depth?=?1;?

if?(i?<?16)?{?
/*?
*?16?old-style?INTA-cycle?interrupts:?
*/?
irq_desc.handler?=?&i8259A_irq_type;?
}?else?{?
/*?
*?'high'?PCI?IRQs?filled?in?on?demand?
*/?
irq_desc.handler?=?&no_irq_type;?
}?
}?
}?
初始化的過程很簡單:中斷向量0x20~0x2f分別與中斷描述符irq_desc[0]~irq_desc[15]相對應,因此它們的handler指針指向i8259A_irq_type,因為它們的中斷請求來自于主、從8259A中斷控制器。而其余軟中斷描述符的handler指針則指向no_irq_type這個虛擬中斷控制器描述符。?

5.4.5?注冊驅動程序的ISR?
Linux在include/linux/sched.h頭文件中聲明了函數接口request_irq()和free_irq(),以供設備驅動程序向內核注冊和注銷驅動程序所提供的ISR函數。這兩個函數都是實現在文件arch/i386/kernel/irq.c中。?
首先,我們來分析request_irq()函數。該函數有5個參數:(1)irq:外設所使用的IRQ線號。(2)handler函數指針:設備驅動程序所實現的ISR函數。(3)irqflags:設備驅動程序指定的中斷請求類型標志,它可以是下列三個值的“或”:SA_SHIRQ、SA_INTERRUPT和SA_SAMPLE_RANDOM。(4)devname指針:設備名字字符串。(5)dev_id:指向全局唯一的設備標識ID,這是一個void類型的指針,可供設備驅動程序自行解釋。該函數的源碼如下:?
/**?
*?request_irq?-?allocate?an?interrupt?line?
*?@irq:?Interrupt?line?to?allocate?
*?@handler:?Function?to?be?called?when?the?IRQ?occurs?
*?@irqflags:?Interrupt?type?flags?
*?@devname:?An?ascii?name?for?the?claiming?device?
*?@dev_id:?A?cookie?passed?back?to?the?handler?function?
*?
*?This?call?allocates?interrupt?resources?and?enables?the?
*?interrupt?line?and?IRQ?handling.?From?the?point?this?
*?call?is?made?your?handler?function?may?be?invoked.?Since?
*?your?handler?function?must?clear?any?interrupt?the?board?
*?raises,?you?must?take?care?both?to?initialise?your?hardware?
*?and?to?set?up?the?interrupt?handler?in?the?right?order.?
*?
*?Dev_id?must?be?globally?unique.?Normally?the?address?of?the?
*?device?data?structure?is?used?as?the?cookie.?Since?the?handler?
*?receives?this?value?it?makes?sense?to?use?it.?
*?
*?If?your?interrupt?is?shared?you?must?pass?a?non?NULL?dev_id?
*?as?this?is?required?when?freeing?the?interrupt.?
*?
*?Flags:?
*?
*?SA_SHIRQ?Interrupt?is?shared?
*?
*?SA_INTERRUPT?Disable?local?interrupts?while?processing?
*?
*?SA_SAMPLE_RANDOM?The?interrupt?can?be?used?for?entropy?
*?
*/?

int?request_irq(unsigned?int?irq,?
void?(*handler)(int,?void?*,?struct?pt_regs?*),?
unsigned?long?irqflags,?
const?char?*?devname,?
void?*dev_id)?
{?
int?retval;?
struct?irqaction?*?action;?

#if?1?
/*?
*?Sanity-check:?shared?interrupts?should?REALLY?pass?in?
*?a?real?dev-ID,?otherwise?we'll?have?trouble?later?trying?
*?to?figure?out?which?interrupt?is?which?(messes?up?the?
*?interrupt?freeing?logic?etc).?
*/?
if?(irqflags?&?SA_SHIRQ)?{?
if?(!dev_id)?
printk("Bad?boy:?%s?(at?0x%x)?called?us?without?a?dev_id!\n",?devname,?(&irq)[-1]);?
}?
#endif?

if?(irq?>=?NR_IRQS)?
return?-EINVAL;?
if?(!handler)?
return?-EINVAL;?

action?=?(struct?irqaction?*)?
kmalloc(sizeof(struct?irqaction),?GFP_KERNEL);?
if?(!action)?
return?-ENOMEM;?

action->handler?=?handler;?
action->flags?=?irqflags;?
action->mask?=?0;?
action->name?=?devname;?
action->next?=?NULL;?
action->dev_id?=?dev_id;?

retval?=?setup_irq(irq,?action);?
if?(retval)?
kfree(action);?
return?retval;?
}?
對該函數的NOTE如下:?
(1)首先進行參數檢查。①在指定了中斷共享標志IRQ_SHIRQ標志時,參數dev_id必須有效,不能為NULL;②IRQ線號參數irq不能大于NR_IRQS;③handler指針不能為NULL。?
(2)調用kmalloc()函數在SLAB分配器緩存中為結構類型irqaction分配內存,以構建一個中斷服務描述符。如果分配失敗,則返回-ENOMEM,表示系統內存不足。?
(3)然后,根據參數相應地初始化剛剛構建的中斷服務描述符中的各個成員。?
(4)最后調用setup_irq()函數將上述構建號的中斷服務描述符插入到參數irq所對應的中斷服務隊列中去。如果setup_irq()函數返回非0值,表示插入失敗,因此調用kfree()函數將前面構建的中斷服務描述符釋放掉。?
(5)最后,返回返回值retval。0表示成功,非0表示失敗。?

函數setup_irq()用來將一個已經構建好的中斷服務描述符插入到相應的中斷服務隊列中。參數irq指定IRQ輸入線號,它指定將中斷描述符插到哪一個中斷服務隊列中去;參數new指針指向待插入的中斷服務描述符。該函數的源碼如下:?

/*?this?was?setup_x86_irq?but?it?seems?pretty?generic?*/?
int?setup_irq(unsigned?int?irq,?struct?irqaction?*?new)?
{?
int?shared?=?0;?
unsigned?long?flags;?
struct?irqaction?*old,?**p;?
irq_desc_t?*desc?=?irq_desc?+?irq;?

/*?
*?Some?drivers?like?serial.c?use?request_irq()?heavily,?
*?so?we?have?to?be?careful?not?to?interfere?with?a?
*?running?system.?
*/?
if?(new->flags?&?SA_SAMPLE_RANDOM)?{?
/*?
*?This?function?might?sleep,?we?want?to?call?it?first,?
*?outside?of?the?atomic?block.?
*?Yes,?this?might?clear?the?entropy?pool?if?the?wrong?
*?driver?is?attempted?to?be?loaded,?without?actually?
*?installing?a?new?handler,?but?is?this?really?a?problem,?
*?only?the?sysadmin?is?able?to?do?this.?
*/?
rand_initialize_irq(irq);?
}?

/*?
*?The?following?block?of?code?has?to?be?executed?atomically?
*/?
spin_lock_irqsave(&desc->lock,flags);?
p?=?&desc->action;?
if?((old?=?*p)?!=?NULL)?{?
/*?Can't?share?interrupts?unless?both?agree?to?*/?
if?(!(old->flags?&?new->flags?&?SA_SHIRQ))?{?
spin_unlock_irqrestore(&desc->lock,flags);?
return?-EBUSY;?
}?

/*?add?new?interrupt?at?end?of?irq?queue?*/?
do?{?
p?=?&old->next;?
old?=?*p;?
}?while?(old);?
shared?=?1;?
}?

*p?=?new;?

if?(!shared)?{?
desc->depth?=?0;?
desc->status?&=?~(IRQ_DISABLED?|?IRQ_AUTODETECT?|?IRQ_WAITING);?
desc->handler->startup(irq);?
}?
spin_unlock_irqrestore(&desc->lock,flags);?

register_irq_proc(irq);?
return?0;?
}?
對該函數的NOTE如下:?
(1)首先根據參數irq的值找到相應的中斷請求描述符,也即irq_desc?+?irq,并讓指針desc指向它。?
(2)如果待插入中斷服務描述符中的flags成員中設置了SA_SAMPLE_RANDOM標志,那就調用rand_initialize_irq()函數來引入一些隨機性。一般設備驅動程序很少使用這個標志。?
(3)因為接下來要對中斷請求描述符desc進行訪問,所以調用spin_lock_irqsave()函數對自旋鎖desc->lock進行加鎖,并同時關中斷。?
(4)將指針p指向desc->action成員。指針desc->action指向將要進行插入操作的中斷服務隊列的第一個元素。因此*p也就等于desc->action。此外,讓指針old等于(*p)。因此old也就指向中斷服務隊列的第一個元素。?
(5)然后判斷(*p)所指向的中斷服務隊列是否為空。如果不為空:①判斷中斷服務隊列的第一個中斷服務描述符和new所指向的待插入中斷服務描述符是否同時都設置了SA_SHIRQ標志。如果沒有,返回錯誤值-EBUSY表示參數irq所指定的IRQ輸入線已經被使用了。注意!必須二者都同意共享IRQ輸入線才行。②通過一個do{}while循環來依次遍歷整個中斷服務隊列,直到隊列中的最后一個元素。當從do{}while循環退出時,指針p指向隊列中最后一個中斷服務描述符的next指針成員。③將局部變量shared置1,表示發生中斷共享。?
(6)讓(*p)等于new指針,從而將new所指向的中斷服務描述符插到中斷服務隊列的尾部。注意!如果原來的中斷服務隊列為空的話,new所指向的中斷服務描述符將成為隊列中唯一的一個元素。?
(7)如果shared變量為0,說明new是中斷服務隊列中插入的第一個元素,因此對中斷請求描述符desc進行相應的初始化設置,包括:將depth置0,清除IRQ_DISABLED、IRQ_AUTODETECT和IRQ_WAITING標志,以及調用中斷控制器描述符的startup()函數來使能irq所指定的IRQ輸入線。?
(8)至此,插入操作結束,因此調用spin_unlock_irqrestore()函數進行解鎖和開中斷。?
(9)最后,調用register_irq_proc()函數注冊相應的/proc文件系統。?

5.4.6?注銷驅動程序的ISR?
函數free_irq()用來注銷驅動程序先前通過request_irq()函數所注冊的ISR函數。其源碼如下:?
/**?
*?free_irq?-?free?an?interrupt?
*?@irq:?Interrupt?line?to?free?
*?@dev_id:?Device?identity?to?free?
*?
*?Remove?an?interrupt?handler.?The?handler?is?removed?and?if?the?
*?interrupt?line?is?no?longer?in?use?by?any?driver?it?is?disabled.?
*?On?a?shared?IRQ?the?caller?must?ensure?the?interrupt?is?disabled?
*?on?the?card?it?drives?before?calling?this?function.?The?function?
*?does?not?return?until?any?executing?interrupts?for?this?IRQ?
*?have?completed.?
*?
*?This?function?may?be?called?from?interrupt?context.?
*?
*?Bugs:?Attempting?to?free?an?irq?in?a?handler?for?the?same?irq?hangs?
*?the?machine.?
*/?

void?free_irq(unsigned?int?irq,?void?*dev_id)?
{?
irq_desc_t?*desc;?
struct?irqaction?**p;?
unsigned?long?flags;?

if?(irq?>=?NR_IRQS)?
return;?

desc?=?irq_desc?+?irq;?
spin_lock_irqsave(&desc->lock,flags);?
p?=?&desc->action;?
for?(;;)?{?
struct?irqaction?*?action?=?*p;?
if?(action)?{?
struct?irqaction?**pp?=?p;?
p?=?&action->next;?
if?(action->dev_id?!=?dev_id)?
continue;?

/*?Found?it?-?now?remove?it?from?the?list?of?entries?*/?
*pp?=?action->next;?
if?(!desc->action)?{?
desc->status?|=?IRQ_DISABLED;?
desc->handler->shutdown(irq);?
}?
spin_unlock_irqrestore(&desc->lock,flags);?

#ifdef?CONFIG_SMP?
/*?Wait?to?make?sure?it's?not?being?used?on?another?CPU?*/?
while?(desc->status?&?IRQ_INPROGRESS)?
barrier();?
#endif?
kfree(action);?
return;?
}?
printk("Trying?to?free?free?IRQ%d\n",irq);?
spin_unlock_irqrestore(&desc->lock,flags);?
return;?
}?
}?
對該函數的NOTE如下:?
(1)為遍歷中斷服務隊列做準備:首先,根據參數irq所指定的IRQ號找到相應的中斷請求描述符desc(=irq_desc+irq)。然后調用spin_lock_irqsave()函數進行加鎖和關中斷。最后,讓指針p指向當前被掃描隊列元素的前一個元素的next指針成員,因此(*p)就指向隊列中當前正被掃描的中斷服務描述符。初始時,讓指針p指向中斷請求描述符desc的action指針成員,也即(*p)指向中斷服務隊列的第一個元素。?
(2)用一個for死循環來遍歷隊列。循環體的執行步驟如下:?
n?讓action指針等于(*p),表示當前正被掃描的隊列元素。?
n?如果action指針不為空:①讓指針pp等于p,因此pp也就指向當前被掃描隊列元素的前一個元素的next指針成員。②更新指針p,讓它指向當前被掃描的中斷服務描述符action的next指針成員,因此(*p)也就指向下一個隊列元素。③比較參數dev_id和當前中斷服務描述符action的dev_id成員是否不相等,如果不相等,那就執行continue語句繼續掃描隊列。如果相等,則說明我們已經找到要刪除的中斷服務描述符,也即是當前被掃描的中斷服務描述符action。④找到以后,先將所找到的中斷服務描述符action從中斷服務隊列中摘除。語句*pp=action->next完成這一點,也即讓前一個元素的next指針指向當前被掃描元素的下一個元素。⑤判斷一下desc->action所指向的中斷服務隊列是否為空,因為中斷服務隊列中可能就只有一個元素,因此前一步的摘除操作又可能會使中斷服務隊列變為空。如果為空,那就在中斷請求描述符的status中設置IRQ_DISABLED標志,并調用PIC描述符的shutdown()函數禁止這個IRQ輸入線。⑥最后,解除自旋鎖并開中斷,接著調用kfree()函數釋放內存后,函數就可以直接return了。?
n?如果action指針為空,說明已經遍歷到隊列尾部,而此時我們還沒有找到參數dev_id所指定的中斷服務描述符,因此打印警告信息,然后解鎖并開中斷。函數以失敗結束執行。?



我的未來不是夢!?

文章選項:???????????
?
zhanrk
(journeyman)
03-02-14?12:08
??[精華]?Re:?Linux內核的中斷機制分析(continue...)?[re:?zhanrk]????
?


§5.5?Linux對8259A中斷控制器的編程實現?
Linux對主、從8259A中斷控制器的編程實現在源碼文件arch/i386/kernel/i8259.c中,主要包含兩部分:(1)對主、從8259A?PIC的初始化;(2)對控制器描述符i8259A_irq_type中定義的各函數的實現。?

5.5.1?對8259A的初始化?
函數init_8259A()完成對主、從8259A中斷控制器的初始化工作。如前所述,該函數是被init_ISA_irqs()函數所調用的(參見5.4.4節),其源碼如下:?
void?__init?init_8259A(int?auto_eoi)?
{?
unsigned?long?flags;?

spin_lock_irqsave(&i8259A_lock,?flags);?

outb(0xff,?0x21);?/*?mask?all?of?8259A-1?*/?
outb(0xff,?0xA1);?/*?mask?all?of?8259A-2?*/?

/*?
*?outb_p?-?this?has?to?work?on?a?wide?range?of?PC?hardware.?
*/?
outb_p(0x11,?0x20);?/*?ICW1:?select?8259A-1?init?*/?
outb_p(0x20?+?0,?0x21);?/*?ICW2:?8259A-1?IR0-7?mapped?to?0x20-0x27?*/?
outb_p(0x04,?0x21);?/*?8259A-1?(the?master)?has?a?slave?on?IR2?*/?
if?(auto_eoi)?
outb_p(0x03,?0x21);?/*?master?does?Auto?EOI?*/?
else?
outb_p(0x01,?0x21);?/*?master?expects?normal?EOI?*/?

outb_p(0x11,?0xA0);?/*?ICW1:?select?8259A-2?init?*/?
outb_p(0x20?+?8,?0xA1);?/*?ICW2:?8259A-2?IR0-7?mapped?to?0x28-0x2f?*/?
outb_p(0x02,?0xA1);?/*?8259A-2?is?a?slave?on?master's?IR2?*/?
outb_p(0x01,?0xA1);?/*?(slave's?support?for?AEOI?in?flat?mode?
is?to?be?investigated)?*/?

if?(auto_eoi)?
/*?
*?in?AEOI?mode?we?just?have?to?mask?the?interrupt?
*?when?acking.?
*/?
i8259A_irq_type.ack?=?disable_8259A_irq;?
else?
i8259A_irq_type.ack?=?mask_and_ack_8259A;?

udelay(100);?/*?wait?for?8259A?to?initialize?*/?

outb(cached_21,?0x21);?/*?restore?master?IRQ?mask?*/?
outb(cached_A1,?0xA1);?/*?restore?slave?IRQ?mask?*/?

spin_unlock_irqrestore(&i8259A_lock,?flags);?
}?
參數atuo_eoi決定是否讓8259A工作在AEOI模式下。對該函數的注釋如下:?
(1)首先調用函數spin_lock_irqsave()對自旋鎖i8259A_lock進行加鎖。所有對主、從8259A進行編程的代碼都首先必須進行這一步操作,以保證對主、從8259A的操作是互斥的。?
(2)分別向主、從8259A寫入屏蔽掩碼0xff,以屏蔽所有的IRQ輸入。?
(3)通過向主8259A發送一些列ICW來初始化主8259A:①ICW1=0x11,也即:Edge?Triggered?Mode、AOI=0、Cascade?Mode(ICW3?Needed)、ICW4?Needed;②ICW2=0x20,也即:IRQ0的中斷向量為0x20;③ICW3=0x04,也即:主8259A通過IRQ2級連了一個從8259A;④如果參數auto_eoi非零,則讓ICW4=0x03,也即:Auto?EOI、80x86?mode;否則如果auto_eoi為0,則讓ICW4=0x01,也即:Normal?EOI、80x86?mode。?
(4)通過向從8259A發送一系列ICW來初始化它:①ICW1與主8259A的相同;②ICW2=0x28,表示從8259A的IRQ0的中斷向量為0x28;③ICW3=0x02,表示從8259A是連接在主8259A的IRQ2上;④ICW4=0x01,表示從8259A只工作在Normal?EOI模式下。?
這里需要注意的是,寫端口時最好用outb_p()函數,以等待慢速的8259A中斷控制器。?
(5)如果參數auto_eoi非零,表示工作在“自動中斷結束(AEOI)模式,因此就要將i8259A_irq_type的應答函數ack設置成disable_8259A_irq()函數;否則就將其設置成mask_and_ack_8259A()函數。?
(6)至此,寫初始化命令字的過程結束。然后調用udelay()函數延時100&micro;s,以等待8259A中斷控制器完成其自身的硬件初始化。?
(7)最后,從全局變量cached_irq_mask中恢復主、從8259A的IRQ屏蔽掩碼。關于cached_irq_mask這個全局屏蔽掩碼下面馬上會談到。?

5.5.2?對PIC描述符i8259A_irq_type的實現?
(1)全局屏蔽掩碼cached_irq_mask?
Linux在arch/i386/kernel/i8259.c文件中定義了一個全局變量cached_irq_mask來表示8259A中斷控制器的當前屏蔽狀態。其中,bit[7:0]表示Master?8259A的屏蔽掩碼,bit[15:8]表示Slave?8259A的屏蔽掩碼。如下所示:?
/*?
*?This?contains?the?irq?mask?for?both?8259A?irq?controllers,?
*/?
static?unsigned?int?cached_irq_mask?=?0xffff;?

#define?__byte(x,y)?(((unsigned?char?*)&(y))[x])?
#define?cached_21?(__byte(0,cached_irq_mask))?
#define?cached_A1?(__byte(1,cached_irq_mask))?

(2)禁止一個特定的IRQ?
函數disable_8259A_irq()通過將8259A的IMR中的相應位設置成1來實現禁止某個特定的IRQ,其源碼如下:?
void?disable_8259A_irq(unsigned?int?irq)?
{?
unsigned?int?mask?=?1?<<?irq;?
unsigned?long?flags;?

spin_lock_irqsave(&i8259A_lock,?flags);?
cached_irq_mask?|=?mask;?
if?(irq?&?8)?
outb(cached_A1,0xA1);?
else?
outb(cached_21,0x21);?
spin_unlock_irqrestore(&i8259A_lock,?flags);?
}?
(1)參數irq取值范圍為0~15,指定對哪一個IRQ線進行屏蔽。?
(2)通過一個“或”操作將cached_irq_mask中的相應位設置為1。?
(3)如果irq大于等于8(也即irq&8的結果非0),則說明這個IRQ來自于Slave?8259A,否則就應來自于Master?8259A。?

(3)使能一個特定的IRQ?
函數enable_8259A_irq()通過將8259A的IMR寄存器中的相應位清零來實現使能一個特定的IRQ。該函數與disable_8259A_irq()剛好相反。如下所示:?
void?enable_8259A_irq(unsigned?int?irq)?
{?
unsigned?int?mask?=?~(1?<<?irq);?
unsigned?long?flags;?

spin_lock_irqsave(&i8259A_lock,?flags);?
cached_irq_mask?&=?mask;?
if?(irq?&?8)?
outb(cached_A1,0xA1);?
else?
outb(cached_21,0x21);?
spin_unlock_irqrestore(&i8259A_lock,?flags);?
}?

(4)8259A中斷控制器的startup()函數和shutdown()函數?
8259A中斷控制器描述符i8259A_irq_type的shutdown()函數和startup()函數實際上就是其disable函數和enable函數。?
#define?shutdown_8259A_irq?disable_8259A_irq?
……?
static?unsigned?int?startup_8259A_irq(unsigned?int?irq)?
{?
enable_8259A_irq(irq);?
return?0;?/*?never?anything?pending?*/?
}?
(5)end_8259A_irq()函數?
8259A中斷控制器描述符i8259_irq_type的end函數指針被定義成指向函數end_8259A_irq()。該函數的源碼如下:?
static?void?end_8259A_irq?(unsigned?int?irq)?
{?
if?(!(irq_desc[irq].status?&?(IRQ_DISABLED|IRQ_INPROGRESS)))?
enable_8259A_irq(irq);?
}?
該函數的實現也是基于enable_8259A_irq()函數,它在相應IRQ描述符的status成員沒有設置IRQ_DISABLED標志和IRQ_INPROGRESS標志時,通過調用enable_8259A_irq()函數來使能參數irq所指定的IRQ。?

(6)應答函數?
中斷控制器描述符中的應答函數ack用來向PIC發送EOI命令,表示中斷服務的結束。具體到8259A來講,函數mask_and_ack_8259A()用來向主、從8259A發送EOI命令。向8259A應答因該遵循這樣的順序:首先,屏蔽相應的IRQ;然后,發送EOI命令。此外,如果IRQ來自于從8259A,還必須先向Slave?8259A發送EOI命令,再向Master?8259A發送EOI命令。如果IRQ來自于Master?8259A,則僅僅向Master?8259A發送EOI命令就可以了。?
函數mask_and_ack_8259A()的源碼如下所示:?

/*?
*?Careful!?The?8259A?is?a?fragile?beast,?it?pretty?
*?much?_has_?to?be?done?exactly?like?this?(mask?it?
*?first,?_then_?send?the?EOI,?and?the?order?of?EOI?
*?to?the?two?8259s?is?important!?
*/?
void?mask_and_ack_8259A(unsigned?int?irq)?
{?
unsigned?int?irqmask?=?1?<<?irq;?
unsigned?long?flags;?

spin_lock_irqsave(&i8259A_lock,?flags);?
/*?
*?Lightweight?spurious?IRQ?detection.?We?do?not?want?
*?to?overdo?spurious?IRQ?handling?-?it's?usually?a?sign?
*?of?hardware?problems,?so?we?only?do?the?checks?we?can?
*?do?without?slowing?down?good?hardware?unnecesserily.?
*?
*?Note?that?IRQ7?and?IRQ15?(the?two?spurious?IRQs?
*?usually?resulting?from?the?8259A-1|2?PICs)?occur?
*?even?if?the?IRQ?is?masked?in?the?8259A.?Thus?we?
*?can?check?spurious?8259A?IRQs?without?doing?the?
*?quite?slow?i8259A_irq_real()?call?for?every?IRQ.?
*?This?does?not?cover?100%?of?spurious?interrupts,?
*?but?should?be?enough?to?warn?the?user?that?there?
*?is?something?bad?going?on?...?
*/?
if?(cached_irq_mask?&?irqmask)?
goto?spurious_8259A_irq;?
cached_irq_mask?|=?irqmask;?

handle_real_irq:?
if?(irq?&?8)?{?
inb(0xA1);?/*?DUMMY?-?(do?we?need?this?)?*/?
outb(cached_A1,0xA1);?
outb(0x60+(irq&7),0xA0);/*?'Specific?EOI'?to?slave?*/?
outb(0x62,0x20);?/*?'Specific?EOI'?to?master-IRQ2?*/?
}?else?{?
inb(0x21);?/*?DUMMY?-?(do?we?need?this?)?*/?
outb(cached_21,0x21);?
outb(0x60+irq,0x20);?/*?'Specific?EOI'?to?master?*/?
}?
spin_unlock_irqrestore(&i8259A_lock,?flags);?
return;?

spurious_8259A_irq:?
/*?
*?this?is?the?slow?path?-?should?happen?rarely.?
*/?
if?(i8259A_irq_real(irq))?
/*?
*?oops,?the?IRQ?_is_?in?service?according?to?the?
*?8259A?-?not?spurious,?go?handle?it.?
*/?
goto?handle_real_irq;?

{?
static?int?spurious_irq_mask;?
/*?
*?At?this?point?we?can?be?sure?the?IRQ?is?spurious,?
*?lets?ACK?and?report?it.?[once?per?IRQ]?
*/?
if?(!(spurious_irq_mask?&?irqmask))?{?
printk("spurious?8259A?interrupt:?IRQ%d.\n",?irq);?
spurious_irq_mask?|=?irqmask;?
}?
irq_err_count++;?
/*?
*?Theoretically?we?do?not?have?to?handle?this?IRQ,?
*?but?in?Linux?this?does?not?cause?problems?and?is?
*?simpler?for?us.?
*/?
goto?handle_real_irq;?
}?
}?
對該函數的NOTE如下:?
①首先,通過全局變量cached_irq_mask判斷參數irq所指定的IRQ線是否處于屏蔽狀態。如果已經被屏蔽,則說明8259A在IMR寄存器中的相應位被置1的情況下仍然向CPU發出了相應的中斷信號,因此這是一個假的中斷,所以跳轉到spurious_8259A_irq部分進行處理。有關這方面的詳細描述請參見源碼中的注釋。?
②如果cached_irq_mask中的相應位為0,也即相應的IRQ位被屏蔽,說明我們收到的是一個真實的中斷請求,于是按照上面所述的步驟,先對這個IRQ進行屏蔽,因此將cached_irq_mask中的相應位設置為1。?
③接下來進入真實的中斷請求處理部分(handle_real_irq)。如果irq&8的結果非0,說明這個中斷請求來自于Slave?8259A。否則這個中斷請求來自于Master?8259A。?
對于來自Slave?8259A的情形:①先將屏蔽字cached_irq_mask中的高字節cache_A1寫入端口0xA1,以屏蔽相應的IRQ輸入線。②向從8259A的端口0xA0寫操作命令字OCW2,其值等于0x60+(irq&7)——Specific?EOI、對irq&7這個IR進行操作。③向Master?8259A的端口0x20寫入操作命令字OCW2,其值等于0x62——Specific?EOI、對IR2進行操作(因為從8259A通過主8259A的IR2進行級連)。?
對于來自Master?8259A的情形:①先將屏蔽字cached_irq_mask中的低字節cache_21寫入端口0x21,以屏蔽相應的IRQ輸入線。②向主8259A的端口0x20寫操作命令字OCW2,其值等于0x60+irq——Specific?EOI、對irq這個IR進行操作。?
④執行完hadle_real_irq程序段后,對真實中斷請求的應答過程就宣告結束。因此函數可以立即返回了。?
⑤spurious_8259A_irq部分——對假的8259A?中斷請求進行處理。首先,調用i8259A_irq_real()函數來根據8259A的ISR寄存器判斷這是否是一個真實的由8259A發給CPU的中斷請求。如果i8259A_irq_real()函數返回為1,則說明是一個真實的中斷請求,于是跳轉回handle_real_irq部分對其進行處理。否則,如果i8259A_irq_real()返回0值,說明我們的CPU真的是受到一個虛假的中斷請求信號。?
⑥對于真的受到一個虛假中斷請求這種情形,分三個步驟來進行處理:①視需要打印一條內核信息向用戶發出警告。②將全局變量irq_err_count的值加1(該變量定義在irq.c文件中)。③從理論上來講,對于虛假的中斷請求并不需要進行任何處理。但是在Linux中,將它按照真實的中斷請求進行應答處理也不會引起任何問題,因此最后又跳轉回handl_real_irq部分將它按照真實的中斷請求進行應答處理。?

函數i8259_real_irq()是定義在i8259.c文件中的一個內部函數。它根據8259A的ISR寄存器中的內容判斷參數irq所指定的IRQ輸入線上是否真的產生了一個中斷請求。其源碼如下所示:?

/*?
*?This?function?assumes?to?be?called?rarely.?Switching?between?
*?8259A?registers?is?slow.?
*?This?has?to?be?protected?by?the?irq?controller?spinlock?
*?before?being?called.?
*/?
static?inline?int?i8259A_irq_real(unsigned?int?irq)?
{?
int?value;?
int?irqmask?=?1<<irq;?

if?(irq?<?8)?{?
outb(0x0B,0x20);?/*?ISR?register?*/?
value?=?inb(0x20)?&?irqmask;?
outb(0x0A,0x20);?/*?back?to?the?IRR?register?*/?
return?value;?
}?
outb(0x0B,0xA0);?/*?ISR?register?*/?
value?=?inb(0xA0)?&?(irqmask?>>?8);?
outb(0x0A,0xA0);?/*?back?to?the?IRR?register?*/?
return?value;?
}?
對該函數的注釋如下:?
由于端口0x20和0xA0對讀指令默認的是IRR寄存器,因此要向端口0x20/0xA0寫入操作命令字OCW3=0x0B,以切換到ISR寄存器。然后通過inb()函數讀端口0x20/0xA0,以得到ISR寄存器的當前值,如果ISR&irqmask非0,說明指定的IRQ輸入線上真的產生了一個中斷請求;否則就沒有。最后記得要將端口0x20/0xA0切換回IRR寄存器。?

(7)函數i8259_irq_pending()?
該函數并不是描述符i8259A_irq_type中定義的函數。該函數用來判斷某個指定的IRQ是否未得到服務而一直處于pending狀態。其源碼如下:?
int?i8259A_irq_pending(unsigned?int?irq)?
{?
unsigned?int?mask?=?1<<irq;?
unsigned?long?flags;?
int?ret;?

spin_lock_irqsave(&i8259A_lock,?flags);?
if?(irq?<?8)?
ret?=?inb(0x20)?&?mask;?
else?
ret?=?inb(0xA0)?&?(mask?>>?8);?
spin_unlock_irqrestore(&i8259A_lock,?flags);?

return?ret;?
}?
顯然,端口0x20/0xA0對于讀操作默認的是返回IRR寄存器的值。如果IRR寄存器中的某個位被置1,就表示相應的中斷請求正等待CPU的服務(通過一個INTA-cycle),因此該中斷請求也就處于pending狀態。?

§5.6?CPU的中斷請求統計信息?
Linux在頭文件include/asm-i386/hardirq.h和include/linux/irq_cpustat.h中定義了和中斷請求相關的CPU統計信息數據結構以及相應的操作宏。?
首先,Linux在頭文件hardirq.h中定義了數據結構irq_cpustat_t,以描述一個CPU對中斷請求進行服務的歷史統計信息。如下所示:?
/*?entry.S?is?sensitive?to?the?offsets?of?these?fields?*/?
typedef?struct?{?
unsigned?int?__softirq_active;?
unsigned?int?__softirq_mask;?
unsigned?int?__local_irq_count;?
unsigned?int?__local_bh_count;?
unsigned?int?__syscall_count;?
unsigned?int?__nmi_count;?/*?arch?dependent?*/?
}?____cacheline_aligned?irq_cpustat_t;?
上述結構中各成員的命名已經清楚地表達了其各自的含義,這里就不詳述。?

在此基礎上,Linux又在kernel/softirq.c文件中定義了全局數組irq_stat[NR_CPUS],以分別描述每個CPU各自的中斷統計信息。這一點主要是從SMP體系結構來考慮的。該數組的定義如下所示:?
/*?No?separate?irq_stat?for?s390,?it?is?part?of?PSA?*/?
#if?!defined(CONFIG_ARCH_S390)?
irq_cpustat_t?irq_stat[NR_CPUS];?
#endif?/*?CONFIG_ARCH_S390?*/?
該數組的原型聲明在頭文件irq_cpustat.h中,如下:?
extern?irq_cpustat_t?irq_stat[];?/*?defined?in?asm/hardirq.h?*/?

5.6.1?引用數據結構irq_cpustat_t中的成員?
首先,Linux在頭文件irq_cpustat.h中通過宏__IRQ_STAT來定義了一個引用數據結構irq_cpustat_t中各成員的操作模板,如下所示:?
#ifdef?CONFIG_SMP?
#define?__IRQ_STAT(cpu,?member)?(irq_stat[cpu].member)?
#else?
#define?__IRQ_STAT(cpu,?member)?((void)(cpu),?irq_stat[0].member)?
#endif?
顯然,在單CPU系統中,我們總是引用irq_stat[0]中的成員,此時參數cpu是一個無用的參數。?

基于上述引用模板,Linux分別為irq_cpustat_t中各成員定義了顯示的引用操作宏(irq_cpustat.h),如下所示:?
/*?arch?independent?irq_stat?fields?*/?
#define?softirq_active(cpu)?__IRQ_STAT((cpu),?__softirq_active)?
#define?softirq_mask(cpu)?__IRQ_STAT((cpu),?__softirq_mask)?
#define?local_irq_count(cpu)?__IRQ_STAT((cpu),?__local_irq_count)?
#define?local_bh_count(cpu)?__IRQ_STAT((cpu),?__local_bh_count)?
#define?syscall_count(cpu)?__IRQ_STAT((cpu),?__syscall_count)?
/*?arch?dependent?irq_stat?fields?*/?
#define?nmi_count(cpu)?__IRQ_STAT((cpu),?__nmi_count)?/*?i386,?ia64?*/?

5.6.2?判斷一個CPU是否處于中斷上下文中?
通過數據結構irq_cpustat_t的__local_irq_count成員和__local_bh_count成員的值,我們可以判斷出當前CPU當前是否正處于中斷服務上下文中。為此,Linux在hardirq.h頭文件中定義了宏in_interrupt()和in_irq(),如下所示:?
/*?
*?Are?we?in?an?interrupt?context??Either?doing?bottom?half?
*?or?hardware?interrupt?processing??
*/?
#define?in_interrupt()?({?int?__cpu?=?smp_processor_id();?\?
(local_irq_count(__cpu)?+?local_bh_count(__cpu)?!=?0);?})?
#define?in_irq()?(local_irq_count(smp_processor_id())?!=?0)?
因此,只要當前CPU處于硬件中斷處理或執行bottom?half時,in_interrupt()宏就返回非零值。而對于in_irq()宏而言,則只有當CPU處于硬件中斷處理時,才返回非0值。?

5.6.3?增加/減少CPU的本地中斷請求計數?
當進入中斷請求處理時,Linux必須將當前CPU的硬件中斷請求計數值__local_irq_count加1(后面我們將會看到這一點)。而在退出硬件中斷請求處理時將其減1。如下所示(hardirq.h):?
#ifndef?CONFIG_SMP?

#define?hardirq_trylock(cpu)?(local_irq_count(cpu)?==?0)?
#define?hardirq_endlock(cpu)?do?{?}?while?(0)?

#define?irq_enter(cpu,?irq)?(local_irq_count(cpu)++)?
#define?irq_exit(cpu,?irq)?(local_irq_count(cpu)--)?

#define?synchronize_irq()?barrier()?

#else?

#include?<asm/atomic.h>?
#include?<asm/smp.h>?

extern?unsigned?char?global_irq_holder;?
extern?unsigned?volatile?long?global_irq_lock;?/*?long?for?set_bit?-RR?*/?

static?inline?int?irqs_running?(void)?
{?
int?i;?

for?(i?=?0;?i?<?smp_num_cpus;?i++)?
if?(local_irq_count(i))?
return?1;?
return?0;?
}?

static?inline?void?release_irqlock(int?cpu)?
{?
/*?if?we?didn't?own?the?irq?lock,?just?ignore..?*/?
if?(global_irq_holder?==?(unsigned?char)?cpu)?{?
global_irq_holder?=?NO_PROC_ID;?
clear_bit(0,&global_irq_lock);?
}?
}?

static?inline?void?irq_enter(int?cpu,?int?irq)?
{?
++local_irq_count(cpu);?

while?(test_bit(0,&global_irq_lock))?{?
/*?nothing?*/;?
}?
}?

static?inline?void?irq_exit(int?cpu,?int?irq)?
{?
--local_irq_count(cpu);?
}?

static?inline?int?hardirq_trylock(int?cpu)?
{?
return?!local_irq_count(cpu)?&&?!test_bit(0,&global_irq_lock);?
}?

#define?hardirq_endlock(cpu)?do?{?}?while?(0)?

extern?void?synchronize_irq(void);?

#endif?/*?CONFIG_SMP?*/?

§5.7?中斷服務的總控程序do_IRQ?
在§5.3節我們談到,由IDT表項所指向的中斷服務程序IRQ0xYY_interrupt()全部都跳轉到common_interrupt這個公共的中斷服務程序,而common_interrupt函數只作三件事:(1)用SAVE_ALL宏來保存現場;(2)然后調用中斷服務程序的總控函數do_IRQ對中斷請求進行真正的服務;(3)從do_IRQ返回后,跳轉到中斷返回函數ret_from_intr以執行中斷返回操作。?
另外,在§5.4節中我們也談到,PCI總線允許不同的外設共享同一個IRQ輸入線號,每個設備驅動程序都通過request_irq()接口將驅動程序的ISR注冊到相對應的中斷服務對列中。因此do_IRQ()函數要真正地服務一個中斷請求,就必須遍歷相應的中斷服務隊列,以便讓相對應正確的ISR得到執行(注意!通常每個設備驅動程序的ISR一進入就判斷它所驅動的硬件是否真的產生了中斷請求,如果不是它就立即返回,如果是它才繼續向下執行,從而真正地服務中斷請求)。下面我們就詳細地分析一下do_IRQ()函數是如何遍歷IRQ描述符中的中斷服務隊列的。?
函數do_IRQ()以及其相關的底層支持函數全部都是現在arch/i386/kernel/irq.c文件中。函數do_IRQ()只有唯一的一個參數regs,它是一個pt_regs結構類型,該數據結構定義在include/asm-i386/ptrace.h中。如下所示:?
struct?pt_regs?{?
long?ebx;?
long?ecx;?
long?edx;?
long?esi;?
long?edi;?
long?ebp;?
long?eax;?
int?xds;?
int?xes;?
long?orig_eax;?
long?eip;?
int?xcs;?
long?eflags;?
long?esp;?
int?xss;?
};?
由上述pt_regs數據結構的內容可見,SAVE_ALL宏的作用不僅再與保存中斷現場,它也為函數do_IRQ()模擬出了一個函數調用環境。?
函數do_IRQ()的源碼如下:?

/*?
*?do_IRQ?handles?all?normal?device?IRQ's?(the?special?
*?SMP?cross-CPU?interrupts?have?their?own?specific?
*?handlers).?
*/?
asmlinkage?unsigned?int?do_IRQ(struct?pt_regs?regs)?
{?
/*?
*?We?ack?quickly,?we?don't?want?the?irq?controller?
*?thinking?we're?snobs?just?because?some?other?CPU?has?
*?disabled?global?interrupts?(we?have?already?done?the?
*?INT_ACK?cycles,?it's?too?late?to?try?to?pretend?to?the?
*?controller?that?we?aren't?taking?the?interrupt).?
*?
*?0?return?value?means?that?this?irq?is?already?being?
*?handled?by?some?other?CPU.?(or?is?disabled)?
*/?
int?irq?=?regs.orig_eax?&?0xff;?/*?high?bits?used?in?ret_from_?code?*/?
int?cpu?=?smp_processor_id();?
irq_desc_t?*desc?=?irq_desc?+?irq;?
struct?irqaction?*?action;?
unsigned?int?status;?

kstat.irqs[cpu][irq]++;?
spin_lock(&desc->lock);?
desc->handler->ack(irq);?
/*?
REPLAY?is?when?Linux?resends?an?IRQ?that?was?dropped?earlier?
WAITING?is?used?by?probe?to?mark?irqs?that?are?being?tested?
*/?
status?=?desc->status?&?~(IRQ_REPLAY?|?IRQ_WAITING);?
status?|=?IRQ_PENDING;?/*?we?_want_?to?handle?it?*/?

/*?
*?If?the?IRQ?is?disabled?for?whatever?reason,?we?cannot?
*?use?the?action?we?have.?
*/?
action?=?NULL;?
if?(!(status?&?(IRQ_DISABLED?|?IRQ_INPROGRESS)))?{?
action?=?desc->action;?
status?&=?~IRQ_PENDING;?/*?we?commit?to?handling?*/?
status?|=?IRQ_INPROGRESS;?/*?we?are?handling?it?*/?
}?
desc->status?=?status;?

/*?
*?If?there?is?no?IRQ?handler?or?it?was?disabled,?exit?early.?
Since?we?set?PENDING,?if?another?processor?is?handling?
a?different?instance?of?this?same?irq,?the?other?processor?
will?take?care?of?it.?
*/?
if?(!action)?
goto?out;?

/*?
*?Edge?triggered?interrupts?need?to?remember?
*?pending?events.?
*?This?applies?to?any?hw?interrupts?that?allow?a?second?
*?instance?of?the?same?irq?to?arrive?while?we?are?in?do_IRQ?
*?or?in?the?handler.?But?the?code?here?only?handles?the?_second_?
*?instance?of?the?irq,?not?the?third?or?fourth.?So?it?is?mostly?
*?useful?for?irq?hardware?that?does?not?mask?cleanly?in?an?
*?SMP?environment.?
*/?
for?(;;)?{?
spin_unlock(&desc->lock);?
handle_IRQ_event(irq,?&regs,?action);?
spin_lock(&desc->lock);?

if?(!(desc->status?&?IRQ_PENDING))?
break;?
desc->status?&=?~IRQ_PENDING;?
}?
desc->status?&=?~IRQ_INPROGRESS;?
out:?
/*?
*?The?->end()?handler?has?to?deal?with?interrupts?which?got?
*?disabled?while?the?handler?was?running.?
*/?
desc->handler->end(irq);?
spin_unlock(&desc->lock);?

if?(softirq_active(cpu)?&?softirq_mask(cpu))?
do_softirq();?
return?1;?
}?
對該函數的NOTE如下:?
(1)首先,通過參數regs.orig_eax來獲取此次中斷請求的IRQ號。然后調用smp_processor_id()函數得到當前CPU的ID。指針desc指向相應于此次中斷請求的IRQ描述符。?
(2)將內核統計變量kstat.irqs數組中的相應元素kstat.irqs[cpu][irq]加1。并對中斷請求描述符desc中的自旋鎖成員lock進行加鎖,以便使隨后對中斷服務隊列的操作互斥。?
(3)向中斷控制器發出應答。具體到8259A來說,則是調用mask_and_ack_8259A()函數來向8259A發送EOI命令,表示中斷結束,以便讓8259A繼續接收其它中斷請求信號。注意,mask_and_ack_8259A函數同時還將屏蔽變量irq所對應的IRQ輸入線。比如,當前服務的是IRQ3,那么在do_IRQ()執行期間,IRQ3是被8259A所屏蔽的。這一點需要特別注意。?
(4)接下來,主要是設置中斷請求的狀態。先將IRQ描述符的status成員去掉IRQ_DISABLED標志位和IRQ_WAITING標志位(如果已經設置了的話)。然后在狀態中設置IRQ_PENDING標志,表示這個中斷請求的服務還未完成。注意!這里的IRQ_PENDING狀態與前面所述的8259A?IRQ?pending狀態是有區別的。8259A的IRQ?pending是指在8259A已經向CPU發出了中斷請求信號但CPU并沒有向8259A發出中斷應答(第一個INTA-cycle)時的狀態,只要CPU向8259A發出了第一個INTA-cycle,8259A的IRQ?pending狀態即宣告結束。而這里的IRQ_PENDING標志的真正含義是指已經進入到do_IRQ()函數、但中斷服務隊列還未開始執行的意思。?
(5)根據前面設置好的狀態來確定中斷服務隊列。只有當IRQ狀態中沒有同時設置IRQ_DISABLED標志和IRQ_INPROGRESS標志時,才讓action指針指向IRQ描述符中定義的中斷服務隊列(由desc->action所指向)。IEQ_DISABLED標志表示該中斷請求已經被禁止,因此不需要被服務。而IRQ_INPROGRESS則表示中斷請求正在被另一個CPU服務。因此當前CPU就不需要再對這個中斷請求進行服務了。?
在設置好action指針后,就清除中斷請求狀態中的IRQ_PENDING標志,同時在狀態中設置IRQ_INPROGRESS標志,因為接下來馬上就要開始服務這個中斷請求了。最后,用剛剛設置好的狀態值來更新IRQ描述符中的status值,以便讓它對其它CPU可見。?
(6)判斷action指針是否為空,如果為空,說明沒有任何中斷服務行為等待執行,因此跳轉到out部分,以便退出do_IRQ()函數。?
(7)接下來的for死循環真正地遍歷中斷服務隊列并調用其中的ISR來執行。循環體的步驟如下:?
1.?首先,解除IRQ描述符中的自旋鎖lock。這是因為在執行中斷服務隊列中的各個ISR時,ISR并不會訪問IRQ描述符中的中斷服務隊列。?
2.?調用handle_IRQ_event()函數來依次執行由action所指向的中斷服務隊列中的所有ISR。?
3.?由于接下來又要訪問IRQ描述符中的成員值,因此對IRQ描述符中的自旋鎖lock進行加鎖操作。?
4.?最后測試IRQ描述符的status成員是否設置了IRQ_PENDING標志。如果沒有,就執行break語句退出for循環。如果設置了IRQ_PENDING標志,則說明有一次中斷請求未得到服務,于是首先清除IRQ_PENDING標志,然后繼續for循環,以便為該中斷請求補上一次中斷服務。這個概念就成為“IRQ_REPLAY”。為什么需要這樣呢?這是應為在SMP體系結構中,假設CPU1正在為一個IRQ執行do_IRQ()函數,且CPU1已經在相應IRQ描述符的status成員中設置了IRQ_INPROGRESS標志,而此時CPU2上又收到一次同級的中斷請求,于是CPU2也執行do_IRQ()函數,但CPU2由于看到相應IRQ描述符的status成員中已經設置了IRQ_INPROGRESS標志,因此CPU2知道另一個CPU(它無需知道是哪個具體的CPU,反正不是他自己:-)已經正在為同級中斷請求服務了,于是CPU2就簡單地在相應IRQ描述符的status成員中設置一個IRQ_PENDING標志,然后就退出do_IRQ()函數,而把中斷服務留給CPU1去執行。當CPU1從handle_IRQ_event()函數返回時,它看到設置了IRQ_PENDING標志,知道其它CPU把中斷服務留給他來執行了,于是CPU1先清除IRQ_PENDING標志,然后繼續for循環,以便補上一次中斷服務。注意!這種機制可能會造成中斷服務丟失現象的。?
(6)從for循環退出后,CPU對硬件中斷請求的服務也就宣告結束,因此,它清除相應IRQ描述符的status成員中的IRQ_INPROGRESS標志。?
(7)out部分:接下來就是do_IRQ()函數的退出部分。為此,它首先調用中斷控制器描述符中的end()函數。具體到8259A來講,也就是調用end_8259A_irq()函數,該函數實際上就是通過enable_8259A_irq()函數來重新使能8259A的相應IRQ輸入線(因為mask_and_ack_8259A()函數已經將它屏蔽,所以這里必須將其重新開啟)。然后解除相應IRQ描述符中自旋鎖lock。?
(8)最后,在退出do_IRQ()函數之前,看看是否需要執行軟中斷。如果需要,就調用do_softirq()函數來執行軟中斷或設備驅動程序的bottom?half函數。?

5.7.1?函數handle_IRQ_event?
函數handle_IRQ_event()用來執行一個中斷服務隊列中的所有ISR。它的實現相當簡單,其核心思想就是用一個do{}while循環來依次執行中斷服務隊列中的各個ISR,之所以用do{}while循環而不用while循環,是因為:這個函數只被do_IRQ()函數所調用,而do_IRQ()在調用它時已經保證了中斷服務隊列不為空。該函數的源碼如下:?
int?handle_IRQ_event(unsigned?int?irq,?struct?pt_regs?*?regs,?struct?irqaction?*?action)?
{?
int?status;?
int?cpu?=?smp_processor_id();?

irq_enter(cpu,?irq);?

status?=?1;?/*?Force?the?"do?bottom?halves"?bit?*/?

if?(!(action->flags?&?SA_INTERRUPT))?
__sti();?

do?{?
status?|=?action->flags;?
action->handler(irq,?action->dev_id,?regs);?
action?=?action->next;?
}?while?(action);?
if?(status?&?SA_SAMPLE_RANDOM)?
add_interrupt_randomness(irq);?
__cli();?

irq_exit(cpu,?irq);?

return?status;?
}?
對這個函數請注意三點:?
(1)如果中斷服務隊列中第一個中斷服務描述符沒有設置SA_INTERRUPT標志,那么整個隊列中的ISR都是在CPU開中斷的情況下執行的。但在整個隊列都行完畢后,handle_IRQ_event()函數又重新用__cli()函數關閉中斷。?
(2)只要中斷服務隊列中有一個中斷服務描述符中設置了隨機標志,那么handle_IRQ_event()函數就將通過add_interrupt_randomness()函數為中斷引入一些隨機性。但是大多數driver都不使用這個隨機標志。?
(3)請注意這里對irq_enter()和irq_exit()函數對的使用。?

§5.8?中斷返回ret_from_intr?
從總控程序do_IRQ()返回后,common_interrupt所作的第三件事情就是通過jmp指令跳轉到ret_from_intr程序段,以執行中斷返回過程。?
程序段ret_from_intr定義在arch/i386/kernel/entry.S文件中,如下所示:?
ENTRY(ret_from_intr)?
GET_CURRENT(%ebx)?
movl?EFLAGS(%esp),%eax?#?mix?EFLAGS?and?CS?
movb?CS(%esp),%al?
testl?$(VM_MASK?|?3),%eax?#?return?to?VM86?mode?or?non-supervisor??
jne?ret_with_reschedule?
jmp?restore_all?
(1)首先,通過GET_CURRENT()宏將當前進程的task_struct結構的指針置入寄存器EBX中。?
(2)然后,將內核堆棧中的EFLAGS寄存器的值放入EAX寄存器中,EFLAGS(%esp)表示地址為“堆棧指針%esp加上常數EFLAGS”處的內容,也即內核堆棧中的EFLAGS寄存器的值。?
(3)將內核堆棧中CS寄存器的值置入al寄存器中。AL寄存器也就是EAX寄存器的低16位。這樣,通過這兩步也就把EFLAGS寄存器的高16位和CS寄存器的值平湊在一起,放到EAX寄存器中。這樣做的目的有兩個:?
l?檢查中斷前夕CPU是否運行于VM86模式下。因為EFLAGS寄存器中的bit[16]表示CPU是否運行于VM86模式。?
l?檢查中斷前夕CPU是否運行在用戶臺下。因為CS寄存器的bit[1:0]表示CPU的運行級別。只要CS的最低兩位非0,就說明中斷前夕CPU運行在用戶臺下。?
(4)將EAX寄存器與立即數(VM_MASK|3)進行位測試,如果測試結果非0,則說明上述兩種情況(VM86模式或用戶態)之一發生,于是就跳轉到ret_with_reschedule程序段。如果測試結果非0,則說明中斷前夕CPU運行在內核態下,于是跳轉到restore_all程序段。?

5.8.1?返回到用戶態?
由于Linux不使用VM86模式,因此我們假定中斷前夕CPU運行在用戶態下。所以就先跳轉到ret_with_reschedule程序段去執行。如下所示(entry.S):?
ret_with_reschedule:?
cmpl?$0,need_resched(%ebx)?
jne?reschedule?
cmpl?$0,sigpending(%ebx)?
jne?signal_return?
restore_all:?
RESTORE_ALL?
(1)由于EBX寄存器中的值是當前進程的task_struct結構的地址,因此表達式need_resched(%ebx)也就是當前進程的task_struct結構中的need_resched成員的值。因此第一個語句判斷current->need_resched是否為0,如果不為0,表示需要重新調度,于是就跳轉到reschedule程序段。該程序段如下所示:?
reschedule:?
call?SYMBOL_NAME(schedule)?#?test?
jmp?ret_from_sys_call?
(2)判斷當前進程的task_struct結構中的sigpending成員是否為0,如果不為0,就表示有信號需要處理,于是跳轉到signal_return程序段去處理當前進程的信號。?

5.8.2?中斷返回的總出口?
不管是ret_from_syscall程序段還是signal_return程序段,它們最總都要跳回到restore_all程序段,它是一個總出口。該程序段只有一行代碼,也即:執行宏RESTORE_ALL,以恢復內核堆棧到中斷前夕的狀態。宏RESTORE_ALL的定義如下(entry.S):?
#define?RESTORE_ALL?\?
popl?%ebx;?\?
popl?%ecx;?\?
popl?%edx;?\?
popl?%esi;?\?
popl?%edi;?\?
popl?%ebp;?\?
popl?%eax;?\?
1:?popl?%ds;?\?
2:?popl?%es;?\?
addl?$4,%esp;?\?
3:?iret;?
從上述代碼可以看出,它是以和SAVE_ALL相反的順序從內核堆棧中探出各個寄存器的值,直到ES寄存器,以恢復中斷前夕的CPU現場。?
由于內核堆棧中ES寄存器之上的是orig_eax,是用來保存IRQ號或syscall號的,而它現在已經沒有任何用處,因此通過將內核堆棧指針%esp的加上常數4來簡單地將orig_eax的內容從堆棧中丟棄。?
最后,CPU執行iret指令,從而使得CPU從中斷返回。?

至此,整個Linux中斷服務流程宣告結束。

總結

以上是生活随笔為你收集整理的Linux内核的中断机制的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

性欧美videos高清精品 | 无码精品国产va在线观看dvd | 久久国产36精品色熟妇 | 久久国产精品偷任你爽任你 | 性生交大片免费看女人按摩摩 | 国产精品久久久久7777 | 亚洲中文无码av永久不收费 | 青草视频在线播放 | 国产精品办公室沙发 | 亚洲精品国产精品乱码视色 | 国产亲子乱弄免费视频 | 亚洲欧洲日本无在线码 | 亚洲另类伦春色综合小说 | 日本免费一区二区三区最新 | 天天躁夜夜躁狠狠是什么心态 | 日本护士xxxxhd少妇 | 国产真实夫妇视频 | 天海翼激烈高潮到腰振不止 | 日本熟妇乱子伦xxxx | 丰满少妇高潮惨叫视频 | 国产热a欧美热a在线视频 | 欧美人妻一区二区三区 | 亚洲爆乳大丰满无码专区 | 亚洲精品一区三区三区在线观看 | 牛和人交xxxx欧美 | 窝窝午夜理论片影院 | 中文字幕av日韩精品一区二区 | 性做久久久久久久免费看 | 久久精品无码一区二区三区 | 亚洲中文字幕在线无码一区二区 | 国产精品99爱免费视频 | 午夜熟女插插xx免费视频 | 国产乱码精品一品二品 | 国产精品嫩草久久久久 | 一个人看的www免费视频在线观看 | 中文字幕无码乱人伦 | 亚欧洲精品在线视频免费观看 | 狠狠色噜噜狠狠狠狠7777米奇 | 蜜桃视频插满18在线观看 | 国产无遮挡吃胸膜奶免费看 | 理论片87福利理论电影 | 久久久亚洲欧洲日产国码αv | 天天摸天天碰天天添 | 少妇无套内谢久久久久 | 日韩欧美成人免费观看 | 内射老妇bbwx0c0ck | 亚洲国产精品久久人人爱 | 天天综合网天天综合色 | 亚洲成色www久久网站 | 色一情一乱一伦一视频免费看 | 国产一区二区不卡老阿姨 | 麻豆国产97在线 | 欧洲 | 在线精品国产一区二区三区 | 亚洲 欧美 激情 小说 另类 | 永久免费精品精品永久-夜色 | 永久免费观看国产裸体美女 | 欧美兽交xxxx×视频 | 乱码午夜-极国产极内射 | 成熟女人特级毛片www免费 | 久久精品中文闷骚内射 | 成人精品视频一区二区三区尤物 | 在线亚洲高清揄拍自拍一品区 | 精品国产国产综合精品 | 88国产精品欧美一区二区三区 | 国产高清不卡无码视频 | 精品成人av一区二区三区 | 九九热爱视频精品 | 国产成人无码av在线影院 | 国产午夜无码视频在线观看 | 男女爱爱好爽视频免费看 | 亚洲欧美日韩国产精品一区二区 | 成人亚洲精品久久久久 | 免费男性肉肉影院 | 亚洲理论电影在线观看 | 国产高潮视频在线观看 | 欧美精品国产综合久久 | 亚洲日韩av一区二区三区四区 | 国产乱人伦app精品久久 国产在线无码精品电影网 国产国产精品人在线视 | 久久精品一区二区三区四区 | 欧美高清在线精品一区 | 国产精品久久久久无码av色戒 | 波多野结衣av在线观看 | 国产精品嫩草久久久久 | 麻豆国产人妻欲求不满 | 性啪啪chinese东北女人 | 俺去俺来也在线www色官网 | 精品欧美一区二区三区久久久 | 人妻无码αv中文字幕久久琪琪布 | 国产人妻人伦精品1国产丝袜 | 欧美丰满熟妇xxxx | 精品无码一区二区三区的天堂 | 色爱情人网站 | 日本熟妇人妻xxxxx人hd | 性色欲网站人妻丰满中文久久不卡 | 奇米影视7777久久精品人人爽 | 欧美黑人巨大xxxxx | 免费人成在线观看网站 | 欧美熟妇另类久久久久久多毛 | 免费观看的无遮挡av | 天天摸天天透天天添 | 国产成人精品久久亚洲高清不卡 | 精品久久久久久人妻无码中文字幕 | 黑人巨大精品欧美黑寡妇 | 日产精品99久久久久久 | 亚洲国产精品美女久久久久 | 天天拍夜夜添久久精品 | 久久久久99精品成人片 | 久久久久se色偷偷亚洲精品av | 无码人妻少妇伦在线电影 | 荡女精品导航 | 国产精品亚洲а∨无码播放麻豆 | 亚洲日本一区二区三区在线 | 纯爱无遮挡h肉动漫在线播放 | 亚洲自偷自拍另类第1页 | 亚洲自偷自拍另类第1页 | 久精品国产欧美亚洲色aⅴ大片 | 少妇性l交大片欧洲热妇乱xxx | 最近免费中文字幕中文高清百度 | 精品偷拍一区二区三区在线看 | 久久国内精品自在自线 | 99久久精品无码一区二区毛片 | 久久精品人妻少妇一区二区三区 | 无码免费一区二区三区 | ass日本丰满熟妇pics | 国产色精品久久人妻 | 国产一区二区三区四区五区加勒比 | 少妇无码av无码专区在线观看 | 在线观看欧美一区二区三区 | 免费观看激色视频网站 | 日本精品人妻无码免费大全 | 亚洲精品成a人在线观看 | 撕开奶罩揉吮奶头视频 | 国产无遮挡吃胸膜奶免费看 | 大肉大捧一进一出好爽视频 | 久青草影院在线观看国产 | 中文字幕亚洲情99在线 | 男女爱爱好爽视频免费看 | 18精品久久久无码午夜福利 | 性欧美牲交xxxxx视频 | 领导边摸边吃奶边做爽在线观看 | 荫蒂添的好舒服视频囗交 | 国产精品福利视频导航 | 天干天干啦夜天干天2017 | 成熟人妻av无码专区 | 秋霞特色aa大片 | 蜜臀av无码人妻精品 | 中文字幕乱妇无码av在线 | 亚洲欧洲无卡二区视頻 | 骚片av蜜桃精品一区 | yw尤物av无码国产在线观看 | 国产精品亚洲专区无码不卡 | 国产激情综合五月久久 | 亚洲天堂2017无码 | 亚洲色欲色欲天天天www | 老熟妇乱子伦牲交视频 | 天堂久久天堂av色综合 | 亚洲国产成人av在线观看 | 激情内射亚州一区二区三区爱妻 | 无码av中文字幕免费放 | 99久久精品国产一区二区蜜芽 | 午夜熟女插插xx免费视频 | 精品成在人线av无码免费看 | 日本熟妇大屁股人妻 | 中文字幕乱码亚洲无线三区 | 亚洲精品国产第一综合99久久 | 久久视频在线观看精品 | 玩弄少妇高潮ⅹxxxyw | 在线 国产 欧美 亚洲 天堂 | 伊人久久大香线蕉午夜 | 麻豆md0077饥渴少妇 | 国产精品无码成人午夜电影 | 亚洲熟悉妇女xxx妇女av | 亚洲中文字幕av在天堂 | 国产免费观看黄av片 | 久久99精品国产.久久久久 | 中文字幕av日韩精品一区二区 | 久久久久久久久888 | 福利一区二区三区视频在线观看 | 日日碰狠狠躁久久躁蜜桃 | 人妻无码久久精品人妻 | 日日摸日日碰夜夜爽av | 一区二区三区乱码在线 | 欧洲 | 又湿又紧又大又爽a视频国产 | 美女毛片一区二区三区四区 | 国产精品99爱免费视频 | 青草青草久热国产精品 | 人妻天天爽夜夜爽一区二区 | 伊人久久婷婷五月综合97色 | 香蕉久久久久久av成人 | 国内揄拍国内精品少妇国语 | 色婷婷av一区二区三区之红樱桃 | 亚洲一区二区三区含羞草 | 亚洲男人av香蕉爽爽爽爽 | 婷婷丁香六月激情综合啪 | 无码人妻丰满熟妇区五十路百度 | 无码人妻出轨黑人中文字幕 | 国内精品久久毛片一区二区 | 亚洲区欧美区综合区自拍区 | 成人一在线视频日韩国产 | 国产精品对白交换视频 | 国产真人无遮挡作爱免费视频 | 国产精品久久久 | 噜噜噜亚洲色成人网站 | 一个人免费观看的www视频 | 精品午夜福利在线观看 | 国产人妻久久精品二区三区老狼 | 99er热精品视频 | 国产精品久久久 | 日日天日日夜日日摸 | 一本大道久久东京热无码av | 麻豆蜜桃av蜜臀av色欲av | 成人一在线视频日韩国产 | 亚洲成在人网站无码天堂 | 波多野结衣高清一区二区三区 | 激情亚洲一区国产精品 | 色偷偷av老熟女 久久精品人妻少妇一区二区三区 | 成年美女黄网站色大免费视频 | 欧美自拍另类欧美综合图片区 | 妺妺窝人体色www在线小说 | 亚洲色无码一区二区三区 | 亚洲小说图区综合在线 | 性生交大片免费看女人按摩摩 | 日韩人妻系列无码专区 | aⅴ在线视频男人的天堂 | 国产女主播喷水视频在线观看 | 欧美成人午夜精品久久久 | 四十如虎的丰满熟妇啪啪 | 色综合久久中文娱乐网 | 中文字幕日韩精品一区二区三区 | 日本肉体xxxx裸交 | 欧美激情内射喷水高潮 | 精品夜夜澡人妻无码av蜜桃 | 最近免费中文字幕中文高清百度 | 色综合久久久无码网中文 | 久久综合久久自在自线精品自 | 宝宝好涨水快流出来免费视频 | 亚洲色大成网站www | 国产亚洲精品久久久ai换 | 理论片87福利理论电影 | 男人的天堂av网站 | 俄罗斯老熟妇色xxxx | 西西人体www44rt大胆高清 | 国产人成高清在线视频99最全资源 | 久久天天躁狠狠躁夜夜免费观看 | 娇妻被黑人粗大高潮白浆 | 女人被爽到呻吟gif动态图视看 | 蜜桃视频插满18在线观看 | 天天躁夜夜躁狠狠是什么心态 | 中文字幕乱码人妻二区三区 | 欧美放荡的少妇 | 久久亚洲a片com人成 | 一本久久伊人热热精品中文字幕 | 嫩b人妻精品一区二区三区 | 欧美日韩精品 | 未满成年国产在线观看 | 在线观看免费人成视频 | 亚洲欧美国产精品久久 | 人妻熟女一区 | 欧美35页视频在线观看 | 国产精品毛片一区二区 | 亚洲精品一区二区三区四区五区 | 久久亚洲中文字幕精品一区 | 国产97在线 | 亚洲 | 99久久99久久免费精品蜜桃 | 人人澡人人妻人人爽人人蜜桃 | 色五月五月丁香亚洲综合网 | 国产成人无码av在线影院 | 国产手机在线αⅴ片无码观看 | 国产亚洲欧美日韩亚洲中文色 | 亚洲精品一区二区三区在线观看 | 99精品久久毛片a片 | 亚洲s色大片在线观看 | 欧美日韩在线亚洲综合国产人 | 蜜桃视频插满18在线观看 | 亚洲午夜无码久久 | 亚洲va欧美va天堂v国产综合 | 宝宝好涨水快流出来免费视频 | 天下第一社区视频www日本 | 日韩人妻无码中文字幕视频 | 狠狠色噜噜狠狠狠狠7777米奇 | 国产熟女一区二区三区四区五区 | 久久人人爽人人爽人人片ⅴ | 国产精品人人爽人人做我的可爱 | 色一情一乱一伦一视频免费看 | 蜜桃臀无码内射一区二区三区 | 荫蒂被男人添的好舒服爽免费视频 | 免费无码av一区二区 | 亚洲区小说区激情区图片区 | 欧美性色19p | 国产成人无码午夜视频在线观看 | 国产suv精品一区二区五 | 午夜福利电影 | 骚片av蜜桃精品一区 | 兔费看少妇性l交大片免费 | 国产色在线 | 国产 | 任你躁国产自任一区二区三区 | 无码av最新清无码专区吞精 | 亚洲一区二区三区无码久久 | 国产精品亚洲一区二区三区喷水 | 激情五月综合色婷婷一区二区 | 国产真人无遮挡作爱免费视频 | 激情五月综合色婷婷一区二区 | 欧美成人家庭影院 | 国产婷婷色一区二区三区在线 | 国产成人精品必看 | 久久久亚洲欧洲日产国码αv | 国产午夜无码视频在线观看 | 精品国产福利一区二区 | 欧美黑人性暴力猛交喷水 | 熟妇人妻无码xxx视频 | 99er热精品视频 | 成人欧美一区二区三区黑人免费 | 美女黄网站人色视频免费国产 | 国产av一区二区三区最新精品 | 色婷婷久久一区二区三区麻豆 | 精品欧美一区二区三区久久久 | 国产无遮挡又黄又爽又色 | 日本精品久久久久中文字幕 | 久久精品人人做人人综合试看 | 午夜福利不卡在线视频 | 99久久人妻精品免费一区 | 亚洲天堂2017无码中文 | 扒开双腿疯狂进出爽爽爽视频 | 欧美老妇与禽交 | 亚洲成av人综合在线观看 | 色婷婷综合激情综在线播放 | 亚洲爆乳大丰满无码专区 | 黑人巨大精品欧美一区二区 | 亚洲欧洲中文日韩av乱码 | 精品日本一区二区三区在线观看 | 欧美三级不卡在线观看 | 亚拍精品一区二区三区探花 | 国产偷国产偷精品高清尤物 | 亚洲中文字幕在线无码一区二区 | 无码国模国产在线观看 | 波多野结衣av一区二区全免费观看 | 天天av天天av天天透 | 国产色xx群视频射精 | 午夜免费福利小电影 | 丝袜人妻一区二区三区 | 亚洲精品久久久久avwww潮水 | 午夜熟女插插xx免费视频 | 国产xxx69麻豆国语对白 | 欧洲欧美人成视频在线 | 中文字幕乱妇无码av在线 | 人妻互换免费中文字幕 | 精品欧洲av无码一区二区三区 | 久久国产36精品色熟妇 | 欧美日韩在线亚洲综合国产人 | 精品偷自拍另类在线观看 | 成人无码视频免费播放 | 欧美阿v高清资源不卡在线播放 | 亚洲成a人一区二区三区 | 97无码免费人妻超级碰碰夜夜 | 亚洲无人区一区二区三区 | 亚洲色在线无码国产精品不卡 | 无套内谢老熟女 | ass日本丰满熟妇pics | 久久亚洲国产成人精品性色 | 精品久久久久久人妻无码中文字幕 | 国产av无码专区亚洲awww | 成人免费视频在线观看 | 久久综合狠狠综合久久综合88 | 日韩精品无码一区二区中文字幕 | 亚洲伊人久久精品影院 | 国产精品久久久久9999小说 | 黑人粗大猛烈进出高潮视频 | 久久国产自偷自偷免费一区调 | 亚洲中文字幕成人无码 | 国产精品多人p群无码 | 国产一区二区三区精品视频 | 中文字幕av日韩精品一区二区 | 亚洲人交乣女bbw | 久久精品人人做人人综合试看 | 又大又紧又粉嫩18p少妇 | 国产真人无遮挡作爱免费视频 | 欧美性猛交内射兽交老熟妇 | 国产成人午夜福利在线播放 | 伊人久久大香线蕉亚洲 | 粗大的内捧猛烈进出视频 | 久久99精品国产麻豆 | 日本一区二区三区免费播放 | 欧美人与禽猛交狂配 | 亚洲国产精品久久人人爱 | 亚洲精品国偷拍自产在线观看蜜桃 | 日日天日日夜日日摸 | 人人妻人人澡人人爽精品欧美 | 国产精品久久久久影院嫩草 | 国产精品多人p群无码 | aⅴ亚洲 日韩 色 图网站 播放 | 丝袜人妻一区二区三区 | 狂野欧美激情性xxxx | 伊人久久大香线蕉av一区二区 | 成人无码视频免费播放 | aa片在线观看视频在线播放 | 国产日产欧产精品精品app | 日韩无码专区 | 成熟妇人a片免费看网站 | 色综合视频一区二区三区 | 国产综合在线观看 | 亚洲中文字幕va福利 | 精品国产乱码久久久久乱码 | aⅴ在线视频男人的天堂 | 激情人妻另类人妻伦 | 久久国产精品二国产精品 | 啦啦啦www在线观看免费视频 | 久久精品人人做人人综合试看 | 成人免费无码大片a毛片 | 人妻aⅴ无码一区二区三区 | 99精品视频在线观看免费 | 国产午夜视频在线观看 | 欧美性猛交xxxx富婆 | 成人欧美一区二区三区 | 国产精华av午夜在线观看 | 人妻天天爽夜夜爽一区二区 | 99在线 | 亚洲 | 自拍偷自拍亚洲精品被多人伦好爽 | 久久久www成人免费毛片 | 国产激情精品一区二区三区 | 亚洲色www成人永久网址 | 久久五月精品中文字幕 | 老熟女乱子伦 | 国产亚洲精品久久久久久 | 老子影院午夜精品无码 | 欧美成人午夜精品久久久 | 国产亚洲美女精品久久久2020 | 一本色道久久综合狠狠躁 | 日韩精品无码一区二区中文字幕 | 中文字幕无码av波多野吉衣 | 国产 浪潮av性色四虎 | 中文精品久久久久人妻不卡 | 精品无码成人片一区二区98 | 5858s亚洲色大成网站www | 久久人人爽人人爽人人片av高清 | 国产偷国产偷精品高清尤物 | 国产成人人人97超碰超爽8 | 亚洲热妇无码av在线播放 | 亚洲自偷精品视频自拍 | 奇米综合四色77777久久 东京无码熟妇人妻av在线网址 | 大地资源中文第3页 | 老子影院午夜伦不卡 | 中文字幕+乱码+中文字幕一区 | 亚拍精品一区二区三区探花 | 成人无码精品1区2区3区免费看 | 白嫩日本少妇做爰 | 久久精品国产亚洲精品 | 欧美人与动性行为视频 | 日本一区二区三区免费高清 | 在线播放亚洲第一字幕 | 精品无码成人片一区二区98 | 亚洲无人区午夜福利码高清完整版 | 日本欧美一区二区三区乱码 | 久久人人97超碰a片精品 | 十八禁真人啪啪免费网站 | 欧美精品国产综合久久 | 久久这里只有精品视频9 | 玩弄少妇高潮ⅹxxxyw | 全黄性性激高免费视频 | 日韩精品无码一本二本三本色 | 国产偷自视频区视频 | 樱花草在线播放免费中文 | 日韩精品乱码av一区二区 | 日韩av无码一区二区三区 | 精品成人av一区二区三区 | 蜜桃视频韩日免费播放 | 麻花豆传媒剧国产免费mv在线 | 人人妻人人澡人人爽精品欧美 | 精品亚洲韩国一区二区三区 | 久久午夜无码鲁丝片午夜精品 | 97夜夜澡人人爽人人喊中国片 | 无遮无挡爽爽免费视频 | 国产精品人妻一区二区三区四 | 久久久中文久久久无码 | 亚洲国产精品久久久久久 | 久久综合激激的五月天 | 无码人妻丰满熟妇区毛片18 | 午夜熟女插插xx免费视频 | 日韩精品无码免费一区二区三区 | 国产成人无码av在线影院 | 亚洲欧美精品伊人久久 | 久久亚洲精品成人无码 | 5858s亚洲色大成网站www | 色综合久久久久综合一本到桃花网 | 午夜福利一区二区三区在线观看 | 久久久成人毛片无码 | 女人和拘做爰正片视频 | 丰满岳乱妇在线观看中字无码 | 日韩亚洲欧美精品综合 | 少妇性l交大片欧洲热妇乱xxx | 亚洲精品中文字幕久久久久 | 少妇无码av无码专区在线观看 | yw尤物av无码国产在线观看 | 欧美精品一区二区精品久久 | 激情爆乳一区二区三区 | 久久人人97超碰a片精品 | 欧美国产日韩亚洲中文 | 国产精品永久免费视频 | 国产精品人妻一区二区三区四 | 日韩视频 中文字幕 视频一区 | 欧美日韩一区二区综合 | 亚洲精品国产品国语在线观看 | 日日躁夜夜躁狠狠躁 | 2020久久超碰国产精品最新 | 国产两女互慰高潮视频在线观看 | 漂亮人妻洗澡被公强 日日躁 | 天堂а√在线中文在线 | 久久精品人人做人人综合试看 | 亚洲人成影院在线无码按摩店 | 99精品无人区乱码1区2区3区 | 色诱久久久久综合网ywww | 国产人妖乱国产精品人妖 | 国产在线精品一区二区三区直播 | 日韩精品乱码av一区二区 | 国产激情综合五月久久 | 色一情一乱一伦一区二区三欧美 | 国内精品一区二区三区不卡 | 狠狠色欧美亚洲狠狠色www | 国产亚洲tv在线观看 | 黑人巨大精品欧美一区二区 | 人人妻人人藻人人爽欧美一区 | 欧美zoozzooz性欧美 | 中文字幕+乱码+中文字幕一区 | 对白脏话肉麻粗话av | 欧美性生交活xxxxxdddd | 国产一精品一av一免费 | 国产无套粉嫩白浆在线 | 欧美国产亚洲日韩在线二区 | 青春草在线视频免费观看 | 水蜜桃av无码 | 日本爽爽爽爽爽爽在线观看免 | 亚洲无人区午夜福利码高清完整版 | 亚洲精品成a人在线观看 | 日本一区二区三区免费播放 | 亚洲精品一区二区三区在线 | 久久午夜无码鲁丝片秋霞 | 丰满少妇熟乱xxxxx视频 | 国产亚洲精品久久久ai换 | 图片小说视频一区二区 | 亚洲男人av香蕉爽爽爽爽 | 国产色xx群视频射精 | 牲欲强的熟妇农村老妇女 | 亚洲成a人片在线观看无码 | 99久久精品国产一区二区蜜芽 | 中文字幕日韩精品一区二区三区 | 人妻少妇精品视频专区 | 久久天天躁狠狠躁夜夜免费观看 | 免费中文字幕日韩欧美 | 88国产精品欧美一区二区三区 | 国产精品美女久久久 | 国产精品久久久久久久影院 | 亚洲成在人网站无码天堂 | 一本久道久久综合婷婷五月 | 国产精品人人爽人人做我的可爱 | 亚洲精品无码人妻无码 | 麻豆国产丝袜白领秘书在线观看 | 青青草原综合久久大伊人精品 | 大胆欧美熟妇xx | 美女极度色诱视频国产 | 亚洲国产精品无码一区二区三区 | 亚洲精品国偷拍自产在线麻豆 | 国产乱人伦app精品久久 国产在线无码精品电影网 国产国产精品人在线视 | 无码国产色欲xxxxx视频 | 色综合久久88色综合天天 | 精品 日韩 国产 欧美 视频 | 国产片av国语在线观看 | 丰满人妻被黑人猛烈进入 | 18无码粉嫩小泬无套在线观看 | 久久精品人妻少妇一区二区三区 | 色婷婷香蕉在线一区二区 | 300部国产真实乱 | 国产极品美女高潮无套在线观看 | 免费观看激色视频网站 | 国产人妻人伦精品1国产丝袜 | 日韩精品a片一区二区三区妖精 | 女人被爽到呻吟gif动态图视看 | 成年美女黄网站色大免费视频 | 国产精品va在线观看无码 | 欧美成人家庭影院 | 欧美激情内射喷水高潮 | 中文字幕av日韩精品一区二区 | 麻豆av传媒蜜桃天美传媒 | 亚洲人成网站在线播放942 | 女人高潮内射99精品 | 国产精品亚洲lv粉色 | 高潮毛片无遮挡高清免费 | 国产绳艺sm调教室论坛 | 久久亚洲精品成人无码 | 色五月五月丁香亚洲综合网 | 亚洲精品午夜国产va久久成人 | 又色又爽又黄的美女裸体网站 | 欧美丰满老熟妇xxxxx性 | 国产精品久久久久久亚洲毛片 | 中文无码成人免费视频在线观看 | 精品亚洲成av人在线观看 | 水蜜桃亚洲一二三四在线 | 亚洲一区二区观看播放 | 国产精品久久福利网站 | 亚洲精品一区二区三区婷婷月 | 免费视频欧美无人区码 | 亚洲精品综合一区二区三区在线 | 亚洲欧美中文字幕5发布 | 国产亚av手机在线观看 | 亚洲色欲色欲欲www在线 | 亚洲精品成人福利网站 | 日本精品久久久久中文字幕 | 无码任你躁久久久久久久 | 欧美兽交xxxx×视频 | 亚洲一区二区三区 | 亚洲人成网站色7799 | 色综合天天综合狠狠爱 | 国产成人av免费观看 | 全黄性性激高免费视频 | 精品无人国产偷自产在线 | 在线欧美精品一区二区三区 | 波多野结衣av在线观看 | 国产一区二区三区精品视频 | 无码帝国www无码专区色综合 | 日韩人妻少妇一区二区三区 | 国产乱人伦av在线无码 | 波多野结衣 黑人 | 精品日本一区二区三区在线观看 | 国产av人人夜夜澡人人爽麻豆 | 大地资源网第二页免费观看 | 一个人看的www免费视频在线观看 | 大乳丰满人妻中文字幕日本 | 天下第一社区视频www日本 | 国产精品久久久一区二区三区 | 亚洲人成人无码网www国产 | 日本大乳高潮视频在线观看 | 人人妻人人澡人人爽欧美一区 | 亚洲国产高清在线观看视频 | 国产一区二区不卡老阿姨 | 亚洲gv猛男gv无码男同 | 日韩av无码一区二区三区 | 日韩欧美中文字幕公布 | 欧美日韩精品 | 强辱丰满人妻hd中文字幕 | 在线 国产 欧美 亚洲 天堂 | 亚洲色欲色欲欲www在线 | 大地资源网第二页免费观看 | 少妇无码av无码专区在线观看 | 午夜精品一区二区三区在线观看 | 人妻尝试又大又粗久久 | 亚洲中文字幕乱码av波多ji | a片在线免费观看 | 九九在线中文字幕无码 | 国产精品无码一区二区桃花视频 | 免费国产黄网站在线观看 | 四十如虎的丰满熟妇啪啪 | 免费国产成人高清在线观看网站 | 国产精品久久久久7777 | 狠狠亚洲超碰狼人久久 | 18精品久久久无码午夜福利 | 久久久久久国产精品无码下载 | 牲交欧美兽交欧美 | 欧美人与善在线com | 性做久久久久久久久 | 黑人巨大精品欧美黑寡妇 | 中文精品无码中文字幕无码专区 | 久久视频在线观看精品 | 欧美 日韩 亚洲 在线 | 国产精品.xx视频.xxtv | 精品人妻av区 | 色婷婷av一区二区三区之红樱桃 | 国产真人无遮挡作爱免费视频 | 狠狠色噜噜狠狠狠7777奇米 | 偷窥日本少妇撒尿chinese | 国产香蕉尹人视频在线 | 东京无码熟妇人妻av在线网址 | 熟妇人妻无码xxx视频 | 在线视频网站www色 | 久久综合网欧美色妞网 | 国产成人午夜福利在线播放 | 欧美喷潮久久久xxxxx | 东京一本一道一二三区 | 精品无码成人片一区二区98 | 欧美丰满熟妇xxxx | 国产色精品久久人妻 | 国产精品亚洲五月天高清 | 亚洲精品国产精品乱码视色 | 女人被男人躁得好爽免费视频 | 亚洲欧美国产精品专区久久 | 亚洲色欲色欲欲www在线 | 麻豆国产97在线 | 欧洲 | 中文字幕+乱码+中文字幕一区 | 久久精品丝袜高跟鞋 | 国产精品久久久午夜夜伦鲁鲁 | 国产午夜福利亚洲第一 | 亚洲小说春色综合另类 | 老熟妇乱子伦牲交视频 | 久久精品女人天堂av免费观看 | 欧美猛少妇色xxxxx | 国产超级va在线观看视频 | 国产精品无码久久av | 最近中文2019字幕第二页 | 精品无码av一区二区三区 | 国产精品久久国产精品99 | 国产人妻精品一区二区三区 | 日本一区二区更新不卡 | 国产精品资源一区二区 | www国产亚洲精品久久久日本 | 免费乱码人妻系列无码专区 | 久久天天躁狠狠躁夜夜免费观看 | 国产极品美女高潮无套在线观看 | 久久亚洲国产成人精品性色 | 最近免费中文字幕中文高清百度 | 欧美丰满熟妇xxxx性ppx人交 | 亚洲春色在线视频 | 在线成人www免费观看视频 | 精品少妇爆乳无码av无码专区 | 国产香蕉97碰碰久久人人 | 欧美三级a做爰在线观看 | 国产真实夫妇视频 | 成人精品视频一区二区三区尤物 | 又紧又大又爽精品一区二区 | 天天躁日日躁狠狠躁免费麻豆 | 18无码粉嫩小泬无套在线观看 | 色综合久久网 | 国产极品美女高潮无套在线观看 | 国内精品久久久久久中文字幕 | 97人妻精品一区二区三区 | 精品无码一区二区三区爱欲 | 全球成人中文在线 | 国内精品九九久久久精品 | 日韩精品一区二区av在线 | 国产午夜亚洲精品不卡下载 | 国产人妖乱国产精品人妖 | 国产精品亚洲lv粉色 | 成 人 网 站国产免费观看 | 国产成人精品视频ⅴa片软件竹菊 | 日韩成人一区二区三区在线观看 | 亚洲中文字幕乱码av波多ji | 丰满岳乱妇在线观看中字无码 | 激情综合激情五月俺也去 | 伊人色综合久久天天小片 | 少妇高潮一区二区三区99 | 欧美人与动性行为视频 | 高清不卡一区二区三区 | 成 人影片 免费观看 | 亚洲精品美女久久久久久久 | 午夜时刻免费入口 | 草草网站影院白丝内射 | 少妇高潮喷潮久久久影院 | 一个人免费观看的www视频 | 老熟女重囗味hdxx69 | 人妻体内射精一区二区三四 | 在线观看国产一区二区三区 | 国产 浪潮av性色四虎 | 水蜜桃色314在线观看 | 国产精品igao视频网 | 久久精品女人的天堂av | 久久国产精品_国产精品 | 丰满人妻被黑人猛烈进入 | 欧美黑人巨大xxxxx | 亚洲小说春色综合另类 | 国产亚洲日韩欧美另类第八页 | 精品无码国产自产拍在线观看蜜 | 国产精品无码一区二区桃花视频 | 日日摸日日碰夜夜爽av | 亚洲精品久久久久中文第一幕 | 一二三四社区在线中文视频 | 55夜色66夜色国产精品视频 | аⅴ资源天堂资源库在线 | 麻豆国产人妻欲求不满 | 日本va欧美va欧美va精品 | 午夜精品一区二区三区的区别 | 人人妻人人澡人人爽欧美一区九九 | 国产精品美女久久久久av爽李琼 | 精品成在人线av无码免费看 | 日韩精品一区二区av在线 | 大色综合色综合网站 | 大屁股大乳丰满人妻 | 成人一在线视频日韩国产 | 99久久精品国产一区二区蜜芽 | 久久 国产 尿 小便 嘘嘘 | 国产成人精品一区二区在线小狼 | 少妇性俱乐部纵欲狂欢电影 | 波多野结衣aⅴ在线 | 亚洲一区二区观看播放 | 人妻少妇精品无码专区二区 | 日日鲁鲁鲁夜夜爽爽狠狠 | 精品无人区无码乱码毛片国产 | 77777熟女视频在线观看 а天堂中文在线官网 | 亚洲精品一区国产 | 精品久久久久久亚洲精品 | 国产无遮挡又黄又爽免费视频 | 国产精品成人av在线观看 | 少女韩国电视剧在线观看完整 | 粉嫩少妇内射浓精videos | 小鲜肉自慰网站xnxx | 欧美刺激性大交 | 一本精品99久久精品77 | 日本饥渴人妻欲求不满 | 日日夜夜撸啊撸 | 国产偷国产偷精品高清尤物 | av在线亚洲欧洲日产一区二区 | 久久久久亚洲精品男人的天堂 | 又大又硬又爽免费视频 | 成人精品视频一区二区三区尤物 | 免费人成网站视频在线观看 | 色综合久久久久综合一本到桃花网 | 一二三四在线观看免费视频 | 天海翼激烈高潮到腰振不止 | aⅴ在线视频男人的天堂 | 亚洲精品无码国产 | 未满小14洗澡无码视频网站 | 97色伦图片97综合影院 | 亚洲国产精品无码一区二区三区 | 精品久久久无码人妻字幂 | 亚洲人成影院在线无码按摩店 | 亚洲成色www久久网站 | 无码人妻少妇伦在线电影 | 一本无码人妻在中文字幕免费 | 欧美大屁股xxxxhd黑色 | 免费无码肉片在线观看 | 女人被男人躁得好爽免费视频 | 在线精品国产一区二区三区 | 亚洲va欧美va天堂v国产综合 | 成 人 网 站国产免费观看 | 一本久久a久久精品亚洲 | 国模大胆一区二区三区 | 无人区乱码一区二区三区 | 欧美怡红院免费全部视频 | 久久精品国产99精品亚洲 | 精品欧美一区二区三区久久久 | 亚洲成av人片天堂网无码】 | 日韩av无码一区二区三区不卡 | 欧美freesex黑人又粗又大 | 色婷婷av一区二区三区之红樱桃 | 女人被男人爽到呻吟的视频 | 久久精品视频在线看15 | 我要看www免费看插插视频 | 国产精品美女久久久网av | 日韩av无码一区二区三区 | 国产人妻精品一区二区三区 | 在线天堂新版最新版在线8 | 色欲久久久天天天综合网精品 | 国产一区二区三区精品视频 | 日本精品久久久久中文字幕 | 亚洲乱码中文字幕在线 | 1000部啪啪未满十八勿入下载 | 欧美日本精品一区二区三区 | 日韩欧美中文字幕公布 | 老司机亚洲精品影院 | 欧美日本精品一区二区三区 | 熟妇人妻无码xxx视频 | 欧美激情一区二区三区成人 | 欧美黑人巨大xxxxx | 无码任你躁久久久久久久 | 内射欧美老妇wbb | 久久久久99精品国产片 | 亚洲小说图区综合在线 | 久久久久免费看成人影片 | 日日麻批免费40分钟无码 | 国产suv精品一区二区五 | 无码成人精品区在线观看 | 水蜜桃色314在线观看 | 国产在线无码精品电影网 | 强奷人妻日本中文字幕 | 精品无人区无码乱码毛片国产 | 欧美日韩人成综合在线播放 | 国产做国产爱免费视频 | 国产精品久久国产精品99 | 久久99精品国产麻豆 | 亚洲精品综合一区二区三区在线 | 水蜜桃av无码 | 精品偷自拍另类在线观看 | 亚洲一区二区三区播放 | 又粗又大又硬毛片免费看 | 一区二区三区乱码在线 | 欧洲 | a片免费视频在线观看 | 久久婷婷五月综合色国产香蕉 | 亚洲欧洲日本无在线码 | 人人妻在人人 | 日本在线高清不卡免费播放 | 精品久久久久久亚洲精品 | 初尝人妻少妇中文字幕 | 欧美人与牲动交xxxx | 亚洲理论电影在线观看 | 中文字幕乱码中文乱码51精品 | 亚洲国产综合无码一区 | 午夜成人1000部免费视频 | 免费乱码人妻系列无码专区 | 欧美刺激性大交 | 亚洲a无码综合a国产av中文 | 国产成人无码av片在线观看不卡 | 亚洲中文字幕成人无码 | 黄网在线观看免费网站 | 久热国产vs视频在线观看 | 丰满人妻精品国产99aⅴ | 亚洲欧美精品aaaaaa片 | 奇米影视888欧美在线观看 | 无遮无挡爽爽免费视频 | 欧美老人巨大xxxx做受 | 国产真实夫妇视频 | 亚洲色欲久久久综合网东京热 | 扒开双腿疯狂进出爽爽爽视频 | 欧美日韩色另类综合 | 色欲久久久天天天综合网精品 | 色五月五月丁香亚洲综合网 | 男女下面进入的视频免费午夜 | 亚拍精品一区二区三区探花 | 99精品久久毛片a片 | aⅴ亚洲 日韩 色 图网站 播放 | 久精品国产欧美亚洲色aⅴ大片 | 国产办公室秘书无码精品99 | 人妻尝试又大又粗久久 | 色偷偷av老熟女 久久精品人妻少妇一区二区三区 | 亚洲精品中文字幕乱码 | 亚洲综合色区中文字幕 | 久久综合狠狠综合久久综合88 | 国产成人精品三级麻豆 | 国产精品.xx视频.xxtv | 精品一区二区三区无码免费视频 | 亚洲狠狠色丁香婷婷综合 | 高清不卡一区二区三区 | 中文无码成人免费视频在线观看 | 四十如虎的丰满熟妇啪啪 | 精品国产一区二区三区av 性色 | 亚洲大尺度无码无码专区 | 亚洲 高清 成人 动漫 | 久久这里只有精品视频9 | 国产亚洲精品久久久ai换 | 一本加勒比波多野结衣 | 麻豆精品国产精华精华液好用吗 | 青青草原综合久久大伊人精品 | 国产精品亚洲一区二区三区喷水 | 亚洲精品一区二区三区在线 | 亚洲乱亚洲乱妇50p | 国产激情综合五月久久 | 在线播放亚洲第一字幕 | 免费看男女做好爽好硬视频 | 天堂亚洲2017在线观看 | aⅴ在线视频男人的天堂 | 精品国偷自产在线 | 无码人妻黑人中文字幕 | 国产两女互慰高潮视频在线观看 | 99久久久无码国产aaa精品 | 无码一区二区三区在线观看 | 国产乱人伦app精品久久 国产在线无码精品电影网 国产国产精品人在线视 | 亚洲色成人中文字幕网站 | 午夜理论片yy44880影院 | 欧美国产日韩久久mv | 人人妻人人澡人人爽人人精品浪潮 | 国产激情无码一区二区app | 亚洲无人区一区二区三区 | 无码人妻丰满熟妇区五十路百度 | 任你躁国产自任一区二区三区 | 少妇被粗大的猛进出69影院 | 欧美一区二区三区视频在线观看 | 99精品国产综合久久久久五月天 | 亚洲欧美国产精品久久 | 激情爆乳一区二区三区 | 色诱久久久久综合网ywww | 久久久久av无码免费网 | 精品国产一区二区三区四区在线看 | 好屌草这里只有精品 | 欧美性黑人极品hd | 好屌草这里只有精品 | 国产乱人偷精品人妻a片 | 久久久久久久久蜜桃 | 久久午夜无码鲁丝片午夜精品 | 亚洲色在线无码国产精品不卡 | 精品一区二区不卡无码av | 日日麻批免费40分钟无码 | 国产真实夫妇视频 | 人妻少妇精品无码专区动漫 | 亚洲中文字幕无码中文字在线 | 超碰97人人做人人爱少妇 | 天天拍夜夜添久久精品 | 久久99精品国产麻豆蜜芽 | 中文字幕无码热在线视频 | 国产成人无码av一区二区 | 牛和人交xxxx欧美 | 又湿又紧又大又爽a视频国产 | 男女爱爱好爽视频免费看 | 亚洲一区二区三区四区 | 一本大道久久东京热无码av | 国产精品第一区揄拍无码 | 扒开双腿疯狂进出爽爽爽视频 | 美女黄网站人色视频免费国产 | 亚洲色大成网站www国产 | 亚洲码国产精品高潮在线 | 免费视频欧美无人区码 | 女人高潮内射99精品 | 精品国精品国产自在久国产87 | 无码人妻丰满熟妇区五十路百度 | 亚洲大尺度无码无码专区 | 亚洲精品中文字幕 | 女人高潮内射99精品 | 丰满少妇人妻久久久久久 | 88国产精品欧美一区二区三区 | 亚洲精品一区二区三区大桥未久 | av无码电影一区二区三区 | 国产精品va在线播放 | 乱中年女人伦av三区 | 国产综合色产在线精品 | 成熟人妻av无码专区 | 精品国产麻豆免费人成网站 | 国产精品亚洲专区无码不卡 | 无码免费一区二区三区 | 久久精品女人天堂av免费观看 | 国产精品第一国产精品 | 日本一卡2卡3卡4卡无卡免费网站 国产一区二区三区影院 | 午夜理论片yy44880影院 | 国产福利视频一区二区 | 天堂在线观看www | 亚洲一区二区三区无码久久 | 麻豆md0077饥渴少妇 | 丰满少妇人妻久久久久久 | 国产国语老龄妇女a片 | 亚洲欧美日韩成人高清在线一区 | ass日本丰满熟妇pics | 精品少妇爆乳无码av无码专区 | 亚洲精品午夜无码电影网 | 亚洲精品一区三区三区在线观看 | 中文字幕+乱码+中文字幕一区 | 亚洲国产精品一区二区美利坚 | 3d动漫精品啪啪一区二区中 | 国产av人人夜夜澡人人爽麻豆 | 波多野结衣aⅴ在线 | 国内精品人妻无码久久久影院蜜桃 | www一区二区www免费 | www一区二区www免费 | 久久久精品成人免费观看 | 小鲜肉自慰网站xnxx | 狠狠色色综合网站 | 日产国产精品亚洲系列 | 免费无码的av片在线观看 | 中文字幕乱码人妻二区三区 | 波多野结衣av一区二区全免费观看 | 少妇被粗大的猛进出69影院 | 精品少妇爆乳无码av无码专区 | 欧美freesex黑人又粗又大 | 少妇人妻大乳在线视频 | 动漫av一区二区在线观看 | 亚洲综合在线一区二区三区 | 国产精品亚洲一区二区三区喷水 | 国产免费无码一区二区视频 | 国产精品久久福利网站 | 久久久久免费看成人影片 | 亚欧洲精品在线视频免费观看 | 亚洲精品www久久久 | 男人的天堂av网站 | 女人被男人躁得好爽免费视频 | 扒开双腿疯狂进出爽爽爽视频 | 欧美变态另类xxxx | 亚洲 a v无 码免 费 成 人 a v | 精品久久久久久人妻无码中文字幕 | 国产精品久久久久久无码 | 动漫av一区二区在线观看 | 成人免费视频视频在线观看 免费 | 午夜精品久久久久久久久 | 玩弄中年熟妇正在播放 | 鲁一鲁av2019在线 | 午夜福利一区二区三区在线观看 | 99er热精品视频 | 久久综合色之久久综合 | 妺妺窝人体色www婷婷 | 日产国产精品亚洲系列 | 精品日本一区二区三区在线观看 | 亚洲成av人在线观看网址 | 国产人妻大战黑人第1集 | 亚洲の无码国产の无码影院 | 亚洲а∨天堂久久精品2021 | 天天av天天av天天透 | 天天拍夜夜添久久精品大 | 99久久精品国产一区二区蜜芽 | 国产乡下妇女做爰 | 日韩成人一区二区三区在线观看 | 亚洲第一无码av无码专区 | 乌克兰少妇xxxx做受 | 88国产精品欧美一区二区三区 | 人妻少妇精品视频专区 | 妺妺窝人体色www婷婷 | 亚洲人成影院在线无码按摩店 | 51国偷自产一区二区三区 | √天堂中文官网8在线 | 国产精品毛片一区二区 | 国产精品福利视频导航 | 日本丰满护士爆乳xxxx | 牲欲强的熟妇农村老妇女视频 | 香港三级日本三级妇三级 | 亚洲七七久久桃花影院 | 在线天堂新版最新版在线8 | 人人妻人人澡人人爽欧美一区九九 | 国产成人精品视频ⅴa片软件竹菊 | 天堂无码人妻精品一区二区三区 | 国产精品第一国产精品 | 又色又爽又黄的美女裸体网站 | 牛和人交xxxx欧美 | 在线观看国产午夜福利片 | 一二三四在线观看免费视频 | 性生交大片免费看女人按摩摩 | 呦交小u女精品视频 | 永久免费精品精品永久-夜色 | 99久久精品国产一区二区蜜芽 | 一本色道婷婷久久欧美 | 丰满人妻翻云覆雨呻吟视频 | 俄罗斯老熟妇色xxxx | 日韩av激情在线观看 | 亚无码乱人伦一区二区 | 久久综合色之久久综合 | 欧美老熟妇乱xxxxx | 国产成人无码一二三区视频 | 成人无码视频免费播放 | 人妻少妇精品无码专区二区 | 精品国产精品久久一区免费式 | 99久久亚洲精品无码毛片 | 亚洲小说图区综合在线 | 极品嫩模高潮叫床 | 成人精品视频一区二区三区尤物 | 久久 国产 尿 小便 嘘嘘 | 香港三级日本三级妇三级 | 精品人妻人人做人人爽夜夜爽 | 久久久精品成人免费观看 | 1000部啪啪未满十八勿入下载 | 日本在线高清不卡免费播放 | 国产成人综合色在线观看网站 | 日韩视频 中文字幕 视频一区 | 水蜜桃亚洲一二三四在线 | 欧美日本免费一区二区三区 | 国产性猛交╳xxx乱大交 国产精品久久久久久无码 欧洲欧美人成视频在线 | 夜精品a片一区二区三区无码白浆 | 国产欧美熟妇另类久久久 | 久久久精品国产sm最大网站 | 免费人成网站视频在线观看 | 国产又爽又黄又刺激的视频 | 日韩人妻无码一区二区三区久久99 | 精品人妻中文字幕有码在线 | 亚洲欧美精品伊人久久 | 色偷偷人人澡人人爽人人模 | 久久精品人人做人人综合试看 | 人人妻人人澡人人爽精品欧美 | 狠狠色噜噜狠狠狠狠7777米奇 | 日韩成人一区二区三区在线观看 | 天海翼激烈高潮到腰振不止 | 四虎国产精品一区二区 | 国产精品二区一区二区aⅴ污介绍 | 永久免费精品精品永久-夜色 | 亚洲一区二区三区四区 | 国产人成高清在线视频99最全资源 | 人人妻在人人 | 全球成人中文在线 | 欧美三级a做爰在线观看 | 中文字幕无码免费久久9一区9 | 中文无码精品a∨在线观看不卡 | 久久99精品国产.久久久久 | 精品国精品国产自在久国产87 | 久久精品成人欧美大片 | 麻豆国产丝袜白领秘书在线观看 | 日日噜噜噜噜夜夜爽亚洲精品 | 欧洲熟妇精品视频 | 两性色午夜视频免费播放 | 一本大道伊人av久久综合 | 小sao货水好多真紧h无码视频 | 久久久精品456亚洲影院 | 在线观看免费人成视频 | 天天摸天天碰天天添 | 蜜臀av无码人妻精品 | 强伦人妻一区二区三区视频18 | 国产超级va在线观看视频 | 国产成人一区二区三区在线观看 | 亚洲精品国产品国语在线观看 | 国产一区二区不卡老阿姨 | 丝袜 中出 制服 人妻 美腿 | 免费人成在线观看网站 | 国产国语老龄妇女a片 | 欧洲欧美人成视频在线 | 亚洲成av人综合在线观看 | aⅴ亚洲 日韩 色 图网站 播放 | 啦啦啦www在线观看免费视频 | 国产综合在线观看 | 久热国产vs视频在线观看 | 国产色视频一区二区三区 | 亚洲经典千人经典日产 | 熟妇激情内射com | 国产在线一区二区三区四区五区 | 国产亚洲人成在线播放 | 午夜精品一区二区三区在线观看 | 久久精品国产精品国产精品污 | 国产片av国语在线观看 | 国产明星裸体无码xxxx视频 | 国产精品办公室沙发 | 日本精品高清一区二区 | 麻花豆传媒剧国产免费mv在线 | 97人妻精品一区二区三区 | 色欲久久久天天天综合网精品 | 最新国产乱人伦偷精品免费网站 | 理论片87福利理论电影 | 图片小说视频一区二区 | 捆绑白丝粉色jk震动捧喷白浆 | 内射老妇bbwx0c0ck | 在线a亚洲视频播放在线观看 | 久久国产精品偷任你爽任你 | 纯爱无遮挡h肉动漫在线播放 | 国产成人无码午夜视频在线观看 | 在线播放无码字幕亚洲 | √天堂资源地址中文在线 | 女人被男人爽到呻吟的视频 | 成人无码视频免费播放 | 十八禁视频网站在线观看 | 全球成人中文在线 | 无码人妻精品一区二区三区不卡 | 久久精品一区二区三区四区 | 亚洲伊人久久精品影院 | 国产精华av午夜在线观看 | 福利一区二区三区视频在线观看 | 久久国语露脸国产精品电影 | 欧美丰满熟妇xxxx性ppx人交 | 麻豆蜜桃av蜜臀av色欲av | 国产精品无码一区二区桃花视频 | 亚洲国产精品一区二区美利坚 | 久久zyz资源站无码中文动漫 | 国产av久久久久精东av | 中文字幕无码日韩专区 | 成人欧美一区二区三区黑人 | 国产成人精品一区二区在线小狼 | 99久久精品日本一区二区免费 | 国产精品人妻一区二区三区四 | 扒开双腿疯狂进出爽爽爽视频 | 无码纯肉视频在线观看 | 成在人线av无码免费 | 无码任你躁久久久久久久 | 久久精品中文字幕一区 | 99精品无人区乱码1区2区3区 | 日韩成人一区二区三区在线观看 | 久久精品无码一区二区三区 | 亚洲熟妇色xxxxx欧美老妇y | 精品久久久久久亚洲精品 | 无码人妻久久一区二区三区不卡 | 曰韩无码二三区中文字幕 | 永久免费观看美女裸体的网站 | 国产三级久久久精品麻豆三级 | 欧美阿v高清资源不卡在线播放 | 高潮喷水的毛片 | 99riav国产精品视频 | 亚洲人成人无码网www国产 | 大色综合色综合网站 | 色五月丁香五月综合五月 | 青春草在线视频免费观看 | 一本大道伊人av久久综合 | 国产又粗又硬又大爽黄老大爷视 | 亚洲国产午夜精品理论片 | 亚拍精品一区二区三区探花 | 亚洲精品一区三区三区在线观看 | 天下第一社区视频www日本 | 国产卡一卡二卡三 | 免费乱码人妻系列无码专区 | 色窝窝无码一区二区三区色欲 | 久久久久国色av免费观看性色 | 日本一本二本三区免费 | 国精产品一品二品国精品69xx | 亚洲精品国偷拍自产在线观看蜜桃 | 一本大道久久东京热无码av | 熟女少妇人妻中文字幕 | 性生交大片免费看女人按摩摩 | 亚洲乱亚洲乱妇50p | 久久亚洲中文字幕精品一区 | 少妇久久久久久人妻无码 | 丰满少妇人妻久久久久久 | 99久久久国产精品无码免费 | 永久免费观看国产裸体美女 | 无码人妻少妇伦在线电影 | 久久精品国产一区二区三区肥胖 | 国产sm调教视频在线观看 | 亚洲精品国产精品乱码视色 | 亚洲国产综合无码一区 | 成人一区二区免费视频 | 中文字幕色婷婷在线视频 | 精品夜夜澡人妻无码av蜜桃 | 亚洲区欧美区综合区自拍区 | 久久国语露脸国产精品电影 | 性史性农村dvd毛片 | 97久久国产亚洲精品超碰热 | 高潮毛片无遮挡高清免费视频 | 国产精品久久久久久无码 | 成人精品一区二区三区中文字幕 | 福利一区二区三区视频在线观看 | 大色综合色综合网站 | 欧美日韩人成综合在线播放 | 色爱情人网站 | 色一情一乱一伦 | 国产精品手机免费 | 国产亚洲视频中文字幕97精品 | 亚洲日韩中文字幕在线播放 | 亚洲国产成人av在线观看 | 日本免费一区二区三区最新 | 红桃av一区二区三区在线无码av | 一本大道伊人av久久综合 | 人人妻人人澡人人爽欧美一区 | 色狠狠av一区二区三区 | 无码成人精品区在线观看 | 亚洲另类伦春色综合小说 | 色综合久久久久综合一本到桃花网 | 亚洲精品美女久久久久久久 | 国产激情综合五月久久 | 成人精品一区二区三区中文字幕 | 伊人久久婷婷五月综合97色 | 国产午夜手机精彩视频 | а√资源新版在线天堂 | 综合激情五月综合激情五月激情1 | 国产av人人夜夜澡人人爽麻豆 | 亚洲中文字幕av在天堂 | 精品国偷自产在线 | 亚洲色www成人永久网址 | 亚洲国产欧美国产综合一区 | 色综合视频一区二区三区 | 国产午夜无码视频在线观看 | 久久国内精品自在自线 | 亚洲啪av永久无码精品放毛片 | 51国偷自产一区二区三区 | 乱人伦中文视频在线观看 | 亚洲日韩av一区二区三区四区 | 巨爆乳无码视频在线观看 | 大色综合色综合网站 | 久久亚洲日韩精品一区二区三区 | 又大又硬又黄的免费视频 | 亚洲成熟女人毛毛耸耸多 | 俺去俺来也在线www色官网 | 中文字幕精品av一区二区五区 | 六月丁香婷婷色狠狠久久 | 成熟人妻av无码专区 | 国产精品a成v人在线播放 | 精品亚洲成av人在线观看 | 人人妻人人澡人人爽人人精品浪潮 | 国产精品丝袜黑色高跟鞋 | 国产亚洲tv在线观看 | 97久久精品无码一区二区 | 欧美喷潮久久久xxxxx | 人人妻人人澡人人爽人人精品浪潮 | 国产精品亚洲а∨无码播放麻豆 | 无码人妻少妇伦在线电影 | 欧美日韩久久久精品a片 | 日本一区二区三区免费播放 | 成人女人看片免费视频放人 | 日韩av无码中文无码电影 | 免费无码午夜福利片69 | 乱人伦人妻中文字幕无码久久网 | 中文无码精品a∨在线观看不卡 | 无码午夜成人1000部免费视频 | 国产精品无码mv在线观看 | 亚洲国产午夜精品理论片 | 少妇性荡欲午夜性开放视频剧场 | 四虎影视成人永久免费观看视频 | 欧美 亚洲 国产 另类 | 无码任你躁久久久久久久 | 丰满肥臀大屁股熟妇激情视频 | 国产精品毛片一区二区 | 任你躁在线精品免费 | 精品国精品国产自在久国产87 | 国产精品久久久 | 久久亚洲精品成人无码 | 亚洲精品午夜无码电影网 | 国产国产精品人在线视 | 亚洲日韩av一区二区三区四区 | 狠狠噜狠狠狠狠丁香五月 | 国产又爽又黄又刺激的视频 | 国产麻豆精品一区二区三区v视界 | 国产特级毛片aaaaaa高潮流水 | 伊人色综合久久天天小片 | 亚洲中文字幕va福利 | 中文毛片无遮挡高清免费 | 国产成人亚洲综合无码 | 欧美人与善在线com | 日日橹狠狠爱欧美视频 | 18无码粉嫩小泬无套在线观看 | 未满小14洗澡无码视频网站 | 午夜男女很黄的视频 | 午夜时刻免费入口 | 欧美性生交xxxxx久久久 | 亚洲自偷精品视频自拍 | 亚洲国产综合无码一区 | 色噜噜亚洲男人的天堂 | 成人亚洲精品久久久久 | 日本肉体xxxx裸交 | 久久久久亚洲精品男人的天堂 | 丝袜足控一区二区三区 | 免费看少妇作爱视频 | 国产成人精品无码播放 | 乱人伦人妻中文字幕无码久久网 | 日日天干夜夜狠狠爱 | 宝宝好涨水快流出来免费视频 | 免费人成在线视频无码 | 国模大胆一区二区三区 | 国产精品无码久久av | 亚洲成a人片在线观看无码 | 久久国产精品萌白酱免费 | 国产凸凹视频一区二区 | 人人妻人人藻人人爽欧美一区 | 欧美午夜特黄aaaaaa片 | 国产乱码精品一品二品 | 午夜福利一区二区三区在线观看 | 国产高潮视频在线观看 | 老熟女重囗味hdxx69 | 亚洲va欧美va天堂v国产综合 | 扒开双腿疯狂进出爽爽爽视频 | 亚洲精品美女久久久久久久 | 宝宝好涨水快流出来免费视频 | 免费男性肉肉影院 | 午夜嘿嘿嘿影院 | aⅴ亚洲 日韩 色 图网站 播放 | 亚洲欧洲中文日韩av乱码 | 国产精品无码永久免费888 | 曰本女人与公拘交酡免费视频 | 青春草在线视频免费观看 | 无遮挡国产高潮视频免费观看 | 内射巨臀欧美在线视频 | 55夜色66夜色国产精品视频 | 大色综合色综合网站 | 无码人妻丰满熟妇区毛片18 | 国产偷自视频区视频 | av人摸人人人澡人人超碰下载 | 成 人 网 站国产免费观看 | 精品偷自拍另类在线观看 | 精品国产一区二区三区四区 | 成人精品视频一区二区 | 日日碰狠狠躁久久躁蜜桃 | 狠狠色丁香久久婷婷综合五月 | 国产乱人伦偷精品视频 | 日本精品人妻无码77777 天堂一区人妻无码 | 国产精品无码mv在线观看 | 无遮挡国产高潮视频免费观看 | 少妇太爽了在线观看 | 人人妻人人澡人人爽欧美一区九九 | 熟妇女人妻丰满少妇中文字幕 | 人人爽人人爽人人片av亚洲 | 天堂亚洲免费视频 | 国产精品igao视频网 | 国产亚洲精品久久久久久久久动漫 | 久久无码人妻影院 | 国产精品办公室沙发 | 欧美野外疯狂做受xxxx高潮 | 俄罗斯老熟妇色xxxx | 中文字幕无线码 | 超碰97人人做人人爱少妇 | 国产精品理论片在线观看 | 在线播放无码字幕亚洲 | 在线 国产 欧美 亚洲 天堂 | 亚洲国产高清在线观看视频 | 熟女俱乐部五十路六十路av | 国产一精品一av一免费 | 国产乱人无码伦av在线a | 成人无码精品一区二区三区 | 中文字幕乱码亚洲无线三区 | 粉嫩少妇内射浓精videos | 成人无码视频免费播放 | 国产精品久久久久久无码 | 熟女体下毛毛黑森林 | 77777熟女视频在线观看 а天堂中文在线官网 | 国产精品人人爽人人做我的可爱 | 亚洲性无码av中文字幕 | 亚洲欧美日韩综合久久久 | 日本熟妇大屁股人妻 | 天堂一区人妻无码 | 波多野结衣av一区二区全免费观看 | 一本久久伊人热热精品中文字幕 | 精品无码av一区二区三区 | 秋霞成人午夜鲁丝一区二区三区 | 亚洲精品成a人在线观看 | 又色又爽又黄的美女裸体网站 | 76少妇精品导航 | 久久综合色之久久综合 | 红桃av一区二区三区在线无码av | 久久久久久a亚洲欧洲av冫 | 亚洲日韩乱码中文无码蜜桃臀网站 | 国产福利视频一区二区 | 亚洲色欲久久久综合网东京热 | 国产精品va在线播放 | 无码国产乱人伦偷精品视频 | 国产乱码精品一品二品 | 中文字幕乱码人妻二区三区 | 狠狠色噜噜狠狠狠狠7777米奇 | 亚洲欧美精品aaaaaa片 | 午夜丰满少妇性开放视频 | 国产在线精品一区二区高清不卡 | 午夜精品久久久内射近拍高清 | 清纯唯美经典一区二区 | 色婷婷香蕉在线一区二区 | 久久精品中文字幕一区 | 亚洲成a人片在线观看无码 | 免费无码av一区二区 | 国产在热线精品视频 | 欧美xxxxx精品 | 亚洲国产精品美女久久久久 | 成人亚洲精品久久久久 | 99久久人妻精品免费一区 | 日本一卡二卡不卡视频查询 | 欧美日韩亚洲国产精品 | 亚洲精品一区二区三区在线 | 欧美老人巨大xxxx做受 | 巨爆乳无码视频在线观看 | 双乳奶水饱满少妇呻吟 | 色综合视频一区二区三区 | 亚洲成a人片在线观看无码3d | 国产精品毛多多水多 | 日日躁夜夜躁狠狠躁 | 国产sm调教视频在线观看 | 国产婷婷色一区二区三区在线 | 国产亚洲精品精品国产亚洲综合 | 成人欧美一区二区三区 | 人人妻人人澡人人爽欧美一区 | 99re在线播放 | 性生交大片免费看l | 特黄特色大片免费播放器图片 | 亚洲爆乳无码专区 | 日日躁夜夜躁狠狠躁 | 久久久久久九九精品久 | 九九综合va免费看 | 国精品人妻无码一区二区三区蜜柚 | 精品日本一区二区三区在线观看 | 中文字幕日韩精品一区二区三区 | 高清国产亚洲精品自在久久 | 亚洲精品一区二区三区大桥未久 | 亚洲精品国产a久久久久久 | 无码国模国产在线观看 | 亚洲自偷精品视频自拍 | 熟妇女人妻丰满少妇中文字幕 | 任你躁在线精品免费 | 成人欧美一区二区三区 | 蜜桃av抽搐高潮一区二区 | 成人精品一区二区三区中文字幕 | 国产莉萝无码av在线播放 | 日本熟妇人妻xxxxx人hd | 亚洲国产高清在线观看视频 | 国产乱子伦视频在线播放 | 久久无码人妻影院 | 国产绳艺sm调教室论坛 | 久久亚洲精品成人无码 | 国产无av码在线观看 | 毛片内射-百度 | 久久这里只有精品视频9 | 精品久久久久久人妻无码中文字幕 | 国产成人无码av片在线观看不卡 | 亚洲 欧美 激情 小说 另类 | 精品国产一区av天美传媒 | 日韩精品无码一区二区中文字幕 | 六十路熟妇乱子伦 | 亚洲国产成人av在线观看 | 日本大香伊一区二区三区 | 国产情侣作爱视频免费观看 | 亚洲a无码综合a国产av中文 | 国产成人精品久久亚洲高清不卡 | 国产熟女一区二区三区四区五区 | 色综合久久久无码中文字幕 | 国产高清不卡无码视频 | 动漫av一区二区在线观看 | 亚洲精品无码人妻无码 | 国产欧美精品一区二区三区 | 亚洲日韩一区二区 | 久久人人爽人人爽人人片ⅴ | 亚洲人交乣女bbw | 狠狠躁日日躁夜夜躁2020 | 在线播放免费人成毛片乱码 | 女人被爽到呻吟gif动态图视看 | 4hu四虎永久在线观看 | 九一九色国产 | 天天做天天爱天天爽综合网 | 日韩精品无码一本二本三本色 | 97资源共享在线视频 | 在线播放无码字幕亚洲 | 亚洲大尺度无码无码专区 | 国产精品高潮呻吟av久久 | 久久久久se色偷偷亚洲精品av | 国产精品欧美成人 | 成人性做爰aaa片免费看 | 奇米影视7777久久精品人人爽 | 亚洲一区二区三区偷拍女厕 | av在线亚洲欧洲日产一区二区 | 丰满岳乱妇在线观看中字无码 | 亚洲爆乳精品无码一区二区三区 | 久久久成人毛片无码 | 香港三级日本三级妇三级 | 亚洲精品国偷拍自产在线观看蜜桃 | 久久国产劲爆∧v内射 | 欧美三级a做爰在线观看 | 国产区女主播在线观看 | 国产色视频一区二区三区 | 99久久久无码国产aaa精品 | 国产成人精品优优av | 无码人妻丰满熟妇区五十路百度 | 中文字幕乱码中文乱码51精品 | 亚洲 另类 在线 欧美 制服 | 欧美性色19p | 精品久久久中文字幕人妻 | 欧美日韩一区二区免费视频 | 久久zyz资源站无码中文动漫 | 影音先锋中文字幕无码 | 久久久久久九九精品久 | 免费无码午夜福利片69 | 无码吃奶揉捏奶头高潮视频 | 亚洲无人区一区二区三区 | 国产一区二区三区四区五区加勒比 | 国产成人av免费观看 | 国产精品成人av在线观看 | 国产激情一区二区三区 | 亚洲国产成人av在线观看 | 久久久久久亚洲精品a片成人 | 亚洲国产一区二区三区在线观看 | 美女张开腿让人桶 | 97久久超碰中文字幕 | 最近中文2019字幕第二页 | 又大又黄又粗又爽的免费视频 | 动漫av一区二区在线观看 | 18禁黄网站男男禁片免费观看 | 国产精品久久久久久久9999 | 国产亚洲美女精品久久久2020 | 人妻少妇精品无码专区动漫 | 日韩欧美中文字幕在线三区 | 少妇性l交大片欧洲热妇乱xxx | 国产亚洲精品久久久闺蜜 | 久久久久成人精品免费播放动漫 | 亚洲精品午夜无码电影网 | 亚洲中文字幕成人无码 | 亚无码乱人伦一区二区 | 免费男性肉肉影院 | 亚洲精品一区二区三区婷婷月 | 国产精品多人p群无码 | 偷窥日本少妇撒尿chinese | 亚洲色www成人永久网址 | 妺妺窝人体色www在线小说 | 国产精品美女久久久 | 久久久精品456亚洲影院 | 少妇人妻av毛片在线看 | 性做久久久久久久免费看 | 欧美日韩综合一区二区三区 | 日本一区二区更新不卡 | 婷婷丁香六月激情综合啪 | 正在播放东北夫妻内射 | 初尝人妻少妇中文字幕 | 免费乱码人妻系列无码专区 | 亚洲一区二区三区含羞草 | 一本久久a久久精品vr综合 | 中文字幕无码免费久久9一区9 | 日日鲁鲁鲁夜夜爽爽狠狠 | 国产欧美亚洲精品a | 无码福利日韩神码福利片 | 黑人巨大精品欧美一区二区 | 国内精品久久久久久中文字幕 | 无码一区二区三区在线 | 亚洲国产精品无码一区二区三区 | 蜜桃视频韩日免费播放 | 国产精品丝袜黑色高跟鞋 | 强辱丰满人妻hd中文字幕 | 丰满肥臀大屁股熟妇激情视频 | 久久99国产综合精品 | 麻豆国产人妻欲求不满 | 丰满少妇高潮惨叫视频 | 国产区女主播在线观看 | 99视频精品全部免费免费观看 | 免费人成在线观看网站 | 国产在线一区二区三区四区五区 | 狠狠躁日日躁夜夜躁2020 | 99久久精品午夜一区二区 | 亚洲一区二区三区无码久久 | 亚洲欧美国产精品专区久久 | 国产精品亚洲五月天高清 | 国产精品对白交换视频 | 国产精品18久久久久久麻辣 | 国内精品九九久久久精品 | 亚洲熟妇色xxxxx欧美老妇y | 亚洲 另类 在线 欧美 制服 | 精品亚洲成av人在线观看 | 99er热精品视频 | 欧美丰满少妇xxxx性 | 免费国产黄网站在线观看 | 欧美性黑人极品hd | 性色欲网站人妻丰满中文久久不卡 | yw尤物av无码国产在线观看 | 小鲜肉自慰网站xnxx | 无码午夜成人1000部免费视频 | 免费人成网站视频在线观看 | 少妇性l交大片欧洲热妇乱xxx | 天天躁夜夜躁狠狠是什么心态 | 特级做a爰片毛片免费69 | 日本护士毛茸茸高潮 |