plan9fox/sys/src/9/pc/cga.c
cinap_lenrek 4898050282 cga: capture cga console contents on boot, make sure cgapos is in range
to capture bios and bootloader messages, convert the contents
on the screen to kmesg.

on machines without legacy cga, the cga registers read out as
0xFF, resuting in out of bounds cgapos. so set cgapos to 0 in
that case.
2017-11-26 17:11:01 +01:00

216 lines
4.5 KiB
C

#include "u.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "../port/error.h"
enum {
Black,
Blue,
Green,
Cyan,
Red,
Magenta,
Brown,
Grey,
Bright = 0x08,
Blinking = 0x80,
Yellow = Bright|Brown,
White = Bright|Grey,
};
enum {
Width = 80*2,
Height = 25,
Attr = (Black<<4)|Grey, /* high nibble background
* low foreground
*/
};
#define CGASCREENBASE ((uchar*)KADDR(0xB8000))
static int cgapos;
static Lock cgascreenlock;
static Rune cp437[256] = {
0x2007,0x263A,0x263B,0x2665,0x2666,0x2663,0x2660,0x2022,
0x25D8,0x25CB,0x25D9,0x2642,0x2640,0x266A,0x266B,0x263C,
0x25BA,0x25C4,0x2195,0x203C,0x00B6,0x00A7,0x25AC,0x21A8,
0x2191,0x2193,0x2192,0x2190,0x221F,0x2194,0x25B2,0x25BC,
0x0020,0x0021,0x0022,0x0023,0x0024,0x0025,0x0026,0x0027,
0x0028,0x0029,0x002A,0x002B,0x002C,0x002D,0x002E,0x002F,
0x0030,0x0031,0x0032,0x0033,0x0034,0x0035,0x0036,0x0037,
0x0038,0x0039,0x003A,0x003B,0x003C,0x003D,0x003E,0x003F,
0x0040,0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047,
0x0048,0x0049,0x004A,0x004B,0x004C,0x004D,0x004E,0x004F,
0x0050,0x0051,0x0052,0x0053,0x0054,0x0055,0x0056,0x0057,
0x0058,0x0059,0x005A,0x005B,0x005C,0x005D,0x005E,0x005F,
0x0060,0x0061,0x0062,0x0063,0x0064,0x0065,0x0066,0x0067,
0x0068,0x0069,0x006A,0x006B,0x006C,0x006D,0x006E,0x006F,
0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076,0x0077,
0x0078,0x0079,0x007A,0x007B,0x007C,0x007D,0x007E,0x2302,
0x00C7,0x00FC,0x00E9,0x00E2,0x00E4,0x00E0,0x00E5,0x00E7,
0x00EA,0x00EB,0x00E8,0x00EF,0x00EE,0x00EC,0x00C4,0x00C5,
0x00C9,0x00E6,0x00C6,0x00F4,0x00F6,0x00F2,0x00FB,0x00F9,
0x00FF,0x00D6,0x00DC,0x00A2,0x00A3,0x00A5,0x20A7,0x0192,
0x00E1,0x00ED,0x00F3,0x00FA,0x00F1,0x00D1,0x00AA,0x00BA,
0x00BF,0x2310,0x00AC,0x00BD,0x00BC,0x00A1,0x00AB,0x00BB,
0x2591,0x2592,0x2593,0x2502,0x2524,0x2561,0x2562,0x2556,
0x2555,0x2563,0x2551,0x2557,0x255D,0x255C,0x255B,0x2510,
0x2514,0x2534,0x252C,0x251C,0x2500,0x253C,0x255E,0x255F,
0x255A,0x2554,0x2569,0x2566,0x2560,0x2550,0x256C,0x2567,
0x2568,0x2564,0x2565,0x2559,0x2558,0x2552,0x2553,0x256B,
0x256A,0x2518,0x250C,0x2588,0x2584,0x258C,0x2590,0x2580,
0x03B1,0x00DF,0x0393,0x03C0,0x03A3,0x03C3,0x00B5,0x03C4,
0x03A6,0x0398,0x03A9,0x03B4,0x221E,0x03C6,0x03B5,0x2229,
0x2261,0x00B1,0x2265,0x2264,0x2320,0x2321,0x00F7,0x2248,
0x00B0,0x2219,0x00B7,0x221A,0x207F,0x00B2,0x25A0,0x00A0,
};
static uchar
cgaregr(int index)
{
outb(0x3D4, index);
return inb(0x3D4+1) & 0xFF;
}
static void
cgaregw(int index, int data)
{
outb(0x3D4, index);
outb(0x3D4+1, data);
}
static void
movecursor(void)
{
cgaregw(0x0E, (cgapos/2>>8) & 0xFF);
cgaregw(0x0F, cgapos/2 & 0xFF);
CGASCREENBASE[cgapos+1] = Attr;
}
static void
cgascreenputc(Rune c)
{
int i;
uchar *p;
if(c == '\0')
return;
else if(c == '\n'){
cgapos = cgapos/Width;
cgapos = (cgapos+1)*Width;
}
else if(c == '\t'){
i = 8 - ((cgapos/2)&7);
while(i-->0)
cgascreenputc(' ');
}
else if(c == '\b'){
if(cgapos >= 2)
cgapos -= 2;
cgascreenputc(' ');
cgapos -= 2;
}
else{
for(i=0; i<nelem(cp437); i++)
if(cp437[i] == c)
break;
if(i == nelem(cp437))
i = 0xfe; /* peter */
CGASCREENBASE[cgapos++] = i;
CGASCREENBASE[cgapos++] = Attr;
}
if(cgapos >= Width*Height){
memmove(CGASCREENBASE, &CGASCREENBASE[Width], Width*(Height-1));
p = &CGASCREENBASE[Width*(Height-1)];
for(i=0; i<Width/2; i++){
*p++ = ' ';
*p++ = Attr;
}
cgapos = Width*(Height-1);
}
movecursor();
}
static void
cgascreenputs(char* s, int n)
{
static char rb[UTFmax];
static int nrb;
char *e;
Rune r;
if(!islo()){
/*
* Don't deadlock trying to
* print in an interrupt.
*/
if(!canlock(&cgascreenlock))
return;
}
else
lock(&cgascreenlock);
e = s + n;
while(s < e){
rb[nrb++] = *s++;
if(nrb >= UTFmax || fullrune(rb, nrb)){
chartorune(&r, rb);
cgascreenputc(r);
nrb = 0;
}
}
unlock(&cgascreenlock);
}
static void
cgatokmesg(void)
{
int i, n;
char *p;
ilock(&kmesg.lk);
n = kmesg.n;
for(i = cgapos-2; i >= 0 && n < sizeof kmesg.buf-UTFmax-1; i -= 2){
if((i % Width) == Width-2)
n++;
n += runelen(cp437[CGASCREENBASE[i]]);
}
n -= kmesg.n;
if(n > 0){
memmove(kmesg.buf+n, kmesg.buf, kmesg.n);
kmesg.n += n;
p = kmesg.buf;
for(i += 2; i >= 0 && i < cgapos && p < kmesg.buf+n; i += 2){
p += runetochar(p, &cp437[CGASCREENBASE[i]]);
if((i % Width) == Width-2)
*p++ = '\n';
}
}
iunlock(&kmesg.lk);
}
void
screeninit(void)
{
cgapos = cgaregr(0x0E)<<8;
cgapos |= cgaregr(0x0F);
cgapos *= 2;
if(cgapos >= Width*Height){
cgapos = 0;
movecursor();
}
cgatokmesg();
screenputs = cgascreenputs;
}