【问题标题】:Asm volatile ("int $0x3") call restarts the machineasm volatile ("int $0x3") 调用重启机器
【发布时间】:2014-08-19 00:35:23
【问题描述】:

我正在学习内核开发。要测试我的中断处理程序,我需要运行 asm volatile ("idt $0x3") 命令。每当在我的 main.c 中调用此命令时,机器总是会重新启动。我什至试图删除中断处理程序。没有改变。我该怎么办?

gdt 汇编:

[extern _start]

lgdt [gdt_descriptor]
jmp CODE_SEG:initgdt

initgdt:
mov ax, DATA_SEG     
mov ds, ax       
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
mov ebp, 0x90000
mov esp, ebp
call _start ;main.c function
jmp $

gdt_star:

gdt_null:
dd 0x0      
dd 0x0      

gdt_code:
dw 0xffff   
dw 0x0010
db 0x00     
db 10011011b
db 01001111b
db 0x00 

gdt_data:
dw 0xffff
dw 0x0020
db 0x00
db 10010010b
db 01001111b
db 0x0              


gdt_end:

gdt_descriptor:
dw gdt_end - gdt_star - 1
dd gdt_star

CODE_SEG equ gdt_code - gdt_star
DATA_SEG equ gdt_data - gdt_star

descriptor_tables.c:

extern void idt_flush(uint32_t);
extern void isr0();
extern void isr1();
....
extern void isr31();


static void init_idt()
{
    idt_ptr.limit = sizeof(idt_entry_t) * 256 -1;
    idt_ptr.base  = (uint32_t)&idt_entries;

    memset((uint8_t*)&idt_entries, 0, sizeof(idt_entry_t)*256);

    idt_set_gate(0, (uint32_t)isr0, 0x08, 0x8E);
    idt_set_gate(1, (uint32_t)isr1, 0x08, 0x8E);
    ....
    idt_set_gate(31, (uint32_t)isr31, 0x08, 0x8E);

    idt_flush((uint32_t)&idt_ptr);
}

static void idt_set_gate(uint8_t num, uint32_t base, uint16_t sel, uint8_t flags)
{
   idt_entries[num].base_lo = base & 0xFFFF;
   idt_entries[num].base_hi = (base >> 16) & 0xFFFF;

   idt_entries[num].sel     = sel;
   idt_entries[num].always0 = 0;
   idt_entries[num].flags   = flags
}

interrupt.asm:

%macro ISR_NOERRCODE 1 
  [GLOBAL _isr%1]       
  _isr%1:
    cli
    push byte 0
    push byte %1
    jmp isr_common_stub
%endmacro

%macro ISR_ERRCODE 1
  [GLOBAL _isr%1]
  _isr%1:
    cli
    push byte %1
    jmp isr_common_stub
%endmacro

ISR_NOERRCODE 0
ISR_NOERRCODE 1
....
ISR_NOERRCODE 31

[EXTERN _isr_handler]

isr_common_stub:
pusha                    

mov ax, ds               
push eax                

mov ax, 0x10 
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax

call _isr_handler

pop eax        
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax

popa                    
add esp, 8     
sti
iret  

isr.c:

void isr_handler(registers_t regs)
{
   uint8_t str[12] = "\ninterrupt:";
   str[11] = 0;
   puts(str, FALSE);
   itoa(str, 10, regs.int_no);
   puts(str, FALSE);
   str[0] = '\n';
   str[1] = 0;
   puts(str, TRUE);
}

kernel_entry.asm:

....
[global _idt_flush]
_idt_flush:
   mov eax, [esp+4]  
   lidt [eax]       
   ret

【问题讨论】:

  • 您是否设置了 GDT 和 IDT?没有这些中断将不会做任何事情。另外,如果可以,请链接到相关代码。我怀疑您没有正确设置 GDT 和 IDT 表
  • 如果没有相关代码,很难猜出问题所在。您能否发布一些 IDT/GDT 设置的 sn-ps 以及您的中断处理代码。
  • 我看到您的 ISR 已设置,但没有 IRQ 设置的相关代码。不确定这是否会导致它。你也试过让你的 isr_handler 什么都不做吗?我只是想确保您的 puts 和 itoa 函数不会导致处理器异常。
  • 不,这些都不是问题。你会看我的回答吗?我解决了这个问题,但我仍然有问题。谢谢。

标签: kernel interrupt-handling


【解决方案1】:

我将descriptor_tables.c C 代码转换为汇编代码并使用以下宏:

%macro IDT_ENTRY 1
dw _isr%1
dw 0x08
db 0x0
db 0x8E
dw 0x0000
%endmacro

现在,它可以工作了。但我不确定为什么它不接受 C 代码。此外,以下宏也不起作用:

%macro IDT_ENTRY 1
dw (_isr%1 - $$) & 0xFFFF
dw 0x08
db 0x0
db 0x8E
dw ((_isr%1 - $$) >> 16) & 0xFFFF
%endmacro

同样,我不确定为什么第二个宏不起作用。

【讨论】:

    猜你喜欢
    • 2013-01-05
    • 2015-08-23
    • 2012-08-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多