/*- * 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" );