PKUOS - Pintos
Pintos source browser for PKU Operating System course
vga.c
Go to the documentation of this file.
1#include "devices/vga.h"
2#include <round.h>
3#include <stdint.h>
4#include <stddef.h>
5#include <string.h>
6#include "devices/speaker.h"
7#include "threads/io.h"
8#include "threads/interrupt.h"
9#include "threads/vaddr.h"
10
11/** VGA text screen support. See [FREEVGA] for more information. */
12
13/** Number of columns and rows on the text display. */
14#define COL_CNT 80
15#define ROW_CNT 25
16
17/** Current cursor position. (0,0) is in the upper left corner of
18 the display. */
19static size_t cx, cy;
20
21/** Attribute value for gray text on a black background. */
22#define GRAY_ON_BLACK 0x07
23
24/** Framebuffer. See [FREEVGA] under "VGA Text Mode Operation".
25 The character at (x,y) is fb[y][x][0].
26 The attribute at (x,y) is fb[y][x][1]. */
27static uint8_t (*fb)[COL_CNT][2];
28
29static void clear_row (size_t y);
30static void cls (void);
31static void newline (void);
32static void move_cursor (void);
33static void find_cursor (size_t *x, size_t *y);
34
35/** Initializes the VGA text display. */
36static void
37init (void)
38{
39 /* Already initialized? */
40 static bool inited;
41 if (!inited)
42 {
43 fb = ptov (0xb8000);
44 find_cursor (&cx, &cy);
45 inited = true;
46 }
47}
48
49/** Writes C to the VGA text display, interpreting control
50 characters in the conventional ways. */
51void
52vga_putc (int c)
53{
54 /* Disable interrupts to lock out interrupt handlers
55 that might write to the console. */
56 enum intr_level old_level = intr_disable ();
57
58 init ();
59
60 switch (c)
61 {
62 case '\n':
63 newline ();
64 break;
65
66 case '\f':
67 cls ();
68 break;
69
70 case '\b':
71 if (cx > 0)
72 cx--;
73 break;
74
75 case '\r':
76 cx = 0;
77 break;
78
79 case '\t':
80 cx = ROUND_UP (cx + 1, 8);
81 if (cx >= COL_CNT)
82 newline ();
83 break;
84
85 case '\a':
86 intr_set_level (old_level);
87 speaker_beep ();
88 intr_disable ();
89 break;
90
91 default:
92 fb[cy][cx][0] = c;
93 fb[cy][cx][1] = GRAY_ON_BLACK;
94 if (++cx >= COL_CNT)
95 newline ();
96 break;
97 }
98
99 /* Update cursor position. */
100 move_cursor ();
101
102 intr_set_level (old_level);
103}
104
105/** Clears the screen and moves the cursor to the upper left. */
106static void
107cls (void)
108{
109 size_t y;
110
111 for (y = 0; y < ROW_CNT; y++)
112 clear_row (y);
113
114 cx = cy = 0;
115 move_cursor ();
116}
117
118/** Clears row Y to spaces. */
119static void
120clear_row (size_t y)
121{
122 size_t x;
123
124 for (x = 0; x < COL_CNT; x++)
125 {
126 fb[y][x][0] = ' ';
127 fb[y][x][1] = GRAY_ON_BLACK;
128 }
129}
130
131/** Advances the cursor to the first column in the next line on
132 the screen. If the cursor is already on the last line on the
133 screen, scrolls the screen upward one line. */
134static void
136{
137 cx = 0;
138 cy++;
139 if (cy >= ROW_CNT)
140 {
141 cy = ROW_CNT - 1;
142 memmove (&fb[0], &fb[1], sizeof fb[0] * (ROW_CNT - 1));
143 clear_row (ROW_CNT - 1);
144 }
145}
146
147/** Moves the hardware cursor to (cx,cy). */
148static void
150{
151 /* See [FREEVGA] under "Manipulating the Text-mode Cursor". */
152 uint16_t cp = cx + COL_CNT * cy;
153 outw (0x3d4, 0x0e | (cp & 0xff00));
154 outw (0x3d4, 0x0f | (cp << 8));
155}
156
157/** Reads the current hardware cursor position into (*X,*Y). */
158static void
159find_cursor (size_t *x, size_t *y)
160{
161 /* See [FREEVGA] under "Manipulating the Text-mode Cursor". */
162 uint16_t cp;
163
164 outb (0x3d4, 0x0e);
165 cp = inb (0x3d5) << 8;
166
167 outb (0x3d4, 0x0f);
168 cp |= inb (0x3d5);
169
170 *x = cp % COL_CNT;
171 *y = cp / COL_CNT;
172}
enum intr_level intr_disable(void)
Disables interrupts and returns the previous interrupt status.
Definition: interrupt.c:104
enum intr_level intr_set_level(enum intr_level level)
Enables or disables interrupts as specified by LEVEL and returns the previous interrupt status.
Definition: interrupt.c:81
intr_level
Interrupts on or off?
Definition: interrupt.h:9
static uint8_t inb(uint16_t port)
Reads and returns a byte from PORT.
Definition: io.h:9
static void outw(uint16_t port, uint16_t data)
Writes the 16-bit DATA to PORT.
Definition: io.h:83
static void outb(uint16_t port, uint8_t data)
Writes byte DATA to PORT.
Definition: io.h:66
static char x
Verifies that mapping over the data segment is disallowed.
Definition: mmap-over-data.c:9
static bool inited
Already initialized?
Definition: random.c:21
#define ROUND_UP(X, STEP)
Yields X rounded up to the nearest multiple of STEP.
Definition: round.h:6
void speaker_beep(void)
Briefly beep the PC speaker.
Definition: speaker.c:48
unsigned char uint8_t
Definition: stdint.h:20
unsigned short int uint16_t
Definition: stdint.h:23
void * memmove(void *dst_, const void *src_, size_t size)
Copies SIZE bytes from SRC to DST, which are allowed to overlap.
Definition: string.c:24
static void * ptov(uintptr_t paddr)
Returns kernel virtual address at which physical address PADDR is mapped.
Definition: vaddr.h:72
static void init(void)
Initializes the VGA text display.
Definition: vga.c:37
#define GRAY_ON_BLACK
Attribute value for gray text on a black background.
Definition: vga.c:22
static size_t cy
Definition: vga.c:19
void vga_putc(int c)
Writes C to the VGA text display, interpreting control characters in the conventional ways.
Definition: vga.c:52
#define COL_CNT
VGA text screen support.
Definition: vga.c:14
static void cls(void)
Clears the screen and moves the cursor to the upper left.
Definition: vga.c:107
static void clear_row(size_t y)
Clears row Y to spaces.
Definition: vga.c:120
#define ROW_CNT
Definition: vga.c:15
static void find_cursor(size_t *x, size_t *y)
Reads the current hardware cursor position into (*X,*Y).
Definition: vga.c:159
static void newline(void)
Advances the cursor to the first column in the next line on the screen.
Definition: vga.c:135
static void move_cursor(void)
Moves the hardware cursor to (cx,cy).
Definition: vga.c:149
static size_t cx
Current cursor position.
Definition: vga.c:19
static uint8_t(* fb)[COL_CNT][2]
Framebuffer.
Definition: vga.c:27