Commit 82c643ff50dfdd82b89e9c5361fd132c79e0872c
1 parent
457831f4
char device support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1023 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
6 changed files
with
408 additions
and
76 deletions
hw/pc.c
| ... | ... | @@ -324,7 +324,7 @@ void pc_init(int ram_size, int vga_ram_size, int boot_device, |
| 324 | 324 | const char *initrd_filename) |
| 325 | 325 | { |
| 326 | 326 | char buf[1024]; |
| 327 | - int ret, linux_boot, initrd_size, i, nb_nics1, fd; | |
| 327 | + int ret, linux_boot, initrd_size, i, nb_nics1; | |
| 328 | 328 | unsigned long bios_offset, vga_bios_offset; |
| 329 | 329 | int bios_size, isa_bios_size; |
| 330 | 330 | PCIBus *pci_bus; |
| ... | ... | @@ -471,8 +471,7 @@ void pc_init(int ram_size, int vga_ram_size, int boot_device, |
| 471 | 471 | pic_init(); |
| 472 | 472 | pit = pit_init(0x40, 0); |
| 473 | 473 | |
| 474 | - fd = serial_open_device(); | |
| 475 | - serial_init(0x3f8, 4, fd); | |
| 474 | + serial_init(0x3f8, 4, serial_hd); | |
| 476 | 475 | |
| 477 | 476 | if (pci_enabled) { |
| 478 | 477 | for(i = 0; i < nb_nics; i++) { | ... | ... |
hw/ppc_chrp.c
| ... | ... | @@ -126,7 +126,7 @@ void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device, |
| 126 | 126 | openpic_t *openpic; |
| 127 | 127 | m48t59_t *nvram; |
| 128 | 128 | int PPC_io_memory; |
| 129 | - int ret, linux_boot, i, fd; | |
| 129 | + int ret, linux_boot, i; | |
| 130 | 130 | unsigned long bios_offset; |
| 131 | 131 | uint32_t kernel_base, kernel_size, initrd_base, initrd_size; |
| 132 | 132 | PCIBus *pci_bus; |
| ... | ... | @@ -200,8 +200,7 @@ void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device, |
| 200 | 200 | pic_init(); |
| 201 | 201 | |
| 202 | 202 | /* XXX: use Mac Serial port */ |
| 203 | - fd = serial_open_device(); | |
| 204 | - serial_init(0x3f8, 4, fd); | |
| 203 | + serial_init(0x3f8, 4, serial_hd); | |
| 205 | 204 | |
| 206 | 205 | for(i = 0; i < nb_nics; i++) { |
| 207 | 206 | pci_ne2000_init(pci_bus, &nd_table[i]); | ... | ... |
hw/ppc_prep.c
| ... | ... | @@ -415,7 +415,7 @@ void ppc_prep_init(int ram_size, int vga_ram_size, int boot_device, |
| 415 | 415 | char buf[1024]; |
| 416 | 416 | m48t59_t *nvram; |
| 417 | 417 | int PPC_io_memory; |
| 418 | - int ret, linux_boot, i, nb_nics1, fd; | |
| 418 | + int ret, linux_boot, i, nb_nics1; | |
| 419 | 419 | unsigned long bios_offset; |
| 420 | 420 | uint32_t kernel_base, kernel_size, initrd_base, initrd_size; |
| 421 | 421 | PCIBus *pci_bus; |
| ... | ... | @@ -492,8 +492,7 @@ void ppc_prep_init(int ram_size, int vga_ram_size, int boot_device, |
| 492 | 492 | pic_init(); |
| 493 | 493 | // pit = pit_init(0x40, 0); |
| 494 | 494 | |
| 495 | - fd = serial_open_device(); | |
| 496 | - serial_init(0x3f8, 4, fd); | |
| 495 | + serial_init(0x3f8, 4, serial_hd); | |
| 497 | 496 | nb_nics1 = nb_nics; |
| 498 | 497 | if (nb_nics1 > NE2000_NB_MAX) |
| 499 | 498 | nb_nics1 = NE2000_NB_MAX; | ... | ... |
hw/serial.c
| ... | ... | @@ -84,7 +84,7 @@ struct SerialState { |
| 84 | 84 | it can be reset while reading iir */ |
| 85 | 85 | int thr_ipending; |
| 86 | 86 | int irq; |
| 87 | - int out_fd; | |
| 87 | + CharDriverState *chr; | |
| 88 | 88 | }; |
| 89 | 89 | |
| 90 | 90 | static void serial_update_irq(SerialState *s) |
| ... | ... | @@ -107,7 +107,6 @@ static void serial_ioport_write(void *opaque, uint32_t addr, uint32_t val) |
| 107 | 107 | { |
| 108 | 108 | SerialState *s = opaque; |
| 109 | 109 | unsigned char ch; |
| 110 | - int ret; | |
| 111 | 110 | |
| 112 | 111 | addr &= 7; |
| 113 | 112 | #ifdef DEBUG_SERIAL |
| ... | ... | @@ -122,13 +121,8 @@ static void serial_ioport_write(void *opaque, uint32_t addr, uint32_t val) |
| 122 | 121 | s->thr_ipending = 0; |
| 123 | 122 | s->lsr &= ~UART_LSR_THRE; |
| 124 | 123 | serial_update_irq(s); |
| 125 | - | |
| 126 | - if (s->out_fd >= 0) { | |
| 127 | - ch = val; | |
| 128 | - do { | |
| 129 | - ret = write(s->out_fd, &ch, 1); | |
| 130 | - } while (ret != 1); | |
| 131 | - } | |
| 124 | + ch = val; | |
| 125 | + qemu_chr_write(s->chr, &ch, 1); | |
| 132 | 126 | s->thr_ipending = 1; |
| 133 | 127 | s->lsr |= UART_LSR_THRE; |
| 134 | 128 | s->lsr |= UART_LSR_TEMT; |
| ... | ... | @@ -223,19 +217,19 @@ static uint32_t serial_ioport_read(void *opaque, uint32_t addr) |
| 223 | 217 | return ret; |
| 224 | 218 | } |
| 225 | 219 | |
| 226 | -int serial_can_receive(SerialState *s) | |
| 220 | +static int serial_can_receive(SerialState *s) | |
| 227 | 221 | { |
| 228 | 222 | return !(s->lsr & UART_LSR_DR); |
| 229 | 223 | } |
| 230 | 224 | |
| 231 | -void serial_receive_byte(SerialState *s, int ch) | |
| 225 | +static void serial_receive_byte(SerialState *s, int ch) | |
| 232 | 226 | { |
| 233 | 227 | s->rbr = ch; |
| 234 | 228 | s->lsr |= UART_LSR_DR; |
| 235 | 229 | serial_update_irq(s); |
| 236 | 230 | } |
| 237 | 231 | |
| 238 | -void serial_receive_break(SerialState *s) | |
| 232 | +static void serial_receive_break(SerialState *s) | |
| 239 | 233 | { |
| 240 | 234 | s->rbr = 0; |
| 241 | 235 | s->lsr |= UART_LSR_BI | UART_LSR_DR; |
| ... | ... | @@ -254,8 +248,15 @@ static void serial_receive1(void *opaque, const uint8_t *buf, int size) |
| 254 | 248 | serial_receive_byte(s, buf[0]); |
| 255 | 249 | } |
| 256 | 250 | |
| 251 | +static void serial_event(void *opaque, int event) | |
| 252 | +{ | |
| 253 | + SerialState *s = opaque; | |
| 254 | + if (event == CHR_EVENT_BREAK) | |
| 255 | + serial_receive_break(s); | |
| 256 | +} | |
| 257 | + | |
| 257 | 258 | /* If fd is zero, it means that the serial device uses the console */ |
| 258 | -SerialState *serial_init(int base, int irq, int fd) | |
| 259 | +SerialState *serial_init(int base, int irq, CharDriverState *chr) | |
| 259 | 260 | { |
| 260 | 261 | SerialState *s; |
| 261 | 262 | |
| ... | ... | @@ -268,16 +269,8 @@ SerialState *serial_init(int base, int irq, int fd) |
| 268 | 269 | |
| 269 | 270 | register_ioport_write(base, 8, 1, serial_ioport_write, s); |
| 270 | 271 | register_ioport_read(base, 8, 1, serial_ioport_read, s); |
| 271 | - | |
| 272 | - if (fd < 0) { | |
| 273 | - /* no associated device */ | |
| 274 | - s->out_fd = -1; | |
| 275 | - } else if (fd != 0) { | |
| 276 | - qemu_add_fd_read_handler(fd, serial_can_receive1, serial_receive1, s); | |
| 277 | - s->out_fd = fd; | |
| 278 | - } else { | |
| 279 | - serial_console = s; | |
| 280 | - s->out_fd = 1; | |
| 281 | - } | |
| 272 | + s->chr = chr; | |
| 273 | + qemu_chr_add_read_handler(chr, serial_can_receive1, serial_receive1, s); | |
| 274 | + qemu_chr_add_event_handler(chr, serial_event); | |
| 282 | 275 | return s; |
| 283 | 276 | } | ... | ... |
vl.c
| ... | ... | @@ -128,7 +128,6 @@ static char network_script[1024]; |
| 128 | 128 | int pit_min_timer_count = 0; |
| 129 | 129 | int nb_nics; |
| 130 | 130 | NetDriverState nd_table[MAX_NICS]; |
| 131 | -SerialState *serial_console; | |
| 132 | 131 | QEMUTimer *gui_timer; |
| 133 | 132 | int vm_running; |
| 134 | 133 | int audio_enabled = 0; |
| ... | ... | @@ -139,6 +138,7 @@ int cirrus_vga_enabled = 1; |
| 139 | 138 | int graphic_width = 800; |
| 140 | 139 | int graphic_height = 600; |
| 141 | 140 | int graphic_depth = 15; |
| 141 | +TextConsole *vga_console; | |
| 142 | 142 | |
| 143 | 143 | /***********************************************************/ |
| 144 | 144 | /* x86 ISA bus support */ |
| ... | ... | @@ -298,6 +298,22 @@ char *pstrcat(char *buf, int buf_size, const char *s) |
| 298 | 298 | return buf; |
| 299 | 299 | } |
| 300 | 300 | |
| 301 | +int strstart(const char *str, const char *val, const char **ptr) | |
| 302 | +{ | |
| 303 | + const char *p, *q; | |
| 304 | + p = str; | |
| 305 | + q = val; | |
| 306 | + while (*q != '\0') { | |
| 307 | + if (*p != *q) | |
| 308 | + return 0; | |
| 309 | + p++; | |
| 310 | + q++; | |
| 311 | + } | |
| 312 | + if (ptr) | |
| 313 | + *ptr = p; | |
| 314 | + return 1; | |
| 315 | +} | |
| 316 | + | |
| 301 | 317 | /* return the size or -1 if error */ |
| 302 | 318 | int get_image_size(const char *filename) |
| 303 | 319 | { |
| ... | ... | @@ -949,42 +965,273 @@ void quit_timers(void) |
| 949 | 965 | } |
| 950 | 966 | |
| 951 | 967 | /***********************************************************/ |
| 952 | -/* serial device */ | |
| 968 | +/* character device */ | |
| 953 | 969 | |
| 954 | -#ifdef _WIN32 | |
| 970 | +int qemu_chr_write(CharDriverState *s, const uint8_t *buf, int len) | |
| 971 | +{ | |
| 972 | + return s->chr_write(s, buf, len); | |
| 973 | +} | |
| 955 | 974 | |
| 956 | -int serial_open_device(void) | |
| 975 | +void qemu_chr_printf(CharDriverState *s, const char *fmt, ...) | |
| 957 | 976 | { |
| 958 | - return -1; | |
| 977 | + char buf[4096]; | |
| 978 | + va_list ap; | |
| 979 | + va_start(ap, fmt); | |
| 980 | + vsnprintf(buf, sizeof(buf), fmt, ap); | |
| 981 | + qemu_chr_write(s, buf, strlen(buf)); | |
| 982 | + va_end(ap); | |
| 959 | 983 | } |
| 960 | 984 | |
| 961 | -#else | |
| 985 | +void qemu_chr_add_read_handler(CharDriverState *s, | |
| 986 | + IOCanRWHandler *fd_can_read, | |
| 987 | + IOReadHandler *fd_read, void *opaque) | |
| 988 | +{ | |
| 989 | + s->chr_add_read_handler(s, fd_can_read, fd_read, opaque); | |
| 990 | +} | |
| 991 | + | |
| 992 | +void qemu_chr_add_event_handler(CharDriverState *s, IOEventHandler *chr_event) | |
| 993 | +{ | |
| 994 | + s->chr_event = chr_event; | |
| 995 | +} | |
| 962 | 996 | |
| 963 | -int serial_open_device(void) | |
| 997 | +static int null_chr_write(CharDriverState *chr, const uint8_t *buf, int len) | |
| 964 | 998 | { |
| 965 | - if (serial_console == NULL && nographic) { | |
| 966 | - /* use console for serial port */ | |
| 967 | - return 0; | |
| 999 | + return len; | |
| 1000 | +} | |
| 1001 | + | |
| 1002 | +static void null_chr_add_read_handler(CharDriverState *chr, | |
| 1003 | + IOCanRWHandler *fd_can_read, | |
| 1004 | + IOReadHandler *fd_read, void *opaque) | |
| 1005 | +{ | |
| 1006 | +} | |
| 1007 | + | |
| 1008 | +CharDriverState *qemu_chr_open_null(void) | |
| 1009 | +{ | |
| 1010 | + CharDriverState *chr; | |
| 1011 | + | |
| 1012 | + chr = qemu_mallocz(sizeof(CharDriverState)); | |
| 1013 | + if (!chr) | |
| 1014 | + return NULL; | |
| 1015 | + chr->chr_write = null_chr_write; | |
| 1016 | + chr->chr_add_read_handler = null_chr_add_read_handler; | |
| 1017 | + return chr; | |
| 1018 | +} | |
| 1019 | + | |
| 1020 | +#ifndef _WIN32 | |
| 1021 | + | |
| 1022 | +typedef struct { | |
| 1023 | + int fd_in, fd_out; | |
| 1024 | + /* for nographic stdio only */ | |
| 1025 | + IOCanRWHandler *fd_can_read; | |
| 1026 | + IOReadHandler *fd_read; | |
| 1027 | + void *fd_opaque; | |
| 1028 | +} FDCharDriver; | |
| 1029 | + | |
| 1030 | +#define STDIO_MAX_CLIENTS 2 | |
| 1031 | + | |
| 1032 | +static int stdio_nb_clients; | |
| 1033 | +static CharDriverState *stdio_clients[STDIO_MAX_CLIENTS]; | |
| 1034 | + | |
| 1035 | +static int fd_chr_write(CharDriverState *chr, const uint8_t *buf, int len) | |
| 1036 | +{ | |
| 1037 | + FDCharDriver *s = chr->opaque; | |
| 1038 | + return write(s->fd_out, buf, len); | |
| 1039 | +} | |
| 1040 | + | |
| 1041 | +static void fd_chr_add_read_handler(CharDriverState *chr, | |
| 1042 | + IOCanRWHandler *fd_can_read, | |
| 1043 | + IOReadHandler *fd_read, void *opaque) | |
| 1044 | +{ | |
| 1045 | + FDCharDriver *s = chr->opaque; | |
| 1046 | + | |
| 1047 | + if (nographic && s->fd_in == 0) { | |
| 1048 | + s->fd_can_read = fd_can_read; | |
| 1049 | + s->fd_read = fd_read; | |
| 1050 | + s->fd_opaque = opaque; | |
| 968 | 1051 | } else { |
| 969 | -#if 0 | |
| 970 | - char slave_name[1024]; | |
| 971 | - int master_fd, slave_fd; | |
| 972 | - | |
| 973 | - /* Not satisfying */ | |
| 974 | - if (openpty(&master_fd, &slave_fd, slave_name, NULL, NULL) < 0) { | |
| 975 | - fprintf(stderr, "warning: could not create pseudo terminal for serial port\n"); | |
| 976 | - return -1; | |
| 1052 | + qemu_add_fd_read_handler(s->fd_in, fd_can_read, fd_read, opaque); | |
| 1053 | + } | |
| 1054 | +} | |
| 1055 | + | |
| 1056 | +/* open a character device to a unix fd */ | |
| 1057 | +CharDriverState *qemu_chr_open_fd(int fd_in, int fd_out) | |
| 1058 | +{ | |
| 1059 | + CharDriverState *chr; | |
| 1060 | + FDCharDriver *s; | |
| 1061 | + | |
| 1062 | + chr = qemu_mallocz(sizeof(CharDriverState)); | |
| 1063 | + if (!chr) | |
| 1064 | + return NULL; | |
| 1065 | + s = qemu_mallocz(sizeof(FDCharDriver)); | |
| 1066 | + if (!s) { | |
| 1067 | + free(chr); | |
| 1068 | + return NULL; | |
| 1069 | + } | |
| 1070 | + s->fd_in = fd_in; | |
| 1071 | + s->fd_out = fd_out; | |
| 1072 | + chr->opaque = s; | |
| 1073 | + chr->chr_write = fd_chr_write; | |
| 1074 | + chr->chr_add_read_handler = fd_chr_add_read_handler; | |
| 1075 | + return chr; | |
| 1076 | +} | |
| 1077 | + | |
| 1078 | +/* for STDIO, we handle the case where several clients use it | |
| 1079 | + (nographic mode) */ | |
| 1080 | + | |
| 1081 | +#define TERM_ESCAPE 0x01 /* ctrl-a is used for escape */ | |
| 1082 | + | |
| 1083 | +static int term_got_escape, client_index; | |
| 1084 | + | |
| 1085 | +void term_print_help(void) | |
| 1086 | +{ | |
| 1087 | + printf("\n" | |
| 1088 | + "C-a h print this help\n" | |
| 1089 | + "C-a x exit emulator\n" | |
| 1090 | + "C-a s save disk data back to file (if -snapshot)\n" | |
| 1091 | + "C-a b send break (magic sysrq)\n" | |
| 1092 | + "C-a c switch between console and monitor\n" | |
| 1093 | + "C-a C-a send C-a\n" | |
| 1094 | + ); | |
| 1095 | +} | |
| 1096 | + | |
| 1097 | +/* called when a char is received */ | |
| 1098 | +static void stdio_received_byte(int ch) | |
| 1099 | +{ | |
| 1100 | + if (term_got_escape) { | |
| 1101 | + term_got_escape = 0; | |
| 1102 | + switch(ch) { | |
| 1103 | + case 'h': | |
| 1104 | + term_print_help(); | |
| 1105 | + break; | |
| 1106 | + case 'x': | |
| 1107 | + exit(0); | |
| 1108 | + break; | |
| 1109 | + case 's': | |
| 1110 | + { | |
| 1111 | + int i; | |
| 1112 | + for (i = 0; i < MAX_DISKS; i++) { | |
| 1113 | + if (bs_table[i]) | |
| 1114 | + bdrv_commit(bs_table[i]); | |
| 1115 | + } | |
| 1116 | + } | |
| 1117 | + break; | |
| 1118 | + case 'b': | |
| 1119 | + if (client_index < stdio_nb_clients) { | |
| 1120 | + CharDriverState *chr; | |
| 1121 | + FDCharDriver *s; | |
| 1122 | + | |
| 1123 | + chr = stdio_clients[client_index]; | |
| 1124 | + s = chr->opaque; | |
| 1125 | + chr->chr_event(s->fd_opaque, CHR_EVENT_BREAK); | |
| 1126 | + } | |
| 1127 | + break; | |
| 1128 | + case 'c': | |
| 1129 | + client_index++; | |
| 1130 | + if (client_index >= stdio_nb_clients) | |
| 1131 | + client_index = 0; | |
| 1132 | + if (client_index == 0) { | |
| 1133 | + /* send a new line in the monitor to get the prompt */ | |
| 1134 | + ch = '\r'; | |
| 1135 | + goto send_char; | |
| 1136 | + } | |
| 1137 | + break; | |
| 1138 | + case TERM_ESCAPE: | |
| 1139 | + goto send_char; | |
| 1140 | + } | |
| 1141 | + } else if (ch == TERM_ESCAPE) { | |
| 1142 | + term_got_escape = 1; | |
| 1143 | + } else { | |
| 1144 | + send_char: | |
| 1145 | + if (client_index < stdio_nb_clients) { | |
| 1146 | + uint8_t buf[1]; | |
| 1147 | + CharDriverState *chr; | |
| 1148 | + FDCharDriver *s; | |
| 1149 | + | |
| 1150 | + chr = stdio_clients[client_index]; | |
| 1151 | + s = chr->opaque; | |
| 1152 | + buf[0] = ch; | |
| 1153 | + /* XXX: should queue the char if the device is not | |
| 1154 | + ready */ | |
| 1155 | + if (s->fd_can_read(s->fd_opaque) > 0) | |
| 1156 | + s->fd_read(s->fd_opaque, buf, 1); | |
| 977 | 1157 | } |
| 978 | - fprintf(stderr, "Serial port redirected to %s\n", slave_name); | |
| 979 | - return master_fd; | |
| 980 | -#else | |
| 981 | - return -1; | |
| 982 | -#endif | |
| 983 | 1158 | } |
| 984 | 1159 | } |
| 985 | 1160 | |
| 1161 | +static int stdio_can_read(void *opaque) | |
| 1162 | +{ | |
| 1163 | + /* XXX: not strictly correct */ | |
| 1164 | + return 1; | |
| 1165 | +} | |
| 1166 | + | |
| 1167 | +static void stdio_read(void *opaque, const uint8_t *buf, int size) | |
| 1168 | +{ | |
| 1169 | + int i; | |
| 1170 | + for(i = 0; i < size; i++) | |
| 1171 | + stdio_received_byte(buf[i]); | |
| 1172 | +} | |
| 1173 | + | |
| 1174 | +CharDriverState *qemu_chr_open_stdio(void) | |
| 1175 | +{ | |
| 1176 | + CharDriverState *chr; | |
| 1177 | + | |
| 1178 | + if (nographic) { | |
| 1179 | + if (stdio_nb_clients >= STDIO_MAX_CLIENTS) | |
| 1180 | + return NULL; | |
| 1181 | + chr = qemu_chr_open_fd(0, 1); | |
| 1182 | + if (stdio_nb_clients == 0) | |
| 1183 | + qemu_add_fd_read_handler(0, stdio_can_read, stdio_read, NULL); | |
| 1184 | + client_index = stdio_nb_clients; | |
| 1185 | + } else { | |
| 1186 | + if (stdio_nb_clients != 0) | |
| 1187 | + return NULL; | |
| 1188 | + chr = qemu_chr_open_fd(0, 1); | |
| 1189 | + } | |
| 1190 | + stdio_clients[stdio_nb_clients++] = chr; | |
| 1191 | + return chr; | |
| 1192 | +} | |
| 1193 | + | |
| 1194 | +#if defined(__linux__) | |
| 1195 | +CharDriverState *qemu_chr_open_pty(void) | |
| 1196 | +{ | |
| 1197 | + char slave_name[1024]; | |
| 1198 | + int master_fd, slave_fd; | |
| 1199 | + | |
| 1200 | + /* Not satisfying */ | |
| 1201 | + if (openpty(&master_fd, &slave_fd, slave_name, NULL, NULL) < 0) { | |
| 1202 | + return NULL; | |
| 1203 | + } | |
| 1204 | + fprintf(stderr, "char device redirected to %s\n", slave_name); | |
| 1205 | + return qemu_chr_open_fd(master_fd, master_fd); | |
| 1206 | +} | |
| 1207 | +#else | |
| 1208 | +CharDriverState *qemu_chr_open_pty(void) | |
| 1209 | +{ | |
| 1210 | + return NULL; | |
| 1211 | +} | |
| 986 | 1212 | #endif |
| 987 | 1213 | |
| 1214 | +#endif /* !defined(_WIN32) */ | |
| 1215 | + | |
| 1216 | +CharDriverState *qemu_chr_open(const char *filename) | |
| 1217 | +{ | |
| 1218 | + if (!strcmp(filename, "vc")) { | |
| 1219 | + return text_console_init(&display_state); | |
| 1220 | + } else if (!strcmp(filename, "null")) { | |
| 1221 | + return qemu_chr_open_null(); | |
| 1222 | + } else | |
| 1223 | +#ifndef _WIN32 | |
| 1224 | + if (!strcmp(filename, "pty")) { | |
| 1225 | + return qemu_chr_open_pty(); | |
| 1226 | + } else if (!strcmp(filename, "stdio")) { | |
| 1227 | + return qemu_chr_open_stdio(); | |
| 1228 | + } else | |
| 1229 | +#endif | |
| 1230 | + { | |
| 1231 | + return NULL; | |
| 1232 | + } | |
| 1233 | +} | |
| 1234 | + | |
| 988 | 1235 | /***********************************************************/ |
| 989 | 1236 | /* Linux network device redirectors */ |
| 990 | 1237 | |
| ... | ... | @@ -2106,6 +2353,8 @@ void help(void) |
| 2106 | 2353 | "-initrd file use 'file' as initial ram disk\n" |
| 2107 | 2354 | "\n" |
| 2108 | 2355 | "Debug/Expert options:\n" |
| 2356 | + "-monitor dev redirect the monitor to char device 'dev'\n" | |
| 2357 | + "-serial dev redirect the serial port to char device 'dev'\n" | |
| 2109 | 2358 | "-S freeze CPU at startup (use 'c' to start execution)\n" |
| 2110 | 2359 | "-s wait gdb connection to port %d\n" |
| 2111 | 2360 | "-p port change gdb connection port\n" |
| ... | ... | @@ -2121,7 +2370,13 @@ void help(void) |
| 2121 | 2370 | " (default is CL-GD5446 PCI VGA)\n" |
| 2122 | 2371 | #endif |
| 2123 | 2372 | "\n" |
| 2124 | - "During emulation, use C-a h to get terminal commands:\n", | |
| 2373 | + "During emulation, the following keys are useful:\n" | |
| 2374 | + "ctrl-shift-f toggle full screen\n" | |
| 2375 | + "ctrl-shift-Fn switch to virtual console 'n'\n" | |
| 2376 | + "ctrl-shift toggle mouse and keyboard grab\n" | |
| 2377 | + "\n" | |
| 2378 | + "When using -nographic, press 'ctrl-a h' to get some help.\n" | |
| 2379 | + , | |
| 2125 | 2380 | #ifdef CONFIG_SOFTMMU |
| 2126 | 2381 | "qemu", |
| 2127 | 2382 | #else |
| ... | ... | @@ -2131,7 +2386,6 @@ void help(void) |
| 2131 | 2386 | DEFAULT_NETWORK_SCRIPT, |
| 2132 | 2387 | DEFAULT_GDBSTUB_PORT, |
| 2133 | 2388 | "/tmp/qemu.log"); |
| 2134 | - term_print_help(); | |
| 2135 | 2389 | #ifndef CONFIG_SOFTMMU |
| 2136 | 2390 | printf("\n" |
| 2137 | 2391 | "NOTE: this version of QEMU is faster but it needs slightly patched OSes to\n" |
| ... | ... | @@ -2184,6 +2438,8 @@ enum { |
| 2184 | 2438 | QEMU_OPTION_cirrusvga, |
| 2185 | 2439 | QEMU_OPTION_g, |
| 2186 | 2440 | QEMU_OPTION_std_vga, |
| 2441 | + QEMU_OPTION_monitor, | |
| 2442 | + QEMU_OPTION_serial, | |
| 2187 | 2443 | }; |
| 2188 | 2444 | |
| 2189 | 2445 | typedef struct QEMUOption { |
| ... | ... | @@ -2235,7 +2491,9 @@ const QEMUOption qemu_options[] = { |
| 2235 | 2491 | { "localtime", 0, QEMU_OPTION_localtime }, |
| 2236 | 2492 | { "isa", 0, QEMU_OPTION_isa }, |
| 2237 | 2493 | { "std-vga", 0, QEMU_OPTION_std_vga }, |
| 2238 | - | |
| 2494 | + { "monitor", 1, QEMU_OPTION_monitor }, | |
| 2495 | + { "serial", 1, QEMU_OPTION_serial }, | |
| 2496 | + | |
| 2239 | 2497 | /* temporary options */ |
| 2240 | 2498 | { "pci", 0, QEMU_OPTION_pci }, |
| 2241 | 2499 | { "cirrusvga", 0, QEMU_OPTION_cirrusvga }, |
| ... | ... | @@ -2273,6 +2531,9 @@ int main(int argc, char **argv) |
| 2273 | 2531 | int net_if_type, nb_tun_fds, tun_fds[MAX_NICS]; |
| 2274 | 2532 | int optind; |
| 2275 | 2533 | const char *r, *optarg; |
| 2534 | + CharDriverState *monitor_hd; | |
| 2535 | + char monitor_device[128]; | |
| 2536 | + char serial_device[128]; | |
| 2276 | 2537 | |
| 2277 | 2538 | #if !defined(CONFIG_SOFTMMU) |
| 2278 | 2539 | /* we never want that malloc() uses mmap() */ |
| ... | ... | @@ -2297,6 +2558,8 @@ int main(int argc, char **argv) |
| 2297 | 2558 | kernel_cmdline = ""; |
| 2298 | 2559 | has_cdrom = 1; |
| 2299 | 2560 | cyls = heads = secs = 0; |
| 2561 | + pstrcpy(monitor_device, sizeof(monitor_device), "vc"); | |
| 2562 | + pstrcpy(serial_device, sizeof(serial_device), "vc"); | |
| 2300 | 2563 | |
| 2301 | 2564 | nb_tun_fds = 0; |
| 2302 | 2565 | net_if_type = -1; |
| ... | ... | @@ -2308,7 +2571,7 @@ int main(int argc, char **argv) |
| 2308 | 2571 | macaddr[3] = 0x12; |
| 2309 | 2572 | macaddr[4] = 0x34; |
| 2310 | 2573 | macaddr[5] = 0x56; |
| 2311 | - | |
| 2574 | + | |
| 2312 | 2575 | optind = 1; |
| 2313 | 2576 | for(;;) { |
| 2314 | 2577 | if (optind >= argc) |
| ... | ... | @@ -2375,6 +2638,8 @@ int main(int argc, char **argv) |
| 2375 | 2638 | } |
| 2376 | 2639 | break; |
| 2377 | 2640 | case QEMU_OPTION_nographic: |
| 2641 | + pstrcpy(monitor_device, sizeof(monitor_device), "stdio"); | |
| 2642 | + pstrcpy(serial_device, sizeof(serial_device), "stdio"); | |
| 2378 | 2643 | nographic = 1; |
| 2379 | 2644 | break; |
| 2380 | 2645 | case QEMU_OPTION_kernel: |
| ... | ... | @@ -2561,6 +2826,12 @@ int main(int argc, char **argv) |
| 2561 | 2826 | graphic_depth = depth; |
| 2562 | 2827 | } |
| 2563 | 2828 | break; |
| 2829 | + case QEMU_OPTION_monitor: | |
| 2830 | + pstrcpy(monitor_device, sizeof(monitor_device), optarg); | |
| 2831 | + break; | |
| 2832 | + case QEMU_OPTION_serial: | |
| 2833 | + pstrcpy(serial_device, sizeof(serial_device), optarg); | |
| 2834 | + break; | |
| 2564 | 2835 | } |
| 2565 | 2836 | } |
| 2566 | 2837 | } |
| ... | ... | @@ -2750,6 +3021,24 @@ int main(int argc, char **argv) |
| 2750 | 3021 | #endif |
| 2751 | 3022 | } |
| 2752 | 3023 | |
| 3024 | + vga_console = graphic_console_init(ds); | |
| 3025 | + | |
| 3026 | + monitor_hd = qemu_chr_open(monitor_device); | |
| 3027 | + if (!monitor_hd) { | |
| 3028 | + fprintf(stderr, "qemu: could not open monitor device '%s'\n", monitor_device); | |
| 3029 | + exit(1); | |
| 3030 | + } | |
| 3031 | + monitor_init(monitor_hd, !nographic); | |
| 3032 | + | |
| 3033 | + serial_hd = qemu_chr_open(serial_device); | |
| 3034 | + if (!serial_hd) { | |
| 3035 | + fprintf(stderr, "qemu: could not open serial device '%s'\n", serial_device); | |
| 3036 | + exit(1); | |
| 3037 | + } | |
| 3038 | + if (!strcmp(serial_device, "vc")) | |
| 3039 | + qemu_chr_printf(serial_hd, "serial0 console\n"); | |
| 3040 | + | |
| 3041 | + | |
| 2753 | 3042 | /* setup cpu signal handlers for MMU / self modifying code handling */ |
| 2754 | 3043 | #if !defined(CONFIG_SOFTMMU) |
| 2755 | 3044 | |
| ... | ... | @@ -2805,10 +3094,6 @@ int main(int argc, char **argv) |
| 2805 | 3094 | kernel_filename, kernel_cmdline, initrd_filename); |
| 2806 | 3095 | #endif |
| 2807 | 3096 | |
| 2808 | - /* launched after the device init so that it can display or not a | |
| 2809 | - banner */ | |
| 2810 | - monitor_init(); | |
| 2811 | - | |
| 2812 | 3097 | gui_timer = qemu_new_timer(rt_clock, gui_update, NULL); |
| 2813 | 3098 | qemu_mod_timer(gui_timer, qemu_get_clock(rt_clock)); |
| 2814 | 3099 | ... | ... |
vl.h
| ... | ... | @@ -215,8 +215,7 @@ extern const char *bios_dir; |
| 215 | 215 | |
| 216 | 216 | void pstrcpy(char *buf, int buf_size, const char *str); |
| 217 | 217 | char *pstrcat(char *buf, int buf_size, const char *s); |
| 218 | - | |
| 219 | -int serial_open_device(void); | |
| 218 | +int strstart(const char *str, const char *val, const char **ptr); | |
| 220 | 219 | |
| 221 | 220 | extern int vm_running; |
| 222 | 221 | |
| ... | ... | @@ -265,6 +264,31 @@ void qemu_add_mouse_event_handler(QEMUPutMouseEvent *func, void *opaque); |
| 265 | 264 | void kbd_put_keycode(int keycode); |
| 266 | 265 | void kbd_mouse_event(int dx, int dy, int dz, int buttons_state); |
| 267 | 266 | |
| 267 | +/* keysym is a unicode code except for special keys (see QEMU_KEY_xxx | |
| 268 | + constants) */ | |
| 269 | +#define QEMU_KEY_ESC1(c) ((c) | 0xe100) | |
| 270 | +#define QEMU_KEY_BACKSPACE 0x007f | |
| 271 | +#define QEMU_KEY_UP QEMU_KEY_ESC1('A') | |
| 272 | +#define QEMU_KEY_DOWN QEMU_KEY_ESC1('B') | |
| 273 | +#define QEMU_KEY_RIGHT QEMU_KEY_ESC1('C') | |
| 274 | +#define QEMU_KEY_LEFT QEMU_KEY_ESC1('D') | |
| 275 | +#define QEMU_KEY_HOME QEMU_KEY_ESC1(1) | |
| 276 | +#define QEMU_KEY_END QEMU_KEY_ESC1(4) | |
| 277 | +#define QEMU_KEY_PAGEUP QEMU_KEY_ESC1(5) | |
| 278 | +#define QEMU_KEY_PAGEDOWN QEMU_KEY_ESC1(6) | |
| 279 | +#define QEMU_KEY_DELETE QEMU_KEY_ESC1(3) | |
| 280 | + | |
| 281 | +#define QEMU_KEY_CTRL_UP 0xe400 | |
| 282 | +#define QEMU_KEY_CTRL_DOWN 0xe401 | |
| 283 | +#define QEMU_KEY_CTRL_LEFT 0xe402 | |
| 284 | +#define QEMU_KEY_CTRL_RIGHT 0xe403 | |
| 285 | +#define QEMU_KEY_CTRL_HOME 0xe404 | |
| 286 | +#define QEMU_KEY_CTRL_END 0xe405 | |
| 287 | +#define QEMU_KEY_CTRL_PAGEUP 0xe406 | |
| 288 | +#define QEMU_KEY_CTRL_PAGEDOWN 0xe407 | |
| 289 | + | |
| 290 | +void kbd_put_keysym(int keysym); | |
| 291 | + | |
| 268 | 292 | /* async I/O support */ |
| 269 | 293 | |
| 270 | 294 | typedef void IOReadHandler(void *opaque, const uint8_t *buf, int size); |
| ... | ... | @@ -274,6 +298,42 @@ int qemu_add_fd_read_handler(int fd, IOCanRWHandler *fd_can_read, |
| 274 | 298 | IOReadHandler *fd_read, void *opaque); |
| 275 | 299 | void qemu_del_fd_read_handler(int fd); |
| 276 | 300 | |
| 301 | +/* character device */ | |
| 302 | + | |
| 303 | +#define CHR_EVENT_BREAK 0 /* serial break char */ | |
| 304 | + | |
| 305 | +typedef void IOEventHandler(void *opaque, int event); | |
| 306 | + | |
| 307 | +typedef struct CharDriverState { | |
| 308 | + int (*chr_write)(struct CharDriverState *s, const uint8_t *buf, int len); | |
| 309 | + void (*chr_add_read_handler)(struct CharDriverState *s, | |
| 310 | + IOCanRWHandler *fd_can_read, | |
| 311 | + IOReadHandler *fd_read, void *opaque); | |
| 312 | + IOEventHandler *chr_event; | |
| 313 | + void *opaque; | |
| 314 | +} CharDriverState; | |
| 315 | + | |
| 316 | +void qemu_chr_printf(CharDriverState *s, const char *fmt, ...); | |
| 317 | +int qemu_chr_write(CharDriverState *s, const uint8_t *buf, int len); | |
| 318 | +void qemu_chr_add_read_handler(CharDriverState *s, | |
| 319 | + IOCanRWHandler *fd_can_read, | |
| 320 | + IOReadHandler *fd_read, void *opaque); | |
| 321 | +void qemu_chr_add_event_handler(CharDriverState *s, IOEventHandler *chr_event); | |
| 322 | + | |
| 323 | +CharDriverState *serial_hd; | |
| 324 | + | |
| 325 | +/* consoles */ | |
| 326 | + | |
| 327 | +typedef struct DisplayState DisplayState; | |
| 328 | +typedef struct TextConsole TextConsole; | |
| 329 | + | |
| 330 | +extern TextConsole *vga_console; | |
| 331 | + | |
| 332 | +TextConsole *graphic_console_init(DisplayState *ds); | |
| 333 | +int is_active_console(TextConsole *s); | |
| 334 | +CharDriverState *text_console_init(DisplayState *ds); | |
| 335 | +void console_select(unsigned int index); | |
| 336 | + | |
| 277 | 337 | /* network redirectors support */ |
| 278 | 338 | |
| 279 | 339 | #define MAX_NICS 8 |
| ... | ... | @@ -437,6 +497,7 @@ void bdrv_set_change_cb(BlockDriverState *bs, |
| 437 | 497 | |
| 438 | 498 | void bdrv_info(void); |
| 439 | 499 | BlockDriverState *bdrv_find(const char *name); |
| 500 | +void bdrv_iterate(void (*it)(void *opaque, const char *name), void *opaque); | |
| 440 | 501 | |
| 441 | 502 | /* ISA bus */ |
| 442 | 503 | |
| ... | ... | @@ -534,14 +595,16 @@ openpic_t *openpic_init (PCIBus *bus, int *pmem_index, int nb_cpus); |
| 534 | 595 | |
| 535 | 596 | #define VGA_RAM_SIZE (4096 * 1024) |
| 536 | 597 | |
| 537 | -typedef struct DisplayState { | |
| 598 | +struct DisplayState { | |
| 538 | 599 | uint8_t *data; |
| 539 | 600 | int linesize; |
| 540 | 601 | int depth; |
| 602 | + int width; | |
| 603 | + int height; | |
| 541 | 604 | void (*dpy_update)(struct DisplayState *s, int x, int y, int w, int h); |
| 542 | 605 | void (*dpy_resize)(struct DisplayState *s, int w, int h); |
| 543 | 606 | void (*dpy_refresh)(struct DisplayState *s); |
| 544 | -} DisplayState; | |
| 607 | +}; | |
| 545 | 608 | |
| 546 | 609 | static inline void dpy_update(DisplayState *s, int x, int y, int w, int h) |
| 547 | 610 | { |
| ... | ... | @@ -644,13 +707,7 @@ void rtc_set_date(RTCState *s, const struct tm *tm); |
| 644 | 707 | /* serial.c */ |
| 645 | 708 | |
| 646 | 709 | typedef struct SerialState SerialState; |
| 647 | - | |
| 648 | -extern SerialState *serial_console; | |
| 649 | - | |
| 650 | -SerialState *serial_init(int base, int irq, int fd); | |
| 651 | -int serial_can_receive(SerialState *s); | |
| 652 | -void serial_receive_byte(SerialState *s, int ch); | |
| 653 | -void serial_receive_break(SerialState *s); | |
| 710 | +SerialState *serial_init(int base, int irq, CharDriverState *chr); | |
| 654 | 711 | |
| 655 | 712 | /* i8259.c */ |
| 656 | 713 | |
| ... | ... | @@ -767,7 +824,7 @@ extern ADBBusState adb_bus; |
| 767 | 824 | int cuda_init(openpic_t *openpic, int irq); |
| 768 | 825 | |
| 769 | 826 | /* monitor.c */ |
| 770 | -void monitor_init(void); | |
| 827 | +void monitor_init(CharDriverState *hd, int show_banner); | |
| 771 | 828 | void term_printf(const char *fmt, ...) __attribute__ ((__format__ (__printf__, 1, 2))); |
| 772 | 829 | void term_flush(void); |
| 773 | 830 | void term_print_help(void); | ... | ... |