]> git.buserror.net Git - polintos/scott/priv.git/blob - kernel/io/console/vga.cc
d0c044ecba87c1817946fd1d6c8963a9d3ab55d2
[polintos/scott/priv.git] / kernel / io / console / vga.cc
1 // io/console/vga.cc -- Kernel debugging console for standard VGA text mode
2 //
3 // This software is copyright (c) 2006 Scott Wood <scott@buserror.net>.
4 // 
5 // This software is provided 'as-is', without any express or implied warranty.
6 // In no event will the authors or contributors be held liable for any damages
7 // arising from the use of this software.
8 // 
9 // Permission is hereby granted to everyone, free of charge, to use, copy,
10 // modify, prepare derivative works of, publish, distribute, perform,
11 // sublicense, and/or sell copies of the Software, provided that the above
12 // copyright notice and disclaimer of warranty be included in all copies or
13 // substantial portions of this software.
14
15 #include <System/IO.h>
16 #include <kern/kernel.h>
17 #include <kern/console.h>
18 #include <kern/notifier.h>
19 #include <kern/io.h>
20 #include <kern/libc.h>
21 #include <kern/addrs.h>
22 #include <util/lock.h>
23
24 void vga_write(char *str);
25
26 namespace IO {
27 namespace Console {
28         class VGA : public Console {
29                 Lock::SpinLock lock;
30         
31                 u16 *mem_base;
32                 unsigned long io_base;
33                 
34                 int line_width;
35                 int lines;
36                 int pos;
37                 
38                 void putc(int ch, int attr)
39                 {
40                         if (ch == '\n') {
41                                 pos += line_width;
42                                 pos -= pos % line_width;
43                         } else if (ch == '\r') {
44                                 pos -= pos % line_width;
45                         } else {
46                                 // Use ll_swap_le16 rather than store_le16 in the hopes
47                                 // that the compiler can simply change the shifts around
48                                 // rather than assembling it one way and then ll_swapping.
49                                 //
50                                 // It's done as one atomic store rather than two single
51                                 // byte writes (which would eliminate endianness concerns)
52                                 // to eliminate the possibility of a race where the video
53                                 // card reads a character before its attribute has been
54                                 // written.
55                                 
56                                 mem_base[pos++] = ll_swap_le16(ch | (attr << 8));
57                         }
58                         
59                         if (pos >= lines * line_width) {
60                                 pos -= line_width;
61                                 
62                                 // FIXME: until memcpy is more than a stupid byte-at-a-time
63                                 // loop, this could race with the video card.
64                                 
65                                 memcpy(mem_base, mem_base + line_width,
66                                        line_width * (lines - 1) * sizeof(u16));
67                                 
68                                 for (int i = 0; i < line_width; i++)
69                                         mem_base[pos + i] = ll_swap_le16(' ' | (7 << 8));
70                         }
71                 }
72                 
73                 void get_cursor()
74                 {
75                         ll_out_8(0x3d4, 14);
76                         pos = (u16)ll_in_8(0x3d5) << 8;
77                         ll_out_8(0x3d4, 15);
78                         pos |= ll_in_8(0x3d5);
79                 }
80
81                 void set_cursor()
82                 {
83                         ll_out_8(0x3d4, 14);
84                         ll_out_8(0x3d5, pos >> 8);
85                         ll_out_8(0x3d4, 15);
86                         ll_out_8(0x3d5, pos & 0xff);
87                 }
88                 
89         public:
90                 #include <servers/io/console/vga/IO/Console/VGA.h>
91                 
92                 VGA()
93                 {
94                         init_iface();
95
96                         // FIXME: should be PCI mem space, not phys mem.
97                         mem_base = (u16 *)Arch::phys_to_kvirt(0xb8000);
98                         io_base = 0x3d0;
99                         
100                         // FIXME: detect
101                         line_width = 80;
102                         lines = 25;
103
104                         primary_console = this;
105                 }
106                 
107                 void write(Array<octet> buf, u64 *LEN)
108                 {
109                         if (!valid_size_t(*LEN))
110                                 /* throw something */
111                                 return;
112                         
113                         size_t len = *LEN;
114                         
115                         if (len > buf.count)
116                                 /* throw something */
117                                 return;
118                 
119                         Lock::AutoSpinLockRecIRQ autolock(lock);
120                         get_cursor();
121                         
122                         for (size_t i = 0; i < len; i++)
123                                 putc(buf.ptr[i], 7);
124
125                         set_cursor();                   
126                 }
127                 
128                 void write_async(Array<octet> buf, u64 len, Notifier notifier)
129                 {
130                         write(buf, &len);
131                         io_notify(notifier, len, io_result::Success);
132                 }
133         };
134         
135         // Use a static constructor, so that it can be used before
136         // memory management is up and running.
137         
138         VGA vga;
139 }
140 }
141
142 #include <servers/io/console/vga/footer.cc>