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.
User contributions licensed under CC BY-SA 3.0