So as not to create a specific driver for each FD / HD / CD, I thought of using the INT 13H BIOS, read the memory information using INT 15H and INT 16H use for the keyboard keys, implementing a Virtual 8086 handler. My Virtual 8086 Handler is as follows:
Code: Select all
typedef struct
{
unsigned int ds, es, fs, gs;
unsigned int edi, esi, ebp, esp, ebx, edx, ecx, eax;
unsigned int intNo, errCode;
unsigned int eip;
unsigned int cs, eflags;
unsigned int uesp, ss;
} Registers;
typedef struct
{
unsigned int ds, es, fs, gs;
unsigned int edi, esi, ebp, esp, ebx, edx, ecx, eax;
unsigned int intNo, errCode;
unsigned int eip;
unsigned int cs, eflags;
unsigned int vesp, ss;
unsigned int ves, vds, vfs, vgs;
} VirtualRegisters;
typedef struct
{
Registers * regs;
unsigned long stack;
} State;
typedef struct
{
unsigned short ax, bx, cx, dx;
unsigned short ds, es, fs, gs;
unsigned short di, si, bp, sp;
unsigned short flags;
} VirtualContext;
#define VIRTUAL_CMD_O32 0x66
#define VIRTUAL_CMD_A32 0x67
#define VIRTUAL_CMD_NOP 0x90
#define VIRTUAL_CMD_PUSHF 0x9C
#define VIRTUAL_CMD_POPF 0x9D
#define VIRTUAL_CMD_INT 0xCD
#define VIRTUAL_CMD_IRET 0xCF
#define VIRTUAL_CMD_HLT 0xF4
#define VIRTUAL_CMD_CLI 0xFA
#define VIRTUAL_CMD_STI 0xFB
#define VIRTUAL_CMD_INB 0xEC
#define VIRTUAL_CMD_INW 0xED
#define VIRTUAL_CMD_OUTB 0xEE
#define VIRTUAL_CMD_OUTW 0xEF
#define VIRTUAL_CMD_EFLAGS_IF (1 << 9)
#define VIRTUAL_CMD_EFLAGS_VM (1 << 17)
#define VIRTUAL_VALID_EFLAGS 0x7FFF
#define VIRTUAL_NP_TO_LINEAR(seg, off) ((void *) ((seg & 0xFFFF) << 4) + (off & 0xFFFF))
#define VIRTUAL_FP_TO_LINEAR(addr) ((void *) ((addr & 0xFFFF0000) >> 12) + (addr & 0xFFFF))
#define callVirtual() asm("int $0x00")
static int vif = 1;
unsigned long stack;
void handlerVirtual(State * state)
{
unsigned char * ip = VIRTUAL_NP_TO_LINEAR(state->regs->cs, state->regs->eip);
unsigned short * stack16 = VIRTUAL_NP_TO_LINEAR(state->regs->ss, state->regs->uesp);
unsigned int * stack32 = (unsigned int *) stack16;
int done, o32;
done = o32 = 0;
while (!done)
{
switch (* ip)
{
case VIRTUAL_CMD_O32:
{
o32 = 1;
ip++;
state->regs->eip++;
}
break;
case VIRTUAL_CMD_A32:
{
ip++;
state->regs->eip++;
}
break;
case VIRTUAL_CMD_PUSHF:
{
if (o32)
{
stack32--;
stack32[0] = state->regs->eflags & VIRTUAL_VALID_EFLAGS;
if (vif)
stack32[0] |= VIRTUAL_CMD_EFLAGS_IF;
else
stack32[0] &= ~VIRTUAL_CMD_EFLAGS_IF;
state->regs->uesp -= 4;
}
else
{
stack16--;
stack16[0] = state->regs->eflags;
if (vif)
stack16[0] |= VIRTUAL_CMD_EFLAGS_IF;
else
stack16[0] &= ~VIRTUAL_CMD_EFLAGS_IF;
state->regs->uesp -= 2;
}
state->regs->eip++;
done = 1;
}
break;
case VIRTUAL_CMD_POPF:
{
if (o32)
{
state->regs->eflags = VIRTUAL_CMD_EFLAGS_VM | (stack32[0] & VIRTUAL_VALID_EFLAGS);
state->regs->uesp += 4;
vif = ((stack32[0] & VIRTUAL_CMD_EFLAGS_IF) != 0);
}
else
{
state->regs->eflags = VIRTUAL_CMD_EFLAGS_VM | stack16[0];
state->regs->uesp += 2;
vif = ((stack16[0] & VIRTUAL_CMD_EFLAGS_IF) != 0);
}
state->regs->eip++;
done = 1;
}
break;
case VIRTUAL_CMD_INT:
{
unsigned short * ivt = (unsigned short *) 0x00;
stack16 -= 3;
state->regs->uesp -= 6;
stack16[0] = state->regs->eip + 2;
stack16[1] = state->regs->cs;
stack16[2] = state->regs->eflags;
if (vif)
stack16[2] |= VIRTUAL_CMD_EFLAGS_IF;
else
stack16[2] &= ~VIRTUAL_CMD_EFLAGS_IF;
state->regs->cs = ivt[(ip[1] << 1) + 1];
state->regs->eip = ivt[ip[1] << 1];
done = 1;
}
break;
case VIRTUAL_CMD_IRET:
{
state->regs->eip = stack16[0];
state->regs->cs = stack16[1];
state->regs->eflags = VIRTUAL_CMD_EFLAGS_VM | VIRTUAL_CMD_EFLAGS_IF | stack16[2];
state->regs->uesp += 6;
vif = ((stack16[2] & VIRTUAL_CMD_EFLAGS_IF) != 0);
done = 1;
}
break;
case VIRTUAL_CMD_CLI:
{
state->regs->eip++;
vif = 0;
state->regs->eflags &= ~VIRTUAL_CMD_EFLAGS_IF;
done = 1;
}
break;
case VIRTUAL_CMD_STI:
{
state->regs->eip++;
vif = 1;
state->regs->eflags |= VIRTUAL_CMD_EFLAGS_IF;
done = 1;
}
break;
case VIRTUAL_CMD_INB:
{
state->regs->eax = inb(state->regs->edx);
state->regs->eip++;
done = 1;
}
break;
case VIRTUAL_CMD_OUTB:
{
outb(state->regs->edx, state->regs->eax);
state->regs->eip++;
done = 1;
}
break;
case VIRTUAL_CMD_INW:
{
state->regs->eax = inw(state->regs->edx);
state->regs->eip++;
done = 1;
}
break;
case VIRTUAL_CMD_OUTW:
{
if (o32)
outw(state->regs->edx, state->regs->eax);
else
outw(state->regs->edx, state->regs->eax);
state->regs->eip++;
done = 1;
}
break;
case VIRTUAL_CMD_NOP:
{
state->regs->eip++;
done = 1;
}
break;
case VIRTUAL_CMD_HLT:
{
state->stack = stack;
done = 1;
}
break;
default:
{
printf("%X\n", * ip);
state->stack = stack;
done = 1;
}
break;
}
}
}
One more thing, also implemented a way to return to the "Real Mode" in my bootloader. It would be better to return to the RMODE to use BIOS functions, instead use the monitor V86?
Note: This code would only be used in the boot loader in my kernel I would not use THIS FORM.