]> rtime.felk.cvut.cz Git - jailhouse.git/blob - hypervisor/arch/x86/dbg-write.c
Merge remote-tracking branch 'kiszka/master'
[jailhouse.git] / hypervisor / arch / x86 / dbg-write.c
1 /*
2  * Jailhouse, a Linux-based partitioning hypervisor
3  *
4  * Copyright (c) Siemens AG, 2013-2016
5  * Copyright (c) Toshiba, 2016
6  *
7  * Authors:
8  *  Jan Kiszka <jan.kiszka@siemens.com>
9  *  Daniel Sangorrin <daniel.sangorrin@toshiba.co.jp>
10  *
11  * This work is licensed under the terms of the GNU GPL, version 2.  See
12  * the COPYING file in the top-level directory.
13  */
14
15 #include <jailhouse/control.h>
16 #include <jailhouse/entry.h>
17 #include <jailhouse/printk.h>
18 #include <jailhouse/processor.h>
19 #include <asm/io.h>
20
21 #define UART_TX                 0x0
22 #define UART_DLL                0x0
23 #define UART_DLM                0x1
24 #define UART_LCR                0x3
25 #define UART_LCR_8N1            0x03
26 #define UART_LCR_DLAB           0x80
27 #define UART_LSR                0x5
28 #define UART_LSR_THRE           0x20
29
30 static u16 uart_base;
31
32 static void uart_init(void)
33 {
34         if (system_config->debug_console.phys_start == 0 ||
35             system_config->debug_console.flags & JAILHOUSE_MEM_IO)
36                 return;
37
38         uart_base = system_config->debug_console.phys_start;
39
40         outb(UART_LCR_DLAB, uart_base + UART_LCR);
41 #ifdef CONFIG_UART_OXPCIE952
42         outb(0x22, uart_base + UART_DLL);
43 #else
44         outb(1, uart_base + UART_DLL);
45 #endif
46         outb(0, uart_base + UART_DLM);
47         outb(UART_LCR_8N1, uart_base + UART_LCR);
48 }
49
50 static void uart_write(const char *msg)
51 {
52         char c = 0;
53
54         while (1) {
55                 if (c == '\n')
56                         c = '\r';
57                 else
58                         c = *msg++;
59                 if (!c)
60                         break;
61                 while (!(inb(uart_base + UART_LSR) & UART_LSR_THRE))
62                         cpu_relax();
63                 if (panic_in_progress && panic_cpu != phys_processor_id())
64                         break;
65                 outb(c, uart_base + UART_TX);
66         }
67 }
68
69 #define VGA_WIDTH               80
70 #define VGA_HEIGHT              25
71 #define VGA_BLACK               0x0
72 #define VGA_BRIGHT_GREEN        0xA
73 #define VGA_BG_COLOR            VGA_BLACK
74 #define VGA_FG_COLOR            VGA_BRIGHT_GREEN
75 #define VGA_ATTRIBUTE           ((VGA_BG_COLOR | VGA_FG_COLOR) << 8)
76 #define VGA_U16(c)              ((u16)(c) | (u16)VGA_ATTRIBUTE)
77 #define ASCII_NONPRINTABLE      '?'
78
79 static u16 *vga_mem;
80
81 static void vga_init(void)
82 {
83         vga_mem = hypervisor_header.debug_console_base;
84 }
85
86 static void vga_scroll(void)
87 {
88         unsigned int i;
89
90         for (i = 0; i < (VGA_HEIGHT - 1) * VGA_WIDTH; i++)
91                 vga_mem[i] = vga_mem[i + VGA_WIDTH];
92
93         for (i = 0; i < VGA_WIDTH; i++)
94                 vga_mem[(VGA_HEIGHT - 1) * VGA_WIDTH + i] = VGA_U16(' ');
95 }
96
97 static void vga_write(const char *msg)
98 {
99         static u32 row_line;
100         unsigned int pos;
101         u16 row, line;
102
103         /* panic_printk avoids locking 'printk_lock' due to a potential
104            deadlock in case a crash occurs while holding it. For avoiding
105            a data race between printk and panic_printk we take a local
106            snapshot of both static variables and update them on return */
107         row  = (u16)((row_line & 0xFFFF0000) >> 16);
108         line = (u16)(row_line & 0x0000FFFF);
109
110         while (*msg != 0) {
111                 if (panic_in_progress && panic_cpu != phys_processor_id())
112                         return;
113                 if (row == VGA_WIDTH || *msg == '\n') {
114                         row = 0;
115                         if (line == (VGA_HEIGHT - 1))
116                                 vga_scroll();
117                         else
118                                 line++;
119                 }
120                 pos = line * VGA_WIDTH + row;
121                 switch (*msg) {
122                 case '\n':
123                         msg++;
124                         continue;
125                 case ' ' ... '~':
126                         vga_mem[pos] = VGA_U16(*msg);
127                         break;
128                 default:
129                         vga_mem[pos] = VGA_U16(ASCII_NONPRINTABLE);
130                 }
131                 row++;
132                 msg++;
133         }
134
135         row_line = ((u32)row << 16) | (u32)line;
136 }
137
138 void arch_dbg_write_init(void)
139 {
140         vga_init();
141         uart_init();
142 }
143
144 void arch_dbg_write(const char *msg)
145 {
146         if (vga_mem)
147                 vga_write(msg);
148         else if (uart_base)
149                 uart_write(msg);
150 }