How reload interrupt in real mode?

1

I am creating an operating system and I want to call the bios in protected mode, so I switch back to real mode, and I call the bios, but when I try to call the bios my emulator bochs write that as loop :

00002065173i[CPU0 ] BxError: instruction with opcode=0xff
00002065173i[CPU0 ] mod was c0, nnn was 7, rm was 7
00002065173i[CPU0 ] WARNING: Encountered an unknown instruction (signalling illegal instruction)

My code to call the bios is:

[bits 32]

global int32, _int32

struc regs16_t
    .di resw 1
    .si resw 1
    .bp resw 1
    .sp resw 1
    .bx resw 1
    .dx resw 1
    .cx resw 1
    .ax resw 1
    .gs resw 1
    .fs resw 1
    .es resw 1
    .ds resw 1
    .ef resw 1
endstruc

%define INT32_BASE                         0x7C00
%define REBASE(x)                          (((x) - reloc) + INT32_BASE)
%define GDTENTRY(x)                        ((x) << 3)
%define CODE32                             GDTENTRY(1)  ; 0x08
%define DATA32                             GDTENTRY(2)  ; 0x10
%define CODE16                             GDTENTRY(3)  ; 0x18
%define DATA16                             GDTENTRY(4)  ; 0x20
%define STACK16                            (INT32_BASE - regs16_t_size)

section .text
    int32: use32                             ; by Napalm
    _int32:
        cli                                    ; disable interrupts
        pusha                                  ; save register state to 32bit stack
        mov  esi, reloc                        ; set source to code below
        mov  edi, INT32_BASE                   ; set destination to new base address
        mov  ecx, (int32_end - reloc)          ; set copy size to our codes size
        cld                                    ; clear direction flag (so we copy forward)
        rep  movsb                             ; do the actual copy (relocate code to low 16bit space)
        jmp INT32_BASE                         ; jump to new code location
    reloc: use32                             ; by Napalm
        mov  [REBASE(stack32_ptr)], esp        ; save 32bit stack pointer
        sidt [REBASE(idt32_ptr)]               ; save 32bit idt pointer
        sgdt [REBASE(gdt32_ptr)]               ; save 32bit gdt pointer
        lgdt [REBASE(gdt16_ptr)]               ; load 16bit gdt pointer
        lea  esi, [esp+0x24]                   ; set position of intnum on 32bit stack
        lodsd                                  ; read intnum into eax
        mov  [REBASE(ib)], al                  ; set intrrupt immediate byte from our arguments 
        mov  esi, [esi]                        ; read regs pointer in esi as source
        mov  edi, STACK16                      ; set destination to 16bit stack
        mov  ecx, regs16_t_size                ; set copy size to our struct size
        mov  esp, edi                          ; save destination to as 16bit stack offset
        rep  movsb                             ; do the actual copy (32bit stack to 16bit stack)
        jmp  word CODE16:REBASE(p_mode16)      ; switch to 16bit selector (16bit protected mode)
    p_mode16: use16
        mov  ax, DATA16                        ; get our 16bit data selector
        mov  ds, ax                            ; set ds to 16bit selector
        mov  es, ax                            ; set es to 16bit selector
        mov  fs, ax                            ; set fs to 16bit selector
        mov  gs, ax                            ; set gs to 16bit selector
        mov  ss, ax                            ; set ss to 16bit selector
        mov  eax, cr0                          ; get cr0 so we can modify it
        and  al,  ~0x01                        ; mask off PE bit to turn off protected mode
        mov  cr0, eax                          ; set cr0 to result
        jmp  word 0x0000:REBASE(r_mode16)      ; finally set cs:ip to enter real-mode
    r_mode16: use16
        xor  ax, ax                            ; set ax to zero
        mov  ds, ax                            ; set ds so we can access idt16
        mov  ss, ax                            ; set ss so they the stack is valid
        lidt [REBASE(idt16_ptr)]               ; load 16bit idt
        mov  bx, 0x0870                        ; master 8 and slave 112
        call resetpic                          ; set pic's the to real-mode settings
        popa                                   ; load general purpose registers from 16bit stack
        pop  gs                                ; load gs from 16bit stack
        pop  fs                                ; load fs from 16bit stack
        pop  es                                ; load es from 16bit stack
        pop  ds                                ; load ds from 16bit stack
        sti                                    ; enable interrupts
        db 0xCD                                ; opcode of INT instruction with immediate byte
    ib: db 0x00
        cli                                    ; disable interrupts
        xor  sp, sp                            ; zero sp so we can reuse it
        mov  ss, sp                            ; set ss so the stack is valid
        mov  sp, INT32_BASE                    ; set correct stack position so we can copy back
        pushf                                  ; save eflags to 16bit stack
        push ds                                ; save ds to 16bit stack
        push es                                ; save es to 16bit stack
        push fs                                ; save fs to 16bit stack
        push gs                                ; save gs to 16bit stack
        pusha                                  ; save general purpose registers to 16bit stack
        mov  bx, 0x2028                        ; master 32 and slave 40
        call resetpic                          ; restore the pic's to protected mode settings
        mov  eax, cr0                          ; get cr0 so we can modify it
        inc  eax                               ; set PE bit to turn on protected mode
        mov  cr0, eax                          ; set cr0 to result
        jmp  dword CODE32:REBASE(p_mode32)     ; switch to 32bit selector (32bit protected mode)
    p_mode32: use32
        mov  ax, DATA32                        ; get our 32bit data selector
        mov  ds, ax                            ; reset ds selector
        mov  es, ax                            ; reset es selector
        mov  fs, ax                            ; reset fs selector
        mov  gs, ax                            ; reset gs selector
        mov  ss, ax                            ; reset ss selector
        lgdt [REBASE(gdt32_ptr)]               ; restore 32bit gdt pointer
        lidt [REBASE(idt32_ptr)]               ; restore 32bit idt pointer
        mov  esp, [REBASE(stack32_ptr)]        ; restore 32bit stack pointer
        mov  esi, STACK16                      ; set copy source to 16bit stack
        lea  edi, [esp+0x28]                   ; set position of regs pointer on 32bit stack
        mov  edi, [edi]                        ; use regs pointer in edi as copy destination
        mov  ecx, regs16_t_size                ; set copy size to our struct size
        cld                                    ; clear direction flag (so we copy forward)
        rep  movsb                             ; do the actual copy (16bit stack to 32bit stack)
        popa                                   ; restore registers
        sti                                    ; enable interrupts
        ret                                    ; return to caller
        
    resetpic:                                ; reset's 8259 master and slave pic vectors
        push ax                                ; expects bh = master vector, bl = slave vector
        mov  al, 0x11                          ; 0x11 = ICW1_INIT | ICW1_ICW4
        out  0x20, al                          ; send ICW1 to master pic
        out  0xA0, al                          ; send ICW1 to slave pic
        mov  al, bh                            ; get master pic vector param
        out  0x21, al                          ; send ICW2 aka vector to master pic
        mov  al, bl                            ; get slave pic vector param
        out  0xA1, al                          ; send ICW2 aka vector to slave pic
        mov  al, 0x04                          ; 0x04 = set slave to IRQ2
        out  0x21, al                          ; send ICW3 to master pic
        shr  al, 1                             ; 0x02 = tell slave its on IRQ2 of master
        out  0xA1, al                          ; send ICW3 to slave pic
        shr  al, 1                             ; 0x01 = ICW4_8086
        out  0x21, al                          ; send ICW4 to master pic
        out  0xA1, al                          ; send ICW4 to slave pic
        pop  ax                                ; restore ax from stack
        ret                                    ; return to caller
        
    stack32_ptr:                             ; address in 32bit stack after we
        dd 0x00000000                          ;   save all general purpose registers
        
    idt32_ptr:                               ; IDT table pointer for 32bit access
        dw 0x0000                              ; table limit (size)
        dd 0x00000000                          ; table base address
        
    gdt32_ptr:                               ; GDT table pointer for 32bit access
        dw 0x0000                              ; table limit (size)
        dd 0x00000000                          ; table base address
        
    idt16_ptr:                               ; IDT table pointer for 16bit access
        dw 0x03FF                              ; table limit (size)
        dd 0x00000000                          ; table base address
        
    gdt16_base:                              ; GDT descriptor table
        .null:                                 ; 0x00 - null segment descriptor
            dd 0x00000000                        ; must be left zero'd
            dd 0x00000000                        ; must be left zero'd
            
        .code32:                               ; 0x01 - 32bit code segment descriptor 0xFFFFFFFF
            dw 0xFFFF                            ; limit  0:15
            dw 0x0000                            ; base   0:15
            db 0x00                              ; base  16:23
            db 0x9A                              ; present, iopl/0, code, execute/read
            db 0xCF                              ; 4Kbyte granularity, 32bit selector; limit 16:19
            db 0x00                              ; base  24:31
            
        .data32:                               ; 0x02 - 32bit data segment descriptor 0xFFFFFFFF
            dw 0xFFFF                            ; limit  0:15
            dw 0x0000                            ; base   0:15
            db 0x00                              ; base  16:23
            db 0x92                              ; present, iopl/0, data, read/write
            db 0xCF                              ; 4Kbyte granularity, 32bit selector; limit 16:19
            db 0x00                              ; base  24:31
            
        .code16:                               ; 0x03 - 16bit code segment descriptor 0x000FFFFF
            dw 0xFFFF                            ; limit  0:15
            dw 0x0000                            ; base   0:15
            db 0x00                              ; base  16:23
            db 0x9A                              ; present, iopl/0, code, execute/read
            db 0x0F                              ; 1Byte granularity, 16bit selector; limit 16:19
            db 0x00                              ; base  24:31
            
        .data16:                               ; 0x04 - 16bit data segment descriptor 0x000FFFFF
            dw 0xFFFF                            ; limit  0:15
            dw 0x0000                            ; base   0:15
            db 0x00                              ; base  16:23
            db 0x92                              ; present, iopl/0, data, read/write
            db 0x0F                              ; 1Byte granularity, 16bit selector; limit 16:19
            db 0x00                              ; base  24:31
            
    gdt16_ptr:                               ; GDT table pointer for 16bit access
        dw gdt16_ptr - gdt16_base - 1          ; table limit (size)
        dd gdt16_base                          ; table base address
        
    int32_end:                               ; end marker (so we can copy the code)

and the only code befor in the kernel is my gdt init:

#include "../types/types.h"
#include "../lib/lib.h"

#define __GDT__
#include "gdt.h"

void init_gdt_desc(u32 base, u32 limite, u8 acces, u8 other,
                   struct gdtdesc *desc)
{
    desc->lim0_15 = (limite & 0xffff);
    desc->base0_15 = (base & 0xffff);
    desc->base16_23 = (base & 0xff0000) >> 16;
    desc->acces = acces;
    desc->lim16_19 = (limite & 0xf0000) >> 16;
    desc->other = (other & 0xf);
    desc->base24_31 = (base & 0xff000000) >> 24;
    return;
}

void init_gdt(void)
{
    
    default_tss.debug_flag = 0x00;
    default_tss.io_map = 0x00;
    default_tss.esp0 = 0x20000;
    default_tss.ss0 = 0x18;

    init_gdt_desc(0x0, 0x0, 0x0, 0x0, &kgdt[0]);
    init_gdt_desc(0x0, 0xFFFFF, 0x9B, 0x0D, &kgdt[1]);      
    init_gdt_desc(0x0, 0xFFFFF, 0x93, 0x0D, &kgdt[2]);    
    init_gdt_desc(0x0, 0x0, 0x97, 0x0D, &kgdt[3]);          

    //user segment
    init_gdt_desc(0x0, 0xFFFF, 0x9E, 0x0, &kgdt[4]); /* ucode */
    init_gdt_desc(0x0, 0xFFFF, 0x92, 0x0, &kgdt[5]); /* udata */
    //normal gdt
    //init_gdt_desc(0x0, 0xFFFFF, 0xFF, 0x0D, &kgdt[4]); /* ucode */
    //init_gdt_desc(0x0, 0xFFFFF, 0xF3, 0x0D, &kgdt[5]); /* udata */
    init_gdt_desc(0x0, 0x0, 0xF7, 0x0D, &kgdt[6]);      /* ustack */

    init_gdt_desc((u32) &default_tss, 0x67, 0xE9, 0x00, &kgdt[7]); /*TSS*/

    kgdtr.limite = GDTSIZE * 8;
    kgdtr.base = GDTBASE;

    memcpy((char *) kgdtr.base, (char *) kgdt, kgdtr.limite);

    asm("lgdtl (kgdtr)");

    asm("   movw $0x10, %ax \n \
            movw %ax, %ds       \n \
            movw %ax, %es       \n \
            movw %ax, %fs       \n \
            movw %ax, %gs       \n \
            ljmp $0x08, $next   \n \
            next:               \n");
}

If you need the bootloader script ask me in the comment

I just want a script to call the bios if someone want to give me an totally other script which work for me it's a good answer.

c
assembly
x86
operating-system
interrupt
asked on Stack Overflow Feb 8, 2021 by Konect Team • edited Feb 9, 2021 by Konect Team

0 Answers

Nobody has answered this question yet.


User contributions licensed under CC BY-SA 3.0