📄 cons_vesa.cxx
字号:
/* * Copyright (C) 2001, Jonathan S. Shapiro, Michael Hilsdale. * * This file is part of the EROS Operating System. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2, * or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *//* Implementation of the kernel frame buffer console logic. We make * the simplifying assumption here that the console is a VGA * (640x480x256) display. If the machine-specific initialization code * has somehow placed the display buffer in some other state (e.g. we * have a large VESA display or some such), then it is the * responsibility of the machine-specific code to suitably place a * 640x480 bitmap somewhere on the tube. Remember that this console * isn't going to get used for very long -- only until the user-mode * console driver takes over the world. */#include <kerninc/kernel.hxx>#include <kerninc/Console.hxx>#include <kerninc/MsgLog.hxx>#include <disk/DiskKey.hxx>#include <kerninc/BootInfo.h>#include <kerninc/Machine.hxx>#include "oslogo.h"#include "logosm.h"#define cursor() if(TheConsVESA.curOn) Put(TheConsVESA.cursor, col, row, true)#ifdef OLD_SCREEN/*1024x768x32 = VMware mode 0x4022*/#define XRES 1024#define YRES 768#define BPP 32#define BPSL 6400#define BASE 0x40151C80;static uint8_t *screen = (uint8_t *) PTOV(0xA0000u);#define PIX(x, y, c) (*((uint32_t *) (screen + ((uint32_t) (y) * TheConsVESA.bpsl + (x) * ((TheConsVESA.bpp + 7) / 8)))) = c)#else#define PIX(x, y, c) (*((uint32_t *) (Machine::frameBuffer + ((uint32_t) (y) * TheConsVESA.bpsl + (x) * ((TheConsVESA.bpp + 7) / 8)))) = c)#define XORPIX(x, y, c) (*((uint32_t *) (Machine::frameBuffer + ((uint32_t) (y) * TheConsVESA.bpsl + (x) * ((TheConsVESA.bpp + 7) / 8)))) ^= c)#endifvoid drawHeader();void drawLogo(const uint16_t x, const uint16_t y);void drawLogo2(const uint16_t x, const uint16_t y);void animate();void putPixel(const uint16_t x, const uint16_t y, const uint32_t color);/*#define STABLE_CONFIG*/struct ConsVESA: public Console{ /* screen information */ uint16_t xres; uint16_t yres; uint16_t bpp; uint16_t bpsl; /*uint16_t base;*/ /* 1-based indexing */ uint8_t col; uint8_t row; /* screen borders */ /* (not hard-coding them allows future flexibility) */ uint16_t baseCol; uint16_t baseRow; uint16_t maxCol; uint16_t maxRow; /* fb type */ uint8_t linfb; /* 0 = windowed; 1 = linear */ /* cursor info */ uint8_t curOn; /* 0 = cursor off; 1 = cursor on */ uint8_t cursor; /* ASCII char of cursor */ void Clear(); void Put(uint8_t c); void Put(uint8_t c, uint16_t c, uint16_t r, bool xor = false); void SetFrameBuffer(kva_t); void Scroll(); /* FIX: Make toggle separate from glyph change */ void SetCursor(uint8_t toggle, int16_t c = -1); int16_t GetCursor();};ConsVESA TheConsVESA; /* common cursors: 1 smiley 95 underscore 177 hash 255 custom */struct cursor { enum { smiley = 1, underscore = 95, /* hash = 177, */ block = 219, custom = 255, kangaroo = 255, };};boolConsole::InitVESA(){#ifdef OPTION_VESA_CONSOLE /* hack: make logos work correctly */ /* Gimp macro resets the header_data pointers each time it uses it. */ /* Thus, pointer needs to be reset each time the logo is redrawn. */ orig_header_data = header_data; orig_header_data2 = header_data2; if (!BootInfoPtr->useGraphicsFB) return false; if (BootInfoPtr->consInfo->isBanked) { TheConsVESA.linfb = 0; return false; /* temporary; might even need to remove for debug */ } else TheConsVESA.linfb = 1; /* set cursor information */ TheConsVESA.SetCursor(1, cursor::block); /* set the screen parameters */#ifdef OLD_SCREEN screen = (unsigned char *) TheConsVESA.base;#else Machine::frameBuffer = BootInfoPtr->consInfo->frameBuffer; TheConsVESA.xres = BootInfoPtr->consInfo->Xlimit; TheConsVESA.yres = BootInfoPtr->consInfo->Ylimit; TheConsVESA.bpp = BootInfoPtr->consInfo->bpp; TheConsVESA.bpsl = BootInfoPtr->consInfo->bytesPerScanLine;#endif TheConsVESA.baseCol = 1; TheConsVESA.baseRow = 1; TheConsVESA.maxCol = TheConsVESA.xres/8; TheConsVESA.maxRow = TheConsVESA.yres/16; TheConsVESA.col = TheConsVESA.baseCol; TheConsVESA.row = TheConsVESA.baseRow; TheConsVESA.Clear(); drawHeader();#if 0 { unsigned a; /* run through the entire font */ for (a = 0; a < 0xff; a++) { TheConsVESA.Put(a); } }#endif MsgLog::RegisterSink(&TheConsVESA); /*MsgLog::printf("baseCol: %d\n",TheConsVESA.baseCol); MsgLog::printf("baseRow: %d\n",TheConsVESA.baseRow); MsgLog::printf("maxCol : %d\n",TheConsVESA.maxCol); MsgLog::printf("maxRow : %d\n",TheConsVESA.maxRow);*/ return true;#else return false;#endif}voidConsVESA::Put(uint8_t c){ int16_t oldCursor = GetCursor(); /* Erase cursor */ if(TheConsVESA.curOn) cursor(); /* special handling for LF so that CR LF doesn't overwrite first char of previous line with cursor */ if(c==ASCII::LF) /* LF */ { if(row==TheConsVESA.maxRow) Scroll(); else row++; TheConsVESA.SetCursor(1, cursor::kangaroo); cursor(); return; } /* Until otherwise proven: */ TheConsVESA.SetCursor(1, cursor::block); /* Handle special chars here */ switch(c) { case ASCII::NUL: /* NUL */ TheConsVESA.SetCursor(1, oldCursor); cursor(); return; case ASCII::BEL: /* BEL */ /* TODO: handle BEL */ TheConsVESA.SetCursor(1, oldCursor); cursor(); return; case ASCII::BS: /* BS */ if (col != TheConsVESA.baseCol) col--; /* we're not going to jump up lines */ /* Wrongo, moose breath. Backspace impacts the cursor. Only. */#if 0 Put(ASCII::SPC, col, row); /* needed in case cursor is disabled */#endif cursor(); return; case ASCII::TAB: /* HT */ col += 5; if(col > TheConsVESA.maxCol) { col -= TheConsVESA.maxCol; if(row==TheConsVESA.maxRow) Scroll(); else row++; } TheConsVESA.SetCursor(1, oldCursor); cursor(); return;#if 0 case ASCII::SPC: { if (TheConsVESA.GetCursor() == cursor::kangaroo && !(col % 8)) c = '.'; /* kangaroo turds :-) */ break; }#endif case ASCII::CR: /* CR */ col = TheConsVESA.baseCol; cursor(); return;#if 0 case 255: /* why the heck is ASCII 255 a space? You are the weakest link...goodbye. (tm) */ cursor(); return;#endif default: if(c < 32 || c > 255) /* should probably not keep this in code */ { TheConsVESA.SetCursor(1, oldCursor); cursor(); return; } } /* Draw the actual character */ Put(c, col, row); /* Increment cursor position */ col++; /* col should never be > (TheConsVESA.maxCol + 1) at this point */ if(col == TheConsVESA.maxCol+1) { col = TheConsVESA.baseCol; if(row==TheConsVESA.maxRow) Scroll(); else row++; } /* Print cursor */ TheConsVESA.SetCursor(1, oldCursor); cursor();}voidConsVESA::Put(uint8_t c, uint16_t cl, uint16_t rw, bool xor){ uint16_t i, j; uint16_t x, y; signed long int l; if(cl < TheConsVESA.baseCol || cl > TheConsVESA.maxCol || rw < TheConsVESA.baseRow || rw > TheConsVESA.maxRow) return; /* out of bounds */ /* remember that cl & rw use 1-based indexing */ x = (cl - 1) * 8; y = (rw - 1) * 16; for (i = 0; i < 16; i++) { for (j = 0; j < 8; j++) { l = (uint8_t) console_font[c * 16 + i]; l <<= 24 + j; signed pixcolor = (l >> 31);#if 1 if (c == GetCursor()) { unsigned red = ~0u; red <<= BootInfoPtr->consInfo->redMask; red = ~red; /* correct low bits now 1 */ red <<= BootInfoPtr->consInfo->redShift; pixcolor = pixcolor ? red : 0; }#endif#ifdef STABLE_CONFIG if (xor) XORPIX(x, y, (unsigned) pixcolor); else PIX(x, y, (unsigned) pixcolor);#else if(xor) /*FIXME*/; else putPixel(x, y, (unsigned) pixcolor);#endif /* Color Alternatives: */ /* grey font: */ /* PIX(x, y, (unsigned) ((l>>31) == 0 ? 0 : 0xc0c0c0)); */ /* black on white: */ /* PIX(x, y, (unsigned) ~(l>>31)); */ x++; } x = (cl - 1) * 8; y++; }}voidConsVESA::Clear(){ bzero((char *) Machine::frameBuffer, TheConsVESA.bpsl*TheConsVESA.yres); cursor();#if 0 uint16_t i; /* This is screamingly inefficient... */ TheConsVESA.SetCursor(0); col = TheConsVESA.baseCol; row = TheConsVESA.baseRow; /* TODO: should probably use memcopy instead */ for (i = 0; i < (TheConsVESA.maxRow * TheConsVESA.maxCol); i++) { Put(32); /* automatically increments col & row appropriately */ } col = TheConsVESA.baseCol; row = TheConsVESA.baseRow; TheConsVESA.SetCursor(1);#endif}voidvideo_bcopy(const void *src, void *dest, size_t len){ uint8_t *pdest = (uint8_t *) dest; const uint8_t *psrc = (uint8_t *) src; while (len--) *pdest++ = *psrc++;}voidConsVESA::Scroll(){ /* Scroll display down one line */ uint16_t a; a=a; if(linfb) goto lin; else goto win; lin: /* #define video_bcopy bcopy */ /* scroll up */ video_bcopy((const char *) Machine::frameBuffer + bpsl*16 + (baseRow-1)*bpsl*16, (char *) Machine::frameBuffer + (baseRow-1)*bpsl*16, bpsl*16*(maxRow-baseRow)); /* erase last line */ bzero((char *) Machine::frameBuffer + bpsl*16*(maxRow-1),bpsl*16); return;#if 0 /* inefficient; should zero memory instead */ for(a = 1; a<=maxCol; a++) { Put(ASCII::SPC, a, maxRow); } return;#endif win: return;}voidConsVESA::SetCursor(uint8_t toggle, int16_t c = -1){ if(toggle) TheConsVESA.curOn = 1; else TheConsVESA.curOn = 0; if(c!= -1) TheConsVESA.cursor = (uint8_t) c;}int16_tConsVESA::GetCursor(){ return TheConsVESA.cursor;}voiddrawHeader(){#if 0 /* Issue: cute, but..., well, cute at least. */ animate();#endif drawLogo(0,0); drawLogo2(TheConsVESA.xres-width2,TheConsVESA.yres-height2); /* Define new scren margins */ TheConsVESA.baseRow = height/16 + 2; TheConsVESA.maxRow -= height2/16 +1; /* Do I really need any of the following lines? */ /*TheConsVESA.row += TheConsVESA.baseRow - 1; TheConsVESA.row = TheConsVESA.baseRow;*/}voidredrawLogos(){ drawLogo(0,0); drawLogo2(TheConsVESA.xres-width2,0);}voiddrawLogo(const uint16_t x, const uint16_t y){ uint16_t lx, ly; uint8_t p[3]; header_data = orig_header_data; for(ly = y; ly < (height + y); ly++) { for(lx = x; lx < (width + x); lx++) { HEADER_PIXEL(header_data, p); PIX(lx, ly, ((p[0] << 16) + (p[1] << 8) + (p[2]))); /* R+G+B */ } }}voiddrawLogo2(const uint16_t x, const uint16_t y){ uint16_t lx, ly; uint8_t p[3]; header_data2 = orig_header_data2; for(ly = y; ly < (height2 + y); ly++) { for(lx = x; lx < (width2 + x); lx++) { HEADER_PIXEL2(header_data2, p); PIX(lx, ly, ((p[0] << 16) + (p[1] << 8) + (p[2]))); /* R+G+B */ } }}voidanimate(){ uint16_t x, y; uint16_t i, j; /* left -> right */ for (x = 0; x <= TheConsVESA.xres - width; x++) { drawLogo(x,0); if(x!=0) { for(j = 0; j < height; j++) { PIX(x-1, j, (uint32_t) 0); } } } /* top -> bottom */ for (y = 0; y <= TheConsVESA.yres - height; y++) { drawLogo(TheConsVESA.xres-width,y); if(y!=0) { for(i = 0; i < width; i++) { PIX(i+(TheConsVESA.xres-width), y-1, (uint32_t) 0); } } } /* right -> left */ for (x = 0; x <= TheConsVESA.xres - width; x++) { drawLogo(TheConsVESA.xres-width-x,TheConsVESA.yres-height); if(x!=0) { for(j = 0; j < height; j++) { PIX(TheConsVESA.xres-(x), j+(TheConsVESA.yres-height), (uint32_t) 0); } } } /* bottom -> top */ for (y = 0; y <= TheConsVESA.yres - height; y++) { drawLogo(0,TheConsVESA.yres-height-y); if(y!=0) { for(i = 0; i < width; i++) { PIX(i, TheConsVESA.yres-(y), (uint32_t) 0); } } }}void putPixel(const uint16_t x, const uint16_t y, const uint32_t color){ /* Issue: if bits per pixel is not a multiple of 8, then the naive computation fails. */ uint32_t offset = (uint32_t) y * TheConsVESA.bpsl + x * ((TheConsVESA.bpp + 7) / 8); /* Assume 64k banks for the moment */ if(!TheConsVESA.linfb) { /*setBank(offset >> 16);*/ /* Note: general thing here would be offset -= (curBank * BankSize); */ offset &= 0xffffu; } /* Logically: effectiveAddress = frameBufferBase + (BankOffset + BankRelativeOffset); */ /* Issue: absence of funny cases (like 15 bits per pixel) was causing drawing to be entirely suppressed. */ /* *(frameBufferBase + (offset & 0xFFFF)) = (char) color; */ if (TheConsVESA.bpp <= 8) { /* 7, 8 bit modes use bytes */ *((uint8_t *) (Machine::frameBuffer + offset)) = color; } else if (TheConsVESA.bpp <= 16) { /* 15, 16 bit modes use 16 bit values */ *((uint16_t *) (Machine::frameBuffer + offset)) = color; } else { /* >16 bit modes use 32 bit values in the frame buffer. */ *((uint32_t *) (Machine::frameBuffer + offset)) = color; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -