1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (C) 2019 Leandro Lupori 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 19 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 21 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 23 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 24 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27 #include <sys/cdefs.h> 28 __FBSDID("$FreeBSD$"); 29 30 #include <sys/linker_set.h> 31 32 #include <dev/ofw/openfirm.h> 33 #include <gdb/gdb.h> 34 35 #include "phyp-hvcall.h" 36 37 static gdb_probe_f uart_phyp_dbg_probe; 38 static gdb_init_f uart_phyp_dbg_init; 39 static gdb_term_f uart_phyp_dbg_term; 40 static gdb_getc_f uart_phyp_dbg_getc; 41 static gdb_putc_f uart_phyp_dbg_putc; 42 43 GDB_DBGPORT(uart_phyp, uart_phyp_dbg_probe, 44 uart_phyp_dbg_init, uart_phyp_dbg_term, 45 uart_phyp_dbg_getc, uart_phyp_dbg_putc); 46 47 static struct uart_phyp_dbgport { 48 cell_t vtermid; 49 union { 50 uint64_t u64[2]; 51 char str[16]; 52 } inbuf; 53 uint64_t inbuflen; 54 } dbgport; 55 56 static int 57 uart_phyp_dbg_probe(void) 58 { 59 char buf[64]; 60 cell_t reg; 61 phandle_t vty; 62 63 if (!getenv_string("hw.uart.dbgport", buf, sizeof(buf))) 64 return (-1); 65 66 if ((vty = OF_finddevice(buf)) == -1) 67 return (-1); 68 69 if (OF_getprop(vty, "name", buf, sizeof(buf)) <= 0) 70 return (-1); 71 if (strcmp(buf, "vty") != 0) 72 return (-1); 73 74 if (OF_getprop(vty, "device_type", buf, sizeof(buf)) == -1) 75 return (-1); 76 if (strcmp(buf, "serial") != 0) 77 return (-1); 78 79 if (OF_getprop(vty, "compatible", buf, sizeof(buf)) <= 0) 80 return (-1); 81 if (strcmp(buf, "hvterm1") != 0) 82 return (-1); 83 84 reg = ~0U; 85 OF_getencprop(vty, "reg", ®, sizeof(reg)); 86 if (reg == ~0U) 87 return (-1); 88 89 dbgport.vtermid = reg; 90 dbgport.inbuflen = 0; 91 92 return (0); 93 } 94 95 static void 96 uart_phyp_dbg_init(void) 97 { 98 } 99 100 static void 101 uart_phyp_dbg_term(void) 102 { 103 } 104 105 static int 106 uart_phyp_dbg_getc(void) 107 { 108 int c, err, next; 109 110 if (dbgport.inbuflen == 0) { 111 err = phyp_pft_hcall(H_GET_TERM_CHAR, dbgport.vtermid, 112 0, 0, 0, &dbgport.inbuflen, &dbgport.inbuf.u64[0], 113 &dbgport.inbuf.u64[1]); 114 if (err != H_SUCCESS) 115 return (-1); 116 } 117 118 if (dbgport.inbuflen == 0) 119 return (-1); 120 121 c = dbgport.inbuf.str[0]; 122 dbgport.inbuflen--; 123 124 if (dbgport.inbuflen == 0) 125 return (c); 126 127 /* 128 * Since version 2.11.0, QEMU became bug-compatible 129 * with PowerVM's vty, by inserting a \0 after every \r. 130 * Filter it here. 131 */ 132 next = 1; 133 if (c == '\r' && dbgport.inbuf.str[next] == '\0') { 134 next++; 135 dbgport.inbuflen--; 136 } 137 138 if (dbgport.inbuflen > 0) 139 memmove(&dbgport.inbuf.str[0], &dbgport.inbuf.str[next], 140 dbgport.inbuflen); 141 142 return (c); 143 } 144 145 static void 146 uart_phyp_dbg_putc(int c) 147 { 148 int err; 149 150 union { 151 uint64_t u64; 152 unsigned char bytes[8]; 153 } cbuf; 154 155 cbuf.bytes[0] = (unsigned char)c; 156 157 do { 158 err = phyp_hcall(H_PUT_TERM_CHAR, dbgport.vtermid, 1, 159 cbuf.u64, 0); 160 DELAY(100); 161 } while (err == H_BUSY); 162 } 163