/* Video.c, Copyright (c) by Lukas Ruf, lr@lpr.ch, Swiss Federal Institute of Technology, Computer Engineering and Networks Laboratory. TOPSY -- A Teachable Operating System. Implementation of a tiny and simple micro kernel for teaching purposes. For further information, please visit http://www.tik.ee.ethz.ch/~topsy This software is provided under the terms of the GNU General Public Licence. A full copy of the GNU GPL is provided in the file COPYING found in the development root of Topsy. */ /* File: $Source: /usr/drwho/vault/cvs/topsy/Topsy/IO/Drivers/ia32/Video.c,v $ Author(s): Lukas Ruf, lr@lpr.ch Affiliation: ETH Zuerich, TIK Version: $Revision: 1.3 $ Creation Date: Last Date of Change: $Date: 2000/06/05 15:05:36 $ by: $Author: ruf $ $Log: Video.c,v $ Revision 1.3 2000/06/05 15:05:36 ruf *** empty log message *** Revision 1.2 1999/12/13 21:48:27 ruf GNU General Public Licence Update Revision 1.1 1999/06/06 20:58:32 jeker putting everything together for Topsy 2.0 Revision 1.1 1999/05/13 17:05:30 jeker Initial revision */ #include "Tools.h" #include "Video.h" #include "video.h" #include "SupportAsm.h" /* This needs being included for resolving the "variable argument list" */ #include #include "tm-include.h" #define KILO 1024 static VideoT AtCursor; static WindowT vWindow; #define vIOBUFFERSIZE KILO #define DEBUGwVIDEO #define DEBUGwCONTEXT static char vIOBuffer[vIOBUFFERSIZE]; static char vIODebugBuffer[vIOBUFFERSIZE]; static long vMutex; #define PRINTLOCK 0 #define DEBUGLOCK 1 #define OUTPUTLOCK 2 #define KPRINTLOCK 3 void VideoInit() { vWindow.X1 = 0; vWindow.Y1 = 0; vWindow.X2 = 79; vWindow.Y2 = 23; // preserve space for status line AtCursor.X = vWindow.X1; AtCursor.Y = vWindow.Y1; AtCursor.TextAttr = 0x1F; vMutex = 0; return; } void Printstr(long pY, long pX, char pTextAttr, char *ps) { long lXY = pY*80*2 + pX*2; if (ps) for (;(*ps && (lXY < 3999));ps++) { __printchar(lXY,pTextAttr,(char)*ps); lXY+=2; } return; } unsigned char TextAttr(unsigned char pNewAttr) { char xold = AtCursor.TextAttr; AtCursor.TextAttr = pNewAttr; return xold; } void GotoYX(char pY, char pX) { pY += vWindow.Y1; pX += vWindow.X1; AtCursor.Y = pY % (vWindow.Y2+1); AtCursor.X = pX % (vWindow.X2+1); return; } unsigned char GetTextAttr() { return AtCursor.TextAttr; } void WhereYX(char *pY, char *pX) { *pY = AtCursor.Y; *pX = AtCursor.X; return; } void WindowState(char *pY1, char *pX1, char *pY2, char *pX2, char *pAttr) { *pY1 = vWindow.Y1; *pX1 = vWindow.X1; *pY2 = vWindow.Y2; *pX2 = vWindow.X2; *pAttr = AtCursor.TextAttr; return; } void Window(char pY1, char pX1, char pY2, char pX2) { pY1 %= 24; pX1 %= 80; pY2 %= 24; pX2 %= 80; if ((pY2 > pY1) && (pX2 > pX1)) { vWindow.Y1 = pY1; vWindow.X1 = pX1; vWindow.Y2 = pY2; vWindow.X2 = pX2; AtCursor.X = vWindow.X1; AtCursor.Y = vWindow.Y1; } return; } void ClearScreen() { long y; for (y = vWindow.Y1; (y <= vWindow.Y2); y++) __clearLine((y*80+vWindow.X1) << 1, vWindow.X2-vWindow.X1 + 1, AtCursor.TextAttr); AtCursor.X = vWindow.X1; AtCursor.Y = vWindow.Y1; return; } void SaveScreen(char *pBuff, char pY1, char pX1, char pY2, char pX2) { long y; pX1 %= 80; pY1 %= 24; pX2 %= 80; pY2 %= 24; for (y = pY1; (y <= pY2); y++) __getWindowLine(&(pBuff[(y-pY1)*(pX2-pX1+1)*2]),(y*80+pX1)<<1, pX2-pX1+1); return; } void RestoreScreen(char *pBuff, char pY1, char pX1, char pY2, char pX2) { long y; pX1 %= 80; pY1 %= 24; pX2 %= 80; pY2 %= 24; for (y = pY1; (y <= pY2); y++) __setWindowLine(&(pBuff[(y-pY1)*(pX2-pX1+1)*2]),(y*80+pX1)<<1, pX2-pX1+1); return; } void ScrollWindowUp() { __scrollWindowUp((vWindow.Y1*80 + vWindow.X1)*2, vWindow.Y2-vWindow.Y1, vWindow.X2-vWindow.X1 + 1, AtCursor.TextAttr); return; } void kprintc(char pc) { unsigned short lpos; __mutex(&vMutex,KPRINTLOCK); lpos = (AtCursor.Y*80+AtCursor.X) * 2; if (pc == '\n') AtCursor.X=vWindow.X2+1; else { if (lpos < 3999) __printchar(lpos,AtCursor.TextAttr,pc); AtCursor.X++; } if (AtCursor.X > vWindow.X2) { AtCursor.Y++; AtCursor.X=vWindow.X1; } if (AtCursor.Y > vWindow.Y2) { AtCursor.Y=vWindow.Y2; ScrollWindowUp(); } __setCursor((unsigned long)(AtCursor.X+AtCursor.Y*80)); __demutex(&vMutex,KPRINTLOCK); return; } void kprintf(char *ps) { if (!ps) ps = "(null)"; while (*ps) { kprintc(*ps); ps++; } return; } /* -- LR, 20000422 = renamed to avoid conflicts with Support.c */ void k_vsprintf(char *buffer, char *fmt, va_list ap) { char *s, c, ih[12]; int i,x = 0, len = 0; while (*fmt) { if (x >= vIOBUFFERSIZE) break; if (*fmt == '%') { fmt++; if ((*fmt >= '0') && (*fmt <= '9')) { i = 0; len = 0; while ((fmt[i] >= '0') && (fmt[i] <= '9')) len = len*10 + (fmt[i++] - '0'); if (((fmt[i] == 'c') || (fmt[i] == 's') || (fmt[i] == 'i') || (fmt[i] == 'x'))) fmt += i; // if not legal modifier -> print format string } switch (*fmt) { case 'c' : c = va_arg(ap, char); buffer[x++] = c; break; case 's' : s = va_arg(ap, char *); if (!s) s = "(null)"; i = 0; while (s[i]) buffer[x++] = (s[i++]); break; case 'i' : len %= 13; i = va_arg(ap, int); if (len) itoal(i,ih,(char)len); else itoa(i,ih); i = 0; while (ih[i]) buffer[x++] = ih[i++]; break; case 'x' : len %= 9; i = va_arg(ap, int); if (len) itoahl(i,ih,(char)len); else itoah(i,ih); i = 0; while (ih[i]) buffer[x++] = ih[i++]; break; default : buffer[x++] = '%'; buffer[x++] = *fmt; break; } } else buffer[x++] = *fmt; fmt++; len = 0; } buffer[x] = 0; return; } void printf(char *fmt, ...) { va_list ap; va_start(ap, fmt); k_vsprintf(vIOBuffer,fmt,ap); kprintf(vIOBuffer); va_end(ap); return; } void Debug(char *fmt, ...) { #ifdef DEBUGwVIDEO va_list ap; va_start(ap, fmt); k_vsprintf(vIODebugBuffer,fmt,ap); kprintf(vIODebugBuffer); va_end(ap); #endif return; } void sprintf(char *pbuff, char *fmt, ...) { va_list ap; va_start(ap, fmt); k_vsprintf(pbuff,fmt,ap); va_end(ap); return; } void DisplayContext(char *ps, ProcContextPtr ctx) { printf("%s\n",ps); printf("addr(ProcContext) = 0x%8x\n",(unsigned int)ctx); if (((unsigned int)ctx < 0x8000) || ((unsigned int)ctx > 256*KILO)) { printf("Context Address looks strange to me: 0x%8x\n",(unsigned int)ctx); asm(" movl %esp,%eax ; \ movl $0x70000,%esp ; \ pushl %eax ; \ pushl %esp ; \ call DumpStack "); /* set exception stack */ printf(" Something went completely wrong :-( \n"); asm(" hlt "); } #ifdef DEBUGwCONTEXT printf("EAX 0x%8x EBX 0x%8x ECX 0x%8x EDX 0x%8x\n", ctx->tf_eax, ctx->tf_ebx, ctx->tf_ecx, ctx->tf_edx); printf("CS 0x%8x DS 0x%8x ES 0x%8x FS 0x%8x\n", ctx->tf_cs , ctx->tf_ds , ctx->tf_es , ctx->tf_fs ); printf("GS 0x%8x SS 0x%8x EIP 0x%8x EF 0x%8x\n", ctx->tf_gs , ctx->tf_ss , ctx->tf_eip, ctx->tf_eflags); printf("ESP 0x%8x EBP 0x%8x EDI 0x%8x ESI 0x%8x\n", ctx->tf_esp, ctx->tf_ebp, ctx->tf_edi, ctx->tf_esi); printf("tSP 0x%8x trp 0x%8x err 0x%8x size 0x%8x\n", ctx->tf_temp_esp, ctx->tf_trapno, ctx->tf_err, sizeof(ProcContext)); #endif ERROR("DISPLAYCONTEXT"); return; } void MemoryDump(char *ps,unsigned int Addr) { int i, lpos; char *c = (char *)Addr; printf("Dumping \"%s\" at 0x%8x\n",ps,Addr); for (i = 0; (i < 10*80); i++) { lpos = (AtCursor.Y*80+AtCursor.X) * 2; if (lpos < 3999) __printchar(lpos,AtCursor.TextAttr,c[i]); AtCursor.X++; if (AtCursor.X > vWindow.X2) { AtCursor.Y++; AtCursor.X=vWindow.X1; } if (AtCursor.Y > vWindow.Y2) { AtCursor.Y=vWindow.Y2; ScrollWindowUp(); } } printf("\"%s\" successfully dumped :-)\n",ps); } void DumpStack(unsigned int esp); void DumpStack(unsigned int esp) { char *stack; int i; stack = (char *)(esp - 32); printf("Stack Dump: esp:[esp] // orig esp = 0x%8x // esp = 0x%8x // esp+0x%x",(unsigned int)esp,(unsigned int)stack,32); for (i = 0; i < 32; i++) { if (!(i % 3)) printf("\n"); printf("0x%2x:0x%8x ",i*4,*stack); stack+=4; } printf("\n"); }