Прерывания в защищённом режиме. непонятки...

Тема в разделе "WASM.OS.DEVEL", создана пользователем ExXtor, 13 май 2009.

  1. ExXtor

    ExXtor New Member

    Публикаций:
    0
    Регистрация:
    3 июл 2008
    Сообщения:
    4
    Здравствуйте!
    В общем пишу ОСь. начальный загрузчик читает файл "kernel" из корня диска в память и передаёт управление ему.
    Kernel загружается по адресу 0x2000, успешно включает защищённый режим, выводит сообщения на экран через видеопамять.
    Используя примеры удалось перейти на 32 битный сишный код.

    Ассемблерная часть ядра:
    Код (Text):
    1. KERNEL_SIZE EQU 0x100 ;(512byte sector unit, 0x100 sector = 128KB)
    2. KERNEL_START16 EQU 0x2000;:0
    3.  
    4.  
    5. [BITS 16]
    6.  
    7. start:
    8.  
    9.    ;setting stack base:offset (SS:SP)
    10.    mov ax, 0x0
    11.    mov ss, ax
    12.    mov ds, ax
    13.    mov ax, KERNEL_START16
    14.    mov sp, ax
    15.  
    16.    ;enabling A20
    17. delay1:
    18.    in al, 0x64
    19.    test al, 2
    20.    jnz delay1
    21.    mov al, 0xD1
    22.    out 0x64, al
    23. delay2:
    24.    in al, 0x64
    25.    and ax, byte 2
    26.    jnz delay2
    27.    mov al, 0xDF
    28.    out 0x60, al
    29.  
    30.    cli ;disable interrupts
    31.    
    32.    lgdt [gdt_48]
    33.    lidt [idt_48]
    34.  
    35.    ;enter in protected mode
    36.    mov eax, cr0
    37.    or eax,1
    38.    mov cr0, eax
    39.  
    40.    ;IA 386 suggest to make a jmp after the
    41.    ;swith to pmode in order to clear the pipeline
    42.    jmp 0x8 : protected_mode
    43.  
    44.  
    45. [BITS 32]
    46. [EXTERN kernel_main]
    47.    
    48. protected_mode:
    49.  
    50.  
    51.  
    52.    ;init data segment to gdt[2]
    53.    mov ax,0x10
    54.    mov ds, ax
    55.    mov es, ax
    56.    mov fs, ax
    57.    mov gs, ax
    58.    
    59.    ;init stack segment to gdt[2] too
    60.    mov ss, ax
    61.    mov esp, 0xA0000 ;use this area for stack (640KB->0KB)
    62.  
    63.  
    64.  
    65.  mov esi, msg_pm
    66.  call kputs
    67.  
    68. call  kernel_main
    69.  
    70.  
    71.    
    72. cursor:    dd 240
    73. %define VIDEO_RAM 0xB8000
    74. ;; Функция выполняет прямой вывод в память видеоадаптера,
    75. ;; которая находится в VGA-картах по адресу 0xB8000
    76. kputs:
    77.  pusha
    78. .loop:
    79.  lodsb
    80.  test al, al
    81.  mov ah, 2 ;green
    82.  jz .quit
    83.  mov ecx, [cursor]
    84.  mov [VIDEO_RAM+ecx*2], ax
    85.  inc dword [cursor]
    86.  jmp short .loop
    87. .quit:
    88.  popa
    89.  ret
    90.  
    91.    
    92.    
    93.  ;  jmp 0x8 : KERNEL_START32 ;do not use call
    94.  
    95. ; IDT Register 48bit
    96. ; _______________________________________
    97. ;|       IDT 0-31       |    SIZE 0-15   |  
    98. ; _______________________________________  
    99. idt_48:
    100.    dw 256*8
    101.    dd 0x100000
    102.    
    103. ; GDT Register 48bit
    104. ; _______________________________________
    105. ;|       GDT 0-31       |    SIZE 0-15   |  
    106. ; _______________________________________  
    107. gdt_48:
    108.    dw gdt_end - gdt - 1 ;gdt size
    109.    dd gdt               ;gdt address
    110.  
    111. ; GDT GATE
    112. ; 31         24       19           15                   7          0      
    113. ; |__________|_________|___________|____________________|__________|
    114. ; |BASE 31-24|G|D|0|AVL|LIMIT 16-19|P|DPL|S|    Type    |BASE 16-23|  
    115. ; |________________________________________________________________  
    116. ; |           BASE 15-0            |          LIMIT 0-15           |
    117. ;  ________________________________________________________________
    118.      
    119. gdt:                    ; Address for the GDT
    120.  
    121. gdt_null:               ; Null Segment
    122.         dd 0
    123.         dd 0
    124.  
    125. gdt_code:               ; Code segment, read/execute
    126.         dw 0FFFFh       ; LIMIT 0-15 = 0xFFFF
    127.         dw 0            ; BASE 0-15 = 0
    128.         db 0            ; BASE 16-23
    129.         db 10011010b    ; P=1, DPL=00, S=1, Type=1010 (Code Read/Execute)
    130.         db 11001111b    ; G=1 (4kb unit), D=1, 0, AVL=1, LIMIT 16-19 = 0xF
    131.         db 0            ; BASE 31-24 = 0
    132.  
    133. gdt_data:               ; Data segment, read/write
    134.         dw 0FFFFh       ; LIMIT 0-15 = 0xFFFF
    135.         dw 0            ; BASE 0-15 = 0
    136.         db 0            ; BASE 16-23
    137.         db 10010010b    ; P=1, DPL=00, S=1, Type=0010 (Data Read/Write)
    138.         db 11001111b    ; G=1 (4kb unit), D=1, 0, AVL=1, LIMIT 16-19 = 0xF
    139.         db 0            ; BASE 31-24 = 0
    140.  
    141. gdt_end:                ; Used to calculate the size of the GDT
    142.  
    143. msg_pm: db "32-bit Protected Mode run...",0
    Сишная часть ядра:
    Код (Text):
    1. #include "ioports.h"
    2.  
    3. #define IDT_TABLE 0x100000
    4. #define IDT_REG 0x100800
    5. #define SYS_CODE_SELECTOR 0x8
    6. //Функция i_install() устанавливает в качестве обработчика vector функцию func.
    7. //Тип шлюза (прерывания [0x8e] или ловушки [0x8f]) указывается параметром type.
    8. //Фактически, эта функция создает (или изменяет) соответствующий дескриптор в таблице IDT
    9.  
    10. #define IRQ_HANDLER(func) void func (void);\
    11.  asm(#func ": pusha \n call _" #func " \n movb $0x20, %al \n outb %al, $0x20 \n popa \n iret \n");\
    12.  void _ ## func(void)
    13.  
    14.  
    15.  
    16. //Функция i_setup() загружает регистр IDTR
    17. void i_setup()
    18. {
    19.   unsigned short *table_limit = IDT_REG;
    20.   unsigned int *table_address = IDT_REG+2;
    21.   *table_limit = 256*8 - 1;
    22.   *table_address = IDT_TABLE;
    23.   asm("lidt 0(,%0,)"::"a"(IDT_REG));
    24.   asm("sti");
    25. }
    26. //Включение обработки прерываний
    27. void i_enable()
    28. {
    29.   asm("sti");
    30. }
    31. //Отключение обработки прерываний
    32. void i_disable()
    33. {
    34.   asm("cli");
    35. }
    36.  
    37.  
    38. IRQ_HANDLER(irq_timer)
    39. {
    40.  
    41. };
    42.  
    43. //Здесь мы храним состояние шифта
    44. char shift = 0;
    45. IRQ_HANDLER(irq_keyboard)
    46. {
    47.   unsigned char scancode, ascii;
    48.   unsigned char creg;
    49.   //Прочитаем скан-код из порта 0x60
    50.  
    51.  
    52.   scancode = inportb(0x60);
    53.  
    54.   switch(scancode) {
    55.  
    56.     //Скан-коды нажатого шифта
    57.   case 0x36:
    58.   case 0x2A:
    59.     shift = 1;
    60.     break;
    61.     //Скан-коды отпущенного шифта
    62.   case 0x36 + 0x80:
    63.   case 0x2A + 0x80:
    64.     shift = 0;
    65.     break;
    66.  
    67.   default:
    68.   //Если клавиша отпущена...
    69.     if(scancode >= 0x80) {
    70.     //То ничего не делать
    71.  
    72.     } else {
    73.     //А если нажата...
    74.  
    75.       if(shift){
    76.       //Если шифт нажат, но преобразовать скан-код в "шифтнутое" ASCII
    77. ascii = scancodes_shifted[scancode];
    78.       } else {
    79.       //А если не нажат - то в обычное
    80. ascii = scancodes[scancode];
    81.       }
    82.  
    83.       //Если в результате преобразования нажата клавиша с каким-либо
    84.       //символом, то вывести его на экран
    85.       if(ascii != 0) {
    86. putchar(ascii);
    87.       }
    88.     }
    89.     break;
    90.   }
    91.   //Считаем байт состояния клавиатуры
    92.   creg = inportb(0x61);
    93.  
    94.   //Установим в нем старший бит
    95.   creg |= 1;
    96.   //И запишем обратно
    97.   outportb(0x61, creg);
    98. };
    99.  
    100. void i_install(unsigned char vector, void (*func)(), unsigned char type)
    101. {
    102.   unsigned char * idt_table=IDT_TABLE;
    103.  
    104.   unsigned char i;
    105.   unsigned char b[8];
    106.   b[0]=  (unsigned int)func & 0x000000FF;
    107.   b[1]=( (unsigned int)func & 0x0000FF00) >> 8;
    108.   b[2]=SYS_CODE_SELECTOR;
    109.   b[3]=0;
    110.   b[4]=0;
    111.   b[5]=type;
    112.   b[6]=( (unsigned int)func & 0x00FF0000) >> 16;
    113.   b[7]=( (unsigned int)func & 0xFF000000) >> 24;
    114.  
    115.  
    116.   for(i=0;i<8;i++){
    117.     *(idt_table+vector*8+i)=b[i];
    118.  
    119.  
    120.   }
    121.  
    122.  
    123. }
    124.  
    125. void init_interrupts()
    126. {
    127.  
    128. i_install(0x20, &irq_timer, 0x8e);
    129. i_install(0x21, &irq_keyboard, 0x8e);
    130.  
    131. i_setup();
    132. i_enable();
    133. }
    При включении прерываний в main система падает с kernel fault(использую vmware 6).
    Если на все прерывания поставить заглушки, то система не падает.

    В чём может быть проблема и как правильно написать обработчики прерываний?

    заранее спасибо
     
  2. Pavia

    Pavia Well-Known Member

    Публикаций:
    0
    Регистрация:
    17 июн 2003
    Сообщения:
    2.409
    Адрес:
    Fryazino
    Дело в том что макрос
    Код (Text):
    1. #define IRQ_HANDLER(func)
    Срабатывает только один раз.

    Вообщем правильнее сделать так. Создаешь два файла один на Си другой на ассемблере.
    В ассемблере вызываешь процедуры из Си. Дя этого надо их в ассемблерном файле объявить как внешнии(экспортировать) а в Си шном надо опобликовать(паблик). Поищи на board.sysbin.com пример. Тема поднималась не однократно.
     
  3. ExXtor

    ExXtor New Member

    Публикаций:
    0
    Регистрация:
    3 июл 2008
    Сообщения:
    4
    Pavia
    спасибо!
    а просто макрос расписать не получится? т.е. вручную в каждый сишный обработчик добавить ассемблерные вставки? с экспортом будет сложнее и файлы расплодятся(
     
  4. Pavia

    Pavia Well-Known Member

    Публикаций:
    0
    Регистрация:
    17 июн 2003
    Сообщения:
    2.409
    Адрес:
    Fryazino
    Можно. Только лучше всетаки из ассемблера вызывать Си подпрограмы тогда проблем с локальными переменными не будет.

    Ничуть. Во первых у тебя уже есть ассемблерный файл в него можно поместить код. А экспорт это всего одна ну две лишнии строчки.