1 
2 #include <stdbool.h>
3 #include <stdint.h>
4 
5 #include <sys/spinlock.h>
6 #include <sys/kmem.h>
7 #include <sys/thread.h>
8 
9 #include "console.h"
10 #include "x86/vgacons.h"
11 #include "x86/sercons.h"
12 #include "x86/debugcons.h"
13 
14 Spinlock consoleLock;
15 Console consoles;
16 
17 /*
18  * Initialize console devices for debugging purposes.  At this point interrupts
19  * and device state is not initialized.
20  */
21 void
Console_Init()22 Console_Init()
23 {
24     VGA_Init();
25     Serial_Init();
26     DebugConsole_Init();
27 
28     Console_Puts("Castor Operating System\n");
29 
30     Spinlock_Init(&consoleLock, "Console Lock", SPINLOCK_TYPE_NORMAL);
31 
32     Spinlock_Init(&consoles.keyLock, "Console Keyboard Lock", SPINLOCK_TYPE_NORMAL);
33     consoles.nextKey = 0;
34     consoles.lastKey = 0;
35 }
36 
37 /*
38  * Setup interrupts and input devices that may not be ready
39  */
40 void
Console_LateInit()41 Console_LateInit()
42 {
43     Serial_LateInit();
44 }
45 
46 char
Console_Getc()47 Console_Getc()
48 {
49     while (1) {
50 	Spinlock_Lock(&consoles.keyLock);
51 	if (consoles.nextKey != consoles.lastKey) {
52 	    char key = consoles.keyBuf[consoles.nextKey];
53 	    consoles.nextKey = (consoles.nextKey + 1) % CONSOLE_KEYBUF_MAXLEN;
54 	    Spinlock_Unlock(&consoles.keyLock);
55 	    return key;
56 	}
57 	Spinlock_Unlock(&consoles.keyLock);
58 
59 	// Support serial debugging if interrupts are disabled
60 	if (Serial_HasData()) {
61 	    char key = Serial_Getc();
62 	    switch (key) {
63 		case '\r':
64 		    return '\n';
65 		case 0x7f:
66 		    return '\b';
67 		default:
68 		    return key;
69 	    }
70 	}
71     }
72 }
73 
74 void
Console_EnqueueKey(char key)75 Console_EnqueueKey(char key)
76 {
77     Spinlock_Lock(&consoles.keyLock);
78     if (((consoles.lastKey + 1) % CONSOLE_KEYBUF_MAXLEN) == consoles.lastKey) {
79 	Spinlock_Unlock(&consoles.keyLock);
80 	return;
81     }
82     consoles.keyBuf[consoles.lastKey] = key;
83     consoles.lastKey = (consoles.lastKey + 1) % CONSOLE_KEYBUF_MAXLEN;
84     Spinlock_Unlock(&consoles.keyLock);
85 }
86 
87 void
Console_Gets(char * str,size_t n)88 Console_Gets(char *str, size_t n)
89 {
90     int i;
91 
92     for (i = 0; i < (n - 1); i++)
93     {
94 	char ch = Console_Getc();
95 	if (ch == '\b') {
96 	    if (i > 0) {
97 		Console_Putc(ch);
98 		i--;
99 	    }
100 	    i--;
101 	    continue;
102 	}
103 	if (ch == '\n') {
104 	    Console_Putc('\n');
105 	    str[i] = '\0';
106 	    return;
107 	}
108 	if (ch == '\r') {
109 	    Console_Putc('\n');
110 	    str[i] = '\0';
111 	    return;
112 	}
113 	if (ch == '\t') {
114 	    Console_Putc('\t');
115 	    str[i] = '\t';
116 	    continue;
117 	}
118 	if (ch < 0x20)
119 	{
120 	    // Unprintable character
121 	    continue;
122 	}
123 	Console_Putc(ch);
124 	str[i] = ch;
125     }
126 
127     str[i+1] = '\0';
128 }
129 
130 void
Console_Putc(char ch)131 Console_Putc(char ch)
132 {
133     Spinlock_Lock(&consoleLock);
134     VGA_Putc(ch);
135     Serial_Putc(ch);
136     DebugConsole_Putc(ch);
137     Spinlock_Unlock(&consoleLock);
138 }
139 
140 void
Console_Puts(const char * str)141 Console_Puts(const char *str)
142 {
143     Spinlock_Lock(&consoleLock);
144     VGA_Puts(str);
145     Serial_Puts(str);
146     DebugConsole_Puts(str);
147     Spinlock_Unlock(&consoleLock);
148 }
149 
150 int
Console_Read(Handle * handle,void * buf,uint64_t off,uint64_t len)151 Console_Read(Handle *handle, void *buf, uint64_t off, uint64_t len)
152 {
153     uintptr_t b = (uintptr_t)buf;
154     uint64_t i;
155 
156     for (i = 0; i < len; i++)
157     {
158 	char c = Console_Getc();
159 	Console_Putc(c);
160 	Copy_Out(&c, b+i, 1);
161     }
162 
163     return len;
164 }
165 
166 int
Console_Write(Handle * handle,void * buf,uint64_t off,uint64_t len)167 Console_Write(Handle *handle, void *buf, uint64_t off, uint64_t len)
168 {
169     int i;
170     uintptr_t b = (uintptr_t)buf;
171     char kbuf[512];
172     uint64_t nbytes = 0;
173 
174     while (len > nbytes) {
175 	uint64_t chunksz = len > 512 ? 512 : len;
176 	Copy_In(b + nbytes, &kbuf, chunksz);
177 	nbytes += chunksz;
178 
179 	for (i = 0; i < chunksz; i++)
180 	    Console_Putc(kbuf[i]);
181     }
182 
183     return nbytes;
184 }
185 
186 int
Console_Flush(Handle * handle)187 Console_Flush(Handle *handle)
188 {
189     return 0;
190 }
191 
192 int
Console_Close(Handle * handle)193 Console_Close(Handle *handle)
194 {
195     Handle_Free(handle);
196     return 0;
197 }
198 
199 Handle *
Console_OpenHandle()200 Console_OpenHandle()
201 {
202     Handle *handle = Handle_Alloc();
203     if (!handle)
204 	return NULL;
205 
206     handle->read = &Console_Read;
207     handle->write = &Console_Write;
208     handle->flush = &Console_Flush;
209     handle->close = &Console_Close;
210 
211     return handle;
212 }
213 
214