]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/pc/vga.c
kernel: fix bounds check in screenputc()
[plan9front.git] / sys / src / 9 / pc / vga.c
1 #include "u.h"
2 #include "../port/lib.h"
3 #include "mem.h"
4 #include "dat.h"
5 #include "fns.h"
6 #include "io.h"
7 #include "../port/error.h"
8
9 #define Image   IMAGE
10 #include <draw.h>
11 #include <memdraw.h>
12 #include <cursor.h>
13 #include "screen.h"
14
15 static Memimage *conscol;
16 static Memimage *back;
17
18 static Point curpos;
19 static Rectangle window;
20 static int *xp;
21 static int xbuf[256];
22 Lock vgascreenlock;
23
24 void
25 vgaimageinit(ulong)
26 {
27         conscol = memblack;
28         back = memwhite;
29 }
30
31 static void
32 vgascroll(VGAscr* scr)
33 {
34         int h, o;
35         Point p;
36         Rectangle r;
37
38         h = scr->memdefont->height;
39         o = 8*h;
40         r = Rpt(window.min, Pt(window.max.x, window.max.y-o));
41         p = Pt(window.min.x, window.min.y+o);
42         memimagedraw(scr->gscreen, r, scr->gscreen, p, nil, p, S);
43         r = Rpt(Pt(window.min.x, window.max.y-o), window.max);
44         memimagedraw(scr->gscreen, r, back, ZP, nil, ZP, S);
45
46         curpos.y -= o;
47 }
48
49 static void
50 vgascreenputc(VGAscr* scr, char* buf, Rectangle *flushr)
51 {
52         Point p;
53         int h, w, pos;
54         Rectangle r;
55
56         if(xp < xbuf || xp >= &xbuf[nelem(xbuf)])
57                 xp = xbuf;
58
59         h = scr->memdefont->height;
60         switch(buf[0]){
61         case '\n':
62                 if(curpos.y+h >= window.max.y){
63                         vgascroll(scr);
64                         *flushr = window;
65                 }
66                 curpos.y += h;
67                 vgascreenputc(scr, "\r", flushr);
68                 break;
69
70         case '\r':
71                 xp = xbuf;
72                 curpos.x = window.min.x;
73                 break;
74
75         case '\t':
76                 p = memsubfontwidth(scr->memdefont, " ");
77                 w = p.x;
78                 if(curpos.x >= window.max.x-4*w)
79                         vgascreenputc(scr, "\n", flushr);
80
81                 pos = (curpos.x-window.min.x)/w;
82                 pos = 4-(pos%4);
83                 *xp++ = curpos.x;
84                 r = Rect(curpos.x, curpos.y, curpos.x+pos*w, curpos.y + h);
85                 memimagedraw(scr->gscreen, r, back, ZP, nil, ZP, S);
86                 curpos.x += pos*w;
87                 break;
88
89         case '\b':
90                 if(xp <= xbuf)
91                         break;
92                 xp--;
93                 r = Rect(*xp, curpos.y, curpos.x, curpos.y+h);
94                 memimagedraw(scr->gscreen, r, back, r.min, nil, ZP, S);
95                 combinerect(flushr, r);
96                 curpos.x = *xp;
97                 break;
98
99         case '\0':
100                 break;
101
102         default:
103                 p = memsubfontwidth(scr->memdefont, buf);
104                 w = p.x;
105
106                 if(curpos.x >= window.max.x-w)
107                         vgascreenputc(scr, "\n", flushr);
108
109                 *xp++ = curpos.x;
110                 r = Rect(curpos.x, curpos.y, curpos.x+w, curpos.y+h);
111                 memimagedraw(scr->gscreen, r, back, r.min, nil, ZP, S);
112                 memimagestring(scr->gscreen, curpos, conscol, ZP, scr->memdefont, buf);
113                 combinerect(flushr, r);
114                 curpos.x += w;
115         }
116 }
117
118 static void
119 vgascreenputs(char* s, int n)
120 {
121         static char rb[UTFmax+1];
122         static int nrb;
123         char *e;
124         int gotdraw;
125         VGAscr *scr;
126         Rectangle flushr;
127
128         scr = &vgascreen[0];
129
130         if(!islo()){
131                 /*
132                  * Don't deadlock trying to
133                  * print in an interrupt.
134                  */
135                 if(!canlock(&vgascreenlock))
136                         return;
137         }
138         else
139                 lock(&vgascreenlock);
140
141         /*
142          * Be nice to hold this, but not going to deadlock
143          * waiting for it.  Just try and see.
144          */
145         gotdraw = canqlock(&drawlock);
146
147         flushr = Rect(10000, 10000, -10000, -10000);
148
149         e = s + n;
150         while(s < e){
151                 rb[nrb++] = *s++;
152                 if(nrb >= UTFmax || fullrune(rb, nrb)){
153                         rb[nrb] = 0;
154                         vgascreenputc(scr, rb, &flushr);
155                         nrb = 0;
156                 }
157         }
158         flushmemscreen(flushr);
159
160         if(gotdraw)
161                 qunlock(&drawlock);
162         unlock(&vgascreenlock);
163 }
164
165 static Memimage*
166 mkcolor(Memimage *screen, ulong color)
167 {
168         Memimage *i;
169
170         if(i = allocmemimage(Rect(0,0,1,1), screen->chan)){
171                 i->flags |= Frepl;
172                 i->clipr = screen->r;
173                 memfillcolor(i, color);
174         }
175         return i;
176 }
177
178 void
179 vgascreenwin(VGAscr* scr)
180 {
181         Memimage *i;
182         Rectangle r;
183         Point p;
184         int h;
185
186         qlock(&drawlock);
187         
188         h = scr->memdefont->height;
189         r = scr->gscreen->r;
190
191         if(i = mkcolor(scr->gscreen, 0x0D686BFF)){
192                 memimagedraw(scr->gscreen, r, i, ZP, nil, ZP, S);
193                 freememimage(i);
194         }
195
196         window = insetrect(r, 20);
197         memimagedraw(scr->gscreen, window, conscol, ZP, memopaque, ZP, S);
198         window = insetrect(window, 4);
199         memimagedraw(scr->gscreen, window, back, ZP, memopaque, ZP, S);
200
201         if(i = mkcolor(scr->gscreen, 0xAAAAAAFF)){
202                 memimagedraw(scr->gscreen, Rect(window.min.x, window.min.y,
203                         window.max.x, window.min.y+h+5+6), i, ZP, nil, ZP, S);
204                 freememimage(i);
205
206                 window = insetrect(window, 5);
207                 p = addpt(window.min, Pt(10, 0));
208                 memimagestring(scr->gscreen, p, memblack, ZP, scr->memdefont, " Plan 9 Console ");
209                 window.min.y += h+6;
210         } else
211                 window = insetrect(window, 5);
212
213         window.max.y = window.min.y+(Dy(window)/h)*h;
214         curpos = window.min;
215
216         flushmemscreen(r);
217
218         qunlock(&drawlock);
219
220         screenputs = vgascreenputs;
221 }
222
223 /*
224  * Supposedly this is the way to turn DPMS
225  * monitors off using just the VGA registers.
226  * Unfortunately, it seems to mess up the video mode
227  * on the cards I've tried.
228  */
229 void
230 vgablank(VGAscr*, int blank)
231 {
232         uchar seq1, crtc17;
233
234         if(blank) {
235                 seq1 = 0x00;
236                 crtc17 = 0x80;
237         } else {
238                 seq1 = 0x20;
239                 crtc17 = 0x00;
240         }
241
242         outs(Seqx, 0x0100);                     /* synchronous reset */
243         seq1 |= vgaxi(Seqx, 1) & ~0x20;
244         vgaxo(Seqx, 1, seq1);
245         crtc17 |= vgaxi(Crtx, 0x17) & ~0x80;
246         delay(10);
247         vgaxo(Crtx, 0x17, crtc17);
248         outs(Crtx, 0x0300);                             /* end synchronous reset */
249 }
250
251 void
252 addvgaseg(char *name, ulong pa, ulong size)
253 {
254         Physseg seg;
255
256         memset(&seg, 0, sizeof seg);
257         seg.attr = SG_PHYSICAL;
258         seg.name = name;
259         seg.pa = pa;
260         seg.size = size;
261         addphysseg(&seg);
262 }