<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    posts - 403, comments - 310, trackbacks - 0, articles - 7
      BlogJava :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理

    OSLab之中斷處理

    Posted on 2008-09-02 11:55 ZelluX 閱讀(641) 評(píng)論(5)  編輯  收藏 所屬分類: SystemCourses
    發(fā)信人: Zellux (null), 信區(qū): Software_06
    標(biāo) 題: OSLab之中斷處理
    發(fā)信站: 日月光華 (2008年08月30日20:15:58 星期六), 站內(nèi)信件

    1. 準(zhǔn)備工作
    在開始分析Support Code之前,先配置下我們的Source Insight,使它能夠支持.s文件的搜索。

    在Options->Document Options->Document Types中選擇x86 Asm Source File,在File fileter中增加一個(gè)*.s,變成*.asm;*.inc;*.s 然后在Project->Add and Remove
    Project Files中重新將整個(gè)oslab的目錄加入,這樣以后進(jìn)行文本搜索時(shí).s文件也不會(huì)漏掉了。

    2. Source Insight使用
    接下來簡(jiǎn)單分析下內(nèi)核啟動(dòng)的過程,在瀏覽代碼的過程中可以迅速的掌握Source Insight的使用技巧。

    lib/multiboot /multiboot.s完成了初始化工作,可以看到其中一句call
    EXT(multiboot_main)調(diào)用了C函數(shù)multiboot_main,使用ctrl+/搜索包含multiboot_main的所有文件,最終base_multiboot_main.c中找到了它的定義。依次進(jìn)行cpu、內(nèi)存的初
    始化,然后開啟中斷,跳轉(zhuǎn)到kernel_main函數(shù),也是Lab1中所要改寫的函數(shù)之一。另外
    在這里可以通過ctrl+單擊或者ctrl+=跳轉(zhuǎn)到相應(yīng)的函數(shù)定義處,很方便。

    3. irq處理初始化工作
    來看下Lab 1的重點(diǎn)之一,irq的處理。跟蹤multiboot_main->base_cpu_setup->base_cp
    u_init->base_irq_init,可以看到這行代碼
    gate_init(base_idt, base_irq_inittab, KERNEL_CS);
    繼續(xù)使用ctrl+/找到base_irq_inittab的藏身之處:base_irq_inittab.s

    4. base_irq_inittab.s
    這個(gè)匯編文件做了不少重復(fù)性工作,方便我們?cè)赾語言級(jí)別實(shí)現(xiàn)各種handler。
    GATE_INITTAB_BEGIN(base_irq_inittab) /* irq處理函數(shù)表的起始,還記得jump
    table 嗎? */
    MASTER(0, 0) /* irq0 對(duì)應(yīng)的函數(shù) */


    來看看這個(gè)MASTER(0, 0)宏展開后是什么樣子:
    #define MASTER(irq, num) \
    GATE_ENTRY(BASE_IRQ_MASTER_BASE + (num), 0f, ACC_PL_K|ACC_INTR_GATE) ;\
    P2ALIGN(TEXT_ALIGN) ;\
    0: ;\
    pushl $(irq) /* error code = irq vector */ ;\
    pushl $BASE_IRQ_MASTER_BASE + (num) /* trap number */ ;\
    pusha /* save general registers */ ;\
    movl $(irq),%ecx /* irq vector number */ ;\
    movb $1 << num,%dl /* pic mask for this irq */ ;\
    jmp master_ints

    依次push irq號(hào),trap號(hào)(0x20+irq號(hào)),通用寄存器(eax ecx等)入棧,把irq號(hào)保
    存到ecx寄存器,然后跳轉(zhuǎn)到master_ints,master_ints是所有master interrupts公用
    的代碼。

    跳過master_ints的前幾行,從第七行開始
    /* Acknowledge the interrupt */
    movb $0x20,%al
    outb %al,$0x20

    /* Save the rest of the standard trap frame (oskit/x86/base_trap.h). */
    pushl %ds
    pushl %es
    pushl %fs
    pushl %gs

    /* Load the kernel's segment registers. */
    movw %ss,%dx
    movw %dx,%ds
    movw %dx,%es

    /* Increment the hardware interrupt nesting counter */
    incb EXT(base_irq_nest)

    /* Load the handler vector */
    movl EXT(base_irq_handlers)(,%ecx,4),%esi

    注釋寫得很詳細(xì),首先發(fā)送0x20到0x20端口,也就是Lab1文檔上所說的發(fā)送INT_CTL_DON
    E到INT_CTL_REG,看來這一步support code已經(jīng)替我們完成了。接下來保存四個(gè)段寄存
    器ds es fs gs,并讀入kernel態(tài)的段寄存器信息。

    最后一句很關(guān)鍵,把base_irq_handlers + %ecx * 4這個(gè)值保存到了esi寄存器中,%ecx
    中保存了irq號(hào),而*4則是一個(gè)函數(shù)指針的大小,那么base_irq_handlers是什么呢?繼
    續(xù)用ctrl+/搜索,可以在base_irq.c中找到這個(gè)數(shù)組的定義
    unsigned int (*base_irq_handlers[BASE_IRQ_COUNT])(struct trap_state *ts)
    且初始時(shí)這個(gè)數(shù)組的每一項(xiàng)都是base_irq_default_handler

    看來這句匯編代碼的功能是把處理irq對(duì)應(yīng)的函數(shù)地址保存到了esi寄存器中。
    為了證實(shí)這一點(diǎn),繼續(xù)看base_irq_inittab.s的代碼:
    #else
    /* Call the interrupt handler with the trap frame as a parameter */
    pushl %esp
    call *%esi
    popl %edx
    #endif
    果然,在保存了esp值后,緊接著就調(diào)用了esi指向的那個(gè)函數(shù)。而從那個(gè)函數(shù)返回后,
    之前在棧上保存的相關(guān)信息都被恢復(fù)了:

    /* blah blah blah */
    /* Return from the interrupt */
    popl %gs
    popl %fs
    popl %es
    popl %ds
    popa
    addl $4*2,%esp /* Pop trap number and error code */
    iret
    這樣就恢復(fù)到了進(jìn)入這個(gè)irq處理單元前的狀態(tài),文檔中所要求的保存通用寄存器這一步
    其實(shí)在這里也已經(jīng)完成了,不需要我們自己寫代碼。

    好了,這樣一分析后,我們要做的事情就很簡(jiǎn)單,就是把base_irq_handlers數(shù)組中的對(duì)
    應(yīng)項(xiàng)改成相應(yīng)的handler函數(shù)就行了。
    注意index是相應(yīng)的idt_entry號(hào)減去BASE_IRQ_SLAVE_BASE,或者直接使用IRQ號(hào)。

    另外這個(gè)數(shù)組的初始值都是base_irq_default_handler,用ctrl+左鍵跳到這個(gè)函數(shù)的定
    義,可以看到這個(gè)函數(shù)只有一句簡(jiǎn)單的輸出語句:
    printf("Unexpected interrupt %d\n", ts->err);
    而這就是沒有注冊(cè)handler前我們所看到的那句Unexpected interrupt 0的來源了。

    5. struct trap_state *ts
    所有的handler函數(shù)的參數(shù)都是一個(gè)struct trap_state *ts,這個(gè)參數(shù)是哪來的呢?
    注意call *%esi的前一行
    /* Call the interrupt handler with the trap frame as a parameter */
    pushl %esp
    這里把當(dāng)前的esp當(dāng)作指向ts的指針傳給了handler,列一下從esp指向的地址開始的內(nèi)容
    ,也就是在此之前push入棧的內(nèi)容:

    pushl $(irq) /* error code = irq vector */ ;\
    pushl $BASE_IRQ_MASTER_BASE + (num) /* trap number */ ;\
    pusha /* save general registers */ ;\
    pushl %ds
    pushl %es
    pushl %fs
    pushl %gs

    再看一下trap_state的定義,你會(huì)發(fā)現(xiàn)正好和push的順序相反:
    /* Saved segment registers */
    unsigned int gs;
    unsigned int fs;
    unsigned int es;
    unsigned int ds;

    /* PUSHA register state frame */
    unsigned int edi;
    unsigned int esi;
    unsigned int ebp;
    unsigned int cr2; /* we save cr2 over esp for page faults */
    unsigned int ebx;
    unsigned int edx;
    unsigned int ecx;
    unsigned int eax;

    /* Processor trap number, 0-31. */
    unsigned int trapno;

    /* Error code pushed by the processor, 0 if none. */
    unsigned int err;

    而這個(gè)定義后面的
    /* Processor state frame */
    unsigned int eip;
    unsigned int cs;
    unsigned int eflags;
    unsigned int esp;
    unsigned int ss;
    則是發(fā)生interrupt時(shí)硬件自動(dòng)push的五個(gè)數(shù)據(jù)(參見Understand the Linux Kernel)

    也就是說,ts指針指向的是調(diào)用當(dāng)前handler前的寄存器狀態(tài),也是當(dāng)前handler結(jié)束后
    用來恢復(fù)的寄存器狀態(tài),了解這一點(diǎn)對(duì)以后的幾個(gè)lab幫助很大。

    p.s. 另外提一句和這個(gè)lab無關(guān)的話,非vm86模式下棧上是不會(huì)有v86_es等四個(gè)寄存器
    信息的,所以以后根據(jù)task_struct指針計(jì)算*ts的地址時(shí)使用的偏移量不應(yīng)該是sizeof(
    struct trap_state)

    6. The End
    這樣差不多就把support code中處理interrupt的方法過了一遍(另外還有base_trap_in
    ittab.s,不過和irq的處理很相似)

    了解這些后Lab1就比較簡(jiǎn)單了,不需要任何內(nèi)嵌匯編代碼即可完成。

    評(píng)論

    # re: OSLab之中斷處理 [未登錄]  回復(fù)  更多評(píng)論   

    2008-09-02 13:22 by damocles
    你們做的是哪個(gè)?nachos? 看著覺得不像啊。。。

    # re: OSLab之中斷處理   回復(fù)  更多評(píng)論   

    2008-09-02 13:40 by ZelluX
    @damocles
    CMU的OSLab簡(jiǎn)化版,最后是要實(shí)現(xiàn)一個(gè)支持二級(jí)頁表、多進(jìn)程切換調(diào)度的微內(nèi)核,少了文件系統(tǒng)。

    # re: OSLab之中斷處理   回復(fù)  更多評(píng)論   

    2008-09-07 20:54 by luoyan
    第四點(diǎn)在2.6.9的Linux內(nèi)核中實(shí)際上對(duì)應(yīng)arch/i386/kernel/entry.S

    .data
    ENTRY(interrupt)
    .previous

    vector=0
    ENTRY(irq_entries_start)
    .rept NR_IRQS
    ALIGN
    1: pushl $vector-256
    jmp common_interrupt
    .data
    .long 1b
    .previous
    vector=vector+1
    .endr


    ALIGN
    common_interrupt:
    SAVE_ALL
    call do_IRQ
    jmp ret_from_intr

    實(shí)現(xiàn)的功能是一樣的,只是Linux的匯編更加晦澀

    第五點(diǎn):與arch/i386/kernel/entry.S中的SAVE_ALL,RESTORE_ALL類似,只是PUSHA的寄存器更多一些。
    挺有意思的,呵呵

    # re: OSLab之中斷處理   回復(fù)  更多評(píng)論   

    2008-09-07 22:42 by ZelluX
    @luoyan
    贊羅帥

    # re: OSLab之中斷處理   回復(fù)  更多評(píng)論   

    2008-09-09 09:25 by sherry
    zan~
    主站蜘蛛池模板: 亚洲精品偷拍视频免费观看| 久9这里精品免费视频| 亚洲乱码中文字幕小综合| 久久亚洲精品中文字幕无码| 亚洲AV无码AV男人的天堂| a级成人免费毛片完整版| 亚洲第一网站免费视频| 1000部拍拍拍18勿入免费视频软件| 成人免费视频一区| 国产亚洲AV夜间福利香蕉149 | 久久99免费视频| 久久成人国产精品免费软件| 久久精品九九亚洲精品| 亚洲精品无码一区二区| 免费播放在线日本感人片| gogo全球高清大胆亚洲| 亚洲成av人片在线看片| 国产无遮挡色视频免费观看性色| 女人与禽交视频免费看| 久久久久亚洲AV无码麻豆| 99re热免费精品视频观看| 亚洲狠狠婷婷综合久久久久| 日本视频免费观看| 毛片a级毛片免费播放100| 一级女性全黄久久生活片免费 | 8x8x华人永久免费视频| 亚洲午夜国产精品无码| 黄网站在线播放视频免费观看 | 免费国产污网站在线观看不要卡| 国产亚洲美女精品久久久久狼| 最近2022中文字幕免费视频| 欧洲乱码伦视频免费国产| 亚洲精品一区二区三区四区乱码| 免费无码中文字幕A级毛片| 亚洲第一网站免费视频| 国产在线观看免费视频播放器| 亚洲免费综合色在线视频| 亚洲一区二区三区AV无码| 中文字幕无码一区二区免费| 亚洲一级高清在线中文字幕| 国内永久免费crm系统z在线|