美文网首页
【时钟中断的实现】

【时钟中断的实现】

作者: 月下蓑衣江湖夜雨 | 来源:发表于2020-12-02 23:34 被阅读0次

效果

效果

下面那一行,是main函数中的死循环输出变量!
右上方的字符是时钟中断服务程序打印的。
_start.asm

SELECTOR_KERNEL_CS  equ 8

; 导入函数
extern  cstart
extern  main

; 导入全局变量
extern  gdt_ptr
extern  idt_ptr
extern  c_cs;
extern  c_ds;
extern  c_es;
extern  c_ss;

; 导出 _start
global _start   

[SECTION .bss]
StackSpace      resb    2 * 1024
StackTop:       ; 栈顶

[section .text] ; 代码在此
_start:
    ; 此时内存看上去是这样的(更详细的内存情况在 LOADER.ASM 中有说明):
    ;              ┃                                    ┃
    ;              ┃                 ...                ┃
    ;              ┣━━━━━━━━━━━━━━━━━━┫
    ;              ┃■■■■■■Page  Tables■■■■■■┃
    ;              ┃■■■■■(大小由LOADER决定)■■■■┃ PageTblBase
    ;    00101000h ┣━━━━━━━━━━━━━━━━━━┫
    ;              ┃■■■■Page Directory Table■■■■┃ PageDirBase = 1M
    ;    00100000h ┣━━━━━━━━━━━━━━━━━━┫
    ;              ┃□□□□ Hardware  Reserved □□□□┃ B8000h ← gs
    ;       9FC00h ┣━━━━━━━━━━━━━━━━━━┫
    ;              ┃■■■■■■■LOADER.BIN■■■■■■┃ somewhere in LOADER ← esp
    ;       90000h ┣━━━━━━━━━━━━━━━━━━┫
    ;              ┃■■■■■■■KERNEL.BIN■■■■■■┃
    ;       80000h ┣━━━━━━━━━━━━━━━━━━┫
    ;              ┃■■■■■■■■KERNEL■■■■■■■┃ 30400h ← KERNEL 入口 (KernelEntryPointPhyAddr)
    ;       30000h ┣━━━━━━━━━━━━━━━━━━┫
    ;              ┋                 ...                ┋
    ;              ┋                                    ┋
    ;           0h ┗━━━━━━━━━━━━━━━━━━┛ ← cs, ds, es, fs, ss
    ;
    ;
    ; GDT 以及相应的描述符是这样的:
    ;
    ;                     Descriptors               Selectors
    ;              ┏━━━━━━━━━━━━━━━━━━┓
    ;              ┃         Dummy Descriptor           ┃
    ;              ┣━━━━━━━━━━━━━━━━━━┫
    ;              ┃         DESC_FLAT_C    (0~4G)     ┃   8h = cs
    ;              ┣━━━━━━━━━━━━━━━━━━┫
    ;              ┃         DESC_FLAT_RW   (0~4G)     ┃  10h = ds, es, fs, ss
    ;              ┣━━━━━━━━━━━━━━━━━━┫
    ;              ┃         DESC_VIDEO                 ┃  1Bh = gs
    ;              ┗━━━━━━━━━━━━━━━━━━┛
    ;
    ; 注意! 在使用 C 代码的时候一定要保证 ds, es, ss 这几个段寄存器的值是一样的
    ; 因为编译器有可能编译出使用它们的代码, 而编译器默认它们是一样的. 比如串拷贝操作会用到 ds 和 es.
    ;
    ;


    ; 把 esp 从 LOADER 挪到 KERNEL
    mov esp, StackTop   ; 堆栈在 bss 段中
    sgdt    [gdt_ptr]   ; cstart() 调用的relocate_gdt中将会用到 gdt_ptr
    
    mov word[c_cs], cs
    mov word[c_ds], ds
    mov word[c_es], es
    mov word[c_ss], ss
    
    call    cstart      ; 在此函数中改变了gdt_ptr,让它指向新的GDT
    lgdt    [gdt_ptr]   ; 使用新的GDT
    lidt    [idt_ptr]   ; 使用IDT
    mov ah, 0x74 ;灰底红字
    mov al, 'I'
    mov [gs:((80*0 + 70)*2)], ax
    sti
    call    main        ; 重新放置好GDT后,重新进入main
    ;ud2
    jmp $
    jmp $
    jmp $
    jmp $
    jmp $
    jmp $
    jmp $
    jmp $
    jmp $
    jmp $
    jmp $
    jmp $
    jmp $

cstart.c中的main

// 设置完GDT、IDT后,进入main
PUBLIC void main(){
    uint32 num = 0;
    while(1){
        for(int i=0; i<80; i++){
            print_str_fix_pos((80*24+i)*2, " ");
        }
    
        ++num;
        
       sprintf(buf, "[main], num is %d\n", num);
       print_str_fix_pos((80*24+0)*2, buf);
    }
}

interrupt.c中初始化8259A

PRIVATE void init_8259A(){
    out_byte(INT_M_CTL, 0x11);                  // Master 8259, ICW1. == 0001 0001
    out_byte(INT_S_CTL, 0x11);                  // Slave  8259, ICW1.
    out_byte(INT_M_CTLMASK, INT_VECTOR_IRQ0);   // Master 8259, ICW2. 设置 '主8259' 的中断入口地址为 0x20.
    out_byte(INT_S_CTLMASK, INT_VECTOR_IRQ8);   // Slave  8259, ICW2. 设置 '从8259' 的中断入口地址为 0x28
    out_byte(INT_M_CTLMASK, 0x4);               // Master 8259, ICW3. IR2 对应 '从8259'. 0000 0100
    out_byte(INT_S_CTLMASK, 0x2);               // Slave  8259, ICW3. 对应 '主8259' 的 IR2.
    out_byte(INT_M_CTLMASK, 0x1);               // Master 8259, ICW4. 
    out_byte(INT_S_CTLMASK, 0x1);               // Slave  8259, ICW4.
    //out_byte(INT_M_CTLMASK,   0xFD);          // Master 8259, OCW1. 只打开了键盘中断
    out_byte(INT_M_CTLMASK, 0xFE);              // Master 8259, OCW1. 只打开了时钟中断
    out_byte(INT_S_CTLMASK, 0xFF);              // Slave  8259, OCW1. 
}

时钟中断服务程序!

[section .text] ; 代码在此
ALIGN   16
hwint00:        ; Interrupt routine for irq 0 (the clock).
    pushad
    push ds
    push es
    push fs
    push gs


    inc byte [gs:((80*0 + 70)*2)]
    
    mov al, 20h
    out 20h, al
    
    ;恢复源寄存器的内容
    pop gs
    pop fs
    pop es
    pop ds
    popad
    
    iretd

相关文章

  • Linux C/C++定时器的实现原理和使用方法

    定时器的实现原理 定时器的实现依赖的是CPU时钟中断,时钟中断的精度就决定定时器精度的极限。一个时钟中断源如何实现...

  • 【时钟中断的实现】

    效果 下面那一行,是main函数中的死循环输出变量!右上方的字符是时钟中断服务程序打印的。_start.asm c...

  • 【中断开发:实现时钟中断】(草稿)

    const.h kernel.asm klib.asm protect.h start.c stdarg.h st...

  • 2018-01-10

    自学dsp 。时钟、GPIO、中断

  • 定时器与时钟中断

    时钟中断 时钟中断是一种硬中断,由时间硬件(系统定时器,一种可编程硬件)产生,CPU处理后交由时间中断处理程序来完...

  • 栈切换Format

    golang实现非协作式抢占调度基于此在线程由于时钟中断从睡眠状态中醒来时,内核栈切换到用户栈执行中断处理函数,可...

  • 进程切换和系统的一般执行过程

    进程调度的时机 中断处理过程(包括时钟中断、I/O中断、系统调用和异常)中,直接调用schedule(),或者返回...

  • 常用接口电路芯片

    8.1 可编程定时器/计时器8253 在控制系统中,常常要求有实时时钟以实现定时或延时控制,如定时中断、定时检测、...

  • Keil方法类_中断实验

    中断系统和外部中断 实现一个C51单片机中断需要在中断请求标志位、中断允许标志位和 中断优先级控制位进行组合的实现...

  • STM32F031xx 信息整理

    时钟信号: ADC 采样分析:每20us(50KHz)触发一次中断,开启ADC 采样, 采样250个点, 时钟周期...

网友评论

      本文标题:【时钟中断的实现】

      本文链接:https://www.haomeiwen.com/subject/zospwktx.html