2016-08-08 4 views
1

Je suis en train de mettre en place l'IDT de mon noyau, mais je reçois cette erreur lien:macro nasm ne fonctionne pas correctement

bin/obj/idt.o: In function `setup_idt': 
idt.c:(.text+0x9b): undefined reference to `interrupt_handler_1' 

L'erreur indique que interrupt_handler_1 n'est pas défini mais il est une macro dans interrupt_manager.asm:

%macro no_error_code_interrupt_handler 1 
global interrupt_handler_%1 
interrupt_handler_%1: 
    cli 
    push dword 0      ; push 0 as error code 
    push dword %1     ; push the interrupt number 
    jmp  common_interrupt_handler ; jump to the common handler 
%endmacro 

Voici la fonction setyup_idt:

extern void interrupt_handler_1(); 

void setup_idt() 
{ 
    // Set the special idt_pointer 
    idt_pointer.limit = (sizeof(struct InterruptDescriptorTableEntry) * 256) - 1; // Subsract 1 because sizeof doesn't start from 0 
    idt_pointer.address = (uint32)&idt; 

    // Clear the whole idt to zeros 
    memset(&idt, 0, sizeof(struct InterruptDescriptorTableEntry) * 256); 

    for(unsigned int i = 0; i < 256; i++) 
    { 
     idt_set_gate(i, (uint32)&interrupt_handler_1, 0x8, 0x8E); 
    } 

    __asm__ __volatile__("lidt %0": :"m"(idt_pointer)); 

} 

Qu'est-ce que j'ai fait mal ?

question supplémentaire: Y at-il une macro/une autre façon de lier automatiquement l'entrée i du TDG à l'i gestionnaire d'interruption, je vais essayer de me expliquer mieux:

Ce que je veux faire est quelque chose comme ça :

for(unsigned int i = 0; i < 256; i++) 
    { 
     idt_set_gate(i, (uint32)&interrupt_handler_[i], 0x8, 0x8E); 
    } 

Où interrupt_handler [i] serait le handler_ d'interruption [i] serait remplacé par la macro

+1

Linker ne voit pas les macros. Utilisez une fonction. –

+0

Les macros ne font pas partie du code, vous devez utiliser * * la macro pour être étendu dans le code réel qui est assemblé .. –

+0

@Joachim Pileborg Okey, qu'en la question supplémentaire? –

Répondre

2

nasm Vous devez développer la macro dans votre code MSNA. Une définition de macro elle-même ne génère aucun code. Il doit être explicitement utilisé dans le code NASM.

Vous pouvez utiliser la directive %rep à étendre à plusieurs reprises la macro avec des paramètres différents. Quelque chose comme ceci:

extern common_interrupt_handler 

%macro error_code_interrupt_handler 1 
global interrupt_handler_%1 
interrupt_handler_%1: 
    push dword %1     ; push the interrupt number 
    jmp  common_interrupt_handler ; jump to the common handler 
%endmacro 

%macro no_error_code_interrupt_handler 1 
global interrupt_handler_%1 
interrupt_handler_%1: 
    push dword 0      ; push 0 as error code 
    push dword %1     ; push the interrupt number 
    jmp  common_interrupt_handler ; jump to the common handler 
%endmacro 

; Some CPU exceptions have error codes, some don't 

%assign intnum 0 
%rep 8 - intnum 
    no_error_code_interrupt_handler intnum 
    %assign intnum intnum + 1 
%endrep 

error_code_interrupt_handler 8 
no_error_code_interrupt_handler 9 

%assign intnum 10 
%rep 16 - intnum 
    error_code_interrupt_handler intnum 
    %assign intnum intnum + 1 
%endrep 

no_error_code_interrupt_handler 16 
error_code_interrupt_handler 17 
no_error_code_interrupt_handler 18 
no_error_code_interrupt_handler 19 
no_error_code_interrupt_handler 20 

%assign intnum 21 ; first (currently) unassigned CPU exception 
%rep 32 - intnum 
    no_error_code_interrupt_handler intnum 
    %assign intnum intnum + 1 
%endrep 

%assign intnum 32 ; first user defined interrupt 
%rep 256 - intnum 
    no_error_code_interrupt_handler intnum 
    %assign intnum intnum + 1 
%endrep 

; define a table of interrupt handlers for C code to use 

    global interrupt_handler_table 
interrupt_handler_table: 

%assign intnum 0 
%rep 256 
    dd interrupt_handler_ %+ intnum 
    %assign intnum intnum + 1 
%endrep 

Le code ci-dessus crée une table de tous les gestionnaires d'interruption que vous pouvez utiliser dans votre code C comme ceci:

extern uint32 interrupt_handler_table[256]; 

for(unsigned int i = 0; i < 256; i++) 
{ 
    idt_set_gate(i, interrupt_handler_table[i], 0x8, 0x8E); 
} 

Notez que j'ai créé une macro error_code_interrupt_handler pour les exceptions d'UC qui génèrent des codes d'erreur. En outre, j'ai supprimé l'instruction CLI inutile de votre code. Puisque vous utilisez Interrupt Gates dans l'IDT, l'indicateur d'activation d'interruption est automatiquement effacé.

+0

Merci beaucoup, cela a fonctionné parfaitement pour moi! –