/*-
* Copyright (c) 2002-2018 The UbixOS Project.
* All rights reserved.
*
* This was developed by Christopher W. Olsen for the UbixOS Project.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted
* provided that the following conditions are met:
*
* 1) Redistributions of source code must retain the above copyright notice, this list of
* conditions, the following disclaimer and the list of authors.
* 2) Redistributions in binary form must reproduce the above copyright notice, this list of
* conditions, the following disclaimer and the list of authors in the documentation and/or
* other materials provided with the distribution.
* 3) Neither the name of the UbixOS Project nor the names of its contributors may be used to
* endorse or promote products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <ubixos/syscall.h>
#include <ubixos/syscall_posix.h>
#include <sys/idt.h>
#include <sys/gdt.h>
#include <sys/io.h>
#include <ubixos/sched.h>
#include <isa/8259.h>
#include <lib/kprintf.h>
#include <lib/kmalloc.h>
#include <vmm/vmm.h>
#include <ubixos/kpanic.h>
#include <ubixos/endtask.h>
#include <string.h>
#include <sys/trap.h>
#define FP_TO_LINEAR(seg, off) ((void*) ((((uint16_t) (seg)) << 4) + ((uint16_t) (off))))
static ubixDescriptorTable(ubixIDT, 256) {};
static struct {
unsigned short limit __attribute__((packed));
union descriptorTableUnion *idt __attribute__((packed));
} loadidt = { (256 * sizeof(union descriptorTableUnion) - 1), ubixIDT };
/************************************************************************
Function: int idtInit()
Description: This function is used to enable our IDT subsystem
Notes:
02/20/2004 - Approved for quality
************************************************************************/
int idt_init() {
struct tssStruct *sfTSS = (struct tssStruct *) 0x6200;
struct tssStruct *gpfTSS = (struct tssStruct *) 0x4200;
/* Load the IDT into the system */
asm volatile(
"cli \n"
"lidt (%0) \n" /* Load the IDT */
"pushfl \n" /* Clear the NT flag */
"andl $0xffffbfff,(%%esp) \n"
"popfl \n"
"sti \n"
:
: "r" ((char *)&loadidt)
);
/* Set up the basic vectors for the reserved ints */
setVector(_int0, 0, dPresent + dInt + dDpl0);
setVector(_int1, 1, dPresent + dInt + dDpl0);
setVector(_int2, 2, dPresent + dInt + dDpl0);
setVector(_int3, 3, dPresent + dInt + dDpl0);
setVector(_int4, 4, dPresent + dInt + dDpl0);
setVector(_int5, 5, dPresent + dInt + dDpl0);
setVector(_int6, 6, dPresent + dTrap + dDpl0);
setVector(_int7, 7, dPresent + dInt + dDpl0);
setTaskVector(8, dPresent + dTask + dDpl0, 0x40);
setVector(_int9, 9, dPresent + dInt + dDpl0);
setVector(_int10, 10, dPresent + dInt + dDpl0);
setVector(_int11, 11, dPresent + dInt + dDpl0);
setVector(_int12, 12, dPresent + dInt + dDpl0);
setTaskVector(13, dPresent + dTask + dDpl0, 0x38);
setVector(_vmm_pageFault, 14, dPresent + dInt + dDpl0);
setVector(_sys_call_posix, 0x80, dPresent + dTrap + dDpl3);
setVector(_sys_call, 0x81, dPresent + dTrap + dDpl3);
setVector(timerInt, 0x68, (dInt + dPresent + dDpl0));
gpfTSS->back_link = 0x0;
gpfTSS->esp0 = 0x0;
gpfTSS->ss0 = 0x0;
gpfTSS->esp1 = 0x0;
gpfTSS->ss1 = 0x0;
gpfTSS->esp2 = 0x0;
gpfTSS->ss2 = 0x0;
gpfTSS->cr3 = (unsigned int) kernelPageDirectory;
gpfTSS->eip = (unsigned int) &_int13;
gpfTSS->eflags = 0x206;
gpfTSS->esp = 0x1D000;
gpfTSS->ebp = 0x1D000;
gpfTSS->esi = 0x0;
gpfTSS->edi = 0x0;
gpfTSS->es = 0x10;
gpfTSS->cs = 0x08;
gpfTSS->ss = 0x10;
gpfTSS->ds = 0x10;
gpfTSS->fs = 0x10;
gpfTSS->gs = 0x10;
gpfTSS->ldt = 0x0;
gpfTSS->trace_bitmap = 0x0000;
gpfTSS->io_map = 0x8000;
memset(sfTSS, 0x0, sizeof(struct tssStruct));
sfTSS->cr3 = (unsigned int) kernelPageDirectory;
sfTSS->eip = (unsigned int) &_int8;
sfTSS->eflags = 0x206;
sfTSS->esp = 0x1C000;
sfTSS->ebp = 0x1C000;
sfTSS->es = 0x10;
sfTSS->cs = 0x08;
sfTSS->ss = 0x10;
sfTSS->ds = 0x10;
sfTSS->fs = 0x10;
sfTSS->gs = 0x10;
sfTSS->io_map = 0x8000;
/* Print out information for the IDT */
kprintf("idt0 - Address: [0x%X]\n", &ubixIDT);
/* Return so we know all went well */
return (0x0);
}
/* Sets Up IDT Vector */
void setVector(void *handler, unsigned char interrupt, unsigned short controlMajor) {
unsigned short codesegment = 0x08;
asm volatile ("movw %%cs,%0":"=g" (codesegment));
ubixIDT[interrupt].gate.offsetLow = (unsigned short) (((unsigned long) handler) & 0xffff);
ubixIDT[interrupt].gate.selector = codesegment;
ubixIDT[interrupt].gate.access = controlMajor;
ubixIDT[interrupt].gate.offsetHigh = (unsigned short) (((unsigned long) handler) >> 16);
}
/************************************************************************
Function: void setTaskVector(uInt8,uInt16,uInt8);
Description: This Function Sets Up An IDT Task Vector
Notes:
************************************************************************/
void setTaskVector(uInt8 interrupt, uInt16 controlMajor, uInt8 selector) {
uInt16 codesegment = 0x08;
asm volatile ("movw %%cs,%0":"=g" (codesegment));
ubixIDT[interrupt].gate.offsetLow = 0x0;
ubixIDT[interrupt].gate.selector = selector;
ubixIDT[interrupt].gate.access = controlMajor;
ubixIDT[interrupt].gate.offsetHigh = 0x0;
}
/* Null Intterupt Descriptor */
void intNull() {
kprintf("Invalid Interrupt[%i]\n", _current->id);
}
asm(
".globl _int0 \n"
"_int0: \n"
" pushl $0x0 \n"
" pushl $0x6 \n"
" pushal \n" /* Save all registers */
" push %ds \n"
" push %es \n"
" push %fs \n"
" push %gs \n"
" push %esp \n"
" call __int0 \n"
" pop %gs \n"
" pop %fs \n"
" pop %es \n"
" pop %ds \n"
" popal \n"
" iret \n" /* Exit interrupt */
);
void __int0(struct trapframe *frame) {
die_if_kernel("Divid-by-Zer0", frame, 0);
kpanic("int0: Divide-by-Zero [%i]\n", _current->id);
endTask(_current->id);
sched_yield();
}
void _int1() {
kpanic("int1: Debug exception [%i]\n", _current->id);
endTask(_current->id);
sched_yield();
}
void _int2() {
kpanic("int2: unknown error [%i]\n", _current->id);
endTask(_current->id);
sched_yield();
}
void _int3() {
kpanic("int3: Breakpoint [%i]\n", _current->id);
endTask(_current->id);
sched_yield();
}
void _int4() {
kpanic("int4: Overflow [%i]\n", _current->id);
endTask(_current->id);
sched_yield();
}
void _int5() {
kpanic("int5: Bounds check [%i]\n", _current->id);
endTask(_current->id);
sched_yield();
}
asm(
".globl _int6 \n"
"_int6: \n"
" pushl $0x0 \n"
" pushl $0x6 \n"
" pushal \n" /* Save all registers */
" push %ds \n"
" push %es \n"
" push %fs \n"
" push %gs \n"
" push %esp \n"
" call __int6 \n"
" pop %gs \n"
" pop %fs \n"
" pop %es \n"
" pop %ds \n"
" popal \n"
" iret \n" /* Exit interrupt */
);
void __int6(struct trapframe *frame) {
die_if_kernel("invalid_opcode", frame, 6);
endTask(_current->id);
sched_yield();
}
void _int8() {
struct tssStruct *sfTSS = (struct tssStruct *) 0x6200;
kpanic("int8: Double Fault! [%i]\n", _current->id);
sfTSS->cr3 = (unsigned int) kernelPageDirectory;
sfTSS->eip = (unsigned int) &_int8;
sfTSS->eflags = 0x206;
sfTSS->esp = 0x1C000;
sfTSS->ebp = 0x1C000;
sfTSS->es = 0x10;
sfTSS->cs = 0x08;
sfTSS->ss = 0x10;
sfTSS->ds = 0x10;
sfTSS->fs = 0x10;
sfTSS->gs = 0x10;
sfTSS->io_map = 0x8000;
while (1)
asm("nop");
}
void _int9() {
kpanic("int9: Coprocessor Segment Overrun! [%i]\n", _current->id);
endTask(_current->id);
sched_yield();
}
void _int10() {
kpanic("int10: Invalid TSS! [%i]\n", _current->id);
endTask(_current->id);
sched_yield();
}
void _int11() {
kpanic("int11: Segment Not Present! [%i]\n", _current->id);
endTask(_current->id);
sched_yield();
}
void _int12() {
kpanic("int12: Stack-Segment Fault! [%i]\n", _current->id);
endTask(_current->id);
sched_yield();
}
void _int13() {
uint8_t *ip = 0x0;
uint16_t *stack = 0x0, *ivt = 0x0;
uint32_t *stack32 = 0x0;
bool isOperand32 = FALSE, isAddress32 = FALSE;
struct tssStruct *gpfTSS = (struct tssStruct *) 0x4200;
irqDisable(0x0);
gpfTSS->eip = (unsigned int) &_int13;
gpfTSS->esp = 0x1D000;
gpfTSS->ebp = 0x1D000;
gpfTSS->eflags = 0x206;
ip = FP_TO_LINEAR(_current->tss.cs, _current->tss.eip);
ivt = (uInt16 *) 0x0;
stack = (uInt16 *) FP_TO_LINEAR(_current->tss.ss, _current->tss.esp);
stack32 = (uInt32 *) stack;
gpfStart: switch (ip[0]) {
case 0xCD: /* INT n */
switch (ip[1]) {
case 0x69:
kprintf("Exit Bios [0x%X]\n", _current->id);
_current->state = DEAD;
break;
case 0x20:
case 0x21:
kpanic("GPF OP 0x20/0x21\n");
break;
default:
stack -= 3;
_current->tss.esp = ((_current->tss.esp & 0xffff) - 6) & 0xffff;
stack[0] = (uInt16) (_current->tss.eip + 2);
stack[1] = _current->tss.cs;
stack[2] = (uInt16) _current->tss.eflags;
if (_current->oInfo.v86If)
stack[2] |= EFLAG_IF;
else
stack[2] &= ~EFLAG_IF;
_current->tss.cs = ivt[ip[1] * 2 + 1] & 0xFFFF;
_current->tss.eip = ivt[ip[1] * 2] & 0xFFFF;
break;
}
break;
case 0x66:
isOperand32 = TRUE;
ip++;
_current->tss.eip = (uInt16) (_current->tss.eip + 1);
goto gpfStart;
break;
case 0x67:
isAddress32 = TRUE;
ip++;
_current->tss.eip = (uInt16) (_current->tss.eip + 1);
goto gpfStart;
break;
case 0xF0:
_current->tss.eip = (uInt16) (_current->tss.eip + 1);
kpanic("GPF OP 0xF0\n");
break;
case 0x9C:
if (isOperand32 == TRUE) {
_current->tss.esp = ((_current->tss.esp & 0xffff) - 4) & 0xffff;
stack32--;
stack32[0] = _current->tss.eflags & 0xDFF;
if (_current->oInfo.v86If == TRUE)
stack32[0] |= EFLAG_IF;
else
stack32[0] &= ~EFLAG_IF;
}
else {
_current->tss.esp = ((_current->tss.esp & 0xffff) - 2) & 0xffff;
stack--;
stack[0] = (uInt16) _current->tss.eflags;
if (_current->oInfo.v86If == TRUE)
stack[0] |= EFLAG_IF;
else
stack[0] &= ~EFLAG_IF;
_current->tss.eip = (uInt16) (_current->tss.eip + 1);
}
break;
case 0x9D:
if (isOperand32 == TRUE) {
_current->tss.eflags = EFLAG_IF | EFLAG_VM | (stack32[0] & 0xDFF);
_current->oInfo.v86If = (stack32[0] & EFLAG_IF) != 0;
_current->tss.esp = ((_current->tss.esp & 0xffff) + 4) & 0xffff;
}
else {
_current->tss.eflags = EFLAG_IF | EFLAG_VM | stack[0];
_current->oInfo.v86If = (stack[0] & EFLAG_IF) != 0;
_current->tss.esp = ((_current->tss.esp & 0xffff) + 2) & 0xffff;
}
_current->tss.eip = (uInt16) (_current->tss.eip + 1);
/* kprintf("popf [0x%X]\n",_current->id); */
break;
case 0xFA:
_current->oInfo.v86If = FALSE;
_current->tss.eflags &= ~EFLAG_IF;
_current->tss.eip = (uInt16) (_current->tss.eip + 1);
_current->oInfo.timer = 0x1;
break;
case 0xFB:
_current->oInfo.v86If = TRUE;
_current->tss.eflags |= EFLAG_IF;
_current->tss.eip = (uInt16) (_current->tss.eip + 1);
_current->oInfo.timer = 0x0;
/* kprintf("sti [0x%X]\n",_current->id); */
break;
case 0xCF:
_current->tss.eip = stack[0];
_current->tss.cs = stack[1];
_current->tss.eflags = EFLAG_IF | EFLAG_VM | stack[2];
_current->oInfo.v86If = (stack[2] & EFLAG_IF) != 0;
_current->tss.esp = ((_current->tss.esp & 0xffff) + 6) & 0xffff;
/* kprintf("iret [0x%X]\n",_current->id); */
break;
case 0xEC: /* IN AL,DX */
_current->tss.eax = (_current->tss.eax & ~0xFF) | inportByte(_current->tss.edx);
_current->tss.eip = (uInt16) (_current->tss.eip + 1);
break;
case 0xED: /* IN AX,DX */
_current->tss.eax = (_current->tss.eax & ~0xFFFF) | inportWord(_current->tss.edx);
_current->tss.eip = (uInt16) (_current->tss.eip + 1);
break;
case 0xEE: /* OUT DX,AL */
outportByte(_current->tss.edx, _current->tss.eax & 0xFF);
_current->tss.eip = (uInt16) (_current->tss.eip + 1);
break;
case 0xEF:
outportWord(_current->tss.edx, _current->tss.eax);
_current->tss.eip = (uInt16) (_current->tss.eip + 1);
break;
case 0xF4:
_current->tss.eip = (uInt16) (_current->tss.eip + 1);
break;
default: /* something wrong */
kprintf("NonHandled OpCode [0x%X:0x%X]\n", _current->id, ip[0]);
_current->state = DEAD;
break;
}
irqEnable(0);
while (1)
;
}
/* Removed static however this is the only place it's called from */
void mathStateRestore() {
if (_usedMath != 0x0) {
asm(
"fnsave %0"
:
: "m" (_usedMath->i387)
);
}
if (_current->usedMath != 0x0) {
asm(
"frstor %0"
:
: "m" (_current->i387)
);
}
else {
asm("fninit");
_current->usedMath = 0x1;
}
_usedMath = _current;
//Return
}
void _int7();
asm(
".globl _int7 \n"
"_int7: \n"
" pushl %eax \n"
" clts \n"
" movl _current,%eax \n"
" cmpl _usedMath,%eax \n"
" je mathDone \n"
" call mathStateRestore \n"
"mathDone: \n"
" popl %eax \n"
" iret \n"
);