Commit 80cabfad16384ca47f783a7c494bd1c3c6e3c4bc
1 parent
38ca2abc
separated more devices from emulator
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@656 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
10 changed files
with
2936 additions
and
2554 deletions
Makefile.target
| 1 | 1 | include config.mak |
| 2 | 2 | |
| 3 | 3 | TARGET_PATH=$(SRC_PATH)/target-$(TARGET_ARCH) |
| 4 | -VPATH=$(SRC_PATH):$(TARGET_PATH) | |
| 4 | +VPATH=$(SRC_PATH):$(TARGET_PATH):$(SRC_PATH)/hw | |
| 5 | 5 | CFLAGS=-Wall -O2 -g |
| 6 | 6 | LDFLAGS=-g |
| 7 | 7 | LIBS= |
| ... | ... | @@ -204,7 +204,8 @@ ifeq ($(ARCH),alpha) |
| 204 | 204 | endif |
| 205 | 205 | |
| 206 | 206 | # must use static linking to avoid leaving stuff in virtual address space |
| 207 | -VL_OBJS=vl.o block.o ide.o vga.o sb16.o dma.o oss.o fdc.o osdep.o | |
| 207 | +VL_OBJS=vl.o osdep.o block.o ide.o ne2000.o pckbd.o vga.o sb16.o dma.o oss.o \ | |
| 208 | + fdc.o mc146818rtc.o serial.o i8259.o i8254.o pc.o | |
| 208 | 209 | ifeq ($(TARGET_ARCH), ppc) |
| 209 | 210 | VL_OBJS+= hw.o |
| 210 | 211 | endif | ... | ... |
hw/i8254.c
0 → 100644
| 1 | +/* | |
| 2 | + * QEMU 8253/8254 interval timer emulation | |
| 3 | + * | |
| 4 | + * Copyright (c) 2003-2004 Fabrice Bellard | |
| 5 | + * | |
| 6 | + * Permission is hereby granted, free of charge, to any person obtaining a copy | |
| 7 | + * of this software and associated documentation files (the "Software"), to deal | |
| 8 | + * in the Software without restriction, including without limitation the rights | |
| 9 | + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
| 10 | + * copies of the Software, and to permit persons to whom the Software is | |
| 11 | + * furnished to do so, subject to the following conditions: | |
| 12 | + * | |
| 13 | + * The above copyright notice and this permission notice shall be included in | |
| 14 | + * all copies or substantial portions of the Software. | |
| 15 | + * | |
| 16 | + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 17 | + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 18 | + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
| 19 | + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 20 | + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
| 21 | + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
| 22 | + * THE SOFTWARE. | |
| 23 | + */ | |
| 24 | +#include <stdlib.h> | |
| 25 | +#include <stdio.h> | |
| 26 | +#include <stdarg.h> | |
| 27 | +#include <string.h> | |
| 28 | +#include <getopt.h> | |
| 29 | +#include <inttypes.h> | |
| 30 | +#include <unistd.h> | |
| 31 | +#include <sys/mman.h> | |
| 32 | +#include <fcntl.h> | |
| 33 | +#include <signal.h> | |
| 34 | +#include <time.h> | |
| 35 | +#include <sys/time.h> | |
| 36 | +#include <malloc.h> | |
| 37 | +#include <termios.h> | |
| 38 | +#include <sys/poll.h> | |
| 39 | +#include <errno.h> | |
| 40 | +#include <sys/wait.h> | |
| 41 | +#include <netinet/in.h> | |
| 42 | + | |
| 43 | +#include "cpu.h" | |
| 44 | +#include "vl.h" | |
| 45 | + | |
| 46 | +#define RW_STATE_LSB 0 | |
| 47 | +#define RW_STATE_MSB 1 | |
| 48 | +#define RW_STATE_WORD0 2 | |
| 49 | +#define RW_STATE_WORD1 3 | |
| 50 | +#define RW_STATE_LATCHED_WORD0 4 | |
| 51 | +#define RW_STATE_LATCHED_WORD1 5 | |
| 52 | + | |
| 53 | +PITChannelState pit_channels[3]; | |
| 54 | + | |
| 55 | +static int pit_get_count(PITChannelState *s) | |
| 56 | +{ | |
| 57 | + uint64_t d; | |
| 58 | + int counter; | |
| 59 | + | |
| 60 | + d = muldiv64(cpu_get_ticks() - s->count_load_time, PIT_FREQ, ticks_per_sec); | |
| 61 | + switch(s->mode) { | |
| 62 | + case 0: | |
| 63 | + case 1: | |
| 64 | + case 4: | |
| 65 | + case 5: | |
| 66 | + counter = (s->count - d) & 0xffff; | |
| 67 | + break; | |
| 68 | + case 3: | |
| 69 | + /* XXX: may be incorrect for odd counts */ | |
| 70 | + counter = s->count - ((2 * d) % s->count); | |
| 71 | + break; | |
| 72 | + default: | |
| 73 | + counter = s->count - (d % s->count); | |
| 74 | + break; | |
| 75 | + } | |
| 76 | + return counter; | |
| 77 | +} | |
| 78 | + | |
| 79 | +/* get pit output bit */ | |
| 80 | +int pit_get_out(PITChannelState *s) | |
| 81 | +{ | |
| 82 | + uint64_t d; | |
| 83 | + int out; | |
| 84 | + | |
| 85 | + d = muldiv64(cpu_get_ticks() - s->count_load_time, PIT_FREQ, ticks_per_sec); | |
| 86 | + switch(s->mode) { | |
| 87 | + default: | |
| 88 | + case 0: | |
| 89 | + out = (d >= s->count); | |
| 90 | + break; | |
| 91 | + case 1: | |
| 92 | + out = (d < s->count); | |
| 93 | + break; | |
| 94 | + case 2: | |
| 95 | + if ((d % s->count) == 0 && d != 0) | |
| 96 | + out = 1; | |
| 97 | + else | |
| 98 | + out = 0; | |
| 99 | + break; | |
| 100 | + case 3: | |
| 101 | + out = (d % s->count) < ((s->count + 1) >> 1); | |
| 102 | + break; | |
| 103 | + case 4: | |
| 104 | + case 5: | |
| 105 | + out = (d == s->count); | |
| 106 | + break; | |
| 107 | + } | |
| 108 | + return out; | |
| 109 | +} | |
| 110 | + | |
| 111 | +/* get the number of 0 to 1 transitions we had since we call this | |
| 112 | + function */ | |
| 113 | +/* XXX: maybe better to use ticks precision to avoid getting edges | |
| 114 | + twice if checks are done at very small intervals */ | |
| 115 | +int pit_get_out_edges(PITChannelState *s) | |
| 116 | +{ | |
| 117 | + uint64_t d1, d2; | |
| 118 | + int64_t ticks; | |
| 119 | + int ret, v; | |
| 120 | + | |
| 121 | + ticks = cpu_get_ticks(); | |
| 122 | + d1 = muldiv64(s->count_last_edge_check_time - s->count_load_time, | |
| 123 | + PIT_FREQ, ticks_per_sec); | |
| 124 | + d2 = muldiv64(ticks - s->count_load_time, | |
| 125 | + PIT_FREQ, ticks_per_sec); | |
| 126 | + s->count_last_edge_check_time = ticks; | |
| 127 | + switch(s->mode) { | |
| 128 | + default: | |
| 129 | + case 0: | |
| 130 | + if (d1 < s->count && d2 >= s->count) | |
| 131 | + ret = 1; | |
| 132 | + else | |
| 133 | + ret = 0; | |
| 134 | + break; | |
| 135 | + case 1: | |
| 136 | + ret = 0; | |
| 137 | + break; | |
| 138 | + case 2: | |
| 139 | + d1 /= s->count; | |
| 140 | + d2 /= s->count; | |
| 141 | + ret = d2 - d1; | |
| 142 | + break; | |
| 143 | + case 3: | |
| 144 | + v = s->count - ((s->count + 1) >> 1); | |
| 145 | + d1 = (d1 + v) / s->count; | |
| 146 | + d2 = (d2 + v) / s->count; | |
| 147 | + ret = d2 - d1; | |
| 148 | + break; | |
| 149 | + case 4: | |
| 150 | + case 5: | |
| 151 | + if (d1 < s->count && d2 >= s->count) | |
| 152 | + ret = 1; | |
| 153 | + else | |
| 154 | + ret = 0; | |
| 155 | + break; | |
| 156 | + } | |
| 157 | + return ret; | |
| 158 | +} | |
| 159 | + | |
| 160 | +/* val must be 0 or 1 */ | |
| 161 | +void pit_set_gate(PITChannelState *s, int val) | |
| 162 | +{ | |
| 163 | + switch(s->mode) { | |
| 164 | + default: | |
| 165 | + case 0: | |
| 166 | + case 4: | |
| 167 | + /* XXX: just disable/enable counting */ | |
| 168 | + break; | |
| 169 | + case 1: | |
| 170 | + case 5: | |
| 171 | + if (s->gate < val) { | |
| 172 | + /* restart counting on rising edge */ | |
| 173 | + s->count_load_time = cpu_get_ticks(); | |
| 174 | + s->count_last_edge_check_time = s->count_load_time; | |
| 175 | + } | |
| 176 | + break; | |
| 177 | + case 2: | |
| 178 | + case 3: | |
| 179 | + if (s->gate < val) { | |
| 180 | + /* restart counting on rising edge */ | |
| 181 | + s->count_load_time = cpu_get_ticks(); | |
| 182 | + s->count_last_edge_check_time = s->count_load_time; | |
| 183 | + } | |
| 184 | + /* XXX: disable/enable counting */ | |
| 185 | + break; | |
| 186 | + } | |
| 187 | + s->gate = val; | |
| 188 | +} | |
| 189 | + | |
| 190 | +static inline void pit_load_count(PITChannelState *s, int val) | |
| 191 | +{ | |
| 192 | + if (val == 0) | |
| 193 | + val = 0x10000; | |
| 194 | + s->count_load_time = cpu_get_ticks(); | |
| 195 | + s->count_last_edge_check_time = s->count_load_time; | |
| 196 | + s->count = val; | |
| 197 | + if (s == &pit_channels[0] && val <= pit_min_timer_count) { | |
| 198 | + fprintf(stderr, | |
| 199 | + "\nWARNING: qemu: on your system, accurate timer emulation is impossible if its frequency is more than %d Hz. If using a 2.6 guest Linux kernel, you must patch asm/param.h to change HZ from 1000 to 100.\n\n", | |
| 200 | + PIT_FREQ / pit_min_timer_count); | |
| 201 | + } | |
| 202 | +} | |
| 203 | + | |
| 204 | +void pit_ioport_write(CPUState *env, uint32_t addr, uint32_t val) | |
| 205 | +{ | |
| 206 | + int channel, access; | |
| 207 | + PITChannelState *s; | |
| 208 | + | |
| 209 | + addr &= 3; | |
| 210 | + if (addr == 3) { | |
| 211 | + channel = val >> 6; | |
| 212 | + if (channel == 3) | |
| 213 | + return; | |
| 214 | + s = &pit_channels[channel]; | |
| 215 | + access = (val >> 4) & 3; | |
| 216 | + switch(access) { | |
| 217 | + case 0: | |
| 218 | + s->latched_count = pit_get_count(s); | |
| 219 | + s->rw_state = RW_STATE_LATCHED_WORD0; | |
| 220 | + break; | |
| 221 | + default: | |
| 222 | + s->mode = (val >> 1) & 7; | |
| 223 | + s->bcd = val & 1; | |
| 224 | + s->rw_state = access - 1 + RW_STATE_LSB; | |
| 225 | + break; | |
| 226 | + } | |
| 227 | + } else { | |
| 228 | + s = &pit_channels[addr]; | |
| 229 | + switch(s->rw_state) { | |
| 230 | + case RW_STATE_LSB: | |
| 231 | + pit_load_count(s, val); | |
| 232 | + break; | |
| 233 | + case RW_STATE_MSB: | |
| 234 | + pit_load_count(s, val << 8); | |
| 235 | + break; | |
| 236 | + case RW_STATE_WORD0: | |
| 237 | + case RW_STATE_WORD1: | |
| 238 | + if (s->rw_state & 1) { | |
| 239 | + pit_load_count(s, (s->latched_count & 0xff) | (val << 8)); | |
| 240 | + } else { | |
| 241 | + s->latched_count = val; | |
| 242 | + } | |
| 243 | + s->rw_state ^= 1; | |
| 244 | + break; | |
| 245 | + } | |
| 246 | + } | |
| 247 | +} | |
| 248 | + | |
| 249 | +uint32_t pit_ioport_read(CPUState *env, uint32_t addr) | |
| 250 | +{ | |
| 251 | + int ret, count; | |
| 252 | + PITChannelState *s; | |
| 253 | + | |
| 254 | + addr &= 3; | |
| 255 | + s = &pit_channels[addr]; | |
| 256 | + switch(s->rw_state) { | |
| 257 | + case RW_STATE_LSB: | |
| 258 | + case RW_STATE_MSB: | |
| 259 | + case RW_STATE_WORD0: | |
| 260 | + case RW_STATE_WORD1: | |
| 261 | + count = pit_get_count(s); | |
| 262 | + if (s->rw_state & 1) | |
| 263 | + ret = (count >> 8) & 0xff; | |
| 264 | + else | |
| 265 | + ret = count & 0xff; | |
| 266 | + if (s->rw_state & 2) | |
| 267 | + s->rw_state ^= 1; | |
| 268 | + break; | |
| 269 | + default: | |
| 270 | + case RW_STATE_LATCHED_WORD0: | |
| 271 | + case RW_STATE_LATCHED_WORD1: | |
| 272 | + if (s->rw_state & 1) | |
| 273 | + ret = s->latched_count >> 8; | |
| 274 | + else | |
| 275 | + ret = s->latched_count & 0xff; | |
| 276 | + s->rw_state ^= 1; | |
| 277 | + break; | |
| 278 | + } | |
| 279 | + return ret; | |
| 280 | +} | |
| 281 | + | |
| 282 | +void pit_init(void) | |
| 283 | +{ | |
| 284 | + PITChannelState *s; | |
| 285 | + int i; | |
| 286 | + | |
| 287 | + for(i = 0;i < 3; i++) { | |
| 288 | + s = &pit_channels[i]; | |
| 289 | + s->mode = 3; | |
| 290 | + s->gate = (i != 2); | |
| 291 | + pit_load_count(s, 0); | |
| 292 | + } | |
| 293 | + | |
| 294 | + register_ioport_write(0x40, 4, pit_ioport_write, 1); | |
| 295 | + register_ioport_read(0x40, 3, pit_ioport_read, 1); | |
| 296 | +} | |
| 297 | + | ... | ... |
hw/i8259.c
0 → 100644
| 1 | +/* | |
| 2 | + * QEMU 8259 interrupt controller emulation | |
| 3 | + * | |
| 4 | + * Copyright (c) 2003-2004 Fabrice Bellard | |
| 5 | + * | |
| 6 | + * Permission is hereby granted, free of charge, to any person obtaining a copy | |
| 7 | + * of this software and associated documentation files (the "Software"), to deal | |
| 8 | + * in the Software without restriction, including without limitation the rights | |
| 9 | + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
| 10 | + * copies of the Software, and to permit persons to whom the Software is | |
| 11 | + * furnished to do so, subject to the following conditions: | |
| 12 | + * | |
| 13 | + * The above copyright notice and this permission notice shall be included in | |
| 14 | + * all copies or substantial portions of the Software. | |
| 15 | + * | |
| 16 | + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 17 | + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 18 | + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
| 19 | + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 20 | + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
| 21 | + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
| 22 | + * THE SOFTWARE. | |
| 23 | + */ | |
| 24 | +#include <stdlib.h> | |
| 25 | +#include <stdio.h> | |
| 26 | +#include <stdarg.h> | |
| 27 | +#include <string.h> | |
| 28 | +#include <getopt.h> | |
| 29 | +#include <inttypes.h> | |
| 30 | +#include <unistd.h> | |
| 31 | +#include <sys/mman.h> | |
| 32 | +#include <fcntl.h> | |
| 33 | +#include <signal.h> | |
| 34 | +#include <time.h> | |
| 35 | +#include <sys/time.h> | |
| 36 | +#include <malloc.h> | |
| 37 | +#include <termios.h> | |
| 38 | +#include <sys/poll.h> | |
| 39 | +#include <errno.h> | |
| 40 | +#include <sys/wait.h> | |
| 41 | +#include <netinet/in.h> | |
| 42 | + | |
| 43 | +#include "cpu.h" | |
| 44 | +#include "vl.h" | |
| 45 | + | |
| 46 | +/* debug PIC */ | |
| 47 | +//#define DEBUG_PIC | |
| 48 | + | |
| 49 | +typedef struct PicState { | |
| 50 | + uint8_t last_irr; /* edge detection */ | |
| 51 | + uint8_t irr; /* interrupt request register */ | |
| 52 | + uint8_t imr; /* interrupt mask register */ | |
| 53 | + uint8_t isr; /* interrupt service register */ | |
| 54 | + uint8_t priority_add; /* highest irq priority */ | |
| 55 | + uint8_t irq_base; | |
| 56 | + uint8_t read_reg_select; | |
| 57 | + uint8_t poll; | |
| 58 | + uint8_t special_mask; | |
| 59 | + uint8_t init_state; | |
| 60 | + uint8_t auto_eoi; | |
| 61 | + uint8_t rotate_on_auto_eoi; | |
| 62 | + uint8_t special_fully_nested_mode; | |
| 63 | + uint8_t init4; /* true if 4 byte init */ | |
| 64 | +} PicState; | |
| 65 | + | |
| 66 | +/* 0 is master pic, 1 is slave pic */ | |
| 67 | +PicState pics[2]; | |
| 68 | +int pic_irq_requested; | |
| 69 | + | |
| 70 | +/* set irq level. If an edge is detected, then the IRR is set to 1 */ | |
| 71 | +static inline void pic_set_irq1(PicState *s, int irq, int level) | |
| 72 | +{ | |
| 73 | + int mask; | |
| 74 | + mask = 1 << irq; | |
| 75 | + if (level) { | |
| 76 | + if ((s->last_irr & mask) == 0) | |
| 77 | + s->irr |= mask; | |
| 78 | + s->last_irr |= mask; | |
| 79 | + } else { | |
| 80 | + s->last_irr &= ~mask; | |
| 81 | + } | |
| 82 | +} | |
| 83 | + | |
| 84 | +/* return the highest priority found in mask (highest = smallest | |
| 85 | + number). Return 8 if no irq */ | |
| 86 | +static inline int get_priority(PicState *s, int mask) | |
| 87 | +{ | |
| 88 | + int priority; | |
| 89 | + if (mask == 0) | |
| 90 | + return 8; | |
| 91 | + priority = 0; | |
| 92 | + while ((mask & (1 << ((priority + s->priority_add) & 7))) == 0) | |
| 93 | + priority++; | |
| 94 | + return priority; | |
| 95 | +} | |
| 96 | + | |
| 97 | +/* return the pic wanted interrupt. return -1 if none */ | |
| 98 | +static int pic_get_irq(PicState *s) | |
| 99 | +{ | |
| 100 | + int mask, cur_priority, priority; | |
| 101 | + | |
| 102 | + mask = s->irr & ~s->imr; | |
| 103 | + priority = get_priority(s, mask); | |
| 104 | + if (priority == 8) | |
| 105 | + return -1; | |
| 106 | + /* compute current priority. If special fully nested mode on the | |
| 107 | + master, the IRQ coming from the slave is not taken into account | |
| 108 | + for the priority computation. */ | |
| 109 | + mask = s->isr; | |
| 110 | + if (s->special_fully_nested_mode && s == &pics[0]) | |
| 111 | + mask &= ~(1 << 2); | |
| 112 | + cur_priority = get_priority(s, mask); | |
| 113 | + if (priority < cur_priority) { | |
| 114 | + /* higher priority found: an irq should be generated */ | |
| 115 | + return (priority + s->priority_add) & 7; | |
| 116 | + } else { | |
| 117 | + return -1; | |
| 118 | + } | |
| 119 | +} | |
| 120 | + | |
| 121 | +/* raise irq to CPU if necessary. must be called every time the active | |
| 122 | + irq may change */ | |
| 123 | +void pic_update_irq(void) | |
| 124 | +{ | |
| 125 | + int irq2, irq; | |
| 126 | + | |
| 127 | + /* first look at slave pic */ | |
| 128 | + irq2 = pic_get_irq(&pics[1]); | |
| 129 | + if (irq2 >= 0) { | |
| 130 | + /* if irq request by slave pic, signal master PIC */ | |
| 131 | + pic_set_irq1(&pics[0], 2, 1); | |
| 132 | + pic_set_irq1(&pics[0], 2, 0); | |
| 133 | + } | |
| 134 | + /* look at requested irq */ | |
| 135 | + irq = pic_get_irq(&pics[0]); | |
| 136 | + if (irq >= 0) { | |
| 137 | + if (irq == 2) { | |
| 138 | + /* from slave pic */ | |
| 139 | + pic_irq_requested = 8 + irq2; | |
| 140 | + } else { | |
| 141 | + /* from master pic */ | |
| 142 | + pic_irq_requested = irq; | |
| 143 | + } | |
| 144 | +#if defined(DEBUG_PIC) | |
| 145 | + { | |
| 146 | + int i; | |
| 147 | + for(i = 0; i < 2; i++) { | |
| 148 | + printf("pic%d: imr=%x irr=%x padd=%d\n", | |
| 149 | + i, pics[i].imr, pics[i].irr, pics[i].priority_add); | |
| 150 | + | |
| 151 | + } | |
| 152 | + } | |
| 153 | + printf("pic: cpu_interrupt req=%d\n", pic_irq_requested); | |
| 154 | +#endif | |
| 155 | + cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HARD); | |
| 156 | + } | |
| 157 | +} | |
| 158 | + | |
| 159 | +#ifdef DEBUG_IRQ_LATENCY | |
| 160 | +int64_t irq_time[16]; | |
| 161 | +int64_t cpu_get_ticks(void); | |
| 162 | +#endif | |
| 163 | +#if defined(DEBUG_PIC) | |
| 164 | +int irq_level[16]; | |
| 165 | +#endif | |
| 166 | + | |
| 167 | +void pic_set_irq(int irq, int level) | |
| 168 | +{ | |
| 169 | +#if defined(DEBUG_PIC) | |
| 170 | + if (level != irq_level[irq]) { | |
| 171 | + printf("pic_set_irq: irq=%d level=%d\n", irq, level); | |
| 172 | + irq_level[irq] = level; | |
| 173 | + } | |
| 174 | +#endif | |
| 175 | +#ifdef DEBUG_IRQ_LATENCY | |
| 176 | + if (level) { | |
| 177 | + irq_time[irq] = cpu_get_ticks(); | |
| 178 | + } | |
| 179 | +#endif | |
| 180 | + pic_set_irq1(&pics[irq >> 3], irq & 7, level); | |
| 181 | + pic_update_irq(); | |
| 182 | +} | |
| 183 | + | |
| 184 | +/* acknowledge interrupt 'irq' */ | |
| 185 | +static inline void pic_intack(PicState *s, int irq) | |
| 186 | +{ | |
| 187 | + if (s->auto_eoi) { | |
| 188 | + if (s->rotate_on_auto_eoi) | |
| 189 | + s->priority_add = (irq + 1) & 7; | |
| 190 | + } else { | |
| 191 | + s->isr |= (1 << irq); | |
| 192 | + } | |
| 193 | + s->irr &= ~(1 << irq); | |
| 194 | +} | |
| 195 | + | |
| 196 | +int cpu_x86_get_pic_interrupt(CPUState *env) | |
| 197 | +{ | |
| 198 | + int irq, irq2, intno; | |
| 199 | + | |
| 200 | + /* signal the pic that the irq was acked by the CPU */ | |
| 201 | + irq = pic_irq_requested; | |
| 202 | +#ifdef DEBUG_IRQ_LATENCY | |
| 203 | + printf("IRQ%d latency=%0.3fus\n", | |
| 204 | + irq, | |
| 205 | + (double)(cpu_get_ticks() - irq_time[irq]) * 1000000.0 / ticks_per_sec); | |
| 206 | +#endif | |
| 207 | +#if defined(DEBUG_PIC) | |
| 208 | + printf("pic_interrupt: irq=%d\n", irq); | |
| 209 | +#endif | |
| 210 | + | |
| 211 | + if (irq >= 8) { | |
| 212 | + irq2 = irq & 7; | |
| 213 | + pic_intack(&pics[1], irq2); | |
| 214 | + irq = 2; | |
| 215 | + intno = pics[1].irq_base + irq2; | |
| 216 | + } else { | |
| 217 | + intno = pics[0].irq_base + irq; | |
| 218 | + } | |
| 219 | + pic_intack(&pics[0], irq); | |
| 220 | + return intno; | |
| 221 | +} | |
| 222 | + | |
| 223 | +void pic_ioport_write(CPUState *env, uint32_t addr, uint32_t val) | |
| 224 | +{ | |
| 225 | + PicState *s; | |
| 226 | + int priority, cmd, irq; | |
| 227 | + | |
| 228 | +#ifdef DEBUG_PIC | |
| 229 | + printf("pic_write: addr=0x%02x val=0x%02x\n", addr, val); | |
| 230 | +#endif | |
| 231 | + s = &pics[addr >> 7]; | |
| 232 | + addr &= 1; | |
| 233 | + if (addr == 0) { | |
| 234 | + if (val & 0x10) { | |
| 235 | + /* init */ | |
| 236 | + memset(s, 0, sizeof(PicState)); | |
| 237 | + s->init_state = 1; | |
| 238 | + s->init4 = val & 1; | |
| 239 | + if (val & 0x02) | |
| 240 | + hw_error("single mode not supported"); | |
| 241 | + if (val & 0x08) | |
| 242 | + hw_error("level sensitive irq not supported"); | |
| 243 | + } else if (val & 0x08) { | |
| 244 | + if (val & 0x04) | |
| 245 | + s->poll = 1; | |
| 246 | + if (val & 0x02) | |
| 247 | + s->read_reg_select = val & 1; | |
| 248 | + if (val & 0x40) | |
| 249 | + s->special_mask = (val >> 5) & 1; | |
| 250 | + } else { | |
| 251 | + cmd = val >> 5; | |
| 252 | + switch(cmd) { | |
| 253 | + case 0: | |
| 254 | + case 4: | |
| 255 | + s->rotate_on_auto_eoi = cmd >> 2; | |
| 256 | + break; | |
| 257 | + case 1: /* end of interrupt */ | |
| 258 | + case 5: | |
| 259 | + priority = get_priority(s, s->isr); | |
| 260 | + if (priority != 8) { | |
| 261 | + irq = (priority + s->priority_add) & 7; | |
| 262 | + s->isr &= ~(1 << irq); | |
| 263 | + if (cmd == 5) | |
| 264 | + s->priority_add = (irq + 1) & 7; | |
| 265 | + pic_update_irq(); | |
| 266 | + } | |
| 267 | + break; | |
| 268 | + case 3: | |
| 269 | + irq = val & 7; | |
| 270 | + s->isr &= ~(1 << irq); | |
| 271 | + pic_update_irq(); | |
| 272 | + break; | |
| 273 | + case 6: | |
| 274 | + s->priority_add = (val + 1) & 7; | |
| 275 | + pic_update_irq(); | |
| 276 | + break; | |
| 277 | + case 7: | |
| 278 | + irq = val & 7; | |
| 279 | + s->isr &= ~(1 << irq); | |
| 280 | + s->priority_add = (irq + 1) & 7; | |
| 281 | + pic_update_irq(); | |
| 282 | + break; | |
| 283 | + default: | |
| 284 | + /* no operation */ | |
| 285 | + break; | |
| 286 | + } | |
| 287 | + } | |
| 288 | + } else { | |
| 289 | + switch(s->init_state) { | |
| 290 | + case 0: | |
| 291 | + /* normal mode */ | |
| 292 | + s->imr = val; | |
| 293 | + pic_update_irq(); | |
| 294 | + break; | |
| 295 | + case 1: | |
| 296 | + s->irq_base = val & 0xf8; | |
| 297 | + s->init_state = 2; | |
| 298 | + break; | |
| 299 | + case 2: | |
| 300 | + if (s->init4) { | |
| 301 | + s->init_state = 3; | |
| 302 | + } else { | |
| 303 | + s->init_state = 0; | |
| 304 | + } | |
| 305 | + break; | |
| 306 | + case 3: | |
| 307 | + s->special_fully_nested_mode = (val >> 4) & 1; | |
| 308 | + s->auto_eoi = (val >> 1) & 1; | |
| 309 | + s->init_state = 0; | |
| 310 | + break; | |
| 311 | + } | |
| 312 | + } | |
| 313 | +} | |
| 314 | + | |
| 315 | +static uint32_t pic_poll_read (PicState *s, uint32_t addr1) | |
| 316 | +{ | |
| 317 | + int ret; | |
| 318 | + | |
| 319 | + ret = pic_get_irq(s); | |
| 320 | + if (ret >= 0) { | |
| 321 | + if (addr1 >> 7) { | |
| 322 | + pics[0].isr &= ~(1 << 2); | |
| 323 | + pics[0].irr &= ~(1 << 2); | |
| 324 | + } | |
| 325 | + s->irr &= ~(1 << ret); | |
| 326 | + s->isr &= ~(1 << ret); | |
| 327 | + if (addr1 >> 7 || ret != 2) | |
| 328 | + pic_update_irq(); | |
| 329 | + } else { | |
| 330 | + ret = 0x07; | |
| 331 | + pic_update_irq(); | |
| 332 | + } | |
| 333 | + | |
| 334 | + return ret; | |
| 335 | +} | |
| 336 | + | |
| 337 | +uint32_t pic_ioport_read(CPUState *env, uint32_t addr1) | |
| 338 | +{ | |
| 339 | + PicState *s; | |
| 340 | + unsigned int addr; | |
| 341 | + int ret; | |
| 342 | + | |
| 343 | + addr = addr1; | |
| 344 | + s = &pics[addr >> 7]; | |
| 345 | + addr &= 1; | |
| 346 | + if (s->poll) { | |
| 347 | + ret = pic_poll_read(s, addr1); | |
| 348 | + s->poll = 0; | |
| 349 | + } else { | |
| 350 | + if (addr == 0) { | |
| 351 | + if (s->read_reg_select) | |
| 352 | + ret = s->isr; | |
| 353 | + else | |
| 354 | + ret = s->irr; | |
| 355 | + } else { | |
| 356 | + ret = s->imr; | |
| 357 | + } | |
| 358 | + } | |
| 359 | +#ifdef DEBUG_PIC | |
| 360 | + printf("pic_read: addr=0x%02x val=0x%02x\n", addr1, ret); | |
| 361 | +#endif | |
| 362 | + return ret; | |
| 363 | +} | |
| 364 | + | |
| 365 | +/* memory mapped interrupt status */ | |
| 366 | +uint32_t pic_intack_read(CPUState *env) | |
| 367 | +{ | |
| 368 | + int ret; | |
| 369 | + | |
| 370 | + ret = pic_poll_read(&pics[0], 0x00); | |
| 371 | + if (ret == 2) | |
| 372 | + ret = pic_poll_read(&pics[1], 0x80) + 8; | |
| 373 | + /* Prepare for ISR read */ | |
| 374 | + pics[0].read_reg_select = 1; | |
| 375 | + | |
| 376 | + return ret; | |
| 377 | +} | |
| 378 | + | |
| 379 | +void pic_init(void) | |
| 380 | +{ | |
| 381 | +#if defined (TARGET_I386) || defined (TARGET_PPC) | |
| 382 | + register_ioport_write(0x20, 2, pic_ioport_write, 1); | |
| 383 | + register_ioport_read(0x20, 2, pic_ioport_read, 1); | |
| 384 | + register_ioport_write(0xa0, 2, pic_ioport_write, 1); | |
| 385 | + register_ioport_read(0xa0, 2, pic_ioport_read, 1); | |
| 386 | +#endif | |
| 387 | +} | |
| 388 | + | ... | ... |
hw/mc146818rtc.c
0 → 100644
| 1 | +/* | |
| 2 | + * QEMU MC146818 RTC emulation | |
| 3 | + * | |
| 4 | + * Copyright (c) 2003-2004 Fabrice Bellard | |
| 5 | + * | |
| 6 | + * Permission is hereby granted, free of charge, to any person obtaining a copy | |
| 7 | + * of this software and associated documentation files (the "Software"), to deal | |
| 8 | + * in the Software without restriction, including without limitation the rights | |
| 9 | + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
| 10 | + * copies of the Software, and to permit persons to whom the Software is | |
| 11 | + * furnished to do so, subject to the following conditions: | |
| 12 | + * | |
| 13 | + * The above copyright notice and this permission notice shall be included in | |
| 14 | + * all copies or substantial portions of the Software. | |
| 15 | + * | |
| 16 | + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 17 | + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 18 | + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
| 19 | + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 20 | + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
| 21 | + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
| 22 | + * THE SOFTWARE. | |
| 23 | + */ | |
| 24 | +#include <stdlib.h> | |
| 25 | +#include <stdio.h> | |
| 26 | +#include <stdarg.h> | |
| 27 | +#include <string.h> | |
| 28 | +#include <getopt.h> | |
| 29 | +#include <inttypes.h> | |
| 30 | +#include <unistd.h> | |
| 31 | +#include <sys/mman.h> | |
| 32 | +#include <fcntl.h> | |
| 33 | +#include <signal.h> | |
| 34 | +#include <time.h> | |
| 35 | +#include <sys/time.h> | |
| 36 | +#include <malloc.h> | |
| 37 | +#include <termios.h> | |
| 38 | +#include <sys/poll.h> | |
| 39 | +#include <errno.h> | |
| 40 | +#include <sys/wait.h> | |
| 41 | +#include <netinet/in.h> | |
| 42 | + | |
| 43 | +#include "cpu.h" | |
| 44 | +#include "vl.h" | |
| 45 | + | |
| 46 | +//#define DEBUG_CMOS | |
| 47 | + | |
| 48 | +#define RTC_SECONDS 0 | |
| 49 | +#define RTC_SECONDS_ALARM 1 | |
| 50 | +#define RTC_MINUTES 2 | |
| 51 | +#define RTC_MINUTES_ALARM 3 | |
| 52 | +#define RTC_HOURS 4 | |
| 53 | +#define RTC_HOURS_ALARM 5 | |
| 54 | +#define RTC_ALARM_DONT_CARE 0xC0 | |
| 55 | + | |
| 56 | +#define RTC_DAY_OF_WEEK 6 | |
| 57 | +#define RTC_DAY_OF_MONTH 7 | |
| 58 | +#define RTC_MONTH 8 | |
| 59 | +#define RTC_YEAR 9 | |
| 60 | + | |
| 61 | +#define RTC_REG_A 10 | |
| 62 | +#define RTC_REG_B 11 | |
| 63 | +#define RTC_REG_C 12 | |
| 64 | +#define RTC_REG_D 13 | |
| 65 | + | |
| 66 | +/* PC cmos mappings */ | |
| 67 | +#define REG_IBM_CENTURY_BYTE 0x32 | |
| 68 | +#define REG_IBM_PS2_CENTURY_BYTE 0x37 | |
| 69 | + | |
| 70 | +RTCState rtc_state; | |
| 71 | + | |
| 72 | +static void cmos_ioport_write(CPUState *env, uint32_t addr, uint32_t data) | |
| 73 | +{ | |
| 74 | + RTCState *s = &rtc_state; | |
| 75 | + | |
| 76 | + if ((addr & 1) == 0) { | |
| 77 | + s->cmos_index = data & 0x7f; | |
| 78 | + } else { | |
| 79 | +#ifdef DEBUG_CMOS | |
| 80 | + printf("cmos: write index=0x%02x val=0x%02x\n", | |
| 81 | + s->cmos_index, data); | |
| 82 | +#endif | |
| 83 | + switch(addr) { | |
| 84 | + case RTC_SECONDS_ALARM: | |
| 85 | + case RTC_MINUTES_ALARM: | |
| 86 | + case RTC_HOURS_ALARM: | |
| 87 | + /* XXX: not supported */ | |
| 88 | + s->cmos_data[s->cmos_index] = data; | |
| 89 | + break; | |
| 90 | + case RTC_SECONDS: | |
| 91 | + case RTC_MINUTES: | |
| 92 | + case RTC_HOURS: | |
| 93 | + case RTC_DAY_OF_WEEK: | |
| 94 | + case RTC_DAY_OF_MONTH: | |
| 95 | + case RTC_MONTH: | |
| 96 | + case RTC_YEAR: | |
| 97 | + s->cmos_data[s->cmos_index] = data; | |
| 98 | + break; | |
| 99 | + case RTC_REG_A: | |
| 100 | + case RTC_REG_B: | |
| 101 | + s->cmos_data[s->cmos_index] = data; | |
| 102 | + break; | |
| 103 | + case RTC_REG_C: | |
| 104 | + case RTC_REG_D: | |
| 105 | + /* cannot write to them */ | |
| 106 | + break; | |
| 107 | + default: | |
| 108 | + s->cmos_data[s->cmos_index] = data; | |
| 109 | + break; | |
| 110 | + } | |
| 111 | + } | |
| 112 | +} | |
| 113 | + | |
| 114 | +static inline int to_bcd(int a) | |
| 115 | +{ | |
| 116 | + return ((a / 10) << 4) | (a % 10); | |
| 117 | +} | |
| 118 | + | |
| 119 | +static void cmos_update_time(RTCState *s) | |
| 120 | +{ | |
| 121 | + struct tm *tm; | |
| 122 | + time_t ti; | |
| 123 | + | |
| 124 | + ti = time(NULL); | |
| 125 | + tm = gmtime(&ti); | |
| 126 | + s->cmos_data[RTC_SECONDS] = to_bcd(tm->tm_sec); | |
| 127 | + s->cmos_data[RTC_MINUTES] = to_bcd(tm->tm_min); | |
| 128 | + s->cmos_data[RTC_HOURS] = to_bcd(tm->tm_hour); | |
| 129 | + s->cmos_data[RTC_DAY_OF_WEEK] = to_bcd(tm->tm_wday); | |
| 130 | + s->cmos_data[RTC_DAY_OF_MONTH] = to_bcd(tm->tm_mday); | |
| 131 | + s->cmos_data[RTC_MONTH] = to_bcd(tm->tm_mon + 1); | |
| 132 | + s->cmos_data[RTC_YEAR] = to_bcd(tm->tm_year % 100); | |
| 133 | + s->cmos_data[REG_IBM_CENTURY_BYTE] = to_bcd((tm->tm_year / 100) + 19); | |
| 134 | + s->cmos_data[REG_IBM_PS2_CENTURY_BYTE] = s->cmos_data[REG_IBM_CENTURY_BYTE]; | |
| 135 | +} | |
| 136 | + | |
| 137 | +static uint32_t cmos_ioport_read(CPUState *env, uint32_t addr) | |
| 138 | +{ | |
| 139 | + RTCState *s = &rtc_state; | |
| 140 | + int ret; | |
| 141 | + if ((addr & 1) == 0) { | |
| 142 | + return 0xff; | |
| 143 | + } else { | |
| 144 | + switch(s->cmos_index) { | |
| 145 | + case RTC_SECONDS: | |
| 146 | + case RTC_MINUTES: | |
| 147 | + case RTC_HOURS: | |
| 148 | + case RTC_DAY_OF_WEEK: | |
| 149 | + case RTC_DAY_OF_MONTH: | |
| 150 | + case RTC_MONTH: | |
| 151 | + case RTC_YEAR: | |
| 152 | + case REG_IBM_CENTURY_BYTE: | |
| 153 | + case REG_IBM_PS2_CENTURY_BYTE: | |
| 154 | + cmos_update_time(s); | |
| 155 | + ret = s->cmos_data[s->cmos_index]; | |
| 156 | + break; | |
| 157 | + case RTC_REG_A: | |
| 158 | + ret = s->cmos_data[s->cmos_index]; | |
| 159 | + /* toggle update-in-progress bit for Linux (same hack as | |
| 160 | + plex86) */ | |
| 161 | + s->cmos_data[RTC_REG_A] ^= 0x80; | |
| 162 | + break; | |
| 163 | + case RTC_REG_C: | |
| 164 | + ret = s->cmos_data[s->cmos_index]; | |
| 165 | + pic_set_irq(s->irq, 0); | |
| 166 | + s->cmos_data[RTC_REG_C] = 0x00; | |
| 167 | + break; | |
| 168 | + default: | |
| 169 | + ret = s->cmos_data[s->cmos_index]; | |
| 170 | + break; | |
| 171 | + } | |
| 172 | +#ifdef DEBUG_CMOS | |
| 173 | + printf("cmos: read index=0x%02x val=0x%02x\n", | |
| 174 | + s->cmos_index, ret); | |
| 175 | +#endif | |
| 176 | + return ret; | |
| 177 | + } | |
| 178 | +} | |
| 179 | + | |
| 180 | +void rtc_timer(void) | |
| 181 | +{ | |
| 182 | + RTCState *s = &rtc_state; | |
| 183 | + if (s->cmos_data[RTC_REG_B] & 0x50) { | |
| 184 | + pic_set_irq(s->irq, 1); | |
| 185 | + } | |
| 186 | +} | |
| 187 | + | |
| 188 | +void rtc_init(int base, int irq) | |
| 189 | +{ | |
| 190 | + RTCState *s = &rtc_state; | |
| 191 | + | |
| 192 | + cmos_update_time(s); | |
| 193 | + | |
| 194 | + s->irq = irq; | |
| 195 | + s->cmos_data[RTC_REG_A] = 0x26; | |
| 196 | + s->cmos_data[RTC_REG_B] = 0x02; | |
| 197 | + s->cmos_data[RTC_REG_C] = 0x00; | |
| 198 | + s->cmos_data[RTC_REG_D] = 0x80; | |
| 199 | + | |
| 200 | + register_ioport_write(base, 2, cmos_ioport_write, 1); | |
| 201 | + register_ioport_read(base, 2, cmos_ioport_read, 1); | |
| 202 | +} | |
| 203 | + | ... | ... |
hw/ne2000.c
0 → 100644
| 1 | +/* | |
| 2 | + * QEMU NE2000 emulation | |
| 3 | + * | |
| 4 | + * Copyright (c) 2003-2004 Fabrice Bellard | |
| 5 | + * | |
| 6 | + * Permission is hereby granted, free of charge, to any person obtaining a copy | |
| 7 | + * of this software and associated documentation files (the "Software"), to deal | |
| 8 | + * in the Software without restriction, including without limitation the rights | |
| 9 | + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
| 10 | + * copies of the Software, and to permit persons to whom the Software is | |
| 11 | + * furnished to do so, subject to the following conditions: | |
| 12 | + * | |
| 13 | + * The above copyright notice and this permission notice shall be included in | |
| 14 | + * all copies or substantial portions of the Software. | |
| 15 | + * | |
| 16 | + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 17 | + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 18 | + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
| 19 | + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 20 | + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
| 21 | + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
| 22 | + * THE SOFTWARE. | |
| 23 | + */ | |
| 24 | +#include <stdlib.h> | |
| 25 | +#include <stdio.h> | |
| 26 | +#include <stdarg.h> | |
| 27 | +#include <string.h> | |
| 28 | +#include <getopt.h> | |
| 29 | +#include <inttypes.h> | |
| 30 | +#include <unistd.h> | |
| 31 | +#include <sys/mman.h> | |
| 32 | +#include <fcntl.h> | |
| 33 | +#include <signal.h> | |
| 34 | +#include <time.h> | |
| 35 | +#include <sys/time.h> | |
| 36 | +#include <malloc.h> | |
| 37 | +#include <termios.h> | |
| 38 | +#include <sys/poll.h> | |
| 39 | +#include <errno.h> | |
| 40 | +#include <sys/wait.h> | |
| 41 | +#include <netinet/in.h> | |
| 42 | + | |
| 43 | +#include "cpu.h" | |
| 44 | +#include "vl.h" | |
| 45 | + | |
| 46 | +/* debug NE2000 card */ | |
| 47 | +//#define DEBUG_NE2000 | |
| 48 | + | |
| 49 | +/***********************************************************/ | |
| 50 | +/* ne2000 emulation */ | |
| 51 | + | |
| 52 | +#define E8390_CMD 0x00 /* The command register (for all pages) */ | |
| 53 | +/* Page 0 register offsets. */ | |
| 54 | +#define EN0_CLDALO 0x01 /* Low byte of current local dma addr RD */ | |
| 55 | +#define EN0_STARTPG 0x01 /* Starting page of ring bfr WR */ | |
| 56 | +#define EN0_CLDAHI 0x02 /* High byte of current local dma addr RD */ | |
| 57 | +#define EN0_STOPPG 0x02 /* Ending page +1 of ring bfr WR */ | |
| 58 | +#define EN0_BOUNDARY 0x03 /* Boundary page of ring bfr RD WR */ | |
| 59 | +#define EN0_TSR 0x04 /* Transmit status reg RD */ | |
| 60 | +#define EN0_TPSR 0x04 /* Transmit starting page WR */ | |
| 61 | +#define EN0_NCR 0x05 /* Number of collision reg RD */ | |
| 62 | +#define EN0_TCNTLO 0x05 /* Low byte of tx byte count WR */ | |
| 63 | +#define EN0_FIFO 0x06 /* FIFO RD */ | |
| 64 | +#define EN0_TCNTHI 0x06 /* High byte of tx byte count WR */ | |
| 65 | +#define EN0_ISR 0x07 /* Interrupt status reg RD WR */ | |
| 66 | +#define EN0_CRDALO 0x08 /* low byte of current remote dma address RD */ | |
| 67 | +#define EN0_RSARLO 0x08 /* Remote start address reg 0 */ | |
| 68 | +#define EN0_CRDAHI 0x09 /* high byte, current remote dma address RD */ | |
| 69 | +#define EN0_RSARHI 0x09 /* Remote start address reg 1 */ | |
| 70 | +#define EN0_RCNTLO 0x0a /* Remote byte count reg WR */ | |
| 71 | +#define EN0_RCNTHI 0x0b /* Remote byte count reg WR */ | |
| 72 | +#define EN0_RSR 0x0c /* rx status reg RD */ | |
| 73 | +#define EN0_RXCR 0x0c /* RX configuration reg WR */ | |
| 74 | +#define EN0_TXCR 0x0d /* TX configuration reg WR */ | |
| 75 | +#define EN0_COUNTER0 0x0d /* Rcv alignment error counter RD */ | |
| 76 | +#define EN0_DCFG 0x0e /* Data configuration reg WR */ | |
| 77 | +#define EN0_COUNTER1 0x0e /* Rcv CRC error counter RD */ | |
| 78 | +#define EN0_IMR 0x0f /* Interrupt mask reg WR */ | |
| 79 | +#define EN0_COUNTER2 0x0f /* Rcv missed frame error counter RD */ | |
| 80 | + | |
| 81 | +#define EN1_PHYS 0x11 | |
| 82 | +#define EN1_CURPAG 0x17 | |
| 83 | +#define EN1_MULT 0x18 | |
| 84 | + | |
| 85 | +/* Register accessed at EN_CMD, the 8390 base addr. */ | |
| 86 | +#define E8390_STOP 0x01 /* Stop and reset the chip */ | |
| 87 | +#define E8390_START 0x02 /* Start the chip, clear reset */ | |
| 88 | +#define E8390_TRANS 0x04 /* Transmit a frame */ | |
| 89 | +#define E8390_RREAD 0x08 /* Remote read */ | |
| 90 | +#define E8390_RWRITE 0x10 /* Remote write */ | |
| 91 | +#define E8390_NODMA 0x20 /* Remote DMA */ | |
| 92 | +#define E8390_PAGE0 0x00 /* Select page chip registers */ | |
| 93 | +#define E8390_PAGE1 0x40 /* using the two high-order bits */ | |
| 94 | +#define E8390_PAGE2 0x80 /* Page 3 is invalid. */ | |
| 95 | + | |
| 96 | +/* Bits in EN0_ISR - Interrupt status register */ | |
| 97 | +#define ENISR_RX 0x01 /* Receiver, no error */ | |
| 98 | +#define ENISR_TX 0x02 /* Transmitter, no error */ | |
| 99 | +#define ENISR_RX_ERR 0x04 /* Receiver, with error */ | |
| 100 | +#define ENISR_TX_ERR 0x08 /* Transmitter, with error */ | |
| 101 | +#define ENISR_OVER 0x10 /* Receiver overwrote the ring */ | |
| 102 | +#define ENISR_COUNTERS 0x20 /* Counters need emptying */ | |
| 103 | +#define ENISR_RDC 0x40 /* remote dma complete */ | |
| 104 | +#define ENISR_RESET 0x80 /* Reset completed */ | |
| 105 | +#define ENISR_ALL 0x3f /* Interrupts we will enable */ | |
| 106 | + | |
| 107 | +/* Bits in received packet status byte and EN0_RSR*/ | |
| 108 | +#define ENRSR_RXOK 0x01 /* Received a good packet */ | |
| 109 | +#define ENRSR_CRC 0x02 /* CRC error */ | |
| 110 | +#define ENRSR_FAE 0x04 /* frame alignment error */ | |
| 111 | +#define ENRSR_FO 0x08 /* FIFO overrun */ | |
| 112 | +#define ENRSR_MPA 0x10 /* missed pkt */ | |
| 113 | +#define ENRSR_PHY 0x20 /* physical/multicast address */ | |
| 114 | +#define ENRSR_DIS 0x40 /* receiver disable. set in monitor mode */ | |
| 115 | +#define ENRSR_DEF 0x80 /* deferring */ | |
| 116 | + | |
| 117 | +/* Transmitted packet status, EN0_TSR. */ | |
| 118 | +#define ENTSR_PTX 0x01 /* Packet transmitted without error */ | |
| 119 | +#define ENTSR_ND 0x02 /* The transmit wasn't deferred. */ | |
| 120 | +#define ENTSR_COL 0x04 /* The transmit collided at least once. */ | |
| 121 | +#define ENTSR_ABT 0x08 /* The transmit collided 16 times, and was deferred. */ | |
| 122 | +#define ENTSR_CRS 0x10 /* The carrier sense was lost. */ | |
| 123 | +#define ENTSR_FU 0x20 /* A "FIFO underrun" occurred during transmit. */ | |
| 124 | +#define ENTSR_CDH 0x40 /* The collision detect "heartbeat" signal was lost. */ | |
| 125 | +#define ENTSR_OWC 0x80 /* There was an out-of-window collision. */ | |
| 126 | + | |
| 127 | +#define NE2000_MEM_SIZE 32768 | |
| 128 | + | |
| 129 | +typedef struct NE2000State { | |
| 130 | + uint8_t cmd; | |
| 131 | + uint32_t start; | |
| 132 | + uint32_t stop; | |
| 133 | + uint8_t boundary; | |
| 134 | + uint8_t tsr; | |
| 135 | + uint8_t tpsr; | |
| 136 | + uint16_t tcnt; | |
| 137 | + uint16_t rcnt; | |
| 138 | + uint32_t rsar; | |
| 139 | + uint8_t isr; | |
| 140 | + uint8_t dcfg; | |
| 141 | + uint8_t imr; | |
| 142 | + uint8_t phys[6]; /* mac address */ | |
| 143 | + uint8_t curpag; | |
| 144 | + uint8_t mult[8]; /* multicast mask array */ | |
| 145 | + int irq; | |
| 146 | + uint8_t mem[NE2000_MEM_SIZE]; | |
| 147 | +} NE2000State; | |
| 148 | + | |
| 149 | +static NE2000State ne2000_state; | |
| 150 | +int net_fd = -1; | |
| 151 | + | |
| 152 | +static void ne2000_reset(NE2000State *s) | |
| 153 | +{ | |
| 154 | + int i; | |
| 155 | + | |
| 156 | + s->isr = ENISR_RESET; | |
| 157 | + s->mem[0] = 0x52; | |
| 158 | + s->mem[1] = 0x54; | |
| 159 | + s->mem[2] = 0x00; | |
| 160 | + s->mem[3] = 0x12; | |
| 161 | + s->mem[4] = 0x34; | |
| 162 | + s->mem[5] = 0x56; | |
| 163 | + s->mem[14] = 0x57; | |
| 164 | + s->mem[15] = 0x57; | |
| 165 | + | |
| 166 | + /* duplicate prom data */ | |
| 167 | + for(i = 15;i >= 0; i--) { | |
| 168 | + s->mem[2 * i] = s->mem[i]; | |
| 169 | + s->mem[2 * i + 1] = s->mem[i]; | |
| 170 | + } | |
| 171 | +} | |
| 172 | + | |
| 173 | +static void ne2000_update_irq(NE2000State *s) | |
| 174 | +{ | |
| 175 | + int isr; | |
| 176 | + isr = s->isr & s->imr; | |
| 177 | + if (isr) | |
| 178 | + pic_set_irq(s->irq, 1); | |
| 179 | + else | |
| 180 | + pic_set_irq(s->irq, 0); | |
| 181 | +} | |
| 182 | + | |
| 183 | +/* return true if the NE2000 can receive more data */ | |
| 184 | +int ne2000_can_receive(void) | |
| 185 | +{ | |
| 186 | + NE2000State *s = &ne2000_state; | |
| 187 | + int avail, index, boundary; | |
| 188 | + | |
| 189 | + if (s->cmd & E8390_STOP) | |
| 190 | + return 0; | |
| 191 | + index = s->curpag << 8; | |
| 192 | + boundary = s->boundary << 8; | |
| 193 | + if (index < boundary) | |
| 194 | + avail = boundary - index; | |
| 195 | + else | |
| 196 | + avail = (s->stop - s->start) - (index - boundary); | |
| 197 | + if (avail < (MAX_ETH_FRAME_SIZE + 4)) | |
| 198 | + return 0; | |
| 199 | + return 1; | |
| 200 | +} | |
| 201 | + | |
| 202 | +void ne2000_receive(uint8_t *buf, int size) | |
| 203 | +{ | |
| 204 | + NE2000State *s = &ne2000_state; | |
| 205 | + uint8_t *p; | |
| 206 | + int total_len, next, avail, len, index; | |
| 207 | + | |
| 208 | +#if defined(DEBUG_NE2000) | |
| 209 | + printf("NE2000: received len=%d\n", size); | |
| 210 | +#endif | |
| 211 | + | |
| 212 | + index = s->curpag << 8; | |
| 213 | + /* 4 bytes for header */ | |
| 214 | + total_len = size + 4; | |
| 215 | + /* address for next packet (4 bytes for CRC) */ | |
| 216 | + next = index + ((total_len + 4 + 255) & ~0xff); | |
| 217 | + if (next >= s->stop) | |
| 218 | + next -= (s->stop - s->start); | |
| 219 | + /* prepare packet header */ | |
| 220 | + p = s->mem + index; | |
| 221 | + p[0] = ENRSR_RXOK; /* receive status */ | |
| 222 | + p[1] = next >> 8; | |
| 223 | + p[2] = total_len; | |
| 224 | + p[3] = total_len >> 8; | |
| 225 | + index += 4; | |
| 226 | + | |
| 227 | + /* write packet data */ | |
| 228 | + while (size > 0) { | |
| 229 | + avail = s->stop - index; | |
| 230 | + len = size; | |
| 231 | + if (len > avail) | |
| 232 | + len = avail; | |
| 233 | + memcpy(s->mem + index, buf, len); | |
| 234 | + buf += len; | |
| 235 | + index += len; | |
| 236 | + if (index == s->stop) | |
| 237 | + index = s->start; | |
| 238 | + size -= len; | |
| 239 | + } | |
| 240 | + s->curpag = next >> 8; | |
| 241 | + | |
| 242 | + /* now we can signal we have receive something */ | |
| 243 | + s->isr |= ENISR_RX; | |
| 244 | + ne2000_update_irq(s); | |
| 245 | +} | |
| 246 | + | |
| 247 | +static void ne2000_ioport_write(CPUState *env, uint32_t addr, uint32_t val) | |
| 248 | +{ | |
| 249 | + NE2000State *s = &ne2000_state; | |
| 250 | + int offset, page; | |
| 251 | + | |
| 252 | + addr &= 0xf; | |
| 253 | +#ifdef DEBUG_NE2000 | |
| 254 | + printf("NE2000: write addr=0x%x val=0x%02x\n", addr, val); | |
| 255 | +#endif | |
| 256 | + if (addr == E8390_CMD) { | |
| 257 | + /* control register */ | |
| 258 | + s->cmd = val; | |
| 259 | + if (val & E8390_START) { | |
| 260 | + /* test specific case: zero length transfert */ | |
| 261 | + if ((val & (E8390_RREAD | E8390_RWRITE)) && | |
| 262 | + s->rcnt == 0) { | |
| 263 | + s->isr |= ENISR_RDC; | |
| 264 | + ne2000_update_irq(s); | |
| 265 | + } | |
| 266 | + if (val & E8390_TRANS) { | |
| 267 | + net_send_packet(net_fd, s->mem + (s->tpsr << 8), s->tcnt); | |
| 268 | + /* signal end of transfert */ | |
| 269 | + s->tsr = ENTSR_PTX; | |
| 270 | + s->isr |= ENISR_TX; | |
| 271 | + ne2000_update_irq(s); | |
| 272 | + } | |
| 273 | + } | |
| 274 | + } else { | |
| 275 | + page = s->cmd >> 6; | |
| 276 | + offset = addr | (page << 4); | |
| 277 | + switch(offset) { | |
| 278 | + case EN0_STARTPG: | |
| 279 | + s->start = val << 8; | |
| 280 | + break; | |
| 281 | + case EN0_STOPPG: | |
| 282 | + s->stop = val << 8; | |
| 283 | + break; | |
| 284 | + case EN0_BOUNDARY: | |
| 285 | + s->boundary = val; | |
| 286 | + break; | |
| 287 | + case EN0_IMR: | |
| 288 | + s->imr = val; | |
| 289 | + ne2000_update_irq(s); | |
| 290 | + break; | |
| 291 | + case EN0_TPSR: | |
| 292 | + s->tpsr = val; | |
| 293 | + break; | |
| 294 | + case EN0_TCNTLO: | |
| 295 | + s->tcnt = (s->tcnt & 0xff00) | val; | |
| 296 | + break; | |
| 297 | + case EN0_TCNTHI: | |
| 298 | + s->tcnt = (s->tcnt & 0x00ff) | (val << 8); | |
| 299 | + break; | |
| 300 | + case EN0_RSARLO: | |
| 301 | + s->rsar = (s->rsar & 0xff00) | val; | |
| 302 | + break; | |
| 303 | + case EN0_RSARHI: | |
| 304 | + s->rsar = (s->rsar & 0x00ff) | (val << 8); | |
| 305 | + break; | |
| 306 | + case EN0_RCNTLO: | |
| 307 | + s->rcnt = (s->rcnt & 0xff00) | val; | |
| 308 | + break; | |
| 309 | + case EN0_RCNTHI: | |
| 310 | + s->rcnt = (s->rcnt & 0x00ff) | (val << 8); | |
| 311 | + break; | |
| 312 | + case EN0_DCFG: | |
| 313 | + s->dcfg = val; | |
| 314 | + break; | |
| 315 | + case EN0_ISR: | |
| 316 | + s->isr &= ~val; | |
| 317 | + ne2000_update_irq(s); | |
| 318 | + break; | |
| 319 | + case EN1_PHYS ... EN1_PHYS + 5: | |
| 320 | + s->phys[offset - EN1_PHYS] = val; | |
| 321 | + break; | |
| 322 | + case EN1_CURPAG: | |
| 323 | + s->curpag = val; | |
| 324 | + break; | |
| 325 | + case EN1_MULT ... EN1_MULT + 7: | |
| 326 | + s->mult[offset - EN1_MULT] = val; | |
| 327 | + break; | |
| 328 | + } | |
| 329 | + } | |
| 330 | +} | |
| 331 | + | |
| 332 | +static uint32_t ne2000_ioport_read(CPUState *env, uint32_t addr) | |
| 333 | +{ | |
| 334 | + NE2000State *s = &ne2000_state; | |
| 335 | + int offset, page, ret; | |
| 336 | + | |
| 337 | + addr &= 0xf; | |
| 338 | + if (addr == E8390_CMD) { | |
| 339 | + ret = s->cmd; | |
| 340 | + } else { | |
| 341 | + page = s->cmd >> 6; | |
| 342 | + offset = addr | (page << 4); | |
| 343 | + switch(offset) { | |
| 344 | + case EN0_TSR: | |
| 345 | + ret = s->tsr; | |
| 346 | + break; | |
| 347 | + case EN0_BOUNDARY: | |
| 348 | + ret = s->boundary; | |
| 349 | + break; | |
| 350 | + case EN0_ISR: | |
| 351 | + ret = s->isr; | |
| 352 | + break; | |
| 353 | + case EN1_PHYS ... EN1_PHYS + 5: | |
| 354 | + ret = s->phys[offset - EN1_PHYS]; | |
| 355 | + break; | |
| 356 | + case EN1_CURPAG: | |
| 357 | + ret = s->curpag; | |
| 358 | + break; | |
| 359 | + case EN1_MULT ... EN1_MULT + 7: | |
| 360 | + ret = s->mult[offset - EN1_MULT]; | |
| 361 | + break; | |
| 362 | + default: | |
| 363 | + ret = 0x00; | |
| 364 | + break; | |
| 365 | + } | |
| 366 | + } | |
| 367 | +#ifdef DEBUG_NE2000 | |
| 368 | + printf("NE2000: read addr=0x%x val=%02x\n", addr, ret); | |
| 369 | +#endif | |
| 370 | + return ret; | |
| 371 | +} | |
| 372 | + | |
| 373 | +static void ne2000_asic_ioport_write(CPUState *env, uint32_t addr, uint32_t val) | |
| 374 | +{ | |
| 375 | + NE2000State *s = &ne2000_state; | |
| 376 | + uint8_t *p; | |
| 377 | + | |
| 378 | +#ifdef DEBUG_NE2000 | |
| 379 | + printf("NE2000: asic write val=0x%04x\n", val); | |
| 380 | +#endif | |
| 381 | + p = s->mem + s->rsar; | |
| 382 | + if (s->dcfg & 0x01) { | |
| 383 | + /* 16 bit access */ | |
| 384 | + p[0] = val; | |
| 385 | + p[1] = val >> 8; | |
| 386 | + s->rsar += 2; | |
| 387 | + s->rcnt -= 2; | |
| 388 | + } else { | |
| 389 | + /* 8 bit access */ | |
| 390 | + p[0] = val; | |
| 391 | + s->rsar++; | |
| 392 | + s->rcnt--; | |
| 393 | + } | |
| 394 | + /* wrap */ | |
| 395 | + if (s->rsar == s->stop) | |
| 396 | + s->rsar = s->start; | |
| 397 | + if (s->rcnt == 0) { | |
| 398 | + /* signal end of transfert */ | |
| 399 | + s->isr |= ENISR_RDC; | |
| 400 | + ne2000_update_irq(s); | |
| 401 | + } | |
| 402 | +} | |
| 403 | + | |
| 404 | +static uint32_t ne2000_asic_ioport_read(CPUState *env, uint32_t addr) | |
| 405 | +{ | |
| 406 | + NE2000State *s = &ne2000_state; | |
| 407 | + uint8_t *p; | |
| 408 | + int ret; | |
| 409 | + | |
| 410 | + p = s->mem + s->rsar; | |
| 411 | + if (s->dcfg & 0x01) { | |
| 412 | + /* 16 bit access */ | |
| 413 | + ret = p[0] | (p[1] << 8); | |
| 414 | + s->rsar += 2; | |
| 415 | + s->rcnt -= 2; | |
| 416 | + } else { | |
| 417 | + /* 8 bit access */ | |
| 418 | + ret = p[0]; | |
| 419 | + s->rsar++; | |
| 420 | + s->rcnt--; | |
| 421 | + } | |
| 422 | + /* wrap */ | |
| 423 | + if (s->rsar == s->stop) | |
| 424 | + s->rsar = s->start; | |
| 425 | + if (s->rcnt == 0) { | |
| 426 | + /* signal end of transfert */ | |
| 427 | + s->isr |= ENISR_RDC; | |
| 428 | + ne2000_update_irq(s); | |
| 429 | + } | |
| 430 | +#ifdef DEBUG_NE2000 | |
| 431 | + printf("NE2000: asic read val=0x%04x\n", ret); | |
| 432 | +#endif | |
| 433 | + return ret; | |
| 434 | +} | |
| 435 | + | |
| 436 | +static void ne2000_reset_ioport_write(CPUState *env, uint32_t addr, uint32_t val) | |
| 437 | +{ | |
| 438 | + /* nothing to do (end of reset pulse) */ | |
| 439 | +} | |
| 440 | + | |
| 441 | +static uint32_t ne2000_reset_ioport_read(CPUState *env, uint32_t addr) | |
| 442 | +{ | |
| 443 | + NE2000State *s = &ne2000_state; | |
| 444 | + ne2000_reset(s); | |
| 445 | + return 0; | |
| 446 | +} | |
| 447 | + | |
| 448 | +void ne2000_init(int base, int irq) | |
| 449 | +{ | |
| 450 | + NE2000State *s = &ne2000_state; | |
| 451 | + | |
| 452 | + register_ioport_write(base, 16, ne2000_ioport_write, 1); | |
| 453 | + register_ioport_read(base, 16, ne2000_ioport_read, 1); | |
| 454 | + | |
| 455 | + register_ioport_write(base + 0x10, 1, ne2000_asic_ioport_write, 1); | |
| 456 | + register_ioport_read(base + 0x10, 1, ne2000_asic_ioport_read, 1); | |
| 457 | + register_ioport_write(base + 0x10, 2, ne2000_asic_ioport_write, 2); | |
| 458 | + register_ioport_read(base + 0x10, 2, ne2000_asic_ioport_read, 2); | |
| 459 | + | |
| 460 | + register_ioport_write(base + 0x1f, 1, ne2000_reset_ioport_write, 1); | |
| 461 | + register_ioport_read(base + 0x1f, 1, ne2000_reset_ioport_read, 1); | |
| 462 | + s->irq = irq; | |
| 463 | + | |
| 464 | + ne2000_reset(s); | |
| 465 | +} | ... | ... |
hw/pc.c
0 → 100644
| 1 | +/* | |
| 2 | + * QEMU PC System Emulator | |
| 3 | + * | |
| 4 | + * Copyright (c) 2003-2004 Fabrice Bellard | |
| 5 | + * | |
| 6 | + * Permission is hereby granted, free of charge, to any person obtaining a copy | |
| 7 | + * of this software and associated documentation files (the "Software"), to deal | |
| 8 | + * in the Software without restriction, including without limitation the rights | |
| 9 | + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
| 10 | + * copies of the Software, and to permit persons to whom the Software is | |
| 11 | + * furnished to do so, subject to the following conditions: | |
| 12 | + * | |
| 13 | + * The above copyright notice and this permission notice shall be included in | |
| 14 | + * all copies or substantial portions of the Software. | |
| 15 | + * | |
| 16 | + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 17 | + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 18 | + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
| 19 | + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 20 | + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
| 21 | + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
| 22 | + * THE SOFTWARE. | |
| 23 | + */ | |
| 24 | +#include <stdlib.h> | |
| 25 | +#include <stdio.h> | |
| 26 | +#include <stdarg.h> | |
| 27 | +#include <string.h> | |
| 28 | +#include <getopt.h> | |
| 29 | +#include <inttypes.h> | |
| 30 | +#include <unistd.h> | |
| 31 | +#include <sys/mman.h> | |
| 32 | +#include <fcntl.h> | |
| 33 | +#include <signal.h> | |
| 34 | +#include <time.h> | |
| 35 | +#include <sys/time.h> | |
| 36 | +#include <malloc.h> | |
| 37 | +#include <termios.h> | |
| 38 | +#include <sys/poll.h> | |
| 39 | +#include <errno.h> | |
| 40 | +#include <sys/wait.h> | |
| 41 | +#include <netinet/in.h> | |
| 42 | + | |
| 43 | +#include "cpu.h" | |
| 44 | +#include "vl.h" | |
| 45 | + | |
| 46 | +#define BIOS_FILENAME "bios.bin" | |
| 47 | +#define VGABIOS_FILENAME "vgabios.bin" | |
| 48 | +#define LINUX_BOOT_FILENAME "linux_boot.bin" | |
| 49 | + | |
| 50 | +#define KERNEL_LOAD_ADDR 0x00100000 | |
| 51 | +#define INITRD_LOAD_ADDR 0x00400000 | |
| 52 | +#define KERNEL_PARAMS_ADDR 0x00090000 | |
| 53 | +#define KERNEL_CMDLINE_ADDR 0x00099000 | |
| 54 | + | |
| 55 | +int speaker_data_on; | |
| 56 | +int dummy_refresh_clock; | |
| 57 | + | |
| 58 | +static void ioport80_write(CPUState *env, uint32_t addr, uint32_t data) | |
| 59 | +{ | |
| 60 | +} | |
| 61 | + | |
| 62 | +#define REG_EQUIPMENT_BYTE 0x14 | |
| 63 | + | |
| 64 | +static void cmos_init(int ram_size, int boot_device) | |
| 65 | +{ | |
| 66 | + RTCState *s = &rtc_state; | |
| 67 | + int val; | |
| 68 | + | |
| 69 | + /* various important CMOS locations needed by PC/Bochs bios */ | |
| 70 | + | |
| 71 | + s->cmos_data[REG_EQUIPMENT_BYTE] = 0x02; /* FPU is there */ | |
| 72 | + s->cmos_data[REG_EQUIPMENT_BYTE] |= 0x04; /* PS/2 mouse installed */ | |
| 73 | + | |
| 74 | + /* memory size */ | |
| 75 | + val = (ram_size / 1024) - 1024; | |
| 76 | + if (val > 65535) | |
| 77 | + val = 65535; | |
| 78 | + s->cmos_data[0x17] = val; | |
| 79 | + s->cmos_data[0x18] = val >> 8; | |
| 80 | + s->cmos_data[0x30] = val; | |
| 81 | + s->cmos_data[0x31] = val >> 8; | |
| 82 | + | |
| 83 | + val = (ram_size / 65536) - ((16 * 1024 * 1024) / 65536); | |
| 84 | + if (val > 65535) | |
| 85 | + val = 65535; | |
| 86 | + s->cmos_data[0x34] = val; | |
| 87 | + s->cmos_data[0x35] = val >> 8; | |
| 88 | + | |
| 89 | + switch(boot_device) { | |
| 90 | + case 'a': | |
| 91 | + case 'b': | |
| 92 | + s->cmos_data[0x3d] = 0x01; /* floppy boot */ | |
| 93 | + break; | |
| 94 | + default: | |
| 95 | + case 'c': | |
| 96 | + s->cmos_data[0x3d] = 0x02; /* hard drive boot */ | |
| 97 | + break; | |
| 98 | + case 'd': | |
| 99 | + s->cmos_data[0x3d] = 0x03; /* CD-ROM boot */ | |
| 100 | + break; | |
| 101 | + } | |
| 102 | +} | |
| 103 | + | |
| 104 | +void cmos_register_fd (uint8_t fd0, uint8_t fd1) | |
| 105 | +{ | |
| 106 | + RTCState *s = &rtc_state; | |
| 107 | + int nb = 0; | |
| 108 | + | |
| 109 | + s->cmos_data[0x10] = 0; | |
| 110 | + switch (fd0) { | |
| 111 | + case 0: | |
| 112 | + /* 1.44 Mb 3"5 drive */ | |
| 113 | + s->cmos_data[0x10] |= 0x40; | |
| 114 | + break; | |
| 115 | + case 1: | |
| 116 | + /* 2.88 Mb 3"5 drive */ | |
| 117 | + s->cmos_data[0x10] |= 0x60; | |
| 118 | + break; | |
| 119 | + case 2: | |
| 120 | + /* 1.2 Mb 5"5 drive */ | |
| 121 | + s->cmos_data[0x10] |= 0x20; | |
| 122 | + break; | |
| 123 | + } | |
| 124 | + switch (fd1) { | |
| 125 | + case 0: | |
| 126 | + /* 1.44 Mb 3"5 drive */ | |
| 127 | + s->cmos_data[0x10] |= 0x04; | |
| 128 | + break; | |
| 129 | + case 1: | |
| 130 | + /* 2.88 Mb 3"5 drive */ | |
| 131 | + s->cmos_data[0x10] |= 0x06; | |
| 132 | + break; | |
| 133 | + case 2: | |
| 134 | + /* 1.2 Mb 5"5 drive */ | |
| 135 | + s->cmos_data[0x10] |= 0x02; | |
| 136 | + break; | |
| 137 | + } | |
| 138 | + if (fd0 < 3) | |
| 139 | + nb++; | |
| 140 | + if (fd1 < 3) | |
| 141 | + nb++; | |
| 142 | + switch (nb) { | |
| 143 | + case 0: | |
| 144 | + break; | |
| 145 | + case 1: | |
| 146 | + s->cmos_data[REG_EQUIPMENT_BYTE] |= 0x01; /* 1 drive, ready for boot */ | |
| 147 | + break; | |
| 148 | + case 2: | |
| 149 | + s->cmos_data[REG_EQUIPMENT_BYTE] |= 0x41; /* 2 drives, ready for boot */ | |
| 150 | + break; | |
| 151 | + } | |
| 152 | +} | |
| 153 | + | |
| 154 | +void speaker_ioport_write(CPUState *env, uint32_t addr, uint32_t val) | |
| 155 | +{ | |
| 156 | + speaker_data_on = (val >> 1) & 1; | |
| 157 | + pit_set_gate(&pit_channels[2], val & 1); | |
| 158 | +} | |
| 159 | + | |
| 160 | +uint32_t speaker_ioport_read(CPUState *env, uint32_t addr) | |
| 161 | +{ | |
| 162 | + int out; | |
| 163 | + out = pit_get_out(&pit_channels[2]); | |
| 164 | + dummy_refresh_clock ^= 1; | |
| 165 | + return (speaker_data_on << 1) | pit_channels[2].gate | (out << 5) | | |
| 166 | + (dummy_refresh_clock << 4); | |
| 167 | +} | |
| 168 | + | |
| 169 | +/***********************************************************/ | |
| 170 | +/* PC floppy disk controler emulation glue */ | |
| 171 | +#define PC_FDC_DMA 0x2 | |
| 172 | +#define PC_FDC_IRQ 0x6 | |
| 173 | +#define PC_FDC_BASE 0x3F0 | |
| 174 | + | |
| 175 | +static void fdctrl_register (unsigned char **disknames, int ro, | |
| 176 | + char boot_device) | |
| 177 | +{ | |
| 178 | + int i; | |
| 179 | + | |
| 180 | + fdctrl_init(PC_FDC_IRQ, PC_FDC_DMA, 0, PC_FDC_BASE, boot_device); | |
| 181 | + for (i = 0; i < MAX_FD; i++) { | |
| 182 | + if (disknames[i] != NULL) | |
| 183 | + fdctrl_disk_change(i, disknames[i], ro); | |
| 184 | + } | |
| 185 | +} | |
| 186 | + | |
| 187 | +/***********************************************************/ | |
| 188 | +/* Bochs BIOS debug ports */ | |
| 189 | + | |
| 190 | +void bochs_bios_write(CPUX86State *env, uint32_t addr, uint32_t val) | |
| 191 | +{ | |
| 192 | + switch(addr) { | |
| 193 | + /* Bochs BIOS messages */ | |
| 194 | + case 0x400: | |
| 195 | + case 0x401: | |
| 196 | + fprintf(stderr, "BIOS panic at rombios.c, line %d\n", val); | |
| 197 | + exit(1); | |
| 198 | + case 0x402: | |
| 199 | + case 0x403: | |
| 200 | +#ifdef DEBUG_BIOS | |
| 201 | + fprintf(stderr, "%c", val); | |
| 202 | +#endif | |
| 203 | + break; | |
| 204 | + | |
| 205 | + /* LGPL'ed VGA BIOS messages */ | |
| 206 | + case 0x501: | |
| 207 | + case 0x502: | |
| 208 | + fprintf(stderr, "VGA BIOS panic, line %d\n", val); | |
| 209 | + exit(1); | |
| 210 | + case 0x500: | |
| 211 | + case 0x503: | |
| 212 | +#ifdef DEBUG_BIOS | |
| 213 | + fprintf(stderr, "%c", val); | |
| 214 | +#endif | |
| 215 | + break; | |
| 216 | + } | |
| 217 | +} | |
| 218 | + | |
| 219 | +void bochs_bios_init(void) | |
| 220 | +{ | |
| 221 | + register_ioport_write(0x400, 1, bochs_bios_write, 2); | |
| 222 | + register_ioport_write(0x401, 1, bochs_bios_write, 2); | |
| 223 | + register_ioport_write(0x402, 1, bochs_bios_write, 1); | |
| 224 | + register_ioport_write(0x403, 1, bochs_bios_write, 1); | |
| 225 | + | |
| 226 | + register_ioport_write(0x501, 1, bochs_bios_write, 2); | |
| 227 | + register_ioport_write(0x502, 1, bochs_bios_write, 2); | |
| 228 | + register_ioport_write(0x500, 1, bochs_bios_write, 1); | |
| 229 | + register_ioport_write(0x503, 1, bochs_bios_write, 1); | |
| 230 | +} | |
| 231 | + | |
| 232 | + | |
| 233 | +int load_kernel(const char *filename, uint8_t *addr, | |
| 234 | + uint8_t *real_addr) | |
| 235 | +{ | |
| 236 | + int fd, size; | |
| 237 | + int setup_sects; | |
| 238 | + | |
| 239 | + fd = open(filename, O_RDONLY); | |
| 240 | + if (fd < 0) | |
| 241 | + return -1; | |
| 242 | + | |
| 243 | + /* load 16 bit code */ | |
| 244 | + if (read(fd, real_addr, 512) != 512) | |
| 245 | + goto fail; | |
| 246 | + setup_sects = real_addr[0x1F1]; | |
| 247 | + if (!setup_sects) | |
| 248 | + setup_sects = 4; | |
| 249 | + if (read(fd, real_addr + 512, setup_sects * 512) != | |
| 250 | + setup_sects * 512) | |
| 251 | + goto fail; | |
| 252 | + | |
| 253 | + /* load 32 bit code */ | |
| 254 | + size = read(fd, addr, 16 * 1024 * 1024); | |
| 255 | + if (size < 0) | |
| 256 | + goto fail; | |
| 257 | + close(fd); | |
| 258 | + return size; | |
| 259 | + fail: | |
| 260 | + close(fd); | |
| 261 | + return -1; | |
| 262 | +} | |
| 263 | + | |
| 264 | +/* PC hardware initialisation */ | |
| 265 | +void pc_init(int ram_size, int vga_ram_size, int boot_device, | |
| 266 | + DisplayState *ds, const char **fd_filename, int snapshot, | |
| 267 | + const char *kernel_filename, const char *kernel_cmdline, | |
| 268 | + const char *initrd_filename) | |
| 269 | +{ | |
| 270 | + char buf[1024]; | |
| 271 | + int ret, linux_boot, initrd_size; | |
| 272 | + | |
| 273 | + linux_boot = (kernel_filename != NULL); | |
| 274 | + | |
| 275 | + /* allocate RAM */ | |
| 276 | + cpu_register_physical_memory(0, ram_size, 0); | |
| 277 | + | |
| 278 | + /* BIOS load */ | |
| 279 | + snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME); | |
| 280 | + ret = load_image(buf, phys_ram_base + 0x000f0000); | |
| 281 | + if (ret != 0x10000) { | |
| 282 | + fprintf(stderr, "qemu: could not load PC bios '%s'\n", buf); | |
| 283 | + exit(1); | |
| 284 | + } | |
| 285 | + | |
| 286 | + /* VGA BIOS load */ | |
| 287 | + snprintf(buf, sizeof(buf), "%s/%s", bios_dir, VGABIOS_FILENAME); | |
| 288 | + ret = load_image(buf, phys_ram_base + 0x000c0000); | |
| 289 | + | |
| 290 | + /* setup basic memory access */ | |
| 291 | + cpu_register_physical_memory(0xc0000, 0x10000, 0xc0000 | IO_MEM_ROM); | |
| 292 | + cpu_register_physical_memory(0xf0000, 0x10000, 0xf0000 | IO_MEM_ROM); | |
| 293 | + | |
| 294 | + bochs_bios_init(); | |
| 295 | + | |
| 296 | + if (linux_boot) { | |
| 297 | + uint8_t bootsect[512]; | |
| 298 | + | |
| 299 | + if (bs_table[0] == NULL) { | |
| 300 | + fprintf(stderr, "A disk image must be given for 'hda' when booting a Linux kernel\n"); | |
| 301 | + exit(1); | |
| 302 | + } | |
| 303 | + snprintf(buf, sizeof(buf), "%s/%s", bios_dir, LINUX_BOOT_FILENAME); | |
| 304 | + ret = load_image(buf, bootsect); | |
| 305 | + if (ret != sizeof(bootsect)) { | |
| 306 | + fprintf(stderr, "qemu: could not load linux boot sector '%s'\n", | |
| 307 | + buf); | |
| 308 | + exit(1); | |
| 309 | + } | |
| 310 | + | |
| 311 | + bdrv_set_boot_sector(bs_table[0], bootsect, sizeof(bootsect)); | |
| 312 | + | |
| 313 | + /* now we can load the kernel */ | |
| 314 | + ret = load_kernel(kernel_filename, | |
| 315 | + phys_ram_base + KERNEL_LOAD_ADDR, | |
| 316 | + phys_ram_base + KERNEL_PARAMS_ADDR); | |
| 317 | + if (ret < 0) { | |
| 318 | + fprintf(stderr, "qemu: could not load kernel '%s'\n", | |
| 319 | + kernel_filename); | |
| 320 | + exit(1); | |
| 321 | + } | |
| 322 | + | |
| 323 | + /* load initrd */ | |
| 324 | + initrd_size = 0; | |
| 325 | + if (initrd_filename) { | |
| 326 | + initrd_size = load_image(initrd_filename, phys_ram_base + INITRD_LOAD_ADDR); | |
| 327 | + if (initrd_size < 0) { | |
| 328 | + fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", | |
| 329 | + initrd_filename); | |
| 330 | + exit(1); | |
| 331 | + } | |
| 332 | + } | |
| 333 | + if (initrd_size > 0) { | |
| 334 | + stl_raw(phys_ram_base + KERNEL_PARAMS_ADDR + 0x218, INITRD_LOAD_ADDR); | |
| 335 | + stl_raw(phys_ram_base + KERNEL_PARAMS_ADDR + 0x21c, initrd_size); | |
| 336 | + } | |
| 337 | + pstrcpy(phys_ram_base + KERNEL_CMDLINE_ADDR, 4096, | |
| 338 | + kernel_cmdline); | |
| 339 | + stw_raw(phys_ram_base + KERNEL_PARAMS_ADDR + 0x20, 0xA33F); | |
| 340 | + stw_raw(phys_ram_base + KERNEL_PARAMS_ADDR + 0x22, | |
| 341 | + KERNEL_CMDLINE_ADDR - KERNEL_PARAMS_ADDR); | |
| 342 | + /* loader type */ | |
| 343 | + stw_raw(phys_ram_base + KERNEL_PARAMS_ADDR + 0x210, 0x01); | |
| 344 | + } | |
| 345 | + | |
| 346 | + /* init basic PC hardware */ | |
| 347 | + register_ioport_write(0x80, 1, ioport80_write, 1); | |
| 348 | + | |
| 349 | + vga_initialize(ds, phys_ram_base + ram_size, ram_size, | |
| 350 | + vga_ram_size); | |
| 351 | + | |
| 352 | + rtc_init(0x70, 8); | |
| 353 | + cmos_init(ram_size, boot_device); | |
| 354 | + register_ioport_read(0x61, 1, speaker_ioport_read, 1); | |
| 355 | + register_ioport_write(0x61, 1, speaker_ioport_write, 1); | |
| 356 | + | |
| 357 | + pic_init(); | |
| 358 | + pit_init(); | |
| 359 | + serial_init(0x3f8, 4); | |
| 360 | + ne2000_init(0x300, 9); | |
| 361 | + ide_init(); | |
| 362 | + kbd_init(); | |
| 363 | + AUD_init(); | |
| 364 | + DMA_init(); | |
| 365 | + SB16_init(); | |
| 366 | + | |
| 367 | + fdctrl_register((unsigned char **)fd_filename, snapshot, boot_device); | |
| 368 | +} | ... | ... |
hw/pckbd.c
0 → 100644
| 1 | +/* | |
| 2 | + * QEMU PC keyboard emulation | |
| 3 | + * | |
| 4 | + * Copyright (c) 2003 Fabrice Bellard | |
| 5 | + * | |
| 6 | + * Permission is hereby granted, free of charge, to any person obtaining a copy | |
| 7 | + * of this software and associated documentation files (the "Software"), to deal | |
| 8 | + * in the Software without restriction, including without limitation the rights | |
| 9 | + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
| 10 | + * copies of the Software, and to permit persons to whom the Software is | |
| 11 | + * furnished to do so, subject to the following conditions: | |
| 12 | + * | |
| 13 | + * The above copyright notice and this permission notice shall be included in | |
| 14 | + * all copies or substantial portions of the Software. | |
| 15 | + * | |
| 16 | + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 17 | + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 18 | + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
| 19 | + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 20 | + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
| 21 | + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
| 22 | + * THE SOFTWARE. | |
| 23 | + */ | |
| 24 | +#include <stdlib.h> | |
| 25 | +#include <stdio.h> | |
| 26 | +#include <stdarg.h> | |
| 27 | +#include <string.h> | |
| 28 | +#include <getopt.h> | |
| 29 | +#include <inttypes.h> | |
| 30 | +#include <unistd.h> | |
| 31 | +#include <sys/mman.h> | |
| 32 | +#include <fcntl.h> | |
| 33 | +#include <signal.h> | |
| 34 | +#include <time.h> | |
| 35 | +#include <sys/time.h> | |
| 36 | +#include <malloc.h> | |
| 37 | +#include <termios.h> | |
| 38 | +#include <sys/poll.h> | |
| 39 | +#include <errno.h> | |
| 40 | +#include <sys/wait.h> | |
| 41 | +#include <netinet/in.h> | |
| 42 | + | |
| 43 | +#include "cpu.h" | |
| 44 | +#include "vl.h" | |
| 45 | + | |
| 46 | +/* debug PC keyboard */ | |
| 47 | +//#define DEBUG_KBD | |
| 48 | + | |
| 49 | +/* debug PC keyboard : only mouse */ | |
| 50 | +//#define DEBUG_MOUSE | |
| 51 | + | |
| 52 | +/* Keyboard Controller Commands */ | |
| 53 | +#define KBD_CCMD_READ_MODE 0x20 /* Read mode bits */ | |
| 54 | +#define KBD_CCMD_WRITE_MODE 0x60 /* Write mode bits */ | |
| 55 | +#define KBD_CCMD_GET_VERSION 0xA1 /* Get controller version */ | |
| 56 | +#define KBD_CCMD_MOUSE_DISABLE 0xA7 /* Disable mouse interface */ | |
| 57 | +#define KBD_CCMD_MOUSE_ENABLE 0xA8 /* Enable mouse interface */ | |
| 58 | +#define KBD_CCMD_TEST_MOUSE 0xA9 /* Mouse interface test */ | |
| 59 | +#define KBD_CCMD_SELF_TEST 0xAA /* Controller self test */ | |
| 60 | +#define KBD_CCMD_KBD_TEST 0xAB /* Keyboard interface test */ | |
| 61 | +#define KBD_CCMD_KBD_DISABLE 0xAD /* Keyboard interface disable */ | |
| 62 | +#define KBD_CCMD_KBD_ENABLE 0xAE /* Keyboard interface enable */ | |
| 63 | +#define KBD_CCMD_READ_INPORT 0xC0 /* read input port */ | |
| 64 | +#define KBD_CCMD_READ_OUTPORT 0xD0 /* read output port */ | |
| 65 | +#define KBD_CCMD_WRITE_OUTPORT 0xD1 /* write output port */ | |
| 66 | +#define KBD_CCMD_WRITE_OBUF 0xD2 | |
| 67 | +#define KBD_CCMD_WRITE_AUX_OBUF 0xD3 /* Write to output buffer as if | |
| 68 | + initiated by the auxiliary device */ | |
| 69 | +#define KBD_CCMD_WRITE_MOUSE 0xD4 /* Write the following byte to the mouse */ | |
| 70 | +#define KBD_CCMD_DISABLE_A20 0xDD /* HP vectra only ? */ | |
| 71 | +#define KBD_CCMD_ENABLE_A20 0xDF /* HP vectra only ? */ | |
| 72 | +#define KBD_CCMD_RESET 0xFE | |
| 73 | + | |
| 74 | +/* Keyboard Commands */ | |
| 75 | +#define KBD_CMD_SET_LEDS 0xED /* Set keyboard leds */ | |
| 76 | +#define KBD_CMD_ECHO 0xEE | |
| 77 | +#define KBD_CMD_GET_ID 0xF2 /* get keyboard ID */ | |
| 78 | +#define KBD_CMD_SET_RATE 0xF3 /* Set typematic rate */ | |
| 79 | +#define KBD_CMD_ENABLE 0xF4 /* Enable scanning */ | |
| 80 | +#define KBD_CMD_RESET_DISABLE 0xF5 /* reset and disable scanning */ | |
| 81 | +#define KBD_CMD_RESET_ENABLE 0xF6 /* reset and enable scanning */ | |
| 82 | +#define KBD_CMD_RESET 0xFF /* Reset */ | |
| 83 | + | |
| 84 | +/* Keyboard Replies */ | |
| 85 | +#define KBD_REPLY_POR 0xAA /* Power on reset */ | |
| 86 | +#define KBD_REPLY_ACK 0xFA /* Command ACK */ | |
| 87 | +#define KBD_REPLY_RESEND 0xFE /* Command NACK, send the cmd again */ | |
| 88 | + | |
| 89 | +/* Status Register Bits */ | |
| 90 | +#define KBD_STAT_OBF 0x01 /* Keyboard output buffer full */ | |
| 91 | +#define KBD_STAT_IBF 0x02 /* Keyboard input buffer full */ | |
| 92 | +#define KBD_STAT_SELFTEST 0x04 /* Self test successful */ | |
| 93 | +#define KBD_STAT_CMD 0x08 /* Last write was a command write (0=data) */ | |
| 94 | +#define KBD_STAT_UNLOCKED 0x10 /* Zero if keyboard locked */ | |
| 95 | +#define KBD_STAT_MOUSE_OBF 0x20 /* Mouse output buffer full */ | |
| 96 | +#define KBD_STAT_GTO 0x40 /* General receive/xmit timeout */ | |
| 97 | +#define KBD_STAT_PERR 0x80 /* Parity error */ | |
| 98 | + | |
| 99 | +/* Controller Mode Register Bits */ | |
| 100 | +#define KBD_MODE_KBD_INT 0x01 /* Keyboard data generate IRQ1 */ | |
| 101 | +#define KBD_MODE_MOUSE_INT 0x02 /* Mouse data generate IRQ12 */ | |
| 102 | +#define KBD_MODE_SYS 0x04 /* The system flag (?) */ | |
| 103 | +#define KBD_MODE_NO_KEYLOCK 0x08 /* The keylock doesn't affect the keyboard if set */ | |
| 104 | +#define KBD_MODE_DISABLE_KBD 0x10 /* Disable keyboard interface */ | |
| 105 | +#define KBD_MODE_DISABLE_MOUSE 0x20 /* Disable mouse interface */ | |
| 106 | +#define KBD_MODE_KCC 0x40 /* Scan code conversion to PC format */ | |
| 107 | +#define KBD_MODE_RFU 0x80 | |
| 108 | + | |
| 109 | +/* Mouse Commands */ | |
| 110 | +#define AUX_SET_SCALE11 0xE6 /* Set 1:1 scaling */ | |
| 111 | +#define AUX_SET_SCALE21 0xE7 /* Set 2:1 scaling */ | |
| 112 | +#define AUX_SET_RES 0xE8 /* Set resolution */ | |
| 113 | +#define AUX_GET_SCALE 0xE9 /* Get scaling factor */ | |
| 114 | +#define AUX_SET_STREAM 0xEA /* Set stream mode */ | |
| 115 | +#define AUX_POLL 0xEB /* Poll */ | |
| 116 | +#define AUX_RESET_WRAP 0xEC /* Reset wrap mode */ | |
| 117 | +#define AUX_SET_WRAP 0xEE /* Set wrap mode */ | |
| 118 | +#define AUX_SET_REMOTE 0xF0 /* Set remote mode */ | |
| 119 | +#define AUX_GET_TYPE 0xF2 /* Get type */ | |
| 120 | +#define AUX_SET_SAMPLE 0xF3 /* Set sample rate */ | |
| 121 | +#define AUX_ENABLE_DEV 0xF4 /* Enable aux device */ | |
| 122 | +#define AUX_DISABLE_DEV 0xF5 /* Disable aux device */ | |
| 123 | +#define AUX_SET_DEFAULT 0xF6 | |
| 124 | +#define AUX_RESET 0xFF /* Reset aux device */ | |
| 125 | +#define AUX_ACK 0xFA /* Command byte ACK. */ | |
| 126 | + | |
| 127 | +#define MOUSE_STATUS_REMOTE 0x40 | |
| 128 | +#define MOUSE_STATUS_ENABLED 0x20 | |
| 129 | +#define MOUSE_STATUS_SCALE21 0x10 | |
| 130 | + | |
| 131 | +#define KBD_QUEUE_SIZE 256 | |
| 132 | + | |
| 133 | +typedef struct { | |
| 134 | + uint8_t data[KBD_QUEUE_SIZE]; | |
| 135 | + int rptr, wptr, count; | |
| 136 | +} KBDQueue; | |
| 137 | + | |
| 138 | +typedef struct KBDState { | |
| 139 | + KBDQueue queues[2]; | |
| 140 | + uint8_t write_cmd; /* if non zero, write data to port 60 is expected */ | |
| 141 | + uint8_t status; | |
| 142 | + uint8_t mode; | |
| 143 | + /* keyboard state */ | |
| 144 | + int kbd_write_cmd; | |
| 145 | + int scan_enabled; | |
| 146 | + /* mouse state */ | |
| 147 | + int mouse_write_cmd; | |
| 148 | + uint8_t mouse_status; | |
| 149 | + uint8_t mouse_resolution; | |
| 150 | + uint8_t mouse_sample_rate; | |
| 151 | + uint8_t mouse_wrap; | |
| 152 | + uint8_t mouse_type; /* 0 = PS2, 3 = IMPS/2, 4 = IMEX */ | |
| 153 | + uint8_t mouse_detect_state; | |
| 154 | + int mouse_dx; /* current values, needed for 'poll' mode */ | |
| 155 | + int mouse_dy; | |
| 156 | + int mouse_dz; | |
| 157 | + uint8_t mouse_buttons; | |
| 158 | +} KBDState; | |
| 159 | + | |
| 160 | +KBDState kbd_state; | |
| 161 | +int reset_requested; | |
| 162 | + | |
| 163 | +/* update irq and KBD_STAT_[MOUSE_]OBF */ | |
| 164 | +/* XXX: not generating the irqs if KBD_MODE_DISABLE_KBD is set may be | |
| 165 | + incorrect, but it avoids having to simulate exact delays */ | |
| 166 | +static void kbd_update_irq(KBDState *s) | |
| 167 | +{ | |
| 168 | + int irq12_level, irq1_level; | |
| 169 | + | |
| 170 | + irq1_level = 0; | |
| 171 | + irq12_level = 0; | |
| 172 | + s->status &= ~(KBD_STAT_OBF | KBD_STAT_MOUSE_OBF); | |
| 173 | + if (s->queues[0].count != 0 || | |
| 174 | + s->queues[1].count != 0) { | |
| 175 | + s->status |= KBD_STAT_OBF; | |
| 176 | + if (s->queues[1].count != 0) { | |
| 177 | + s->status |= KBD_STAT_MOUSE_OBF; | |
| 178 | + if (s->mode & KBD_MODE_MOUSE_INT) | |
| 179 | + irq12_level = 1; | |
| 180 | + } else { | |
| 181 | + if ((s->mode & KBD_MODE_KBD_INT) && | |
| 182 | + !(s->mode & KBD_MODE_DISABLE_KBD)) | |
| 183 | + irq1_level = 1; | |
| 184 | + } | |
| 185 | + } | |
| 186 | + pic_set_irq(1, irq1_level); | |
| 187 | + pic_set_irq(12, irq12_level); | |
| 188 | +} | |
| 189 | + | |
| 190 | +static void kbd_queue(KBDState *s, int b, int aux) | |
| 191 | +{ | |
| 192 | + KBDQueue *q = &kbd_state.queues[aux]; | |
| 193 | + | |
| 194 | +#if defined(DEBUG_MOUSE) || defined(DEBUG_KBD) | |
| 195 | + if (aux) | |
| 196 | + printf("mouse event: 0x%02x\n", b); | |
| 197 | +#ifdef DEBUG_KBD | |
| 198 | + else | |
| 199 | + printf("kbd event: 0x%02x\n", b); | |
| 200 | +#endif | |
| 201 | +#endif | |
| 202 | + if (q->count >= KBD_QUEUE_SIZE) | |
| 203 | + return; | |
| 204 | + q->data[q->wptr] = b; | |
| 205 | + if (++q->wptr == KBD_QUEUE_SIZE) | |
| 206 | + q->wptr = 0; | |
| 207 | + q->count++; | |
| 208 | + kbd_update_irq(s); | |
| 209 | +} | |
| 210 | + | |
| 211 | +void kbd_put_keycode(int keycode) | |
| 212 | +{ | |
| 213 | + KBDState *s = &kbd_state; | |
| 214 | + kbd_queue(s, keycode, 0); | |
| 215 | +} | |
| 216 | + | |
| 217 | +static uint32_t kbd_read_status(CPUState *env, uint32_t addr) | |
| 218 | +{ | |
| 219 | + KBDState *s = &kbd_state; | |
| 220 | + int val; | |
| 221 | + val = s->status; | |
| 222 | +#if defined(DEBUG_KBD) | |
| 223 | + printf("kbd: read status=0x%02x\n", val); | |
| 224 | +#endif | |
| 225 | + return val; | |
| 226 | +} | |
| 227 | + | |
| 228 | +static void kbd_write_command(CPUState *env, uint32_t addr, uint32_t val) | |
| 229 | +{ | |
| 230 | + KBDState *s = &kbd_state; | |
| 231 | + | |
| 232 | +#ifdef DEBUG_KBD | |
| 233 | + printf("kbd: write cmd=0x%02x\n", val); | |
| 234 | +#endif | |
| 235 | + switch(val) { | |
| 236 | + case KBD_CCMD_READ_MODE: | |
| 237 | + kbd_queue(s, s->mode, 0); | |
| 238 | + break; | |
| 239 | + case KBD_CCMD_WRITE_MODE: | |
| 240 | + case KBD_CCMD_WRITE_OBUF: | |
| 241 | + case KBD_CCMD_WRITE_AUX_OBUF: | |
| 242 | + case KBD_CCMD_WRITE_MOUSE: | |
| 243 | + case KBD_CCMD_WRITE_OUTPORT: | |
| 244 | + s->write_cmd = val; | |
| 245 | + break; | |
| 246 | + case KBD_CCMD_MOUSE_DISABLE: | |
| 247 | + s->mode |= KBD_MODE_DISABLE_MOUSE; | |
| 248 | + break; | |
| 249 | + case KBD_CCMD_MOUSE_ENABLE: | |
| 250 | + s->mode &= ~KBD_MODE_DISABLE_MOUSE; | |
| 251 | + break; | |
| 252 | + case KBD_CCMD_TEST_MOUSE: | |
| 253 | + kbd_queue(s, 0x00, 0); | |
| 254 | + break; | |
| 255 | + case KBD_CCMD_SELF_TEST: | |
| 256 | + s->status |= KBD_STAT_SELFTEST; | |
| 257 | + kbd_queue(s, 0x55, 0); | |
| 258 | + break; | |
| 259 | + case KBD_CCMD_KBD_TEST: | |
| 260 | + kbd_queue(s, 0x00, 0); | |
| 261 | + break; | |
| 262 | + case KBD_CCMD_KBD_DISABLE: | |
| 263 | + s->mode |= KBD_MODE_DISABLE_KBD; | |
| 264 | + kbd_update_irq(s); | |
| 265 | + break; | |
| 266 | + case KBD_CCMD_KBD_ENABLE: | |
| 267 | + s->mode &= ~KBD_MODE_DISABLE_KBD; | |
| 268 | + kbd_update_irq(s); | |
| 269 | + break; | |
| 270 | + case KBD_CCMD_READ_INPORT: | |
| 271 | + kbd_queue(s, 0x00, 0); | |
| 272 | + break; | |
| 273 | + case KBD_CCMD_READ_OUTPORT: | |
| 274 | + /* XXX: check that */ | |
| 275 | +#ifdef TARGET_I386 | |
| 276 | + val = 0x01 | (((cpu_single_env->a20_mask >> 20) & 1) << 1); | |
| 277 | +#else | |
| 278 | + val = 0x01; | |
| 279 | +#endif | |
| 280 | + if (s->status & KBD_STAT_OBF) | |
| 281 | + val |= 0x10; | |
| 282 | + if (s->status & KBD_STAT_MOUSE_OBF) | |
| 283 | + val |= 0x20; | |
| 284 | + kbd_queue(s, val, 0); | |
| 285 | + break; | |
| 286 | +#ifdef TARGET_I386 | |
| 287 | + case KBD_CCMD_ENABLE_A20: | |
| 288 | + cpu_x86_set_a20(env, 1); | |
| 289 | + break; | |
| 290 | + case KBD_CCMD_DISABLE_A20: | |
| 291 | + cpu_x86_set_a20(env, 0); | |
| 292 | + break; | |
| 293 | +#endif | |
| 294 | + case KBD_CCMD_RESET: | |
| 295 | + reset_requested = 1; | |
| 296 | + cpu_interrupt(cpu_single_env, CPU_INTERRUPT_EXIT); | |
| 297 | + break; | |
| 298 | + case 0xff: | |
| 299 | + /* ignore that - I don't know what is its use */ | |
| 300 | + break; | |
| 301 | + default: | |
| 302 | + fprintf(stderr, "qemu: unsupported keyboard cmd=0x%02x\n", val); | |
| 303 | + break; | |
| 304 | + } | |
| 305 | +} | |
| 306 | + | |
| 307 | +static uint32_t kbd_read_data(CPUState *env, uint32_t addr) | |
| 308 | +{ | |
| 309 | + KBDState *s = &kbd_state; | |
| 310 | + KBDQueue *q; | |
| 311 | + int val, index; | |
| 312 | + | |
| 313 | + q = &s->queues[0]; /* first check KBD data */ | |
| 314 | + if (q->count == 0) | |
| 315 | + q = &s->queues[1]; /* then check AUX data */ | |
| 316 | + if (q->count == 0) { | |
| 317 | + /* NOTE: if no data left, we return the last keyboard one | |
| 318 | + (needed for EMM386) */ | |
| 319 | + /* XXX: need a timer to do things correctly */ | |
| 320 | + q = &s->queues[0]; | |
| 321 | + index = q->rptr - 1; | |
| 322 | + if (index < 0) | |
| 323 | + index = KBD_QUEUE_SIZE - 1; | |
| 324 | + val = q->data[index]; | |
| 325 | + } else { | |
| 326 | + val = q->data[q->rptr]; | |
| 327 | + if (++q->rptr == KBD_QUEUE_SIZE) | |
| 328 | + q->rptr = 0; | |
| 329 | + q->count--; | |
| 330 | + /* reading deasserts IRQ */ | |
| 331 | + if (q == &s->queues[0]) | |
| 332 | + pic_set_irq(1, 0); | |
| 333 | + else | |
| 334 | + pic_set_irq(12, 0); | |
| 335 | + } | |
| 336 | + /* reassert IRQs if data left */ | |
| 337 | + kbd_update_irq(s); | |
| 338 | +#ifdef DEBUG_KBD | |
| 339 | + printf("kbd: read data=0x%02x\n", val); | |
| 340 | +#endif | |
| 341 | + return val; | |
| 342 | +} | |
| 343 | + | |
| 344 | +static void kbd_reset_keyboard(KBDState *s) | |
| 345 | +{ | |
| 346 | + s->scan_enabled = 1; | |
| 347 | +} | |
| 348 | + | |
| 349 | +static void kbd_write_keyboard(KBDState *s, int val) | |
| 350 | +{ | |
| 351 | + switch(s->kbd_write_cmd) { | |
| 352 | + default: | |
| 353 | + case -1: | |
| 354 | + switch(val) { | |
| 355 | + case 0x00: | |
| 356 | + kbd_queue(s, KBD_REPLY_ACK, 0); | |
| 357 | + break; | |
| 358 | + case 0x05: | |
| 359 | + kbd_queue(s, KBD_REPLY_RESEND, 0); | |
| 360 | + break; | |
| 361 | + case KBD_CMD_GET_ID: | |
| 362 | + kbd_queue(s, KBD_REPLY_ACK, 0); | |
| 363 | + kbd_queue(s, 0xab, 0); | |
| 364 | + kbd_queue(s, 0x83, 0); | |
| 365 | + break; | |
| 366 | + case KBD_CMD_ECHO: | |
| 367 | + kbd_queue(s, KBD_CMD_ECHO, 0); | |
| 368 | + break; | |
| 369 | + case KBD_CMD_ENABLE: | |
| 370 | + s->scan_enabled = 1; | |
| 371 | + kbd_queue(s, KBD_REPLY_ACK, 0); | |
| 372 | + break; | |
| 373 | + case KBD_CMD_SET_LEDS: | |
| 374 | + case KBD_CMD_SET_RATE: | |
| 375 | + s->kbd_write_cmd = val; | |
| 376 | + kbd_queue(s, KBD_REPLY_ACK, 0); | |
| 377 | + break; | |
| 378 | + case KBD_CMD_RESET_DISABLE: | |
| 379 | + kbd_reset_keyboard(s); | |
| 380 | + s->scan_enabled = 0; | |
| 381 | + kbd_queue(s, KBD_REPLY_ACK, 0); | |
| 382 | + break; | |
| 383 | + case KBD_CMD_RESET_ENABLE: | |
| 384 | + kbd_reset_keyboard(s); | |
| 385 | + s->scan_enabled = 1; | |
| 386 | + kbd_queue(s, KBD_REPLY_ACK, 0); | |
| 387 | + break; | |
| 388 | + case KBD_CMD_RESET: | |
| 389 | + kbd_reset_keyboard(s); | |
| 390 | + kbd_queue(s, KBD_REPLY_ACK, 0); | |
| 391 | + kbd_queue(s, KBD_REPLY_POR, 0); | |
| 392 | + break; | |
| 393 | + default: | |
| 394 | + kbd_queue(s, KBD_REPLY_ACK, 0); | |
| 395 | + break; | |
| 396 | + } | |
| 397 | + break; | |
| 398 | + case KBD_CMD_SET_LEDS: | |
| 399 | + kbd_queue(s, KBD_REPLY_ACK, 0); | |
| 400 | + s->kbd_write_cmd = -1; | |
| 401 | + break; | |
| 402 | + case KBD_CMD_SET_RATE: | |
| 403 | + kbd_queue(s, KBD_REPLY_ACK, 0); | |
| 404 | + s->kbd_write_cmd = -1; | |
| 405 | + break; | |
| 406 | + } | |
| 407 | +} | |
| 408 | + | |
| 409 | +static void kbd_mouse_send_packet(KBDState *s) | |
| 410 | +{ | |
| 411 | + unsigned int b; | |
| 412 | + int dx1, dy1, dz1; | |
| 413 | + | |
| 414 | + dx1 = s->mouse_dx; | |
| 415 | + dy1 = s->mouse_dy; | |
| 416 | + dz1 = s->mouse_dz; | |
| 417 | + /* XXX: increase range to 8 bits ? */ | |
| 418 | + if (dx1 > 127) | |
| 419 | + dx1 = 127; | |
| 420 | + else if (dx1 < -127) | |
| 421 | + dx1 = -127; | |
| 422 | + if (dy1 > 127) | |
| 423 | + dy1 = 127; | |
| 424 | + else if (dy1 < -127) | |
| 425 | + dy1 = -127; | |
| 426 | + b = 0x08 | ((dx1 < 0) << 4) | ((dy1 < 0) << 5) | (s->mouse_buttons & 0x07); | |
| 427 | + kbd_queue(s, b, 1); | |
| 428 | + kbd_queue(s, dx1 & 0xff, 1); | |
| 429 | + kbd_queue(s, dy1 & 0xff, 1); | |
| 430 | + /* extra byte for IMPS/2 or IMEX */ | |
| 431 | + switch(s->mouse_type) { | |
| 432 | + default: | |
| 433 | + break; | |
| 434 | + case 3: | |
| 435 | + if (dz1 > 127) | |
| 436 | + dz1 = 127; | |
| 437 | + else if (dz1 < -127) | |
| 438 | + dz1 = -127; | |
| 439 | + kbd_queue(s, dz1 & 0xff, 1); | |
| 440 | + break; | |
| 441 | + case 4: | |
| 442 | + if (dz1 > 7) | |
| 443 | + dz1 = 7; | |
| 444 | + else if (dz1 < -7) | |
| 445 | + dz1 = -7; | |
| 446 | + b = (dz1 & 0x0f) | ((s->mouse_buttons & 0x18) << 1); | |
| 447 | + kbd_queue(s, b, 1); | |
| 448 | + break; | |
| 449 | + } | |
| 450 | + | |
| 451 | + /* update deltas */ | |
| 452 | + s->mouse_dx -= dx1; | |
| 453 | + s->mouse_dy -= dy1; | |
| 454 | + s->mouse_dz -= dz1; | |
| 455 | +} | |
| 456 | + | |
| 457 | +void kbd_mouse_event(int dx, int dy, int dz, int buttons_state) | |
| 458 | +{ | |
| 459 | + KBDState *s = &kbd_state; | |
| 460 | + | |
| 461 | + /* check if deltas are recorded when disabled */ | |
| 462 | + if (!(s->mouse_status & MOUSE_STATUS_ENABLED)) | |
| 463 | + return; | |
| 464 | + | |
| 465 | + s->mouse_dx += dx; | |
| 466 | + s->mouse_dy -= dy; | |
| 467 | + s->mouse_dz += dz; | |
| 468 | + s->mouse_buttons = buttons_state; | |
| 469 | + | |
| 470 | + if (!(s->mouse_status & MOUSE_STATUS_REMOTE) && | |
| 471 | + (s->queues[1].count < (KBD_QUEUE_SIZE - 16))) { | |
| 472 | + for(;;) { | |
| 473 | + /* if not remote, send event. Multiple events are sent if | |
| 474 | + too big deltas */ | |
| 475 | + kbd_mouse_send_packet(s); | |
| 476 | + if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0) | |
| 477 | + break; | |
| 478 | + } | |
| 479 | + } | |
| 480 | +} | |
| 481 | + | |
| 482 | +static void kbd_write_mouse(KBDState *s, int val) | |
| 483 | +{ | |
| 484 | +#ifdef DEBUG_MOUSE | |
| 485 | + printf("kbd: write mouse 0x%02x\n", val); | |
| 486 | +#endif | |
| 487 | + switch(s->mouse_write_cmd) { | |
| 488 | + default: | |
| 489 | + case -1: | |
| 490 | + /* mouse command */ | |
| 491 | + if (s->mouse_wrap) { | |
| 492 | + if (val == AUX_RESET_WRAP) { | |
| 493 | + s->mouse_wrap = 0; | |
| 494 | + kbd_queue(s, AUX_ACK, 1); | |
| 495 | + return; | |
| 496 | + } else if (val != AUX_RESET) { | |
| 497 | + kbd_queue(s, val, 1); | |
| 498 | + return; | |
| 499 | + } | |
| 500 | + } | |
| 501 | + switch(val) { | |
| 502 | + case AUX_SET_SCALE11: | |
| 503 | + s->mouse_status &= ~MOUSE_STATUS_SCALE21; | |
| 504 | + kbd_queue(s, AUX_ACK, 1); | |
| 505 | + break; | |
| 506 | + case AUX_SET_SCALE21: | |
| 507 | + s->mouse_status |= MOUSE_STATUS_SCALE21; | |
| 508 | + kbd_queue(s, AUX_ACK, 1); | |
| 509 | + break; | |
| 510 | + case AUX_SET_STREAM: | |
| 511 | + s->mouse_status &= ~MOUSE_STATUS_REMOTE; | |
| 512 | + kbd_queue(s, AUX_ACK, 1); | |
| 513 | + break; | |
| 514 | + case AUX_SET_WRAP: | |
| 515 | + s->mouse_wrap = 1; | |
| 516 | + kbd_queue(s, AUX_ACK, 1); | |
| 517 | + break; | |
| 518 | + case AUX_SET_REMOTE: | |
| 519 | + s->mouse_status |= MOUSE_STATUS_REMOTE; | |
| 520 | + kbd_queue(s, AUX_ACK, 1); | |
| 521 | + break; | |
| 522 | + case AUX_GET_TYPE: | |
| 523 | + kbd_queue(s, AUX_ACK, 1); | |
| 524 | + kbd_queue(s, s->mouse_type, 1); | |
| 525 | + break; | |
| 526 | + case AUX_SET_RES: | |
| 527 | + case AUX_SET_SAMPLE: | |
| 528 | + s->mouse_write_cmd = val; | |
| 529 | + kbd_queue(s, AUX_ACK, 1); | |
| 530 | + break; | |
| 531 | + case AUX_GET_SCALE: | |
| 532 | + kbd_queue(s, AUX_ACK, 1); | |
| 533 | + kbd_queue(s, s->mouse_status, 1); | |
| 534 | + kbd_queue(s, s->mouse_resolution, 1); | |
| 535 | + kbd_queue(s, s->mouse_sample_rate, 1); | |
| 536 | + break; | |
| 537 | + case AUX_POLL: | |
| 538 | + kbd_queue(s, AUX_ACK, 1); | |
| 539 | + kbd_mouse_send_packet(s); | |
| 540 | + break; | |
| 541 | + case AUX_ENABLE_DEV: | |
| 542 | + s->mouse_status |= MOUSE_STATUS_ENABLED; | |
| 543 | + kbd_queue(s, AUX_ACK, 1); | |
| 544 | + break; | |
| 545 | + case AUX_DISABLE_DEV: | |
| 546 | + s->mouse_status &= ~MOUSE_STATUS_ENABLED; | |
| 547 | + kbd_queue(s, AUX_ACK, 1); | |
| 548 | + break; | |
| 549 | + case AUX_SET_DEFAULT: | |
| 550 | + s->mouse_sample_rate = 100; | |
| 551 | + s->mouse_resolution = 2; | |
| 552 | + s->mouse_status = 0; | |
| 553 | + kbd_queue(s, AUX_ACK, 1); | |
| 554 | + break; | |
| 555 | + case AUX_RESET: | |
| 556 | + s->mouse_sample_rate = 100; | |
| 557 | + s->mouse_resolution = 2; | |
| 558 | + s->mouse_status = 0; | |
| 559 | + kbd_queue(s, AUX_ACK, 1); | |
| 560 | + kbd_queue(s, 0xaa, 1); | |
| 561 | + kbd_queue(s, s->mouse_type, 1); | |
| 562 | + break; | |
| 563 | + default: | |
| 564 | + break; | |
| 565 | + } | |
| 566 | + break; | |
| 567 | + case AUX_SET_SAMPLE: | |
| 568 | + s->mouse_sample_rate = val; | |
| 569 | +#if 0 | |
| 570 | + /* detect IMPS/2 or IMEX */ | |
| 571 | + switch(s->mouse_detect_state) { | |
| 572 | + default: | |
| 573 | + case 0: | |
| 574 | + if (val == 200) | |
| 575 | + s->mouse_detect_state = 1; | |
| 576 | + break; | |
| 577 | + case 1: | |
| 578 | + if (val == 100) | |
| 579 | + s->mouse_detect_state = 2; | |
| 580 | + else if (val == 200) | |
| 581 | + s->mouse_detect_state = 3; | |
| 582 | + else | |
| 583 | + s->mouse_detect_state = 0; | |
| 584 | + break; | |
| 585 | + case 2: | |
| 586 | + if (val == 80) | |
| 587 | + s->mouse_type = 3; /* IMPS/2 */ | |
| 588 | + s->mouse_detect_state = 0; | |
| 589 | + break; | |
| 590 | + case 3: | |
| 591 | + if (val == 80) | |
| 592 | + s->mouse_type = 4; /* IMEX */ | |
| 593 | + s->mouse_detect_state = 0; | |
| 594 | + break; | |
| 595 | + } | |
| 596 | +#endif | |
| 597 | + kbd_queue(s, AUX_ACK, 1); | |
| 598 | + s->mouse_write_cmd = -1; | |
| 599 | + break; | |
| 600 | + case AUX_SET_RES: | |
| 601 | + s->mouse_resolution = val; | |
| 602 | + kbd_queue(s, AUX_ACK, 1); | |
| 603 | + s->mouse_write_cmd = -1; | |
| 604 | + break; | |
| 605 | + } | |
| 606 | +} | |
| 607 | + | |
| 608 | +void kbd_write_data(CPUState *env, uint32_t addr, uint32_t val) | |
| 609 | +{ | |
| 610 | + KBDState *s = &kbd_state; | |
| 611 | + | |
| 612 | +#ifdef DEBUG_KBD | |
| 613 | + printf("kbd: write data=0x%02x\n", val); | |
| 614 | +#endif | |
| 615 | + | |
| 616 | + switch(s->write_cmd) { | |
| 617 | + case 0: | |
| 618 | + kbd_write_keyboard(s, val); | |
| 619 | + break; | |
| 620 | + case KBD_CCMD_WRITE_MODE: | |
| 621 | + s->mode = val; | |
| 622 | + kbd_update_irq(s); | |
| 623 | + break; | |
| 624 | + case KBD_CCMD_WRITE_OBUF: | |
| 625 | + kbd_queue(s, val, 0); | |
| 626 | + break; | |
| 627 | + case KBD_CCMD_WRITE_AUX_OBUF: | |
| 628 | + kbd_queue(s, val, 1); | |
| 629 | + break; | |
| 630 | + case KBD_CCMD_WRITE_OUTPORT: | |
| 631 | +#ifdef TARGET_I386 | |
| 632 | + cpu_x86_set_a20(env, (val >> 1) & 1); | |
| 633 | +#endif | |
| 634 | + if (!(val & 1)) { | |
| 635 | + reset_requested = 1; | |
| 636 | + cpu_interrupt(cpu_single_env, CPU_INTERRUPT_EXIT); | |
| 637 | + } | |
| 638 | + break; | |
| 639 | + case KBD_CCMD_WRITE_MOUSE: | |
| 640 | + kbd_write_mouse(s, val); | |
| 641 | + break; | |
| 642 | + default: | |
| 643 | + break; | |
| 644 | + } | |
| 645 | + s->write_cmd = 0; | |
| 646 | +} | |
| 647 | + | |
| 648 | +void kbd_reset(KBDState *s) | |
| 649 | +{ | |
| 650 | + KBDQueue *q; | |
| 651 | + int i; | |
| 652 | + | |
| 653 | + s->kbd_write_cmd = -1; | |
| 654 | + s->mouse_write_cmd = -1; | |
| 655 | + s->mode = KBD_MODE_KBD_INT | KBD_MODE_MOUSE_INT; | |
| 656 | + s->status = KBD_STAT_CMD | KBD_STAT_UNLOCKED; | |
| 657 | + for(i = 0; i < 2; i++) { | |
| 658 | + q = &s->queues[i]; | |
| 659 | + q->rptr = 0; | |
| 660 | + q->wptr = 0; | |
| 661 | + q->count = 0; | |
| 662 | + } | |
| 663 | +} | |
| 664 | + | |
| 665 | +void kbd_init(void) | |
| 666 | +{ | |
| 667 | + kbd_reset(&kbd_state); | |
| 668 | + register_ioport_read(0x60, 1, kbd_read_data, 1); | |
| 669 | + register_ioport_write(0x60, 1, kbd_write_data, 1); | |
| 670 | + register_ioport_read(0x64, 1, kbd_read_status, 1); | |
| 671 | + register_ioport_write(0x64, 1, kbd_write_command, 1); | |
| 672 | +} | ... | ... |
hw/serial.c
0 → 100644
| 1 | +/* | |
| 2 | + * QEMU 16450 UART emulation | |
| 3 | + * | |
| 4 | + * Copyright (c) 2003-2004 Fabrice Bellard | |
| 5 | + * | |
| 6 | + * Permission is hereby granted, free of charge, to any person obtaining a copy | |
| 7 | + * of this software and associated documentation files (the "Software"), to deal | |
| 8 | + * in the Software without restriction, including without limitation the rights | |
| 9 | + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
| 10 | + * copies of the Software, and to permit persons to whom the Software is | |
| 11 | + * furnished to do so, subject to the following conditions: | |
| 12 | + * | |
| 13 | + * The above copyright notice and this permission notice shall be included in | |
| 14 | + * all copies or substantial portions of the Software. | |
| 15 | + * | |
| 16 | + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 17 | + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 18 | + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
| 19 | + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 20 | + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
| 21 | + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
| 22 | + * THE SOFTWARE. | |
| 23 | + */ | |
| 24 | +#include <stdlib.h> | |
| 25 | +#include <stdio.h> | |
| 26 | +#include <stdarg.h> | |
| 27 | +#include <string.h> | |
| 28 | +#include <getopt.h> | |
| 29 | +#include <inttypes.h> | |
| 30 | +#include <unistd.h> | |
| 31 | +#include <sys/mman.h> | |
| 32 | +#include <fcntl.h> | |
| 33 | +#include <signal.h> | |
| 34 | +#include <time.h> | |
| 35 | +#include <sys/time.h> | |
| 36 | +#include <malloc.h> | |
| 37 | +#include <termios.h> | |
| 38 | +#include <sys/poll.h> | |
| 39 | +#include <errno.h> | |
| 40 | +#include <sys/wait.h> | |
| 41 | +#include <netinet/in.h> | |
| 42 | + | |
| 43 | +#include "cpu.h" | |
| 44 | +#include "vl.h" | |
| 45 | + | |
| 46 | +//#define DEBUG_SERIAL | |
| 47 | + | |
| 48 | +#define UART_LCR_DLAB 0x80 /* Divisor latch access bit */ | |
| 49 | + | |
| 50 | +#define UART_IER_MSI 0x08 /* Enable Modem status interrupt */ | |
| 51 | +#define UART_IER_RLSI 0x04 /* Enable receiver line status interrupt */ | |
| 52 | +#define UART_IER_THRI 0x02 /* Enable Transmitter holding register int. */ | |
| 53 | +#define UART_IER_RDI 0x01 /* Enable receiver data interrupt */ | |
| 54 | + | |
| 55 | +#define UART_IIR_NO_INT 0x01 /* No interrupts pending */ | |
| 56 | +#define UART_IIR_ID 0x06 /* Mask for the interrupt ID */ | |
| 57 | + | |
| 58 | +#define UART_IIR_MSI 0x00 /* Modem status interrupt */ | |
| 59 | +#define UART_IIR_THRI 0x02 /* Transmitter holding register empty */ | |
| 60 | +#define UART_IIR_RDI 0x04 /* Receiver data interrupt */ | |
| 61 | +#define UART_IIR_RLSI 0x06 /* Receiver line status interrupt */ | |
| 62 | + | |
| 63 | +/* | |
| 64 | + * These are the definitions for the Modem Control Register | |
| 65 | + */ | |
| 66 | +#define UART_MCR_LOOP 0x10 /* Enable loopback test mode */ | |
| 67 | +#define UART_MCR_OUT2 0x08 /* Out2 complement */ | |
| 68 | +#define UART_MCR_OUT1 0x04 /* Out1 complement */ | |
| 69 | +#define UART_MCR_RTS 0x02 /* RTS complement */ | |
| 70 | +#define UART_MCR_DTR 0x01 /* DTR complement */ | |
| 71 | + | |
| 72 | +/* | |
| 73 | + * These are the definitions for the Modem Status Register | |
| 74 | + */ | |
| 75 | +#define UART_MSR_DCD 0x80 /* Data Carrier Detect */ | |
| 76 | +#define UART_MSR_RI 0x40 /* Ring Indicator */ | |
| 77 | +#define UART_MSR_DSR 0x20 /* Data Set Ready */ | |
| 78 | +#define UART_MSR_CTS 0x10 /* Clear to Send */ | |
| 79 | +#define UART_MSR_DDCD 0x08 /* Delta DCD */ | |
| 80 | +#define UART_MSR_TERI 0x04 /* Trailing edge ring indicator */ | |
| 81 | +#define UART_MSR_DDSR 0x02 /* Delta DSR */ | |
| 82 | +#define UART_MSR_DCTS 0x01 /* Delta CTS */ | |
| 83 | +#define UART_MSR_ANY_DELTA 0x0F /* Any of the delta bits! */ | |
| 84 | + | |
| 85 | +#define UART_LSR_TEMT 0x40 /* Transmitter empty */ | |
| 86 | +#define UART_LSR_THRE 0x20 /* Transmit-hold-register empty */ | |
| 87 | +#define UART_LSR_BI 0x10 /* Break interrupt indicator */ | |
| 88 | +#define UART_LSR_FE 0x08 /* Frame error indicator */ | |
| 89 | +#define UART_LSR_PE 0x04 /* Parity error indicator */ | |
| 90 | +#define UART_LSR_OE 0x02 /* Overrun error indicator */ | |
| 91 | +#define UART_LSR_DR 0x01 /* Receiver data ready */ | |
| 92 | + | |
| 93 | +typedef struct SerialState { | |
| 94 | + uint8_t divider; | |
| 95 | + uint8_t rbr; /* receive register */ | |
| 96 | + uint8_t ier; | |
| 97 | + uint8_t iir; /* read only */ | |
| 98 | + uint8_t lcr; | |
| 99 | + uint8_t mcr; | |
| 100 | + uint8_t lsr; /* read only */ | |
| 101 | + uint8_t msr; | |
| 102 | + uint8_t scr; | |
| 103 | + /* NOTE: this hidden state is necessary for tx irq generation as | |
| 104 | + it can be reset while reading iir */ | |
| 105 | + int thr_ipending; | |
| 106 | + int irq; | |
| 107 | +} SerialState; | |
| 108 | + | |
| 109 | +SerialState serial_ports[1]; | |
| 110 | + | |
| 111 | +void serial_update_irq(void) | |
| 112 | +{ | |
| 113 | + SerialState *s = &serial_ports[0]; | |
| 114 | + | |
| 115 | + if ((s->lsr & UART_LSR_DR) && (s->ier & UART_IER_RDI)) { | |
| 116 | + s->iir = UART_IIR_RDI; | |
| 117 | + } else if (s->thr_ipending && (s->ier & UART_IER_THRI)) { | |
| 118 | + s->iir = UART_IIR_THRI; | |
| 119 | + } else { | |
| 120 | + s->iir = UART_IIR_NO_INT; | |
| 121 | + } | |
| 122 | + if (s->iir != UART_IIR_NO_INT) { | |
| 123 | + pic_set_irq(s->irq, 1); | |
| 124 | + } else { | |
| 125 | + pic_set_irq(s->irq, 0); | |
| 126 | + } | |
| 127 | +} | |
| 128 | + | |
| 129 | +void serial_ioport_write(CPUState *env, uint32_t addr, uint32_t val) | |
| 130 | +{ | |
| 131 | + SerialState *s = &serial_ports[0]; | |
| 132 | + unsigned char ch; | |
| 133 | + int ret; | |
| 134 | + | |
| 135 | + addr &= 7; | |
| 136 | +#ifdef DEBUG_SERIAL | |
| 137 | + printf("serial: write addr=0x%02x val=0x%02x\n", addr, val); | |
| 138 | +#endif | |
| 139 | + switch(addr) { | |
| 140 | + default: | |
| 141 | + case 0: | |
| 142 | + if (s->lcr & UART_LCR_DLAB) { | |
| 143 | + s->divider = (s->divider & 0xff00) | val; | |
| 144 | + } else { | |
| 145 | + s->thr_ipending = 0; | |
| 146 | + s->lsr &= ~UART_LSR_THRE; | |
| 147 | + serial_update_irq(); | |
| 148 | + | |
| 149 | + ch = val; | |
| 150 | + do { | |
| 151 | + ret = write(1, &ch, 1); | |
| 152 | + } while (ret != 1); | |
| 153 | + s->thr_ipending = 1; | |
| 154 | + s->lsr |= UART_LSR_THRE; | |
| 155 | + s->lsr |= UART_LSR_TEMT; | |
| 156 | + serial_update_irq(); | |
| 157 | + } | |
| 158 | + break; | |
| 159 | + case 1: | |
| 160 | + if (s->lcr & UART_LCR_DLAB) { | |
| 161 | + s->divider = (s->divider & 0x00ff) | (val << 8); | |
| 162 | + } else { | |
| 163 | + s->ier = val; | |
| 164 | + serial_update_irq(); | |
| 165 | + } | |
| 166 | + break; | |
| 167 | + case 2: | |
| 168 | + break; | |
| 169 | + case 3: | |
| 170 | + s->lcr = val; | |
| 171 | + break; | |
| 172 | + case 4: | |
| 173 | + s->mcr = val; | |
| 174 | + break; | |
| 175 | + case 5: | |
| 176 | + break; | |
| 177 | + case 6: | |
| 178 | + s->msr = val; | |
| 179 | + break; | |
| 180 | + case 7: | |
| 181 | + s->scr = val; | |
| 182 | + break; | |
| 183 | + } | |
| 184 | +} | |
| 185 | + | |
| 186 | +uint32_t serial_ioport_read(CPUState *env, uint32_t addr) | |
| 187 | +{ | |
| 188 | + SerialState *s = &serial_ports[0]; | |
| 189 | + uint32_t ret; | |
| 190 | + | |
| 191 | + addr &= 7; | |
| 192 | + switch(addr) { | |
| 193 | + default: | |
| 194 | + case 0: | |
| 195 | + if (s->lcr & UART_LCR_DLAB) { | |
| 196 | + ret = s->divider & 0xff; | |
| 197 | + } else { | |
| 198 | + ret = s->rbr; | |
| 199 | + s->lsr &= ~(UART_LSR_DR | UART_LSR_BI); | |
| 200 | + serial_update_irq(); | |
| 201 | + } | |
| 202 | + break; | |
| 203 | + case 1: | |
| 204 | + if (s->lcr & UART_LCR_DLAB) { | |
| 205 | + ret = (s->divider >> 8) & 0xff; | |
| 206 | + } else { | |
| 207 | + ret = s->ier; | |
| 208 | + } | |
| 209 | + break; | |
| 210 | + case 2: | |
| 211 | + ret = s->iir; | |
| 212 | + /* reset THR pending bit */ | |
| 213 | + if ((ret & 0x7) == UART_IIR_THRI) | |
| 214 | + s->thr_ipending = 0; | |
| 215 | + serial_update_irq(); | |
| 216 | + break; | |
| 217 | + case 3: | |
| 218 | + ret = s->lcr; | |
| 219 | + break; | |
| 220 | + case 4: | |
| 221 | + ret = s->mcr; | |
| 222 | + break; | |
| 223 | + case 5: | |
| 224 | + ret = s->lsr; | |
| 225 | + break; | |
| 226 | + case 6: | |
| 227 | + if (s->mcr & UART_MCR_LOOP) { | |
| 228 | + /* in loopback, the modem output pins are connected to the | |
| 229 | + inputs */ | |
| 230 | + ret = (s->mcr & 0x0c) << 4; | |
| 231 | + ret |= (s->mcr & 0x02) << 3; | |
| 232 | + ret |= (s->mcr & 0x01) << 5; | |
| 233 | + } else { | |
| 234 | + ret = s->msr; | |
| 235 | + } | |
| 236 | + break; | |
| 237 | + case 7: | |
| 238 | + ret = s->scr; | |
| 239 | + break; | |
| 240 | + } | |
| 241 | +#ifdef DEBUG_SERIAL | |
| 242 | + printf("serial: read addr=0x%02x val=0x%02x\n", addr, ret); | |
| 243 | +#endif | |
| 244 | + return ret; | |
| 245 | +} | |
| 246 | + | |
| 247 | +int serial_can_receive(void) | |
| 248 | +{ | |
| 249 | + SerialState *s = &serial_ports[0]; | |
| 250 | + return !(s->lsr & UART_LSR_DR); | |
| 251 | +} | |
| 252 | + | |
| 253 | +void serial_receive_byte(int ch) | |
| 254 | +{ | |
| 255 | + SerialState *s = &serial_ports[0]; | |
| 256 | + | |
| 257 | + s->rbr = ch; | |
| 258 | + s->lsr |= UART_LSR_DR; | |
| 259 | + serial_update_irq(); | |
| 260 | +} | |
| 261 | + | |
| 262 | +void serial_receive_break(void) | |
| 263 | +{ | |
| 264 | + SerialState *s = &serial_ports[0]; | |
| 265 | + | |
| 266 | + s->rbr = 0; | |
| 267 | + s->lsr |= UART_LSR_BI | UART_LSR_DR; | |
| 268 | + serial_update_irq(); | |
| 269 | +} | |
| 270 | + | |
| 271 | +void serial_init(int base, int irq) | |
| 272 | +{ | |
| 273 | + SerialState *s = &serial_ports[0]; | |
| 274 | + | |
| 275 | + s->irq = irq; | |
| 276 | + s->lsr = UART_LSR_TEMT | UART_LSR_THRE; | |
| 277 | + s->iir = UART_IIR_NO_INT; | |
| 278 | + | |
| 279 | + register_ioport_write(base, 8, serial_ioport_write, 1); | |
| 280 | + register_ioport_read(base, 8, serial_ioport_read, 1); | |
| 281 | +} | ... | ... |
vl.c
| 1 | 1 | /* |
| 2 | - * QEMU PC System Emulator | |
| 2 | + * QEMU System Emulator | |
| 3 | 3 | * |
| 4 | - * Copyright (c) 2003 Fabrice Bellard | |
| 4 | + * Copyright (c) 2003-2004 Fabrice Bellard | |
| 5 | 5 | * |
| 6 | 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy |
| 7 | 7 | * of this software and associated documentation files (the "Software"), to deal |
| ... | ... | @@ -51,33 +51,9 @@ |
| 51 | 51 | #include "vl.h" |
| 52 | 52 | |
| 53 | 53 | #define DEFAULT_NETWORK_SCRIPT "/etc/qemu-ifup" |
| 54 | -#define BIOS_FILENAME "bios.bin" | |
| 55 | -#define VGABIOS_FILENAME "vgabios.bin" | |
| 56 | -#define LINUX_BOOT_FILENAME "linux_boot.bin" | |
| 57 | 54 | |
| 58 | 55 | //#define DEBUG_UNUSED_IOPORT |
| 59 | 56 | |
| 60 | -//#define DEBUG_IRQ_LATENCY | |
| 61 | - | |
| 62 | -/* output Bochs bios info messages */ | |
| 63 | -//#define DEBUG_BIOS | |
| 64 | - | |
| 65 | -//#define DEBUG_CMOS | |
| 66 | - | |
| 67 | -/* debug PIC */ | |
| 68 | -//#define DEBUG_PIC | |
| 69 | - | |
| 70 | -/* debug NE2000 card */ | |
| 71 | -//#define DEBUG_NE2000 | |
| 72 | - | |
| 73 | -/* debug PC keyboard */ | |
| 74 | -//#define DEBUG_KBD | |
| 75 | - | |
| 76 | -/* debug PC keyboard : only mouse */ | |
| 77 | -//#define DEBUG_MOUSE | |
| 78 | - | |
| 79 | -//#define DEBUG_SERIAL | |
| 80 | - | |
| 81 | 57 | #if !defined(CONFIG_SOFTMMU) |
| 82 | 58 | #define PHYS_RAM_MAX_SIZE (256 * 1024 * 1024) |
| 83 | 59 | #else |
| ... | ... | @@ -85,7 +61,6 @@ |
| 85 | 61 | #endif |
| 86 | 62 | |
| 87 | 63 | #if defined (TARGET_I386) |
| 88 | -#define KERNEL_LOAD_ADDR 0x00100000 | |
| 89 | 64 | #elif defined (TARGET_PPC) |
| 90 | 65 | //#define USE_OPEN_FIRMWARE |
| 91 | 66 | #if !defined (USE_OPEN_FIRMWARE) |
| ... | ... | @@ -96,16 +71,13 @@ |
| 96 | 71 | #define KERNEL_STACK_ADDR 0x00400000 |
| 97 | 72 | #endif |
| 98 | 73 | #endif |
| 99 | -#define INITRD_LOAD_ADDR 0x00400000 | |
| 100 | -#define KERNEL_PARAMS_ADDR 0x00090000 | |
| 101 | -#define KERNEL_CMDLINE_ADDR 0x00099000 | |
| 102 | 74 | |
| 103 | 75 | #define GUI_REFRESH_INTERVAL 30 |
| 104 | 76 | |
| 105 | 77 | /* XXX: use a two level table to limit memory usage */ |
| 106 | 78 | #define MAX_IOPORTS 65536 |
| 107 | 79 | |
| 108 | -static const char *bios_dir = CONFIG_QEMU_SHAREDIR; | |
| 80 | +const char *bios_dir = CONFIG_QEMU_SHAREDIR; | |
| 109 | 81 | char phys_ram_file[1024]; |
| 110 | 82 | CPUState *global_env; |
| 111 | 83 | CPUState *cpu_single_env; |
| ... | ... | @@ -119,6 +91,8 @@ int term_inited; |
| 119 | 91 | int64_t ticks_per_sec; |
| 120 | 92 | int boot_device = 'c'; |
| 121 | 93 | static int ram_size; |
| 94 | +static char network_script[1024]; | |
| 95 | +int pit_min_timer_count = 0; | |
| 122 | 96 | |
| 123 | 97 | /***********************************************************/ |
| 124 | 98 | /* x86 io ports */ |
| ... | ... | @@ -245,39 +219,6 @@ char *pstrcat(char *buf, int buf_size, const char *s) |
| 245 | 219 | return buf; |
| 246 | 220 | } |
| 247 | 221 | |
| 248 | -#if defined (TARGET_I386) | |
| 249 | -int load_kernel(const char *filename, uint8_t *addr, | |
| 250 | - uint8_t *real_addr) | |
| 251 | -{ | |
| 252 | - int fd, size; | |
| 253 | - int setup_sects; | |
| 254 | - | |
| 255 | - fd = open(filename, O_RDONLY); | |
| 256 | - if (fd < 0) | |
| 257 | - return -1; | |
| 258 | - | |
| 259 | - /* load 16 bit code */ | |
| 260 | - if (read(fd, real_addr, 512) != 512) | |
| 261 | - goto fail; | |
| 262 | - setup_sects = real_addr[0x1F1]; | |
| 263 | - if (!setup_sects) | |
| 264 | - setup_sects = 4; | |
| 265 | - if (read(fd, real_addr + 512, setup_sects * 512) != | |
| 266 | - setup_sects * 512) | |
| 267 | - goto fail; | |
| 268 | - | |
| 269 | - /* load 32 bit code */ | |
| 270 | - size = read(fd, addr, 16 * 1024 * 1024); | |
| 271 | - if (size < 0) | |
| 272 | - goto fail; | |
| 273 | - close(fd); | |
| 274 | - return size; | |
| 275 | - fail: | |
| 276 | - close(fd); | |
| 277 | - return -1; | |
| 278 | -} | |
| 279 | -#endif | |
| 280 | - | |
| 281 | 222 | /* return the size or -1 if error */ |
| 282 | 223 | int load_image(const char *filename, uint8_t *addr) |
| 283 | 224 | { |
| ... | ... | @@ -326,10 +267,6 @@ int cpu_inl(CPUState *env, int addr) |
| 326 | 267 | } |
| 327 | 268 | |
| 328 | 269 | /***********************************************************/ |
| 329 | -void ioport80_write(CPUState *env, uint32_t addr, uint32_t data) | |
| 330 | -{ | |
| 331 | -} | |
| 332 | - | |
| 333 | 270 | void hw_error(const char *fmt, ...) |
| 334 | 271 | { |
| 335 | 272 | va_list ap; |
| ... | ... | @@ -347,613 +284,6 @@ void hw_error(const char *fmt, ...) |
| 347 | 284 | abort(); |
| 348 | 285 | } |
| 349 | 286 | |
| 350 | -/***********************************************************/ | |
| 351 | -/* cmos emulation */ | |
| 352 | - | |
| 353 | -#if defined (TARGET_I386) | |
| 354 | -#define RTC_SECONDS 0 | |
| 355 | -#define RTC_SECONDS_ALARM 1 | |
| 356 | -#define RTC_MINUTES 2 | |
| 357 | -#define RTC_MINUTES_ALARM 3 | |
| 358 | -#define RTC_HOURS 4 | |
| 359 | -#define RTC_HOURS_ALARM 5 | |
| 360 | -#define RTC_ALARM_DONT_CARE 0xC0 | |
| 361 | - | |
| 362 | -#define RTC_DAY_OF_WEEK 6 | |
| 363 | -#define RTC_DAY_OF_MONTH 7 | |
| 364 | -#define RTC_MONTH 8 | |
| 365 | -#define RTC_YEAR 9 | |
| 366 | - | |
| 367 | -#define RTC_REG_A 10 | |
| 368 | -#define RTC_REG_B 11 | |
| 369 | -#define RTC_REG_C 12 | |
| 370 | -#define RTC_REG_D 13 | |
| 371 | - | |
| 372 | -/* PC cmos mappings */ | |
| 373 | -#define REG_EQUIPMENT_BYTE 0x14 | |
| 374 | -#define REG_IBM_CENTURY_BYTE 0x32 | |
| 375 | -#define REG_IBM_PS2_CENTURY_BYTE 0x37 | |
| 376 | - | |
| 377 | -uint8_t cmos_data[128]; | |
| 378 | -uint8_t cmos_index; | |
| 379 | - | |
| 380 | -void cmos_ioport_write(CPUState *env, uint32_t addr, uint32_t data) | |
| 381 | -{ | |
| 382 | - if (addr == 0x70) { | |
| 383 | - cmos_index = data & 0x7f; | |
| 384 | - } else { | |
| 385 | -#ifdef DEBUG_CMOS | |
| 386 | - printf("cmos: write index=0x%02x val=0x%02x\n", | |
| 387 | - cmos_index, data); | |
| 388 | -#endif | |
| 389 | - switch(addr) { | |
| 390 | - case RTC_SECONDS_ALARM: | |
| 391 | - case RTC_MINUTES_ALARM: | |
| 392 | - case RTC_HOURS_ALARM: | |
| 393 | - /* XXX: not supported */ | |
| 394 | - cmos_data[cmos_index] = data; | |
| 395 | - break; | |
| 396 | - case RTC_SECONDS: | |
| 397 | - case RTC_MINUTES: | |
| 398 | - case RTC_HOURS: | |
| 399 | - case RTC_DAY_OF_WEEK: | |
| 400 | - case RTC_DAY_OF_MONTH: | |
| 401 | - case RTC_MONTH: | |
| 402 | - case RTC_YEAR: | |
| 403 | - cmos_data[cmos_index] = data; | |
| 404 | - break; | |
| 405 | - case RTC_REG_A: | |
| 406 | - case RTC_REG_B: | |
| 407 | - cmos_data[cmos_index] = data; | |
| 408 | - break; | |
| 409 | - case RTC_REG_C: | |
| 410 | - case RTC_REG_D: | |
| 411 | - /* cannot write to them */ | |
| 412 | - break; | |
| 413 | - default: | |
| 414 | - cmos_data[cmos_index] = data; | |
| 415 | - break; | |
| 416 | - } | |
| 417 | - } | |
| 418 | -} | |
| 419 | - | |
| 420 | -static inline int to_bcd(int a) | |
| 421 | -{ | |
| 422 | - return ((a / 10) << 4) | (a % 10); | |
| 423 | -} | |
| 424 | - | |
| 425 | -static void cmos_update_time(void) | |
| 426 | -{ | |
| 427 | - struct tm *tm; | |
| 428 | - time_t ti; | |
| 429 | - | |
| 430 | - ti = time(NULL); | |
| 431 | - tm = gmtime(&ti); | |
| 432 | - cmos_data[RTC_SECONDS] = to_bcd(tm->tm_sec); | |
| 433 | - cmos_data[RTC_MINUTES] = to_bcd(tm->tm_min); | |
| 434 | - cmos_data[RTC_HOURS] = to_bcd(tm->tm_hour); | |
| 435 | - cmos_data[RTC_DAY_OF_WEEK] = to_bcd(tm->tm_wday); | |
| 436 | - cmos_data[RTC_DAY_OF_MONTH] = to_bcd(tm->tm_mday); | |
| 437 | - cmos_data[RTC_MONTH] = to_bcd(tm->tm_mon + 1); | |
| 438 | - cmos_data[RTC_YEAR] = to_bcd(tm->tm_year % 100); | |
| 439 | - cmos_data[REG_IBM_CENTURY_BYTE] = to_bcd((tm->tm_year / 100) + 19); | |
| 440 | - cmos_data[REG_IBM_PS2_CENTURY_BYTE] = cmos_data[REG_IBM_CENTURY_BYTE]; | |
| 441 | -} | |
| 442 | - | |
| 443 | -uint32_t cmos_ioport_read(CPUState *env, uint32_t addr) | |
| 444 | -{ | |
| 445 | - int ret; | |
| 446 | - | |
| 447 | - if (addr == 0x70) { | |
| 448 | - return 0xff; | |
| 449 | - } else { | |
| 450 | - switch(cmos_index) { | |
| 451 | - case RTC_SECONDS: | |
| 452 | - case RTC_MINUTES: | |
| 453 | - case RTC_HOURS: | |
| 454 | - case RTC_DAY_OF_WEEK: | |
| 455 | - case RTC_DAY_OF_MONTH: | |
| 456 | - case RTC_MONTH: | |
| 457 | - case RTC_YEAR: | |
| 458 | - case REG_IBM_CENTURY_BYTE: | |
| 459 | - case REG_IBM_PS2_CENTURY_BYTE: | |
| 460 | - cmos_update_time(); | |
| 461 | - ret = cmos_data[cmos_index]; | |
| 462 | - break; | |
| 463 | - case RTC_REG_A: | |
| 464 | - ret = cmos_data[cmos_index]; | |
| 465 | - /* toggle update-in-progress bit for Linux (same hack as | |
| 466 | - plex86) */ | |
| 467 | - cmos_data[RTC_REG_A] ^= 0x80; | |
| 468 | - break; | |
| 469 | - case RTC_REG_C: | |
| 470 | - ret = cmos_data[cmos_index]; | |
| 471 | - pic_set_irq(8, 0); | |
| 472 | - cmos_data[RTC_REG_C] = 0x00; | |
| 473 | - break; | |
| 474 | - default: | |
| 475 | - ret = cmos_data[cmos_index]; | |
| 476 | - break; | |
| 477 | - } | |
| 478 | -#ifdef DEBUG_CMOS | |
| 479 | - printf("cmos: read index=0x%02x val=0x%02x\n", | |
| 480 | - cmos_index, ret); | |
| 481 | -#endif | |
| 482 | - return ret; | |
| 483 | - } | |
| 484 | -} | |
| 485 | - | |
| 486 | -void cmos_init(void) | |
| 487 | -{ | |
| 488 | - int val; | |
| 489 | - | |
| 490 | - cmos_update_time(); | |
| 491 | - | |
| 492 | - cmos_data[RTC_REG_A] = 0x26; | |
| 493 | - cmos_data[RTC_REG_B] = 0x02; | |
| 494 | - cmos_data[RTC_REG_C] = 0x00; | |
| 495 | - cmos_data[RTC_REG_D] = 0x80; | |
| 496 | - | |
| 497 | - /* various important CMOS locations needed by PC/Bochs bios */ | |
| 498 | - | |
| 499 | - cmos_data[REG_EQUIPMENT_BYTE] = 0x02; /* FPU is there */ | |
| 500 | - cmos_data[REG_EQUIPMENT_BYTE] |= 0x04; /* PS/2 mouse installed */ | |
| 501 | - | |
| 502 | - /* memory size */ | |
| 503 | - val = (ram_size / 1024) - 1024; | |
| 504 | - if (val > 65535) | |
| 505 | - val = 65535; | |
| 506 | - cmos_data[0x17] = val; | |
| 507 | - cmos_data[0x18] = val >> 8; | |
| 508 | - cmos_data[0x30] = val; | |
| 509 | - cmos_data[0x31] = val >> 8; | |
| 510 | - | |
| 511 | - val = (ram_size / 65536) - ((16 * 1024 * 1024) / 65536); | |
| 512 | - if (val > 65535) | |
| 513 | - val = 65535; | |
| 514 | - cmos_data[0x34] = val; | |
| 515 | - cmos_data[0x35] = val >> 8; | |
| 516 | - | |
| 517 | - switch(boot_device) { | |
| 518 | - case 'a': | |
| 519 | - case 'b': | |
| 520 | - cmos_data[0x3d] = 0x01; /* floppy boot */ | |
| 521 | - break; | |
| 522 | - default: | |
| 523 | - case 'c': | |
| 524 | - cmos_data[0x3d] = 0x02; /* hard drive boot */ | |
| 525 | - break; | |
| 526 | - case 'd': | |
| 527 | - cmos_data[0x3d] = 0x03; /* CD-ROM boot */ | |
| 528 | - break; | |
| 529 | - } | |
| 530 | - | |
| 531 | - register_ioport_write(0x70, 2, cmos_ioport_write, 1); | |
| 532 | - register_ioport_read(0x70, 2, cmos_ioport_read, 1); | |
| 533 | -} | |
| 534 | - | |
| 535 | -void cmos_register_fd (uint8_t fd0, uint8_t fd1) | |
| 536 | -{ | |
| 537 | - int nb = 0; | |
| 538 | - | |
| 539 | - cmos_data[0x10] = 0; | |
| 540 | - switch (fd0) { | |
| 541 | - case 0: | |
| 542 | - /* 1.44 Mb 3"5 drive */ | |
| 543 | - cmos_data[0x10] |= 0x40; | |
| 544 | - break; | |
| 545 | - case 1: | |
| 546 | - /* 2.88 Mb 3"5 drive */ | |
| 547 | - cmos_data[0x10] |= 0x60; | |
| 548 | - break; | |
| 549 | - case 2: | |
| 550 | - /* 1.2 Mb 5"5 drive */ | |
| 551 | - cmos_data[0x10] |= 0x20; | |
| 552 | - break; | |
| 553 | - } | |
| 554 | - switch (fd1) { | |
| 555 | - case 0: | |
| 556 | - /* 1.44 Mb 3"5 drive */ | |
| 557 | - cmos_data[0x10] |= 0x04; | |
| 558 | - break; | |
| 559 | - case 1: | |
| 560 | - /* 2.88 Mb 3"5 drive */ | |
| 561 | - cmos_data[0x10] |= 0x06; | |
| 562 | - break; | |
| 563 | - case 2: | |
| 564 | - /* 1.2 Mb 5"5 drive */ | |
| 565 | - cmos_data[0x10] |= 0x02; | |
| 566 | - break; | |
| 567 | - } | |
| 568 | - if (fd0 < 3) | |
| 569 | - nb++; | |
| 570 | - if (fd1 < 3) | |
| 571 | - nb++; | |
| 572 | - switch (nb) { | |
| 573 | - case 0: | |
| 574 | - break; | |
| 575 | - case 1: | |
| 576 | - cmos_data[REG_EQUIPMENT_BYTE] |= 0x01; /* 1 drive, ready for boot */ | |
| 577 | - break; | |
| 578 | - case 2: | |
| 579 | - cmos_data[REG_EQUIPMENT_BYTE] |= 0x41; /* 2 drives, ready for boot */ | |
| 580 | - break; | |
| 581 | - } | |
| 582 | -} | |
| 583 | -#endif /* TARGET_I386 */ | |
| 584 | - | |
| 585 | -/***********************************************************/ | |
| 586 | -/* 8259 pic emulation */ | |
| 587 | - | |
| 588 | -typedef struct PicState { | |
| 589 | - uint8_t last_irr; /* edge detection */ | |
| 590 | - uint8_t irr; /* interrupt request register */ | |
| 591 | - uint8_t imr; /* interrupt mask register */ | |
| 592 | - uint8_t isr; /* interrupt service register */ | |
| 593 | - uint8_t priority_add; /* highest irq priority */ | |
| 594 | - uint8_t irq_base; | |
| 595 | - uint8_t read_reg_select; | |
| 596 | - uint8_t poll; | |
| 597 | - uint8_t special_mask; | |
| 598 | - uint8_t init_state; | |
| 599 | - uint8_t auto_eoi; | |
| 600 | - uint8_t rotate_on_auto_eoi; | |
| 601 | - uint8_t special_fully_nested_mode; | |
| 602 | - uint8_t init4; /* true if 4 byte init */ | |
| 603 | -} PicState; | |
| 604 | - | |
| 605 | -/* 0 is master pic, 1 is slave pic */ | |
| 606 | -PicState pics[2]; | |
| 607 | -int pic_irq_requested; | |
| 608 | - | |
| 609 | -/* set irq level. If an edge is detected, then the IRR is set to 1 */ | |
| 610 | -static inline void pic_set_irq1(PicState *s, int irq, int level) | |
| 611 | -{ | |
| 612 | - int mask; | |
| 613 | - mask = 1 << irq; | |
| 614 | - if (level) { | |
| 615 | - if ((s->last_irr & mask) == 0) | |
| 616 | - s->irr |= mask; | |
| 617 | - s->last_irr |= mask; | |
| 618 | - } else { | |
| 619 | - s->last_irr &= ~mask; | |
| 620 | - } | |
| 621 | -} | |
| 622 | - | |
| 623 | -/* return the highest priority found in mask (highest = smallest | |
| 624 | - number). Return 8 if no irq */ | |
| 625 | -static inline int get_priority(PicState *s, int mask) | |
| 626 | -{ | |
| 627 | - int priority; | |
| 628 | - if (mask == 0) | |
| 629 | - return 8; | |
| 630 | - priority = 0; | |
| 631 | - while ((mask & (1 << ((priority + s->priority_add) & 7))) == 0) | |
| 632 | - priority++; | |
| 633 | - return priority; | |
| 634 | -} | |
| 635 | - | |
| 636 | -/* return the pic wanted interrupt. return -1 if none */ | |
| 637 | -static int pic_get_irq(PicState *s) | |
| 638 | -{ | |
| 639 | - int mask, cur_priority, priority; | |
| 640 | - | |
| 641 | - mask = s->irr & ~s->imr; | |
| 642 | - priority = get_priority(s, mask); | |
| 643 | - if (priority == 8) | |
| 644 | - return -1; | |
| 645 | - /* compute current priority. If special fully nested mode on the | |
| 646 | - master, the IRQ coming from the slave is not taken into account | |
| 647 | - for the priority computation. */ | |
| 648 | - mask = s->isr; | |
| 649 | - if (s->special_fully_nested_mode && s == &pics[0]) | |
| 650 | - mask &= ~(1 << 2); | |
| 651 | - cur_priority = get_priority(s, mask); | |
| 652 | - if (priority < cur_priority) { | |
| 653 | - /* higher priority found: an irq should be generated */ | |
| 654 | - return (priority + s->priority_add) & 7; | |
| 655 | - } else { | |
| 656 | - return -1; | |
| 657 | - } | |
| 658 | -} | |
| 659 | - | |
| 660 | -/* raise irq to CPU if necessary. must be called every time the active | |
| 661 | - irq may change */ | |
| 662 | -void pic_update_irq(void) | |
| 663 | -{ | |
| 664 | - int irq2, irq; | |
| 665 | - | |
| 666 | - /* first look at slave pic */ | |
| 667 | - irq2 = pic_get_irq(&pics[1]); | |
| 668 | - if (irq2 >= 0) { | |
| 669 | - /* if irq request by slave pic, signal master PIC */ | |
| 670 | - pic_set_irq1(&pics[0], 2, 1); | |
| 671 | - pic_set_irq1(&pics[0], 2, 0); | |
| 672 | - } | |
| 673 | - /* look at requested irq */ | |
| 674 | - irq = pic_get_irq(&pics[0]); | |
| 675 | - if (irq >= 0) { | |
| 676 | - if (irq == 2) { | |
| 677 | - /* from slave pic */ | |
| 678 | - pic_irq_requested = 8 + irq2; | |
| 679 | - } else { | |
| 680 | - /* from master pic */ | |
| 681 | - pic_irq_requested = irq; | |
| 682 | - } | |
| 683 | -#if defined(DEBUG_PIC) | |
| 684 | - { | |
| 685 | - int i; | |
| 686 | - for(i = 0; i < 2; i++) { | |
| 687 | - printf("pic%d: imr=%x irr=%x padd=%d\n", | |
| 688 | - i, pics[i].imr, pics[i].irr, pics[i].priority_add); | |
| 689 | - | |
| 690 | - } | |
| 691 | - } | |
| 692 | - printf("pic: cpu_interrupt req=%d\n", pic_irq_requested); | |
| 693 | -#endif | |
| 694 | - cpu_interrupt(global_env, CPU_INTERRUPT_HARD); | |
| 695 | - } | |
| 696 | -} | |
| 697 | - | |
| 698 | -#ifdef DEBUG_IRQ_LATENCY | |
| 699 | -int64_t irq_time[16]; | |
| 700 | -int64_t cpu_get_ticks(void); | |
| 701 | -#endif | |
| 702 | -#if defined(DEBUG_PIC) | |
| 703 | -int irq_level[16]; | |
| 704 | -#endif | |
| 705 | - | |
| 706 | -void pic_set_irq(int irq, int level) | |
| 707 | -{ | |
| 708 | -#if defined(DEBUG_PIC) | |
| 709 | - if (level != irq_level[irq]) { | |
| 710 | - printf("pic_set_irq: irq=%d level=%d\n", irq, level); | |
| 711 | - irq_level[irq] = level; | |
| 712 | - } | |
| 713 | -#endif | |
| 714 | -#ifdef DEBUG_IRQ_LATENCY | |
| 715 | - if (level) { | |
| 716 | - irq_time[irq] = cpu_get_ticks(); | |
| 717 | - } | |
| 718 | -#endif | |
| 719 | - pic_set_irq1(&pics[irq >> 3], irq & 7, level); | |
| 720 | - pic_update_irq(); | |
| 721 | -} | |
| 722 | - | |
| 723 | -/* acknowledge interrupt 'irq' */ | |
| 724 | -static inline void pic_intack(PicState *s, int irq) | |
| 725 | -{ | |
| 726 | - if (s->auto_eoi) { | |
| 727 | - if (s->rotate_on_auto_eoi) | |
| 728 | - s->priority_add = (irq + 1) & 7; | |
| 729 | - } else { | |
| 730 | - s->isr |= (1 << irq); | |
| 731 | - } | |
| 732 | - s->irr &= ~(1 << irq); | |
| 733 | -} | |
| 734 | - | |
| 735 | -int cpu_x86_get_pic_interrupt(CPUState *env) | |
| 736 | -{ | |
| 737 | - int irq, irq2, intno; | |
| 738 | - | |
| 739 | - /* signal the pic that the irq was acked by the CPU */ | |
| 740 | - irq = pic_irq_requested; | |
| 741 | -#ifdef DEBUG_IRQ_LATENCY | |
| 742 | - printf("IRQ%d latency=%0.3fus\n", | |
| 743 | - irq, | |
| 744 | - (double)(cpu_get_ticks() - irq_time[irq]) * 1000000.0 / ticks_per_sec); | |
| 745 | -#endif | |
| 746 | -#if defined(DEBUG_PIC) | |
| 747 | - printf("pic_interrupt: irq=%d\n", irq); | |
| 748 | -#endif | |
| 749 | - | |
| 750 | - if (irq >= 8) { | |
| 751 | - irq2 = irq & 7; | |
| 752 | - pic_intack(&pics[1], irq2); | |
| 753 | - irq = 2; | |
| 754 | - intno = pics[1].irq_base + irq2; | |
| 755 | - } else { | |
| 756 | - intno = pics[0].irq_base + irq; | |
| 757 | - } | |
| 758 | - pic_intack(&pics[0], irq); | |
| 759 | - return intno; | |
| 760 | -} | |
| 761 | - | |
| 762 | -void pic_ioport_write(CPUState *env, uint32_t addr, uint32_t val) | |
| 763 | -{ | |
| 764 | - PicState *s; | |
| 765 | - int priority, cmd, irq; | |
| 766 | - | |
| 767 | -#ifdef DEBUG_PIC | |
| 768 | - printf("pic_write: addr=0x%02x val=0x%02x\n", addr, val); | |
| 769 | -#endif | |
| 770 | - s = &pics[addr >> 7]; | |
| 771 | - addr &= 1; | |
| 772 | - if (addr == 0) { | |
| 773 | - if (val & 0x10) { | |
| 774 | - /* init */ | |
| 775 | - memset(s, 0, sizeof(PicState)); | |
| 776 | - s->init_state = 1; | |
| 777 | - s->init4 = val & 1; | |
| 778 | - if (val & 0x02) | |
| 779 | - hw_error("single mode not supported"); | |
| 780 | - if (val & 0x08) | |
| 781 | - hw_error("level sensitive irq not supported"); | |
| 782 | - } else if (val & 0x08) { | |
| 783 | - if (val & 0x04) | |
| 784 | - s->poll = 1; | |
| 785 | - if (val & 0x02) | |
| 786 | - s->read_reg_select = val & 1; | |
| 787 | - if (val & 0x40) | |
| 788 | - s->special_mask = (val >> 5) & 1; | |
| 789 | - } else { | |
| 790 | - cmd = val >> 5; | |
| 791 | - switch(cmd) { | |
| 792 | - case 0: | |
| 793 | - case 4: | |
| 794 | - s->rotate_on_auto_eoi = cmd >> 2; | |
| 795 | - break; | |
| 796 | - case 1: /* end of interrupt */ | |
| 797 | - case 5: | |
| 798 | - priority = get_priority(s, s->isr); | |
| 799 | - if (priority != 8) { | |
| 800 | - irq = (priority + s->priority_add) & 7; | |
| 801 | - s->isr &= ~(1 << irq); | |
| 802 | - if (cmd == 5) | |
| 803 | - s->priority_add = (irq + 1) & 7; | |
| 804 | - pic_update_irq(); | |
| 805 | - } | |
| 806 | - break; | |
| 807 | - case 3: | |
| 808 | - irq = val & 7; | |
| 809 | - s->isr &= ~(1 << irq); | |
| 810 | - pic_update_irq(); | |
| 811 | - break; | |
| 812 | - case 6: | |
| 813 | - s->priority_add = (val + 1) & 7; | |
| 814 | - pic_update_irq(); | |
| 815 | - break; | |
| 816 | - case 7: | |
| 817 | - irq = val & 7; | |
| 818 | - s->isr &= ~(1 << irq); | |
| 819 | - s->priority_add = (irq + 1) & 7; | |
| 820 | - pic_update_irq(); | |
| 821 | - break; | |
| 822 | - default: | |
| 823 | - /* no operation */ | |
| 824 | - break; | |
| 825 | - } | |
| 826 | - } | |
| 827 | - } else { | |
| 828 | - switch(s->init_state) { | |
| 829 | - case 0: | |
| 830 | - /* normal mode */ | |
| 831 | - s->imr = val; | |
| 832 | - pic_update_irq(); | |
| 833 | - break; | |
| 834 | - case 1: | |
| 835 | - s->irq_base = val & 0xf8; | |
| 836 | - s->init_state = 2; | |
| 837 | - break; | |
| 838 | - case 2: | |
| 839 | - if (s->init4) { | |
| 840 | - s->init_state = 3; | |
| 841 | - } else { | |
| 842 | - s->init_state = 0; | |
| 843 | - } | |
| 844 | - break; | |
| 845 | - case 3: | |
| 846 | - s->special_fully_nested_mode = (val >> 4) & 1; | |
| 847 | - s->auto_eoi = (val >> 1) & 1; | |
| 848 | - s->init_state = 0; | |
| 849 | - break; | |
| 850 | - } | |
| 851 | - } | |
| 852 | -} | |
| 853 | - | |
| 854 | -static uint32_t pic_poll_read (PicState *s, uint32_t addr1) | |
| 855 | -{ | |
| 856 | - int ret; | |
| 857 | - | |
| 858 | - ret = pic_get_irq(s); | |
| 859 | - if (ret >= 0) { | |
| 860 | - if (addr1 >> 7) { | |
| 861 | - pics[0].isr &= ~(1 << 2); | |
| 862 | - pics[0].irr &= ~(1 << 2); | |
| 863 | - } | |
| 864 | - s->irr &= ~(1 << ret); | |
| 865 | - s->isr &= ~(1 << ret); | |
| 866 | - if (addr1 >> 7 || ret != 2) | |
| 867 | - pic_update_irq(); | |
| 868 | - } else { | |
| 869 | - ret = 0x07; | |
| 870 | - pic_update_irq(); | |
| 871 | - } | |
| 872 | - | |
| 873 | - return ret; | |
| 874 | -} | |
| 875 | - | |
| 876 | -uint32_t pic_ioport_read(CPUState *env, uint32_t addr1) | |
| 877 | -{ | |
| 878 | - PicState *s; | |
| 879 | - unsigned int addr; | |
| 880 | - int ret; | |
| 881 | - | |
| 882 | - addr = addr1; | |
| 883 | - s = &pics[addr >> 7]; | |
| 884 | - addr &= 1; | |
| 885 | - if (s->poll) { | |
| 886 | - ret = pic_poll_read(s, addr1); | |
| 887 | - s->poll = 0; | |
| 888 | - } else { | |
| 889 | - if (addr == 0) { | |
| 890 | - if (s->read_reg_select) | |
| 891 | - ret = s->isr; | |
| 892 | - else | |
| 893 | - ret = s->irr; | |
| 894 | - } else { | |
| 895 | - ret = s->imr; | |
| 896 | - } | |
| 897 | - } | |
| 898 | -#ifdef DEBUG_PIC | |
| 899 | - printf("pic_read: addr=0x%02x val=0x%02x\n", addr1, ret); | |
| 900 | -#endif | |
| 901 | - return ret; | |
| 902 | -} | |
| 903 | - | |
| 904 | -/* memory mapped interrupt status */ | |
| 905 | -uint32_t pic_intack_read(CPUState *env) | |
| 906 | -{ | |
| 907 | - int ret; | |
| 908 | - | |
| 909 | - ret = pic_poll_read(&pics[0], 0x00); | |
| 910 | - if (ret == 2) | |
| 911 | - ret = pic_poll_read(&pics[1], 0x80) + 8; | |
| 912 | - /* Prepare for ISR read */ | |
| 913 | - pics[0].read_reg_select = 1; | |
| 914 | - | |
| 915 | - return ret; | |
| 916 | -} | |
| 917 | - | |
| 918 | -void pic_init(void) | |
| 919 | -{ | |
| 920 | -#if defined (TARGET_I386) || defined (TARGET_PPC) | |
| 921 | - register_ioport_write(0x20, 2, pic_ioport_write, 1); | |
| 922 | - register_ioport_read(0x20, 2, pic_ioport_read, 1); | |
| 923 | - register_ioport_write(0xa0, 2, pic_ioport_write, 1); | |
| 924 | - register_ioport_read(0xa0, 2, pic_ioport_read, 1); | |
| 925 | -#endif | |
| 926 | -} | |
| 927 | - | |
| 928 | -/***********************************************************/ | |
| 929 | -/* 8253 PIT emulation */ | |
| 930 | - | |
| 931 | -#define PIT_FREQ 1193182 | |
| 932 | - | |
| 933 | -#define RW_STATE_LSB 0 | |
| 934 | -#define RW_STATE_MSB 1 | |
| 935 | -#define RW_STATE_WORD0 2 | |
| 936 | -#define RW_STATE_WORD1 3 | |
| 937 | -#define RW_STATE_LATCHED_WORD0 4 | |
| 938 | -#define RW_STATE_LATCHED_WORD1 5 | |
| 939 | - | |
| 940 | -typedef struct PITChannelState { | |
| 941 | - int count; /* can be 65536 */ | |
| 942 | - uint16_t latched_count; | |
| 943 | - uint8_t rw_state; | |
| 944 | - uint8_t mode; | |
| 945 | - uint8_t bcd; /* not supported */ | |
| 946 | - uint8_t gate; /* timer start */ | |
| 947 | - int64_t count_load_time; | |
| 948 | - int64_t count_last_edge_check_time; | |
| 949 | -} PITChannelState; | |
| 950 | - | |
| 951 | -PITChannelState pit_channels[3]; | |
| 952 | -int speaker_data_on; | |
| 953 | -int dummy_refresh_clock; | |
| 954 | -int pit_min_timer_count = 0; | |
| 955 | - | |
| 956 | - | |
| 957 | 287 | #if defined(__powerpc__) |
| 958 | 288 | |
| 959 | 289 | static inline uint32_t get_tbl(void) |
| ... | ... | @@ -1036,7 +366,7 @@ void cpu_calibrate_ticks(void) |
| 1036 | 366 | } |
| 1037 | 367 | |
| 1038 | 368 | /* compute with 96 bit intermediate result: (a*b)/c */ |
| 1039 | -static uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c) | |
| 369 | +uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c) | |
| 1040 | 370 | { |
| 1041 | 371 | union { |
| 1042 | 372 | uint64_t ll; |
| ... | ... | @@ -1059,1809 +389,214 @@ static uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c) |
| 1059 | 389 | return res.ll; |
| 1060 | 390 | } |
| 1061 | 391 | |
| 1062 | -static int pit_get_count(PITChannelState *s) | |
| 1063 | -{ | |
| 1064 | - uint64_t d; | |
| 1065 | - int counter; | |
| 1066 | - | |
| 1067 | - d = muldiv64(cpu_get_ticks() - s->count_load_time, PIT_FREQ, ticks_per_sec); | |
| 1068 | - switch(s->mode) { | |
| 1069 | - case 0: | |
| 1070 | - case 1: | |
| 1071 | - case 4: | |
| 1072 | - case 5: | |
| 1073 | - counter = (s->count - d) & 0xffff; | |
| 1074 | - break; | |
| 1075 | - case 3: | |
| 1076 | - /* XXX: may be incorrect for odd counts */ | |
| 1077 | - counter = s->count - ((2 * d) % s->count); | |
| 1078 | - break; | |
| 1079 | - default: | |
| 1080 | - counter = s->count - (d % s->count); | |
| 1081 | - break; | |
| 1082 | - } | |
| 1083 | - return counter; | |
| 1084 | -} | |
| 1085 | - | |
| 1086 | -/* get pit output bit */ | |
| 1087 | -static int pit_get_out(PITChannelState *s) | |
| 1088 | -{ | |
| 1089 | - uint64_t d; | |
| 1090 | - int out; | |
| 1091 | - | |
| 1092 | - d = muldiv64(cpu_get_ticks() - s->count_load_time, PIT_FREQ, ticks_per_sec); | |
| 1093 | - switch(s->mode) { | |
| 1094 | - default: | |
| 1095 | - case 0: | |
| 1096 | - out = (d >= s->count); | |
| 1097 | - break; | |
| 1098 | - case 1: | |
| 1099 | - out = (d < s->count); | |
| 1100 | - break; | |
| 1101 | - case 2: | |
| 1102 | - if ((d % s->count) == 0 && d != 0) | |
| 1103 | - out = 1; | |
| 1104 | - else | |
| 1105 | - out = 0; | |
| 1106 | - break; | |
| 1107 | - case 3: | |
| 1108 | - out = (d % s->count) < ((s->count + 1) >> 1); | |
| 1109 | - break; | |
| 1110 | - case 4: | |
| 1111 | - case 5: | |
| 1112 | - out = (d == s->count); | |
| 1113 | - break; | |
| 1114 | - } | |
| 1115 | - return out; | |
| 1116 | -} | |
| 1117 | - | |
| 1118 | -/* get the number of 0 to 1 transitions we had since we call this | |
| 1119 | - function */ | |
| 1120 | -/* XXX: maybe better to use ticks precision to avoid getting edges | |
| 1121 | - twice if checks are done at very small intervals */ | |
| 1122 | -static int pit_get_out_edges(PITChannelState *s) | |
| 1123 | -{ | |
| 1124 | - uint64_t d1, d2; | |
| 1125 | - int64_t ticks; | |
| 1126 | - int ret, v; | |
| 1127 | - | |
| 1128 | - ticks = cpu_get_ticks(); | |
| 1129 | - d1 = muldiv64(s->count_last_edge_check_time - s->count_load_time, | |
| 1130 | - PIT_FREQ, ticks_per_sec); | |
| 1131 | - d2 = muldiv64(ticks - s->count_load_time, | |
| 1132 | - PIT_FREQ, ticks_per_sec); | |
| 1133 | - s->count_last_edge_check_time = ticks; | |
| 1134 | - switch(s->mode) { | |
| 1135 | - default: | |
| 1136 | - case 0: | |
| 1137 | - if (d1 < s->count && d2 >= s->count) | |
| 1138 | - ret = 1; | |
| 1139 | - else | |
| 1140 | - ret = 0; | |
| 1141 | - break; | |
| 1142 | - case 1: | |
| 1143 | - ret = 0; | |
| 1144 | - break; | |
| 1145 | - case 2: | |
| 1146 | - d1 /= s->count; | |
| 1147 | - d2 /= s->count; | |
| 1148 | - ret = d2 - d1; | |
| 1149 | - break; | |
| 1150 | - case 3: | |
| 1151 | - v = s->count - ((s->count + 1) >> 1); | |
| 1152 | - d1 = (d1 + v) / s->count; | |
| 1153 | - d2 = (d2 + v) / s->count; | |
| 1154 | - ret = d2 - d1; | |
| 1155 | - break; | |
| 1156 | - case 4: | |
| 1157 | - case 5: | |
| 1158 | - if (d1 < s->count && d2 >= s->count) | |
| 1159 | - ret = 1; | |
| 1160 | - else | |
| 1161 | - ret = 0; | |
| 1162 | - break; | |
| 1163 | - } | |
| 1164 | - return ret; | |
| 1165 | -} | |
| 1166 | - | |
| 1167 | -/* val must be 0 or 1 */ | |
| 1168 | -static inline void pit_set_gate(PITChannelState *s, int val) | |
| 1169 | -{ | |
| 1170 | - switch(s->mode) { | |
| 1171 | - default: | |
| 1172 | - case 0: | |
| 1173 | - case 4: | |
| 1174 | - /* XXX: just disable/enable counting */ | |
| 1175 | - break; | |
| 1176 | - case 1: | |
| 1177 | - case 5: | |
| 1178 | - if (s->gate < val) { | |
| 1179 | - /* restart counting on rising edge */ | |
| 1180 | - s->count_load_time = cpu_get_ticks(); | |
| 1181 | - s->count_last_edge_check_time = s->count_load_time; | |
| 1182 | - } | |
| 1183 | - break; | |
| 1184 | - case 2: | |
| 1185 | - case 3: | |
| 1186 | - if (s->gate < val) { | |
| 1187 | - /* restart counting on rising edge */ | |
| 1188 | - s->count_load_time = cpu_get_ticks(); | |
| 1189 | - s->count_last_edge_check_time = s->count_load_time; | |
| 1190 | - } | |
| 1191 | - /* XXX: disable/enable counting */ | |
| 1192 | - break; | |
| 1193 | - } | |
| 1194 | - s->gate = val; | |
| 1195 | -} | |
| 1196 | - | |
| 1197 | -static inline void pit_load_count(PITChannelState *s, int val) | |
| 1198 | -{ | |
| 1199 | - if (val == 0) | |
| 1200 | - val = 0x10000; | |
| 1201 | - s->count_load_time = cpu_get_ticks(); | |
| 1202 | - s->count_last_edge_check_time = s->count_load_time; | |
| 1203 | - s->count = val; | |
| 1204 | - if (s == &pit_channels[0] && val <= pit_min_timer_count) { | |
| 1205 | - fprintf(stderr, | |
| 1206 | - "\nWARNING: qemu: on your system, accurate timer emulation is impossible if its frequency is more than %d Hz. If using a 2.6 guest Linux kernel, you must patch asm/param.h to change HZ from 1000 to 100.\n\n", | |
| 1207 | - PIT_FREQ / pit_min_timer_count); | |
| 1208 | - } | |
| 1209 | -} | |
| 1210 | - | |
| 1211 | -void pit_ioport_write(CPUState *env, uint32_t addr, uint32_t val) | |
| 1212 | -{ | |
| 1213 | - int channel, access; | |
| 1214 | - PITChannelState *s; | |
| 1215 | - | |
| 1216 | - addr &= 3; | |
| 1217 | - if (addr == 3) { | |
| 1218 | - channel = val >> 6; | |
| 1219 | - if (channel == 3) | |
| 1220 | - return; | |
| 1221 | - s = &pit_channels[channel]; | |
| 1222 | - access = (val >> 4) & 3; | |
| 1223 | - switch(access) { | |
| 1224 | - case 0: | |
| 1225 | - s->latched_count = pit_get_count(s); | |
| 1226 | - s->rw_state = RW_STATE_LATCHED_WORD0; | |
| 1227 | - break; | |
| 1228 | - default: | |
| 1229 | - s->mode = (val >> 1) & 7; | |
| 1230 | - s->bcd = val & 1; | |
| 1231 | - s->rw_state = access - 1 + RW_STATE_LSB; | |
| 1232 | - break; | |
| 1233 | - } | |
| 1234 | - } else { | |
| 1235 | - s = &pit_channels[addr]; | |
| 1236 | - switch(s->rw_state) { | |
| 1237 | - case RW_STATE_LSB: | |
| 1238 | - pit_load_count(s, val); | |
| 1239 | - break; | |
| 1240 | - case RW_STATE_MSB: | |
| 1241 | - pit_load_count(s, val << 8); | |
| 1242 | - break; | |
| 1243 | - case RW_STATE_WORD0: | |
| 1244 | - case RW_STATE_WORD1: | |
| 1245 | - if (s->rw_state & 1) { | |
| 1246 | - pit_load_count(s, (s->latched_count & 0xff) | (val << 8)); | |
| 1247 | - } else { | |
| 1248 | - s->latched_count = val; | |
| 1249 | - } | |
| 1250 | - s->rw_state ^= 1; | |
| 1251 | - break; | |
| 1252 | - } | |
| 1253 | - } | |
| 1254 | -} | |
| 1255 | - | |
| 1256 | -uint32_t pit_ioport_read(CPUState *env, uint32_t addr) | |
| 1257 | -{ | |
| 1258 | - int ret, count; | |
| 1259 | - PITChannelState *s; | |
| 1260 | - | |
| 1261 | - addr &= 3; | |
| 1262 | - s = &pit_channels[addr]; | |
| 1263 | - switch(s->rw_state) { | |
| 1264 | - case RW_STATE_LSB: | |
| 1265 | - case RW_STATE_MSB: | |
| 1266 | - case RW_STATE_WORD0: | |
| 1267 | - case RW_STATE_WORD1: | |
| 1268 | - count = pit_get_count(s); | |
| 1269 | - if (s->rw_state & 1) | |
| 1270 | - ret = (count >> 8) & 0xff; | |
| 1271 | - else | |
| 1272 | - ret = count & 0xff; | |
| 1273 | - if (s->rw_state & 2) | |
| 1274 | - s->rw_state ^= 1; | |
| 1275 | - break; | |
| 1276 | - default: | |
| 1277 | - case RW_STATE_LATCHED_WORD0: | |
| 1278 | - case RW_STATE_LATCHED_WORD1: | |
| 1279 | - if (s->rw_state & 1) | |
| 1280 | - ret = s->latched_count >> 8; | |
| 1281 | - else | |
| 1282 | - ret = s->latched_count & 0xff; | |
| 1283 | - s->rw_state ^= 1; | |
| 1284 | - break; | |
| 1285 | - } | |
| 1286 | - return ret; | |
| 1287 | -} | |
| 1288 | - | |
| 1289 | -#if defined (TARGET_I386) | |
| 1290 | -void speaker_ioport_write(CPUState *env, uint32_t addr, uint32_t val) | |
| 1291 | -{ | |
| 1292 | - speaker_data_on = (val >> 1) & 1; | |
| 1293 | - pit_set_gate(&pit_channels[2], val & 1); | |
| 1294 | -} | |
| 1295 | - | |
| 1296 | -uint32_t speaker_ioport_read(CPUState *env, uint32_t addr) | |
| 1297 | -{ | |
| 1298 | - int out; | |
| 1299 | - out = pit_get_out(&pit_channels[2]); | |
| 1300 | - dummy_refresh_clock ^= 1; | |
| 1301 | - return (speaker_data_on << 1) | pit_channels[2].gate | (out << 5) | | |
| 1302 | - (dummy_refresh_clock << 4); | |
| 1303 | -} | |
| 1304 | -#endif | |
| 392 | +#define TERM_ESCAPE 0x01 /* ctrl-a is used for escape */ | |
| 393 | +static int term_got_escape, term_command; | |
| 394 | +static unsigned char term_cmd_buf[128]; | |
| 1305 | 395 | |
| 1306 | -void pit_init(void) | |
| 1307 | -{ | |
| 1308 | - PITChannelState *s; | |
| 1309 | - int i; | |
| 396 | +typedef struct term_cmd_t { | |
| 397 | + const unsigned char *name; | |
| 398 | + void (*handler)(unsigned char *params); | |
| 399 | +} term_cmd_t; | |
| 1310 | 400 | |
| 1311 | - cpu_calibrate_ticks(); | |
| 1312 | - | |
| 1313 | - for(i = 0;i < 3; i++) { | |
| 1314 | - s = &pit_channels[i]; | |
| 1315 | - s->mode = 3; | |
| 1316 | - s->gate = (i != 2); | |
| 1317 | - pit_load_count(s, 0); | |
| 1318 | - } | |
| 1319 | - | |
| 1320 | - register_ioport_write(0x40, 4, pit_ioport_write, 1); | |
| 1321 | - register_ioport_read(0x40, 3, pit_ioport_read, 1); | |
| 1322 | - | |
| 1323 | -#if defined (TARGET_I386) | |
| 1324 | - register_ioport_read(0x61, 1, speaker_ioport_read, 1); | |
| 1325 | - register_ioport_write(0x61, 1, speaker_ioport_write, 1); | |
| 1326 | -#endif | |
| 1327 | -} | |
| 1328 | - | |
| 1329 | -/***********************************************************/ | |
| 1330 | -/* serial port emulation */ | |
| 1331 | - | |
| 1332 | -#define UART_IRQ 4 | |
| 1333 | - | |
| 1334 | -#define UART_LCR_DLAB 0x80 /* Divisor latch access bit */ | |
| 1335 | - | |
| 1336 | -#define UART_IER_MSI 0x08 /* Enable Modem status interrupt */ | |
| 1337 | -#define UART_IER_RLSI 0x04 /* Enable receiver line status interrupt */ | |
| 1338 | -#define UART_IER_THRI 0x02 /* Enable Transmitter holding register int. */ | |
| 1339 | -#define UART_IER_RDI 0x01 /* Enable receiver data interrupt */ | |
| 1340 | - | |
| 1341 | -#define UART_IIR_NO_INT 0x01 /* No interrupts pending */ | |
| 1342 | -#define UART_IIR_ID 0x06 /* Mask for the interrupt ID */ | |
| 1343 | - | |
| 1344 | -#define UART_IIR_MSI 0x00 /* Modem status interrupt */ | |
| 1345 | -#define UART_IIR_THRI 0x02 /* Transmitter holding register empty */ | |
| 1346 | -#define UART_IIR_RDI 0x04 /* Receiver data interrupt */ | |
| 1347 | -#define UART_IIR_RLSI 0x06 /* Receiver line status interrupt */ | |
| 1348 | - | |
| 1349 | -/* | |
| 1350 | - * These are the definitions for the Modem Control Register | |
| 1351 | - */ | |
| 1352 | -#define UART_MCR_LOOP 0x10 /* Enable loopback test mode */ | |
| 1353 | -#define UART_MCR_OUT2 0x08 /* Out2 complement */ | |
| 1354 | -#define UART_MCR_OUT1 0x04 /* Out1 complement */ | |
| 1355 | -#define UART_MCR_RTS 0x02 /* RTS complement */ | |
| 1356 | -#define UART_MCR_DTR 0x01 /* DTR complement */ | |
| 1357 | - | |
| 1358 | -/* | |
| 1359 | - * These are the definitions for the Modem Status Register | |
| 1360 | - */ | |
| 1361 | -#define UART_MSR_DCD 0x80 /* Data Carrier Detect */ | |
| 1362 | -#define UART_MSR_RI 0x40 /* Ring Indicator */ | |
| 1363 | -#define UART_MSR_DSR 0x20 /* Data Set Ready */ | |
| 1364 | -#define UART_MSR_CTS 0x10 /* Clear to Send */ | |
| 1365 | -#define UART_MSR_DDCD 0x08 /* Delta DCD */ | |
| 1366 | -#define UART_MSR_TERI 0x04 /* Trailing edge ring indicator */ | |
| 1367 | -#define UART_MSR_DDSR 0x02 /* Delta DSR */ | |
| 1368 | -#define UART_MSR_DCTS 0x01 /* Delta CTS */ | |
| 1369 | -#define UART_MSR_ANY_DELTA 0x0F /* Any of the delta bits! */ | |
| 1370 | - | |
| 1371 | -#define UART_LSR_TEMT 0x40 /* Transmitter empty */ | |
| 1372 | -#define UART_LSR_THRE 0x20 /* Transmit-hold-register empty */ | |
| 1373 | -#define UART_LSR_BI 0x10 /* Break interrupt indicator */ | |
| 1374 | -#define UART_LSR_FE 0x08 /* Frame error indicator */ | |
| 1375 | -#define UART_LSR_PE 0x04 /* Parity error indicator */ | |
| 1376 | -#define UART_LSR_OE 0x02 /* Overrun error indicator */ | |
| 1377 | -#define UART_LSR_DR 0x01 /* Receiver data ready */ | |
| 1378 | - | |
| 1379 | -typedef struct SerialState { | |
| 1380 | - uint8_t divider; | |
| 1381 | - uint8_t rbr; /* receive register */ | |
| 1382 | - uint8_t ier; | |
| 1383 | - uint8_t iir; /* read only */ | |
| 1384 | - uint8_t lcr; | |
| 1385 | - uint8_t mcr; | |
| 1386 | - uint8_t lsr; /* read only */ | |
| 1387 | - uint8_t msr; | |
| 1388 | - uint8_t scr; | |
| 1389 | - /* NOTE: this hidden state is necessary for tx irq generation as | |
| 1390 | - it can be reset while reading iir */ | |
| 1391 | - int thr_ipending; | |
| 1392 | -} SerialState; | |
| 1393 | - | |
| 1394 | -SerialState serial_ports[1]; | |
| 1395 | - | |
| 1396 | -void serial_update_irq(void) | |
| 1397 | -{ | |
| 1398 | - SerialState *s = &serial_ports[0]; | |
| 1399 | - | |
| 1400 | - if ((s->lsr & UART_LSR_DR) && (s->ier & UART_IER_RDI)) { | |
| 1401 | - s->iir = UART_IIR_RDI; | |
| 1402 | - } else if (s->thr_ipending && (s->ier & UART_IER_THRI)) { | |
| 1403 | - s->iir = UART_IIR_THRI; | |
| 1404 | - } else { | |
| 1405 | - s->iir = UART_IIR_NO_INT; | |
| 1406 | - } | |
| 1407 | - if (s->iir != UART_IIR_NO_INT) { | |
| 1408 | - pic_set_irq(UART_IRQ, 1); | |
| 1409 | - } else { | |
| 1410 | - pic_set_irq(UART_IRQ, 0); | |
| 1411 | - } | |
| 1412 | -} | |
| 1413 | - | |
| 1414 | -void serial_ioport_write(CPUState *env, uint32_t addr, uint32_t val) | |
| 1415 | -{ | |
| 1416 | - SerialState *s = &serial_ports[0]; | |
| 1417 | - unsigned char ch; | |
| 1418 | - int ret; | |
| 1419 | - | |
| 1420 | - addr &= 7; | |
| 1421 | -#ifdef DEBUG_SERIAL | |
| 1422 | - printf("serial: write addr=0x%02x val=0x%02x\n", addr, val); | |
| 1423 | -#endif | |
| 1424 | - switch(addr) { | |
| 1425 | - default: | |
| 1426 | - case 0: | |
| 1427 | - if (s->lcr & UART_LCR_DLAB) { | |
| 1428 | - s->divider = (s->divider & 0xff00) | val; | |
| 1429 | - } else { | |
| 1430 | - s->thr_ipending = 0; | |
| 1431 | - s->lsr &= ~UART_LSR_THRE; | |
| 1432 | - serial_update_irq(); | |
| 1433 | - | |
| 1434 | - ch = val; | |
| 1435 | - do { | |
| 1436 | - ret = write(1, &ch, 1); | |
| 1437 | - } while (ret != 1); | |
| 1438 | - s->thr_ipending = 1; | |
| 1439 | - s->lsr |= UART_LSR_THRE; | |
| 1440 | - s->lsr |= UART_LSR_TEMT; | |
| 1441 | - serial_update_irq(); | |
| 1442 | - } | |
| 1443 | - break; | |
| 1444 | - case 1: | |
| 1445 | - if (s->lcr & UART_LCR_DLAB) { | |
| 1446 | - s->divider = (s->divider & 0x00ff) | (val << 8); | |
| 1447 | - } else { | |
| 1448 | - s->ier = val; | |
| 1449 | - serial_update_irq(); | |
| 1450 | - } | |
| 1451 | - break; | |
| 1452 | - case 2: | |
| 1453 | - break; | |
| 1454 | - case 3: | |
| 1455 | - s->lcr = val; | |
| 1456 | - break; | |
| 1457 | - case 4: | |
| 1458 | - s->mcr = val; | |
| 1459 | - break; | |
| 1460 | - case 5: | |
| 1461 | - break; | |
| 1462 | - case 6: | |
| 1463 | - s->msr = val; | |
| 1464 | - break; | |
| 1465 | - case 7: | |
| 1466 | - s->scr = val; | |
| 1467 | - break; | |
| 1468 | - } | |
| 1469 | -} | |
| 1470 | - | |
| 1471 | -uint32_t serial_ioport_read(CPUState *env, uint32_t addr) | |
| 1472 | -{ | |
| 1473 | - SerialState *s = &serial_ports[0]; | |
| 1474 | - uint32_t ret; | |
| 1475 | - | |
| 1476 | - addr &= 7; | |
| 1477 | - switch(addr) { | |
| 1478 | - default: | |
| 1479 | - case 0: | |
| 1480 | - if (s->lcr & UART_LCR_DLAB) { | |
| 1481 | - ret = s->divider & 0xff; | |
| 1482 | - } else { | |
| 1483 | - ret = s->rbr; | |
| 1484 | - s->lsr &= ~(UART_LSR_DR | UART_LSR_BI); | |
| 1485 | - serial_update_irq(); | |
| 1486 | - } | |
| 1487 | - break; | |
| 1488 | - case 1: | |
| 1489 | - if (s->lcr & UART_LCR_DLAB) { | |
| 1490 | - ret = (s->divider >> 8) & 0xff; | |
| 1491 | - } else { | |
| 1492 | - ret = s->ier; | |
| 1493 | - } | |
| 1494 | - break; | |
| 1495 | - case 2: | |
| 1496 | - ret = s->iir; | |
| 1497 | - /* reset THR pending bit */ | |
| 1498 | - if ((ret & 0x7) == UART_IIR_THRI) | |
| 1499 | - s->thr_ipending = 0; | |
| 1500 | - serial_update_irq(); | |
| 1501 | - break; | |
| 1502 | - case 3: | |
| 1503 | - ret = s->lcr; | |
| 1504 | - break; | |
| 1505 | - case 4: | |
| 1506 | - ret = s->mcr; | |
| 1507 | - break; | |
| 1508 | - case 5: | |
| 1509 | - ret = s->lsr; | |
| 1510 | - break; | |
| 1511 | - case 6: | |
| 1512 | - if (s->mcr & UART_MCR_LOOP) { | |
| 1513 | - /* in loopback, the modem output pins are connected to the | |
| 1514 | - inputs */ | |
| 1515 | - ret = (s->mcr & 0x0c) << 4; | |
| 1516 | - ret |= (s->mcr & 0x02) << 3; | |
| 1517 | - ret |= (s->mcr & 0x01) << 5; | |
| 1518 | - } else { | |
| 1519 | - ret = s->msr; | |
| 1520 | - } | |
| 1521 | - break; | |
| 1522 | - case 7: | |
| 1523 | - ret = s->scr; | |
| 1524 | - break; | |
| 1525 | - } | |
| 1526 | -#ifdef DEBUG_SERIAL | |
| 1527 | - printf("serial: read addr=0x%02x val=0x%02x\n", addr, ret); | |
| 1528 | -#endif | |
| 1529 | - return ret; | |
| 1530 | -} | |
| 1531 | - | |
| 1532 | -#define TERM_ESCAPE 0x01 /* ctrl-a is used for escape */ | |
| 1533 | -static int term_got_escape, term_command; | |
| 1534 | -static unsigned char term_cmd_buf[128]; | |
| 1535 | - | |
| 1536 | -typedef struct term_cmd_t { | |
| 1537 | - const unsigned char *name; | |
| 1538 | - void (*handler)(unsigned char *params); | |
| 1539 | -} term_cmd_t; | |
| 1540 | - | |
| 1541 | -static void do_change_cdrom (unsigned char *params); | |
| 1542 | -static void do_change_fd0 (unsigned char *params); | |
| 1543 | -static void do_change_fd1 (unsigned char *params); | |
| 401 | +static void do_change_cdrom (unsigned char *params); | |
| 402 | +static void do_change_fd0 (unsigned char *params); | |
| 403 | +static void do_change_fd1 (unsigned char *params); | |
| 1544 | 404 | |
| 1545 | 405 | static term_cmd_t term_cmds[] = { |
| 1546 | 406 | { "changecd", &do_change_cdrom, }, |
| 1547 | 407 | { "changefd0", &do_change_fd0, }, |
| 1548 | 408 | { "changefd1", &do_change_fd1, }, |
| 1549 | - { NULL, NULL, }, | |
| 1550 | -}; | |
| 1551 | - | |
| 1552 | -void term_print_help(void) | |
| 1553 | -{ | |
| 1554 | - printf("\n" | |
| 1555 | - "C-a h print this help\n" | |
| 1556 | - "C-a x exit emulatior\n" | |
| 1557 | - "C-a d switch on/off debug log\n" | |
| 1558 | - "C-a s save disk data back to file (if -snapshot)\n" | |
| 1559 | - "C-a b send break (magic sysrq)\n" | |
| 1560 | - "C-a c send qemu internal command\n" | |
| 1561 | - "C-a C-a send C-a\n" | |
| 1562 | - ); | |
| 1563 | -} | |
| 1564 | - | |
| 1565 | -static void do_change_cdrom (unsigned char *params) | |
| 1566 | -{ | |
| 1567 | - /* Dunno how to do it... */ | |
| 1568 | -} | |
| 1569 | - | |
| 1570 | -static void do_change_fd (int fd, unsigned char *params) | |
| 1571 | -{ | |
| 1572 | - unsigned char *name_start, *name_end, *ros; | |
| 1573 | - int ro; | |
| 1574 | - | |
| 1575 | - for (name_start = params; | |
| 1576 | - isspace(*name_start); name_start++) | |
| 1577 | - continue; | |
| 1578 | - if (*name_start == '\0') | |
| 1579 | - return; | |
| 1580 | - for (name_end = name_start; | |
| 1581 | - !isspace(*name_end) && *name_end != '\0'; name_end++) | |
| 1582 | - continue; | |
| 1583 | - for (ros = name_end + 1; isspace(*ros); ros++) | |
| 1584 | - continue; | |
| 1585 | - if (ros[0] == 'r' && ros[1] == 'o') | |
| 1586 | - ro = 1; | |
| 1587 | - else | |
| 1588 | - ro = 0; | |
| 1589 | - *name_end = '\0'; | |
| 1590 | - printf("Change fd %d to %s (%s)\n", fd, name_start, params); | |
| 1591 | - fdctrl_disk_change(fd, name_start, ro); | |
| 1592 | -} | |
| 1593 | - | |
| 1594 | -static void do_change_fd0 (unsigned char *params) | |
| 1595 | -{ | |
| 1596 | - do_change_fd(0, params); | |
| 1597 | -} | |
| 1598 | - | |
| 1599 | -static void do_change_fd1 (unsigned char *params) | |
| 1600 | -{ | |
| 1601 | - do_change_fd(1, params); | |
| 1602 | -} | |
| 1603 | - | |
| 1604 | -static void serial_treat_command () | |
| 1605 | -{ | |
| 1606 | - unsigned char *cmd_start, *cmd_end; | |
| 1607 | - int i; | |
| 1608 | - | |
| 1609 | - for (cmd_start = term_cmd_buf; isspace(*cmd_start); cmd_start++) | |
| 1610 | - continue; | |
| 1611 | - for (cmd_end = cmd_start; | |
| 1612 | - !isspace(*cmd_end) && *cmd_end != '\0'; cmd_end++) | |
| 1613 | - continue; | |
| 1614 | - for (i = 0; term_cmds[i].name != NULL; i++) { | |
| 1615 | - if (strlen(term_cmds[i].name) == (cmd_end - cmd_start) && | |
| 1616 | - memcmp(term_cmds[i].name, cmd_start, cmd_end - cmd_start) == 0) { | |
| 1617 | - (*term_cmds[i].handler)(cmd_end + 1); | |
| 1618 | - return; | |
| 1619 | - } | |
| 1620 | - } | |
| 1621 | - *cmd_end = '\0'; | |
| 1622 | - printf("Unknown term command: %s\n", cmd_start); | |
| 1623 | -} | |
| 1624 | - | |
| 1625 | -extern FILE *logfile; | |
| 1626 | - | |
| 1627 | -/* called when a char is received */ | |
| 1628 | -void serial_received_byte(SerialState *s, int ch) | |
| 1629 | -{ | |
| 1630 | - if (term_command) { | |
| 1631 | - if (ch == '\n' || ch == '\r' || term_command == 127) { | |
| 1632 | - printf("\n"); | |
| 1633 | - serial_treat_command(); | |
| 1634 | - term_command = 0; | |
| 1635 | - } else { | |
| 1636 | - if (ch == 0x7F || ch == 0x08) { | |
| 1637 | - if (term_command > 1) { | |
| 1638 | - term_cmd_buf[--term_command - 1] = '\0'; | |
| 1639 | - printf("\r " | |
| 1640 | - " "); | |
| 1641 | - printf("\r> %s", term_cmd_buf); | |
| 1642 | - } | |
| 1643 | - } else if (ch > 0x1f) { | |
| 1644 | - term_cmd_buf[term_command++ - 1] = ch; | |
| 1645 | - term_cmd_buf[term_command - 1] = '\0'; | |
| 1646 | - printf("\r> %s", term_cmd_buf); | |
| 1647 | - } | |
| 1648 | - fflush(stdout); | |
| 1649 | - } | |
| 1650 | - } else if (term_got_escape) { | |
| 1651 | - term_got_escape = 0; | |
| 1652 | - switch(ch) { | |
| 1653 | - case 'h': | |
| 1654 | - term_print_help(); | |
| 1655 | - break; | |
| 1656 | - case 'x': | |
| 1657 | - exit(0); | |
| 1658 | - break; | |
| 1659 | - case 's': | |
| 1660 | - { | |
| 1661 | - int i; | |
| 1662 | - for (i = 0; i < MAX_DISKS; i++) { | |
| 1663 | - if (bs_table[i]) | |
| 1664 | - bdrv_commit(bs_table[i]); | |
| 1665 | - } | |
| 1666 | - } | |
| 1667 | - break; | |
| 1668 | - case 'b': | |
| 1669 | - /* send break */ | |
| 1670 | - s->rbr = 0; | |
| 1671 | - s->lsr |= UART_LSR_BI | UART_LSR_DR; | |
| 1672 | - serial_update_irq(); | |
| 1673 | - break; | |
| 1674 | - case 'c': | |
| 1675 | - printf("> "); | |
| 1676 | - fflush(stdout); | |
| 1677 | - term_command = 1; | |
| 1678 | - break; | |
| 1679 | - case 'd': | |
| 1680 | - cpu_set_log(CPU_LOG_ALL); | |
| 1681 | - break; | |
| 1682 | - case TERM_ESCAPE: | |
| 1683 | - goto send_char; | |
| 1684 | - } | |
| 1685 | - } else if (ch == TERM_ESCAPE) { | |
| 1686 | - term_got_escape = 1; | |
| 1687 | - } else { | |
| 1688 | - send_char: | |
| 1689 | - s->rbr = ch; | |
| 1690 | - s->lsr |= UART_LSR_DR; | |
| 1691 | - serial_update_irq(); | |
| 1692 | - } | |
| 1693 | -} | |
| 1694 | - | |
| 1695 | -void serial_init(void) | |
| 1696 | -{ | |
| 1697 | - SerialState *s = &serial_ports[0]; | |
| 1698 | - | |
| 1699 | - s->lsr = UART_LSR_TEMT | UART_LSR_THRE; | |
| 1700 | - s->iir = UART_IIR_NO_INT; | |
| 1701 | - | |
| 1702 | -#if defined(TARGET_I386) || defined (TARGET_PPC) | |
| 1703 | - register_ioport_write(0x3f8, 8, serial_ioport_write, 1); | |
| 1704 | - register_ioport_read(0x3f8, 8, serial_ioport_read, 1); | |
| 1705 | -#endif | |
| 1706 | -} | |
| 1707 | - | |
| 1708 | -/***********************************************************/ | |
| 1709 | -/* ne2000 emulation */ | |
| 1710 | - | |
| 1711 | -#if defined (TARGET_I386) | |
| 1712 | -#define NE2000_IOPORT 0x300 | |
| 1713 | -#define NE2000_IRQ 9 | |
| 1714 | - | |
| 1715 | -#define MAX_ETH_FRAME_SIZE 1514 | |
| 1716 | - | |
| 1717 | -#define E8390_CMD 0x00 /* The command register (for all pages) */ | |
| 1718 | -/* Page 0 register offsets. */ | |
| 1719 | -#define EN0_CLDALO 0x01 /* Low byte of current local dma addr RD */ | |
| 1720 | -#define EN0_STARTPG 0x01 /* Starting page of ring bfr WR */ | |
| 1721 | -#define EN0_CLDAHI 0x02 /* High byte of current local dma addr RD */ | |
| 1722 | -#define EN0_STOPPG 0x02 /* Ending page +1 of ring bfr WR */ | |
| 1723 | -#define EN0_BOUNDARY 0x03 /* Boundary page of ring bfr RD WR */ | |
| 1724 | -#define EN0_TSR 0x04 /* Transmit status reg RD */ | |
| 1725 | -#define EN0_TPSR 0x04 /* Transmit starting page WR */ | |
| 1726 | -#define EN0_NCR 0x05 /* Number of collision reg RD */ | |
| 1727 | -#define EN0_TCNTLO 0x05 /* Low byte of tx byte count WR */ | |
| 1728 | -#define EN0_FIFO 0x06 /* FIFO RD */ | |
| 1729 | -#define EN0_TCNTHI 0x06 /* High byte of tx byte count WR */ | |
| 1730 | -#define EN0_ISR 0x07 /* Interrupt status reg RD WR */ | |
| 1731 | -#define EN0_CRDALO 0x08 /* low byte of current remote dma address RD */ | |
| 1732 | -#define EN0_RSARLO 0x08 /* Remote start address reg 0 */ | |
| 1733 | -#define EN0_CRDAHI 0x09 /* high byte, current remote dma address RD */ | |
| 1734 | -#define EN0_RSARHI 0x09 /* Remote start address reg 1 */ | |
| 1735 | -#define EN0_RCNTLO 0x0a /* Remote byte count reg WR */ | |
| 1736 | -#define EN0_RCNTHI 0x0b /* Remote byte count reg WR */ | |
| 1737 | -#define EN0_RSR 0x0c /* rx status reg RD */ | |
| 1738 | -#define EN0_RXCR 0x0c /* RX configuration reg WR */ | |
| 1739 | -#define EN0_TXCR 0x0d /* TX configuration reg WR */ | |
| 1740 | -#define EN0_COUNTER0 0x0d /* Rcv alignment error counter RD */ | |
| 1741 | -#define EN0_DCFG 0x0e /* Data configuration reg WR */ | |
| 1742 | -#define EN0_COUNTER1 0x0e /* Rcv CRC error counter RD */ | |
| 1743 | -#define EN0_IMR 0x0f /* Interrupt mask reg WR */ | |
| 1744 | -#define EN0_COUNTER2 0x0f /* Rcv missed frame error counter RD */ | |
| 1745 | - | |
| 1746 | -#define EN1_PHYS 0x11 | |
| 1747 | -#define EN1_CURPAG 0x17 | |
| 1748 | -#define EN1_MULT 0x18 | |
| 1749 | - | |
| 1750 | -/* Register accessed at EN_CMD, the 8390 base addr. */ | |
| 1751 | -#define E8390_STOP 0x01 /* Stop and reset the chip */ | |
| 1752 | -#define E8390_START 0x02 /* Start the chip, clear reset */ | |
| 1753 | -#define E8390_TRANS 0x04 /* Transmit a frame */ | |
| 1754 | -#define E8390_RREAD 0x08 /* Remote read */ | |
| 1755 | -#define E8390_RWRITE 0x10 /* Remote write */ | |
| 1756 | -#define E8390_NODMA 0x20 /* Remote DMA */ | |
| 1757 | -#define E8390_PAGE0 0x00 /* Select page chip registers */ | |
| 1758 | -#define E8390_PAGE1 0x40 /* using the two high-order bits */ | |
| 1759 | -#define E8390_PAGE2 0x80 /* Page 3 is invalid. */ | |
| 1760 | - | |
| 1761 | -/* Bits in EN0_ISR - Interrupt status register */ | |
| 1762 | -#define ENISR_RX 0x01 /* Receiver, no error */ | |
| 1763 | -#define ENISR_TX 0x02 /* Transmitter, no error */ | |
| 1764 | -#define ENISR_RX_ERR 0x04 /* Receiver, with error */ | |
| 1765 | -#define ENISR_TX_ERR 0x08 /* Transmitter, with error */ | |
| 1766 | -#define ENISR_OVER 0x10 /* Receiver overwrote the ring */ | |
| 1767 | -#define ENISR_COUNTERS 0x20 /* Counters need emptying */ | |
| 1768 | -#define ENISR_RDC 0x40 /* remote dma complete */ | |
| 1769 | -#define ENISR_RESET 0x80 /* Reset completed */ | |
| 1770 | -#define ENISR_ALL 0x3f /* Interrupts we will enable */ | |
| 1771 | - | |
| 1772 | -/* Bits in received packet status byte and EN0_RSR*/ | |
| 1773 | -#define ENRSR_RXOK 0x01 /* Received a good packet */ | |
| 1774 | -#define ENRSR_CRC 0x02 /* CRC error */ | |
| 1775 | -#define ENRSR_FAE 0x04 /* frame alignment error */ | |
| 1776 | -#define ENRSR_FO 0x08 /* FIFO overrun */ | |
| 1777 | -#define ENRSR_MPA 0x10 /* missed pkt */ | |
| 1778 | -#define ENRSR_PHY 0x20 /* physical/multicast address */ | |
| 1779 | -#define ENRSR_DIS 0x40 /* receiver disable. set in monitor mode */ | |
| 1780 | -#define ENRSR_DEF 0x80 /* deferring */ | |
| 1781 | - | |
| 1782 | -/* Transmitted packet status, EN0_TSR. */ | |
| 1783 | -#define ENTSR_PTX 0x01 /* Packet transmitted without error */ | |
| 1784 | -#define ENTSR_ND 0x02 /* The transmit wasn't deferred. */ | |
| 1785 | -#define ENTSR_COL 0x04 /* The transmit collided at least once. */ | |
| 1786 | -#define ENTSR_ABT 0x08 /* The transmit collided 16 times, and was deferred. */ | |
| 1787 | -#define ENTSR_CRS 0x10 /* The carrier sense was lost. */ | |
| 1788 | -#define ENTSR_FU 0x20 /* A "FIFO underrun" occurred during transmit. */ | |
| 1789 | -#define ENTSR_CDH 0x40 /* The collision detect "heartbeat" signal was lost. */ | |
| 1790 | -#define ENTSR_OWC 0x80 /* There was an out-of-window collision. */ | |
| 1791 | - | |
| 1792 | -#define NE2000_MEM_SIZE 32768 | |
| 1793 | - | |
| 1794 | -typedef struct NE2000State { | |
| 1795 | - uint8_t cmd; | |
| 1796 | - uint32_t start; | |
| 1797 | - uint32_t stop; | |
| 1798 | - uint8_t boundary; | |
| 1799 | - uint8_t tsr; | |
| 1800 | - uint8_t tpsr; | |
| 1801 | - uint16_t tcnt; | |
| 1802 | - uint16_t rcnt; | |
| 1803 | - uint32_t rsar; | |
| 1804 | - uint8_t isr; | |
| 1805 | - uint8_t dcfg; | |
| 1806 | - uint8_t imr; | |
| 1807 | - uint8_t phys[6]; /* mac address */ | |
| 1808 | - uint8_t curpag; | |
| 1809 | - uint8_t mult[8]; /* multicast mask array */ | |
| 1810 | - uint8_t mem[NE2000_MEM_SIZE]; | |
| 1811 | -} NE2000State; | |
| 1812 | - | |
| 1813 | -NE2000State ne2000_state; | |
| 1814 | -int net_fd = -1; | |
| 1815 | -char network_script[1024]; | |
| 1816 | - | |
| 1817 | -void ne2000_reset(void) | |
| 1818 | -{ | |
| 1819 | - NE2000State *s = &ne2000_state; | |
| 1820 | - int i; | |
| 1821 | - | |
| 1822 | - s->isr = ENISR_RESET; | |
| 1823 | - s->mem[0] = 0x52; | |
| 1824 | - s->mem[1] = 0x54; | |
| 1825 | - s->mem[2] = 0x00; | |
| 1826 | - s->mem[3] = 0x12; | |
| 1827 | - s->mem[4] = 0x34; | |
| 1828 | - s->mem[5] = 0x56; | |
| 1829 | - s->mem[14] = 0x57; | |
| 1830 | - s->mem[15] = 0x57; | |
| 1831 | - | |
| 1832 | - /* duplicate prom data */ | |
| 1833 | - for(i = 15;i >= 0; i--) { | |
| 1834 | - s->mem[2 * i] = s->mem[i]; | |
| 1835 | - s->mem[2 * i + 1] = s->mem[i]; | |
| 1836 | - } | |
| 1837 | -} | |
| 1838 | - | |
| 1839 | -void ne2000_update_irq(NE2000State *s) | |
| 1840 | -{ | |
| 1841 | - int isr; | |
| 1842 | - isr = s->isr & s->imr; | |
| 1843 | - if (isr) | |
| 1844 | - pic_set_irq(NE2000_IRQ, 1); | |
| 1845 | - else | |
| 1846 | - pic_set_irq(NE2000_IRQ, 0); | |
| 1847 | -} | |
| 1848 | - | |
| 1849 | -int net_init(void) | |
| 1850 | -{ | |
| 1851 | - struct ifreq ifr; | |
| 1852 | - int fd, ret, pid, status; | |
| 1853 | - | |
| 1854 | - fd = open("/dev/net/tun", O_RDWR); | |
| 1855 | - if (fd < 0) { | |
| 1856 | - fprintf(stderr, "warning: could not open /dev/net/tun: no virtual network emulation\n"); | |
| 1857 | - return -1; | |
| 1858 | - } | |
| 1859 | - memset(&ifr, 0, sizeof(ifr)); | |
| 1860 | - ifr.ifr_flags = IFF_TAP | IFF_NO_PI; | |
| 1861 | - pstrcpy(ifr.ifr_name, IFNAMSIZ, "tun%d"); | |
| 1862 | - ret = ioctl(fd, TUNSETIFF, (void *) &ifr); | |
| 1863 | - if (ret != 0) { | |
| 1864 | - fprintf(stderr, "warning: could not configure /dev/net/tun: no virtual network emulation\n"); | |
| 1865 | - close(fd); | |
| 1866 | - return -1; | |
| 1867 | - } | |
| 1868 | - printf("Connected to host network interface: %s\n", ifr.ifr_name); | |
| 1869 | - fcntl(fd, F_SETFL, O_NONBLOCK); | |
| 1870 | - net_fd = fd; | |
| 1871 | - | |
| 1872 | - /* try to launch network init script */ | |
| 1873 | - pid = fork(); | |
| 1874 | - if (pid >= 0) { | |
| 1875 | - if (pid == 0) { | |
| 1876 | - execl(network_script, network_script, ifr.ifr_name, NULL); | |
| 1877 | - exit(1); | |
| 1878 | - } | |
| 1879 | - while (waitpid(pid, &status, 0) != pid); | |
| 1880 | - if (!WIFEXITED(status) || | |
| 1881 | - WEXITSTATUS(status) != 0) { | |
| 1882 | - fprintf(stderr, "%s: could not launch network script for '%s'\n", | |
| 1883 | - network_script, ifr.ifr_name); | |
| 1884 | - } | |
| 1885 | - } | |
| 1886 | - return 0; | |
| 1887 | -} | |
| 1888 | - | |
| 1889 | -void net_send_packet(NE2000State *s, const uint8_t *buf, int size) | |
| 1890 | -{ | |
| 1891 | -#ifdef DEBUG_NE2000 | |
| 1892 | - printf("NE2000: sending packet size=%d\n", size); | |
| 1893 | -#endif | |
| 1894 | - write(net_fd, buf, size); | |
| 1895 | -} | |
| 1896 | - | |
| 1897 | -/* return true if the NE2000 can receive more data */ | |
| 1898 | -int ne2000_can_receive(NE2000State *s) | |
| 1899 | -{ | |
| 1900 | - int avail, index, boundary; | |
| 1901 | - | |
| 1902 | - if (s->cmd & E8390_STOP) | |
| 1903 | - return 0; | |
| 1904 | - index = s->curpag << 8; | |
| 1905 | - boundary = s->boundary << 8; | |
| 1906 | - if (index < boundary) | |
| 1907 | - avail = boundary - index; | |
| 1908 | - else | |
| 1909 | - avail = (s->stop - s->start) - (index - boundary); | |
| 1910 | - if (avail < (MAX_ETH_FRAME_SIZE + 4)) | |
| 1911 | - return 0; | |
| 1912 | - return 1; | |
| 1913 | -} | |
| 1914 | - | |
| 1915 | -void ne2000_receive(NE2000State *s, uint8_t *buf, int size) | |
| 1916 | -{ | |
| 1917 | - uint8_t *p; | |
| 1918 | - int total_len, next, avail, len, index; | |
| 1919 | - | |
| 1920 | -#if defined(DEBUG_NE2000) | |
| 1921 | - printf("NE2000: received len=%d\n", size); | |
| 1922 | -#endif | |
| 1923 | - | |
| 1924 | - index = s->curpag << 8; | |
| 1925 | - /* 4 bytes for header */ | |
| 1926 | - total_len = size + 4; | |
| 1927 | - /* address for next packet (4 bytes for CRC) */ | |
| 1928 | - next = index + ((total_len + 4 + 255) & ~0xff); | |
| 1929 | - if (next >= s->stop) | |
| 1930 | - next -= (s->stop - s->start); | |
| 1931 | - /* prepare packet header */ | |
| 1932 | - p = s->mem + index; | |
| 1933 | - p[0] = ENRSR_RXOK; /* receive status */ | |
| 1934 | - p[1] = next >> 8; | |
| 1935 | - p[2] = total_len; | |
| 1936 | - p[3] = total_len >> 8; | |
| 1937 | - index += 4; | |
| 1938 | - | |
| 1939 | - /* write packet data */ | |
| 1940 | - while (size > 0) { | |
| 1941 | - avail = s->stop - index; | |
| 1942 | - len = size; | |
| 1943 | - if (len > avail) | |
| 1944 | - len = avail; | |
| 1945 | - memcpy(s->mem + index, buf, len); | |
| 1946 | - buf += len; | |
| 1947 | - index += len; | |
| 1948 | - if (index == s->stop) | |
| 1949 | - index = s->start; | |
| 1950 | - size -= len; | |
| 1951 | - } | |
| 1952 | - s->curpag = next >> 8; | |
| 1953 | - | |
| 1954 | - /* now we can signal we have receive something */ | |
| 1955 | - s->isr |= ENISR_RX; | |
| 1956 | - ne2000_update_irq(s); | |
| 1957 | -} | |
| 1958 | - | |
| 1959 | -void ne2000_ioport_write(CPUState *env, uint32_t addr, uint32_t val) | |
| 1960 | -{ | |
| 1961 | - NE2000State *s = &ne2000_state; | |
| 1962 | - int offset, page; | |
| 1963 | - | |
| 1964 | - addr &= 0xf; | |
| 1965 | -#ifdef DEBUG_NE2000 | |
| 1966 | - printf("NE2000: write addr=0x%x val=0x%02x\n", addr, val); | |
| 1967 | -#endif | |
| 1968 | - if (addr == E8390_CMD) { | |
| 1969 | - /* control register */ | |
| 1970 | - s->cmd = val; | |
| 1971 | - if (val & E8390_START) { | |
| 1972 | - /* test specific case: zero length transfert */ | |
| 1973 | - if ((val & (E8390_RREAD | E8390_RWRITE)) && | |
| 1974 | - s->rcnt == 0) { | |
| 1975 | - s->isr |= ENISR_RDC; | |
| 1976 | - ne2000_update_irq(s); | |
| 1977 | - } | |
| 1978 | - if (val & E8390_TRANS) { | |
| 1979 | - net_send_packet(s, s->mem + (s->tpsr << 8), s->tcnt); | |
| 1980 | - /* signal end of transfert */ | |
| 1981 | - s->tsr = ENTSR_PTX; | |
| 1982 | - s->isr |= ENISR_TX; | |
| 1983 | - ne2000_update_irq(s); | |
| 1984 | - } | |
| 1985 | - } | |
| 1986 | - } else { | |
| 1987 | - page = s->cmd >> 6; | |
| 1988 | - offset = addr | (page << 4); | |
| 1989 | - switch(offset) { | |
| 1990 | - case EN0_STARTPG: | |
| 1991 | - s->start = val << 8; | |
| 1992 | - break; | |
| 1993 | - case EN0_STOPPG: | |
| 1994 | - s->stop = val << 8; | |
| 1995 | - break; | |
| 1996 | - case EN0_BOUNDARY: | |
| 1997 | - s->boundary = val; | |
| 1998 | - break; | |
| 1999 | - case EN0_IMR: | |
| 2000 | - s->imr = val; | |
| 2001 | - ne2000_update_irq(s); | |
| 2002 | - break; | |
| 2003 | - case EN0_TPSR: | |
| 2004 | - s->tpsr = val; | |
| 2005 | - break; | |
| 2006 | - case EN0_TCNTLO: | |
| 2007 | - s->tcnt = (s->tcnt & 0xff00) | val; | |
| 2008 | - break; | |
| 2009 | - case EN0_TCNTHI: | |
| 2010 | - s->tcnt = (s->tcnt & 0x00ff) | (val << 8); | |
| 2011 | - break; | |
| 2012 | - case EN0_RSARLO: | |
| 2013 | - s->rsar = (s->rsar & 0xff00) | val; | |
| 2014 | - break; | |
| 2015 | - case EN0_RSARHI: | |
| 2016 | - s->rsar = (s->rsar & 0x00ff) | (val << 8); | |
| 2017 | - break; | |
| 2018 | - case EN0_RCNTLO: | |
| 2019 | - s->rcnt = (s->rcnt & 0xff00) | val; | |
| 2020 | - break; | |
| 2021 | - case EN0_RCNTHI: | |
| 2022 | - s->rcnt = (s->rcnt & 0x00ff) | (val << 8); | |
| 2023 | - break; | |
| 2024 | - case EN0_DCFG: | |
| 2025 | - s->dcfg = val; | |
| 2026 | - break; | |
| 2027 | - case EN0_ISR: | |
| 2028 | - s->isr &= ~val; | |
| 2029 | - ne2000_update_irq(s); | |
| 2030 | - break; | |
| 2031 | - case EN1_PHYS ... EN1_PHYS + 5: | |
| 2032 | - s->phys[offset - EN1_PHYS] = val; | |
| 2033 | - break; | |
| 2034 | - case EN1_CURPAG: | |
| 2035 | - s->curpag = val; | |
| 2036 | - break; | |
| 2037 | - case EN1_MULT ... EN1_MULT + 7: | |
| 2038 | - s->mult[offset - EN1_MULT] = val; | |
| 2039 | - break; | |
| 2040 | - } | |
| 2041 | - } | |
| 2042 | -} | |
| 2043 | - | |
| 2044 | -uint32_t ne2000_ioport_read(CPUState *env, uint32_t addr) | |
| 2045 | -{ | |
| 2046 | - NE2000State *s = &ne2000_state; | |
| 2047 | - int offset, page, ret; | |
| 2048 | - | |
| 2049 | - addr &= 0xf; | |
| 2050 | - if (addr == E8390_CMD) { | |
| 2051 | - ret = s->cmd; | |
| 2052 | - } else { | |
| 2053 | - page = s->cmd >> 6; | |
| 2054 | - offset = addr | (page << 4); | |
| 2055 | - switch(offset) { | |
| 2056 | - case EN0_TSR: | |
| 2057 | - ret = s->tsr; | |
| 2058 | - break; | |
| 2059 | - case EN0_BOUNDARY: | |
| 2060 | - ret = s->boundary; | |
| 2061 | - break; | |
| 2062 | - case EN0_ISR: | |
| 2063 | - ret = s->isr; | |
| 2064 | - break; | |
| 2065 | - case EN1_PHYS ... EN1_PHYS + 5: | |
| 2066 | - ret = s->phys[offset - EN1_PHYS]; | |
| 2067 | - break; | |
| 2068 | - case EN1_CURPAG: | |
| 2069 | - ret = s->curpag; | |
| 2070 | - break; | |
| 2071 | - case EN1_MULT ... EN1_MULT + 7: | |
| 2072 | - ret = s->mult[offset - EN1_MULT]; | |
| 2073 | - break; | |
| 2074 | - default: | |
| 2075 | - ret = 0x00; | |
| 2076 | - break; | |
| 2077 | - } | |
| 2078 | - } | |
| 2079 | -#ifdef DEBUG_NE2000 | |
| 2080 | - printf("NE2000: read addr=0x%x val=%02x\n", addr, ret); | |
| 2081 | -#endif | |
| 2082 | - return ret; | |
| 2083 | -} | |
| 2084 | - | |
| 2085 | -void ne2000_asic_ioport_write(CPUState *env, uint32_t addr, uint32_t val) | |
| 2086 | -{ | |
| 2087 | - NE2000State *s = &ne2000_state; | |
| 2088 | - uint8_t *p; | |
| 2089 | - | |
| 2090 | -#ifdef DEBUG_NE2000 | |
| 2091 | - printf("NE2000: asic write val=0x%04x\n", val); | |
| 2092 | -#endif | |
| 2093 | - p = s->mem + s->rsar; | |
| 2094 | - if (s->dcfg & 0x01) { | |
| 2095 | - /* 16 bit access */ | |
| 2096 | - p[0] = val; | |
| 2097 | - p[1] = val >> 8; | |
| 2098 | - s->rsar += 2; | |
| 2099 | - s->rcnt -= 2; | |
| 2100 | - } else { | |
| 2101 | - /* 8 bit access */ | |
| 2102 | - p[0] = val; | |
| 2103 | - s->rsar++; | |
| 2104 | - s->rcnt--; | |
| 2105 | - } | |
| 2106 | - /* wrap */ | |
| 2107 | - if (s->rsar == s->stop) | |
| 2108 | - s->rsar = s->start; | |
| 2109 | - if (s->rcnt == 0) { | |
| 2110 | - /* signal end of transfert */ | |
| 2111 | - s->isr |= ENISR_RDC; | |
| 2112 | - ne2000_update_irq(s); | |
| 2113 | - } | |
| 2114 | -} | |
| 2115 | - | |
| 2116 | -uint32_t ne2000_asic_ioport_read(CPUState *env, uint32_t addr) | |
| 2117 | -{ | |
| 2118 | - NE2000State *s = &ne2000_state; | |
| 2119 | - uint8_t *p; | |
| 2120 | - int ret; | |
| 2121 | - | |
| 2122 | - p = s->mem + s->rsar; | |
| 2123 | - if (s->dcfg & 0x01) { | |
| 2124 | - /* 16 bit access */ | |
| 2125 | - ret = p[0] | (p[1] << 8); | |
| 2126 | - s->rsar += 2; | |
| 2127 | - s->rcnt -= 2; | |
| 2128 | - } else { | |
| 2129 | - /* 8 bit access */ | |
| 2130 | - ret = p[0]; | |
| 2131 | - s->rsar++; | |
| 2132 | - s->rcnt--; | |
| 2133 | - } | |
| 2134 | - /* wrap */ | |
| 2135 | - if (s->rsar == s->stop) | |
| 2136 | - s->rsar = s->start; | |
| 2137 | - if (s->rcnt == 0) { | |
| 2138 | - /* signal end of transfert */ | |
| 2139 | - s->isr |= ENISR_RDC; | |
| 2140 | - ne2000_update_irq(s); | |
| 2141 | - } | |
| 2142 | -#ifdef DEBUG_NE2000 | |
| 2143 | - printf("NE2000: asic read val=0x%04x\n", ret); | |
| 2144 | -#endif | |
| 2145 | - return ret; | |
| 2146 | -} | |
| 2147 | - | |
| 2148 | -void ne2000_reset_ioport_write(CPUState *env, uint32_t addr, uint32_t val) | |
| 2149 | -{ | |
| 2150 | - /* nothing to do (end of reset pulse) */ | |
| 2151 | -} | |
| 2152 | - | |
| 2153 | -uint32_t ne2000_reset_ioport_read(CPUState *env, uint32_t addr) | |
| 2154 | -{ | |
| 2155 | - ne2000_reset(); | |
| 2156 | - return 0; | |
| 2157 | -} | |
| 2158 | - | |
| 2159 | -void ne2000_init(void) | |
| 2160 | -{ | |
| 2161 | - register_ioport_write(NE2000_IOPORT, 16, ne2000_ioport_write, 1); | |
| 2162 | - register_ioport_read(NE2000_IOPORT, 16, ne2000_ioport_read, 1); | |
| 2163 | - | |
| 2164 | - register_ioport_write(NE2000_IOPORT + 0x10, 1, ne2000_asic_ioport_write, 1); | |
| 2165 | - register_ioport_read(NE2000_IOPORT + 0x10, 1, ne2000_asic_ioport_read, 1); | |
| 2166 | - register_ioport_write(NE2000_IOPORT + 0x10, 2, ne2000_asic_ioport_write, 2); | |
| 2167 | - register_ioport_read(NE2000_IOPORT + 0x10, 2, ne2000_asic_ioport_read, 2); | |
| 2168 | - | |
| 2169 | - register_ioport_write(NE2000_IOPORT + 0x1f, 1, ne2000_reset_ioport_write, 1); | |
| 2170 | - register_ioport_read(NE2000_IOPORT + 0x1f, 1, ne2000_reset_ioport_read, 1); | |
| 2171 | - ne2000_reset(); | |
| 2172 | -} | |
| 2173 | -#endif | |
| 2174 | - | |
| 2175 | -/***********************************************************/ | |
| 2176 | -/* PC floppy disk controler emulation glue */ | |
| 2177 | -#define PC_FDC_DMA 0x2 | |
| 2178 | -#define PC_FDC_IRQ 0x6 | |
| 2179 | -#define PC_FDC_BASE 0x3F0 | |
| 2180 | - | |
| 2181 | -static void fdctrl_register (unsigned char **disknames, int ro, | |
| 2182 | - char boot_device) | |
| 2183 | -{ | |
| 2184 | - int i; | |
| 2185 | - | |
| 2186 | - fdctrl_init(PC_FDC_IRQ, PC_FDC_DMA, 0, PC_FDC_BASE, boot_device); | |
| 2187 | - for (i = 0; i < MAX_FD; i++) { | |
| 2188 | - if (disknames[i] != NULL) | |
| 2189 | - fdctrl_disk_change(i, disknames[i], ro); | |
| 2190 | - } | |
| 2191 | -} | |
| 2192 | - | |
| 2193 | -/***********************************************************/ | |
| 2194 | -/* keyboard emulation */ | |
| 2195 | - | |
| 2196 | -/* Keyboard Controller Commands */ | |
| 2197 | -#define KBD_CCMD_READ_MODE 0x20 /* Read mode bits */ | |
| 2198 | -#define KBD_CCMD_WRITE_MODE 0x60 /* Write mode bits */ | |
| 2199 | -#define KBD_CCMD_GET_VERSION 0xA1 /* Get controller version */ | |
| 2200 | -#define KBD_CCMD_MOUSE_DISABLE 0xA7 /* Disable mouse interface */ | |
| 2201 | -#define KBD_CCMD_MOUSE_ENABLE 0xA8 /* Enable mouse interface */ | |
| 2202 | -#define KBD_CCMD_TEST_MOUSE 0xA9 /* Mouse interface test */ | |
| 2203 | -#define KBD_CCMD_SELF_TEST 0xAA /* Controller self test */ | |
| 2204 | -#define KBD_CCMD_KBD_TEST 0xAB /* Keyboard interface test */ | |
| 2205 | -#define KBD_CCMD_KBD_DISABLE 0xAD /* Keyboard interface disable */ | |
| 2206 | -#define KBD_CCMD_KBD_ENABLE 0xAE /* Keyboard interface enable */ | |
| 2207 | -#define KBD_CCMD_READ_INPORT 0xC0 /* read input port */ | |
| 2208 | -#define KBD_CCMD_READ_OUTPORT 0xD0 /* read output port */ | |
| 2209 | -#define KBD_CCMD_WRITE_OUTPORT 0xD1 /* write output port */ | |
| 2210 | -#define KBD_CCMD_WRITE_OBUF 0xD2 | |
| 2211 | -#define KBD_CCMD_WRITE_AUX_OBUF 0xD3 /* Write to output buffer as if | |
| 2212 | - initiated by the auxiliary device */ | |
| 2213 | -#define KBD_CCMD_WRITE_MOUSE 0xD4 /* Write the following byte to the mouse */ | |
| 2214 | -#define KBD_CCMD_DISABLE_A20 0xDD /* HP vectra only ? */ | |
| 2215 | -#define KBD_CCMD_ENABLE_A20 0xDF /* HP vectra only ? */ | |
| 2216 | -#define KBD_CCMD_RESET 0xFE | |
| 2217 | - | |
| 2218 | -/* Keyboard Commands */ | |
| 2219 | -#define KBD_CMD_SET_LEDS 0xED /* Set keyboard leds */ | |
| 2220 | -#define KBD_CMD_ECHO 0xEE | |
| 2221 | -#define KBD_CMD_GET_ID 0xF2 /* get keyboard ID */ | |
| 2222 | -#define KBD_CMD_SET_RATE 0xF3 /* Set typematic rate */ | |
| 2223 | -#define KBD_CMD_ENABLE 0xF4 /* Enable scanning */ | |
| 2224 | -#define KBD_CMD_RESET_DISABLE 0xF5 /* reset and disable scanning */ | |
| 2225 | -#define KBD_CMD_RESET_ENABLE 0xF6 /* reset and enable scanning */ | |
| 2226 | -#define KBD_CMD_RESET 0xFF /* Reset */ | |
| 2227 | - | |
| 2228 | -/* Keyboard Replies */ | |
| 2229 | -#define KBD_REPLY_POR 0xAA /* Power on reset */ | |
| 2230 | -#define KBD_REPLY_ACK 0xFA /* Command ACK */ | |
| 2231 | -#define KBD_REPLY_RESEND 0xFE /* Command NACK, send the cmd again */ | |
| 2232 | - | |
| 2233 | -/* Status Register Bits */ | |
| 2234 | -#define KBD_STAT_OBF 0x01 /* Keyboard output buffer full */ | |
| 2235 | -#define KBD_STAT_IBF 0x02 /* Keyboard input buffer full */ | |
| 2236 | -#define KBD_STAT_SELFTEST 0x04 /* Self test successful */ | |
| 2237 | -#define KBD_STAT_CMD 0x08 /* Last write was a command write (0=data) */ | |
| 2238 | -#define KBD_STAT_UNLOCKED 0x10 /* Zero if keyboard locked */ | |
| 2239 | -#define KBD_STAT_MOUSE_OBF 0x20 /* Mouse output buffer full */ | |
| 2240 | -#define KBD_STAT_GTO 0x40 /* General receive/xmit timeout */ | |
| 2241 | -#define KBD_STAT_PERR 0x80 /* Parity error */ | |
| 2242 | - | |
| 2243 | -/* Controller Mode Register Bits */ | |
| 2244 | -#define KBD_MODE_KBD_INT 0x01 /* Keyboard data generate IRQ1 */ | |
| 2245 | -#define KBD_MODE_MOUSE_INT 0x02 /* Mouse data generate IRQ12 */ | |
| 2246 | -#define KBD_MODE_SYS 0x04 /* The system flag (?) */ | |
| 2247 | -#define KBD_MODE_NO_KEYLOCK 0x08 /* The keylock doesn't affect the keyboard if set */ | |
| 2248 | -#define KBD_MODE_DISABLE_KBD 0x10 /* Disable keyboard interface */ | |
| 2249 | -#define KBD_MODE_DISABLE_MOUSE 0x20 /* Disable mouse interface */ | |
| 2250 | -#define KBD_MODE_KCC 0x40 /* Scan code conversion to PC format */ | |
| 2251 | -#define KBD_MODE_RFU 0x80 | |
| 2252 | - | |
| 2253 | -/* Mouse Commands */ | |
| 2254 | -#define AUX_SET_SCALE11 0xE6 /* Set 1:1 scaling */ | |
| 2255 | -#define AUX_SET_SCALE21 0xE7 /* Set 2:1 scaling */ | |
| 2256 | -#define AUX_SET_RES 0xE8 /* Set resolution */ | |
| 2257 | -#define AUX_GET_SCALE 0xE9 /* Get scaling factor */ | |
| 2258 | -#define AUX_SET_STREAM 0xEA /* Set stream mode */ | |
| 2259 | -#define AUX_POLL 0xEB /* Poll */ | |
| 2260 | -#define AUX_RESET_WRAP 0xEC /* Reset wrap mode */ | |
| 2261 | -#define AUX_SET_WRAP 0xEE /* Set wrap mode */ | |
| 2262 | -#define AUX_SET_REMOTE 0xF0 /* Set remote mode */ | |
| 2263 | -#define AUX_GET_TYPE 0xF2 /* Get type */ | |
| 2264 | -#define AUX_SET_SAMPLE 0xF3 /* Set sample rate */ | |
| 2265 | -#define AUX_ENABLE_DEV 0xF4 /* Enable aux device */ | |
| 2266 | -#define AUX_DISABLE_DEV 0xF5 /* Disable aux device */ | |
| 2267 | -#define AUX_SET_DEFAULT 0xF6 | |
| 2268 | -#define AUX_RESET 0xFF /* Reset aux device */ | |
| 2269 | -#define AUX_ACK 0xFA /* Command byte ACK. */ | |
| 2270 | - | |
| 2271 | -#define MOUSE_STATUS_REMOTE 0x40 | |
| 2272 | -#define MOUSE_STATUS_ENABLED 0x20 | |
| 2273 | -#define MOUSE_STATUS_SCALE21 0x10 | |
| 2274 | - | |
| 2275 | -#define KBD_QUEUE_SIZE 256 | |
| 2276 | - | |
| 2277 | -typedef struct { | |
| 2278 | - uint8_t data[KBD_QUEUE_SIZE]; | |
| 2279 | - int rptr, wptr, count; | |
| 2280 | -} KBDQueue; | |
| 2281 | - | |
| 2282 | -typedef struct KBDState { | |
| 2283 | - KBDQueue queues[2]; | |
| 2284 | - uint8_t write_cmd; /* if non zero, write data to port 60 is expected */ | |
| 2285 | - uint8_t status; | |
| 2286 | - uint8_t mode; | |
| 2287 | - /* keyboard state */ | |
| 2288 | - int kbd_write_cmd; | |
| 2289 | - int scan_enabled; | |
| 2290 | - /* mouse state */ | |
| 2291 | - int mouse_write_cmd; | |
| 2292 | - uint8_t mouse_status; | |
| 2293 | - uint8_t mouse_resolution; | |
| 2294 | - uint8_t mouse_sample_rate; | |
| 2295 | - uint8_t mouse_wrap; | |
| 2296 | - uint8_t mouse_type; /* 0 = PS2, 3 = IMPS/2, 4 = IMEX */ | |
| 2297 | - uint8_t mouse_detect_state; | |
| 2298 | - int mouse_dx; /* current values, needed for 'poll' mode */ | |
| 2299 | - int mouse_dy; | |
| 2300 | - int mouse_dz; | |
| 2301 | - uint8_t mouse_buttons; | |
| 2302 | -} KBDState; | |
| 2303 | - | |
| 2304 | -KBDState kbd_state; | |
| 2305 | -int reset_requested; | |
| 2306 | - | |
| 2307 | -/* update irq and KBD_STAT_[MOUSE_]OBF */ | |
| 2308 | -/* XXX: not generating the irqs if KBD_MODE_DISABLE_KBD is set may be | |
| 2309 | - incorrect, but it avoids having to simulate exact delays */ | |
| 2310 | -static void kbd_update_irq(KBDState *s) | |
| 2311 | -{ | |
| 2312 | - int irq12_level, irq1_level; | |
| 2313 | - | |
| 2314 | - irq1_level = 0; | |
| 2315 | - irq12_level = 0; | |
| 2316 | - s->status &= ~(KBD_STAT_OBF | KBD_STAT_MOUSE_OBF); | |
| 2317 | - if (s->queues[0].count != 0 || | |
| 2318 | - s->queues[1].count != 0) { | |
| 2319 | - s->status |= KBD_STAT_OBF; | |
| 2320 | - if (s->queues[1].count != 0) { | |
| 2321 | - s->status |= KBD_STAT_MOUSE_OBF; | |
| 2322 | - if (s->mode & KBD_MODE_MOUSE_INT) | |
| 2323 | - irq12_level = 1; | |
| 2324 | - } else { | |
| 2325 | - if ((s->mode & KBD_MODE_KBD_INT) && | |
| 2326 | - !(s->mode & KBD_MODE_DISABLE_KBD)) | |
| 2327 | - irq1_level = 1; | |
| 2328 | - } | |
| 2329 | - } | |
| 2330 | - pic_set_irq(1, irq1_level); | |
| 2331 | - pic_set_irq(12, irq12_level); | |
| 2332 | -} | |
| 2333 | - | |
| 2334 | -static void kbd_queue(KBDState *s, int b, int aux) | |
| 2335 | -{ | |
| 2336 | - KBDQueue *q = &kbd_state.queues[aux]; | |
| 2337 | - | |
| 2338 | -#if defined(DEBUG_MOUSE) || defined(DEBUG_KBD) | |
| 2339 | - if (aux) | |
| 2340 | - printf("mouse event: 0x%02x\n", b); | |
| 2341 | -#ifdef DEBUG_KBD | |
| 2342 | - else | |
| 2343 | - printf("kbd event: 0x%02x\n", b); | |
| 2344 | -#endif | |
| 2345 | -#endif | |
| 2346 | - if (q->count >= KBD_QUEUE_SIZE) | |
| 2347 | - return; | |
| 2348 | - q->data[q->wptr] = b; | |
| 2349 | - if (++q->wptr == KBD_QUEUE_SIZE) | |
| 2350 | - q->wptr = 0; | |
| 2351 | - q->count++; | |
| 2352 | - kbd_update_irq(s); | |
| 2353 | -} | |
| 2354 | - | |
| 2355 | -void kbd_put_keycode(int keycode) | |
| 2356 | -{ | |
| 2357 | - KBDState *s = &kbd_state; | |
| 2358 | - kbd_queue(s, keycode, 0); | |
| 2359 | -} | |
| 409 | + { NULL, NULL, }, | |
| 410 | +}; | |
| 2360 | 411 | |
| 2361 | -uint32_t kbd_read_status(CPUState *env, uint32_t addr) | |
| 412 | +void term_print_help(void) | |
| 2362 | 413 | { |
| 2363 | - KBDState *s = &kbd_state; | |
| 2364 | - int val; | |
| 2365 | - val = s->status; | |
| 2366 | -#if defined(DEBUG_KBD) | |
| 2367 | - printf("kbd: read status=0x%02x\n", val); | |
| 2368 | -#endif | |
| 2369 | - return val; | |
| 414 | + printf("\n" | |
| 415 | + "C-a h print this help\n" | |
| 416 | + "C-a x exit emulatior\n" | |
| 417 | + "C-a d switch on/off debug log\n" | |
| 418 | + "C-a s save disk data back to file (if -snapshot)\n" | |
| 419 | + "C-a b send break (magic sysrq)\n" | |
| 420 | + "C-a c send qemu internal command\n" | |
| 421 | + "C-a C-a send C-a\n" | |
| 422 | + ); | |
| 2370 | 423 | } |
| 2371 | 424 | |
| 2372 | -void kbd_write_command(CPUState *env, uint32_t addr, uint32_t val) | |
| 425 | +static void do_change_cdrom (unsigned char *params) | |
| 2373 | 426 | { |
| 2374 | - KBDState *s = &kbd_state; | |
| 2375 | - | |
| 2376 | -#ifdef DEBUG_KBD | |
| 2377 | - printf("kbd: write cmd=0x%02x\n", val); | |
| 2378 | -#endif | |
| 2379 | - switch(val) { | |
| 2380 | - case KBD_CCMD_READ_MODE: | |
| 2381 | - kbd_queue(s, s->mode, 0); | |
| 2382 | - break; | |
| 2383 | - case KBD_CCMD_WRITE_MODE: | |
| 2384 | - case KBD_CCMD_WRITE_OBUF: | |
| 2385 | - case KBD_CCMD_WRITE_AUX_OBUF: | |
| 2386 | - case KBD_CCMD_WRITE_MOUSE: | |
| 2387 | - case KBD_CCMD_WRITE_OUTPORT: | |
| 2388 | - s->write_cmd = val; | |
| 2389 | - break; | |
| 2390 | - case KBD_CCMD_MOUSE_DISABLE: | |
| 2391 | - s->mode |= KBD_MODE_DISABLE_MOUSE; | |
| 2392 | - break; | |
| 2393 | - case KBD_CCMD_MOUSE_ENABLE: | |
| 2394 | - s->mode &= ~KBD_MODE_DISABLE_MOUSE; | |
| 2395 | - break; | |
| 2396 | - case KBD_CCMD_TEST_MOUSE: | |
| 2397 | - kbd_queue(s, 0x00, 0); | |
| 2398 | - break; | |
| 2399 | - case KBD_CCMD_SELF_TEST: | |
| 2400 | - s->status |= KBD_STAT_SELFTEST; | |
| 2401 | - kbd_queue(s, 0x55, 0); | |
| 2402 | - break; | |
| 2403 | - case KBD_CCMD_KBD_TEST: | |
| 2404 | - kbd_queue(s, 0x00, 0); | |
| 2405 | - break; | |
| 2406 | - case KBD_CCMD_KBD_DISABLE: | |
| 2407 | - s->mode |= KBD_MODE_DISABLE_KBD; | |
| 2408 | - kbd_update_irq(s); | |
| 2409 | - break; | |
| 2410 | - case KBD_CCMD_KBD_ENABLE: | |
| 2411 | - s->mode &= ~KBD_MODE_DISABLE_KBD; | |
| 2412 | - kbd_update_irq(s); | |
| 2413 | - break; | |
| 2414 | - case KBD_CCMD_READ_INPORT: | |
| 2415 | - kbd_queue(s, 0x00, 0); | |
| 2416 | - break; | |
| 2417 | - case KBD_CCMD_READ_OUTPORT: | |
| 2418 | - /* XXX: check that */ | |
| 2419 | -#ifdef TARGET_I386 | |
| 2420 | - val = 0x01 | (((cpu_single_env->a20_mask >> 20) & 1) << 1); | |
| 2421 | -#else | |
| 2422 | - val = 0x01; | |
| 2423 | -#endif | |
| 2424 | - if (s->status & KBD_STAT_OBF) | |
| 2425 | - val |= 0x10; | |
| 2426 | - if (s->status & KBD_STAT_MOUSE_OBF) | |
| 2427 | - val |= 0x20; | |
| 2428 | - kbd_queue(s, val, 0); | |
| 2429 | - break; | |
| 2430 | -#ifdef TARGET_I386 | |
| 2431 | - case KBD_CCMD_ENABLE_A20: | |
| 2432 | - cpu_x86_set_a20(env, 1); | |
| 2433 | - break; | |
| 2434 | - case KBD_CCMD_DISABLE_A20: | |
| 2435 | - cpu_x86_set_a20(env, 0); | |
| 2436 | - break; | |
| 2437 | -#endif | |
| 2438 | - case KBD_CCMD_RESET: | |
| 2439 | - reset_requested = 1; | |
| 2440 | - cpu_interrupt(global_env, CPU_INTERRUPT_EXIT); | |
| 2441 | - break; | |
| 2442 | - case 0xff: | |
| 2443 | - /* ignore that - I don't know what is its use */ | |
| 2444 | - break; | |
| 2445 | - default: | |
| 2446 | - fprintf(stderr, "qemu: unsupported keyboard cmd=0x%02x\n", val); | |
| 2447 | - break; | |
| 2448 | - } | |
| 427 | + /* Dunno how to do it... */ | |
| 2449 | 428 | } |
| 2450 | 429 | |
| 2451 | -uint32_t kbd_read_data(CPUState *env, uint32_t addr) | |
| 430 | +static void do_change_fd (int fd, unsigned char *params) | |
| 2452 | 431 | { |
| 2453 | - KBDState *s = &kbd_state; | |
| 2454 | - KBDQueue *q; | |
| 2455 | - int val, index; | |
| 2456 | - | |
| 2457 | - q = &s->queues[0]; /* first check KBD data */ | |
| 2458 | - if (q->count == 0) | |
| 2459 | - q = &s->queues[1]; /* then check AUX data */ | |
| 2460 | - if (q->count == 0) { | |
| 2461 | - /* NOTE: if no data left, we return the last keyboard one | |
| 2462 | - (needed for EMM386) */ | |
| 2463 | - /* XXX: need a timer to do things correctly */ | |
| 2464 | - q = &s->queues[0]; | |
| 2465 | - index = q->rptr - 1; | |
| 2466 | - if (index < 0) | |
| 2467 | - index = KBD_QUEUE_SIZE - 1; | |
| 2468 | - val = q->data[index]; | |
| 2469 | - } else { | |
| 2470 | - val = q->data[q->rptr]; | |
| 2471 | - if (++q->rptr == KBD_QUEUE_SIZE) | |
| 2472 | - q->rptr = 0; | |
| 2473 | - q->count--; | |
| 2474 | - /* reading deasserts IRQ */ | |
| 2475 | - if (q == &s->queues[0]) | |
| 2476 | - pic_set_irq(1, 0); | |
| 2477 | - else | |
| 2478 | - pic_set_irq(12, 0); | |
| 2479 | - } | |
| 2480 | - /* reassert IRQs if data left */ | |
| 2481 | - kbd_update_irq(s); | |
| 2482 | -#ifdef DEBUG_KBD | |
| 2483 | - printf("kbd: read data=0x%02x\n", val); | |
| 2484 | -#endif | |
| 2485 | - return val; | |
| 2486 | -} | |
| 432 | + unsigned char *name_start, *name_end, *ros; | |
| 433 | + int ro; | |
| 2487 | 434 | |
| 2488 | -static void kbd_reset_keyboard(KBDState *s) | |
| 2489 | -{ | |
| 2490 | - s->scan_enabled = 1; | |
| 435 | + for (name_start = params; | |
| 436 | + isspace(*name_start); name_start++) | |
| 437 | + continue; | |
| 438 | + if (*name_start == '\0') | |
| 439 | + return; | |
| 440 | + for (name_end = name_start; | |
| 441 | + !isspace(*name_end) && *name_end != '\0'; name_end++) | |
| 442 | + continue; | |
| 443 | + for (ros = name_end + 1; isspace(*ros); ros++) | |
| 444 | + continue; | |
| 445 | + if (ros[0] == 'r' && ros[1] == 'o') | |
| 446 | + ro = 1; | |
| 447 | + else | |
| 448 | + ro = 0; | |
| 449 | + *name_end = '\0'; | |
| 450 | + printf("Change fd %d to %s (%s)\n", fd, name_start, params); | |
| 451 | + fdctrl_disk_change(fd, name_start, ro); | |
| 2491 | 452 | } |
| 2492 | 453 | |
| 2493 | -static void kbd_write_keyboard(KBDState *s, int val) | |
| 454 | +static void do_change_fd0 (unsigned char *params) | |
| 2494 | 455 | { |
| 2495 | - switch(s->kbd_write_cmd) { | |
| 2496 | - default: | |
| 2497 | - case -1: | |
| 2498 | - switch(val) { | |
| 2499 | - case 0x00: | |
| 2500 | - kbd_queue(s, KBD_REPLY_ACK, 0); | |
| 2501 | - break; | |
| 2502 | - case 0x05: | |
| 2503 | - kbd_queue(s, KBD_REPLY_RESEND, 0); | |
| 2504 | - break; | |
| 2505 | - case KBD_CMD_GET_ID: | |
| 2506 | - kbd_queue(s, KBD_REPLY_ACK, 0); | |
| 2507 | - kbd_queue(s, 0xab, 0); | |
| 2508 | - kbd_queue(s, 0x83, 0); | |
| 2509 | - break; | |
| 2510 | - case KBD_CMD_ECHO: | |
| 2511 | - kbd_queue(s, KBD_CMD_ECHO, 0); | |
| 2512 | - break; | |
| 2513 | - case KBD_CMD_ENABLE: | |
| 2514 | - s->scan_enabled = 1; | |
| 2515 | - kbd_queue(s, KBD_REPLY_ACK, 0); | |
| 2516 | - break; | |
| 2517 | - case KBD_CMD_SET_LEDS: | |
| 2518 | - case KBD_CMD_SET_RATE: | |
| 2519 | - s->kbd_write_cmd = val; | |
| 2520 | - kbd_queue(s, KBD_REPLY_ACK, 0); | |
| 2521 | - break; | |
| 2522 | - case KBD_CMD_RESET_DISABLE: | |
| 2523 | - kbd_reset_keyboard(s); | |
| 2524 | - s->scan_enabled = 0; | |
| 2525 | - kbd_queue(s, KBD_REPLY_ACK, 0); | |
| 2526 | - break; | |
| 2527 | - case KBD_CMD_RESET_ENABLE: | |
| 2528 | - kbd_reset_keyboard(s); | |
| 2529 | - s->scan_enabled = 1; | |
| 2530 | - kbd_queue(s, KBD_REPLY_ACK, 0); | |
| 2531 | - break; | |
| 2532 | - case KBD_CMD_RESET: | |
| 2533 | - kbd_reset_keyboard(s); | |
| 2534 | - kbd_queue(s, KBD_REPLY_ACK, 0); | |
| 2535 | - kbd_queue(s, KBD_REPLY_POR, 0); | |
| 2536 | - break; | |
| 2537 | - default: | |
| 2538 | - kbd_queue(s, KBD_REPLY_ACK, 0); | |
| 2539 | - break; | |
| 2540 | - } | |
| 2541 | - break; | |
| 2542 | - case KBD_CMD_SET_LEDS: | |
| 2543 | - kbd_queue(s, KBD_REPLY_ACK, 0); | |
| 2544 | - s->kbd_write_cmd = -1; | |
| 2545 | - break; | |
| 2546 | - case KBD_CMD_SET_RATE: | |
| 2547 | - kbd_queue(s, KBD_REPLY_ACK, 0); | |
| 2548 | - s->kbd_write_cmd = -1; | |
| 2549 | - break; | |
| 2550 | - } | |
| 456 | + do_change_fd(0, params); | |
| 2551 | 457 | } |
| 2552 | 458 | |
| 2553 | -static void kbd_mouse_send_packet(KBDState *s) | |
| 459 | +static void do_change_fd1 (unsigned char *params) | |
| 2554 | 460 | { |
| 2555 | - unsigned int b; | |
| 2556 | - int dx1, dy1, dz1; | |
| 2557 | - | |
| 2558 | - dx1 = s->mouse_dx; | |
| 2559 | - dy1 = s->mouse_dy; | |
| 2560 | - dz1 = s->mouse_dz; | |
| 2561 | - /* XXX: increase range to 8 bits ? */ | |
| 2562 | - if (dx1 > 127) | |
| 2563 | - dx1 = 127; | |
| 2564 | - else if (dx1 < -127) | |
| 2565 | - dx1 = -127; | |
| 2566 | - if (dy1 > 127) | |
| 2567 | - dy1 = 127; | |
| 2568 | - else if (dy1 < -127) | |
| 2569 | - dy1 = -127; | |
| 2570 | - b = 0x08 | ((dx1 < 0) << 4) | ((dy1 < 0) << 5) | (s->mouse_buttons & 0x07); | |
| 2571 | - kbd_queue(s, b, 1); | |
| 2572 | - kbd_queue(s, dx1 & 0xff, 1); | |
| 2573 | - kbd_queue(s, dy1 & 0xff, 1); | |
| 2574 | - /* extra byte for IMPS/2 or IMEX */ | |
| 2575 | - switch(s->mouse_type) { | |
| 2576 | - default: | |
| 2577 | - break; | |
| 2578 | - case 3: | |
| 2579 | - if (dz1 > 127) | |
| 2580 | - dz1 = 127; | |
| 2581 | - else if (dz1 < -127) | |
| 2582 | - dz1 = -127; | |
| 2583 | - kbd_queue(s, dz1 & 0xff, 1); | |
| 2584 | - break; | |
| 2585 | - case 4: | |
| 2586 | - if (dz1 > 7) | |
| 2587 | - dz1 = 7; | |
| 2588 | - else if (dz1 < -7) | |
| 2589 | - dz1 = -7; | |
| 2590 | - b = (dz1 & 0x0f) | ((s->mouse_buttons & 0x18) << 1); | |
| 2591 | - kbd_queue(s, b, 1); | |
| 2592 | - break; | |
| 2593 | - } | |
| 2594 | - | |
| 2595 | - /* update deltas */ | |
| 2596 | - s->mouse_dx -= dx1; | |
| 2597 | - s->mouse_dy -= dy1; | |
| 2598 | - s->mouse_dz -= dz1; | |
| 461 | + do_change_fd(1, params); | |
| 2599 | 462 | } |
| 2600 | 463 | |
| 2601 | -void kbd_mouse_event(int dx, int dy, int dz, int buttons_state) | |
| 464 | +static void term_treat_command(void) | |
| 2602 | 465 | { |
| 2603 | - KBDState *s = &kbd_state; | |
| 2604 | - | |
| 2605 | - /* check if deltas are recorded when disabled */ | |
| 2606 | - if (!(s->mouse_status & MOUSE_STATUS_ENABLED)) | |
| 2607 | - return; | |
| 466 | + unsigned char *cmd_start, *cmd_end; | |
| 467 | + int i; | |
| 2608 | 468 | |
| 2609 | - s->mouse_dx += dx; | |
| 2610 | - s->mouse_dy -= dy; | |
| 2611 | - s->mouse_dz += dz; | |
| 2612 | - s->mouse_buttons = buttons_state; | |
| 2613 | - | |
| 2614 | - if (!(s->mouse_status & MOUSE_STATUS_REMOTE) && | |
| 2615 | - (s->queues[1].count < (KBD_QUEUE_SIZE - 16))) { | |
| 2616 | - for(;;) { | |
| 2617 | - /* if not remote, send event. Multiple events are sent if | |
| 2618 | - too big deltas */ | |
| 2619 | - kbd_mouse_send_packet(s); | |
| 2620 | - if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0) | |
| 2621 | - break; | |
| 469 | + for (cmd_start = term_cmd_buf; isspace(*cmd_start); cmd_start++) | |
| 470 | + continue; | |
| 471 | + for (cmd_end = cmd_start; | |
| 472 | + !isspace(*cmd_end) && *cmd_end != '\0'; cmd_end++) | |
| 473 | + continue; | |
| 474 | + for (i = 0; term_cmds[i].name != NULL; i++) { | |
| 475 | + if (strlen(term_cmds[i].name) == (cmd_end - cmd_start) && | |
| 476 | + memcmp(term_cmds[i].name, cmd_start, cmd_end - cmd_start) == 0) { | |
| 477 | + (*term_cmds[i].handler)(cmd_end + 1); | |
| 478 | + return; | |
| 2622 | 479 | } |
| 2623 | 480 | } |
| 481 | + *cmd_end = '\0'; | |
| 482 | + printf("Unknown term command: %s\n", cmd_start); | |
| 2624 | 483 | } |
| 2625 | 484 | |
| 2626 | -static void kbd_write_mouse(KBDState *s, int val) | |
| 485 | +extern FILE *logfile; | |
| 486 | + | |
| 487 | +/* called when a char is received */ | |
| 488 | +void term_received_byte(int ch) | |
| 2627 | 489 | { |
| 2628 | -#ifdef DEBUG_MOUSE | |
| 2629 | - printf("kbd: write mouse 0x%02x\n", val); | |
| 2630 | -#endif | |
| 2631 | - switch(s->mouse_write_cmd) { | |
| 2632 | - default: | |
| 2633 | - case -1: | |
| 2634 | - /* mouse command */ | |
| 2635 | - if (s->mouse_wrap) { | |
| 2636 | - if (val == AUX_RESET_WRAP) { | |
| 2637 | - s->mouse_wrap = 0; | |
| 2638 | - kbd_queue(s, AUX_ACK, 1); | |
| 2639 | - return; | |
| 2640 | - } else if (val != AUX_RESET) { | |
| 2641 | - kbd_queue(s, val, 1); | |
| 2642 | - return; | |
| 490 | + if (term_command) { | |
| 491 | + if (ch == '\n' || ch == '\r' || term_command == 127) { | |
| 492 | + printf("\n"); | |
| 493 | + term_treat_command(); | |
| 494 | + term_command = 0; | |
| 495 | + } else { | |
| 496 | + if (ch == 0x7F || ch == 0x08) { | |
| 497 | + if (term_command > 1) { | |
| 498 | + term_cmd_buf[--term_command - 1] = '\0'; | |
| 499 | + printf("\r " | |
| 500 | + " "); | |
| 501 | + printf("\r> %s", term_cmd_buf); | |
| 502 | + } | |
| 503 | + } else if (ch > 0x1f) { | |
| 504 | + term_cmd_buf[term_command++ - 1] = ch; | |
| 505 | + term_cmd_buf[term_command - 1] = '\0'; | |
| 506 | + printf("\r> %s", term_cmd_buf); | |
| 2643 | 507 | } |
| 508 | + fflush(stdout); | |
| 2644 | 509 | } |
| 2645 | - switch(val) { | |
| 2646 | - case AUX_SET_SCALE11: | |
| 2647 | - s->mouse_status &= ~MOUSE_STATUS_SCALE21; | |
| 2648 | - kbd_queue(s, AUX_ACK, 1); | |
| 2649 | - break; | |
| 2650 | - case AUX_SET_SCALE21: | |
| 2651 | - s->mouse_status |= MOUSE_STATUS_SCALE21; | |
| 2652 | - kbd_queue(s, AUX_ACK, 1); | |
| 2653 | - break; | |
| 2654 | - case AUX_SET_STREAM: | |
| 2655 | - s->mouse_status &= ~MOUSE_STATUS_REMOTE; | |
| 2656 | - kbd_queue(s, AUX_ACK, 1); | |
| 2657 | - break; | |
| 2658 | - case AUX_SET_WRAP: | |
| 2659 | - s->mouse_wrap = 1; | |
| 2660 | - kbd_queue(s, AUX_ACK, 1); | |
| 2661 | - break; | |
| 2662 | - case AUX_SET_REMOTE: | |
| 2663 | - s->mouse_status |= MOUSE_STATUS_REMOTE; | |
| 2664 | - kbd_queue(s, AUX_ACK, 1); | |
| 2665 | - break; | |
| 2666 | - case AUX_GET_TYPE: | |
| 2667 | - kbd_queue(s, AUX_ACK, 1); | |
| 2668 | - kbd_queue(s, s->mouse_type, 1); | |
| 2669 | - break; | |
| 2670 | - case AUX_SET_RES: | |
| 2671 | - case AUX_SET_SAMPLE: | |
| 2672 | - s->mouse_write_cmd = val; | |
| 2673 | - kbd_queue(s, AUX_ACK, 1); | |
| 2674 | - break; | |
| 2675 | - case AUX_GET_SCALE: | |
| 2676 | - kbd_queue(s, AUX_ACK, 1); | |
| 2677 | - kbd_queue(s, s->mouse_status, 1); | |
| 2678 | - kbd_queue(s, s->mouse_resolution, 1); | |
| 2679 | - kbd_queue(s, s->mouse_sample_rate, 1); | |
| 2680 | - break; | |
| 2681 | - case AUX_POLL: | |
| 2682 | - kbd_queue(s, AUX_ACK, 1); | |
| 2683 | - kbd_mouse_send_packet(s); | |
| 2684 | - break; | |
| 2685 | - case AUX_ENABLE_DEV: | |
| 2686 | - s->mouse_status |= MOUSE_STATUS_ENABLED; | |
| 2687 | - kbd_queue(s, AUX_ACK, 1); | |
| 2688 | - break; | |
| 2689 | - case AUX_DISABLE_DEV: | |
| 2690 | - s->mouse_status &= ~MOUSE_STATUS_ENABLED; | |
| 2691 | - kbd_queue(s, AUX_ACK, 1); | |
| 2692 | - break; | |
| 2693 | - case AUX_SET_DEFAULT: | |
| 2694 | - s->mouse_sample_rate = 100; | |
| 2695 | - s->mouse_resolution = 2; | |
| 2696 | - s->mouse_status = 0; | |
| 2697 | - kbd_queue(s, AUX_ACK, 1); | |
| 2698 | - break; | |
| 2699 | - case AUX_RESET: | |
| 2700 | - s->mouse_sample_rate = 100; | |
| 2701 | - s->mouse_resolution = 2; | |
| 2702 | - s->mouse_status = 0; | |
| 2703 | - kbd_queue(s, AUX_ACK, 1); | |
| 2704 | - kbd_queue(s, 0xaa, 1); | |
| 2705 | - kbd_queue(s, s->mouse_type, 1); | |
| 510 | + } else if (term_got_escape) { | |
| 511 | + term_got_escape = 0; | |
| 512 | + switch(ch) { | |
| 513 | + case 'h': | |
| 514 | + term_print_help(); | |
| 2706 | 515 | break; |
| 2707 | - default: | |
| 516 | + case 'x': | |
| 517 | + exit(0); | |
| 2708 | 518 | break; |
| 2709 | - } | |
| 2710 | - break; | |
| 2711 | - case AUX_SET_SAMPLE: | |
| 2712 | - s->mouse_sample_rate = val; | |
| 2713 | -#if 0 | |
| 2714 | - /* detect IMPS/2 or IMEX */ | |
| 2715 | - switch(s->mouse_detect_state) { | |
| 2716 | - default: | |
| 2717 | - case 0: | |
| 2718 | - if (val == 200) | |
| 2719 | - s->mouse_detect_state = 1; | |
| 519 | + case 's': | |
| 520 | + { | |
| 521 | + int i; | |
| 522 | + for (i = 0; i < MAX_DISKS; i++) { | |
| 523 | + if (bs_table[i]) | |
| 524 | + bdrv_commit(bs_table[i]); | |
| 525 | + } | |
| 526 | + } | |
| 2720 | 527 | break; |
| 2721 | - case 1: | |
| 2722 | - if (val == 100) | |
| 2723 | - s->mouse_detect_state = 2; | |
| 2724 | - else if (val == 200) | |
| 2725 | - s->mouse_detect_state = 3; | |
| 2726 | - else | |
| 2727 | - s->mouse_detect_state = 0; | |
| 528 | + case 'b': | |
| 529 | + serial_receive_break(); | |
| 2728 | 530 | break; |
| 2729 | - case 2: | |
| 2730 | - if (val == 80) | |
| 2731 | - s->mouse_type = 3; /* IMPS/2 */ | |
| 2732 | - s->mouse_detect_state = 0; | |
| 531 | + case 'c': | |
| 532 | + printf("> "); | |
| 533 | + fflush(stdout); | |
| 534 | + term_command = 1; | |
| 2733 | 535 | break; |
| 2734 | - case 3: | |
| 2735 | - if (val == 80) | |
| 2736 | - s->mouse_type = 4; /* IMEX */ | |
| 2737 | - s->mouse_detect_state = 0; | |
| 536 | + case 'd': | |
| 537 | + cpu_set_log(CPU_LOG_ALL); | |
| 2738 | 538 | break; |
| 539 | + case TERM_ESCAPE: | |
| 540 | + goto send_char; | |
| 2739 | 541 | } |
| 2740 | -#endif | |
| 2741 | - kbd_queue(s, AUX_ACK, 1); | |
| 2742 | - s->mouse_write_cmd = -1; | |
| 2743 | - break; | |
| 2744 | - case AUX_SET_RES: | |
| 2745 | - s->mouse_resolution = val; | |
| 2746 | - kbd_queue(s, AUX_ACK, 1); | |
| 2747 | - s->mouse_write_cmd = -1; | |
| 2748 | - break; | |
| 542 | + } else if (ch == TERM_ESCAPE) { | |
| 543 | + term_got_escape = 1; | |
| 544 | + } else { | |
| 545 | + send_char: | |
| 546 | + serial_receive_byte(ch); | |
| 2749 | 547 | } |
| 2750 | 548 | } |
| 2751 | 549 | |
| 2752 | -void kbd_write_data(CPUState *env, uint32_t addr, uint32_t val) | |
| 2753 | -{ | |
| 2754 | - KBDState *s = &kbd_state; | |
| 2755 | - | |
| 2756 | -#ifdef DEBUG_KBD | |
| 2757 | - printf("kbd: write data=0x%02x\n", val); | |
| 2758 | -#endif | |
| 2759 | - | |
| 2760 | - switch(s->write_cmd) { | |
| 2761 | - case 0: | |
| 2762 | - kbd_write_keyboard(s, val); | |
| 2763 | - break; | |
| 2764 | - case KBD_CCMD_WRITE_MODE: | |
| 2765 | - s->mode = val; | |
| 2766 | - kbd_update_irq(s); | |
| 2767 | - break; | |
| 2768 | - case KBD_CCMD_WRITE_OBUF: | |
| 2769 | - kbd_queue(s, val, 0); | |
| 2770 | - break; | |
| 2771 | - case KBD_CCMD_WRITE_AUX_OBUF: | |
| 2772 | - kbd_queue(s, val, 1); | |
| 2773 | - break; | |
| 2774 | - case KBD_CCMD_WRITE_OUTPORT: | |
| 2775 | -#ifdef TARGET_I386 | |
| 2776 | - cpu_x86_set_a20(env, (val >> 1) & 1); | |
| 2777 | -#endif | |
| 2778 | - if (!(val & 1)) { | |
| 2779 | - reset_requested = 1; | |
| 2780 | - cpu_interrupt(global_env, CPU_INTERRUPT_EXIT); | |
| 2781 | - } | |
| 2782 | - break; | |
| 2783 | - case KBD_CCMD_WRITE_MOUSE: | |
| 2784 | - kbd_write_mouse(s, val); | |
| 2785 | - break; | |
| 2786 | - default: | |
| 2787 | - break; | |
| 2788 | - } | |
| 2789 | - s->write_cmd = 0; | |
| 2790 | -} | |
| 550 | +/***********************************************************/ | |
| 551 | +/* Linux network device redirector */ | |
| 2791 | 552 | |
| 2792 | -void kbd_reset(KBDState *s) | |
| 553 | +int net_init(void) | |
| 2793 | 554 | { |
| 2794 | - KBDQueue *q; | |
| 2795 | - int i; | |
| 2796 | - | |
| 2797 | - s->kbd_write_cmd = -1; | |
| 2798 | - s->mouse_write_cmd = -1; | |
| 2799 | - s->mode = KBD_MODE_KBD_INT | KBD_MODE_MOUSE_INT; | |
| 2800 | - s->status = KBD_STAT_CMD | KBD_STAT_UNLOCKED; | |
| 2801 | - for(i = 0; i < 2; i++) { | |
| 2802 | - q = &s->queues[i]; | |
| 2803 | - q->rptr = 0; | |
| 2804 | - q->wptr = 0; | |
| 2805 | - q->count = 0; | |
| 555 | + struct ifreq ifr; | |
| 556 | + int fd, ret, pid, status; | |
| 557 | + | |
| 558 | + fd = open("/dev/net/tun", O_RDWR); | |
| 559 | + if (fd < 0) { | |
| 560 | + fprintf(stderr, "warning: could not open /dev/net/tun: no virtual network emulation\n"); | |
| 561 | + return -1; | |
| 2806 | 562 | } |
| 2807 | -} | |
| 2808 | - | |
| 2809 | -void kbd_init(void) | |
| 2810 | -{ | |
| 2811 | - kbd_reset(&kbd_state); | |
| 2812 | -#if defined (TARGET_I386) || defined (TARGET_PPC) | |
| 2813 | - register_ioport_read(0x60, 1, kbd_read_data, 1); | |
| 2814 | - register_ioport_write(0x60, 1, kbd_write_data, 1); | |
| 2815 | - register_ioport_read(0x64, 1, kbd_read_status, 1); | |
| 2816 | - register_ioport_write(0x64, 1, kbd_write_command, 1); | |
| 2817 | -#endif | |
| 2818 | -} | |
| 2819 | - | |
| 2820 | -/***********************************************************/ | |
| 2821 | -/* Bochs BIOS debug ports */ | |
| 2822 | -#ifdef TARGET_I386 | |
| 2823 | -void bochs_bios_write(CPUX86State *env, uint32_t addr, uint32_t val) | |
| 2824 | -{ | |
| 2825 | - switch(addr) { | |
| 2826 | - /* Bochs BIOS messages */ | |
| 2827 | - case 0x400: | |
| 2828 | - case 0x401: | |
| 2829 | - fprintf(stderr, "BIOS panic at rombios.c, line %d\n", val); | |
| 2830 | - exit(1); | |
| 2831 | - case 0x402: | |
| 2832 | - case 0x403: | |
| 2833 | -#ifdef DEBUG_BIOS | |
| 2834 | - fprintf(stderr, "%c", val); | |
| 2835 | -#endif | |
| 2836 | - break; | |
| 563 | + memset(&ifr, 0, sizeof(ifr)); | |
| 564 | + ifr.ifr_flags = IFF_TAP | IFF_NO_PI; | |
| 565 | + pstrcpy(ifr.ifr_name, IFNAMSIZ, "tun%d"); | |
| 566 | + ret = ioctl(fd, TUNSETIFF, (void *) &ifr); | |
| 567 | + if (ret != 0) { | |
| 568 | + fprintf(stderr, "warning: could not configure /dev/net/tun: no virtual network emulation\n"); | |
| 569 | + close(fd); | |
| 570 | + return -1; | |
| 571 | + } | |
| 572 | + printf("Connected to host network interface: %s\n", ifr.ifr_name); | |
| 573 | + fcntl(fd, F_SETFL, O_NONBLOCK); | |
| 574 | + net_fd = fd; | |
| 2837 | 575 | |
| 2838 | - /* LGPL'ed VGA BIOS messages */ | |
| 2839 | - case 0x501: | |
| 2840 | - case 0x502: | |
| 2841 | - fprintf(stderr, "VGA BIOS panic, line %d\n", val); | |
| 2842 | - exit(1); | |
| 2843 | - case 0x500: | |
| 2844 | - case 0x503: | |
| 2845 | -#ifdef DEBUG_BIOS | |
| 2846 | - fprintf(stderr, "%c", val); | |
| 2847 | -#endif | |
| 2848 | - break; | |
| 576 | + /* try to launch network init script */ | |
| 577 | + pid = fork(); | |
| 578 | + if (pid >= 0) { | |
| 579 | + if (pid == 0) { | |
| 580 | + execl(network_script, network_script, ifr.ifr_name, NULL); | |
| 581 | + exit(1); | |
| 582 | + } | |
| 583 | + while (waitpid(pid, &status, 0) != pid); | |
| 584 | + if (!WIFEXITED(status) || | |
| 585 | + WEXITSTATUS(status) != 0) { | |
| 586 | + fprintf(stderr, "%s: could not launch network script for '%s'\n", | |
| 587 | + network_script, ifr.ifr_name); | |
| 588 | + } | |
| 2849 | 589 | } |
| 590 | + return 0; | |
| 2850 | 591 | } |
| 2851 | 592 | |
| 2852 | -void bochs_bios_init(void) | |
| 593 | +void net_send_packet(int net_fd, const uint8_t *buf, int size) | |
| 2853 | 594 | { |
| 2854 | - register_ioport_write(0x400, 1, bochs_bios_write, 2); | |
| 2855 | - register_ioport_write(0x401, 1, bochs_bios_write, 2); | |
| 2856 | - register_ioport_write(0x402, 1, bochs_bios_write, 1); | |
| 2857 | - register_ioport_write(0x403, 1, bochs_bios_write, 1); | |
| 2858 | - | |
| 2859 | - register_ioport_write(0x501, 1, bochs_bios_write, 2); | |
| 2860 | - register_ioport_write(0x502, 1, bochs_bios_write, 2); | |
| 2861 | - register_ioport_write(0x500, 1, bochs_bios_write, 1); | |
| 2862 | - register_ioport_write(0x503, 1, bochs_bios_write, 1); | |
| 2863 | -} | |
| 595 | +#ifdef DEBUG_NE2000 | |
| 596 | + printf("NE2000: sending packet size=%d\n", size); | |
| 2864 | 597 | #endif |
| 598 | + write(net_fd, buf, size); | |
| 599 | +} | |
| 2865 | 600 | |
| 2866 | 601 | /***********************************************************/ |
| 2867 | 602 | /* dumb display */ |
| ... | ... | @@ -3015,7 +750,7 @@ int main_loop(void *opaque) |
| 3015 | 750 | /* poll any events */ |
| 3016 | 751 | serial_ufd = NULL; |
| 3017 | 752 | pf = ufds; |
| 3018 | - if (serial_ok && !(serial_ports[0].lsr & UART_LSR_DR)) { | |
| 753 | + if (serial_ok && serial_can_receive()) { | |
| 3019 | 754 | serial_ufd = pf; |
| 3020 | 755 | pf->fd = 0; |
| 3021 | 756 | pf->events = POLLIN; |
| ... | ... | @@ -3023,7 +758,7 @@ int main_loop(void *opaque) |
| 3023 | 758 | } |
| 3024 | 759 | #if defined (TARGET_I386) |
| 3025 | 760 | net_ufd = NULL; |
| 3026 | - if (net_fd > 0 && ne2000_can_receive(&ne2000_state)) { | |
| 761 | + if (net_fd > 0 && ne2000_can_receive()) { | |
| 3027 | 762 | net_ufd = pf; |
| 3028 | 763 | pf->fd = net_fd; |
| 3029 | 764 | pf->events = POLLIN; |
| ... | ... | @@ -3043,7 +778,7 @@ int main_loop(void *opaque) |
| 3043 | 778 | if (serial_ufd && (serial_ufd->revents & POLLIN)) { |
| 3044 | 779 | n = read(0, &ch, 1); |
| 3045 | 780 | if (n == 1) { |
| 3046 | - serial_received_byte(&serial_ports[0], ch); | |
| 781 | + term_received_byte(ch); | |
| 3047 | 782 | } else { |
| 3048 | 783 | /* Closed, stop polling. */ |
| 3049 | 784 | serial_ok = 0; |
| ... | ... | @@ -3059,7 +794,7 @@ int main_loop(void *opaque) |
| 3059 | 794 | memset(buf + n, 0, 60 - n); |
| 3060 | 795 | n = 60; |
| 3061 | 796 | } |
| 3062 | - ne2000_receive(&ne2000_state, buf, n); | |
| 797 | + ne2000_receive(buf, n); | |
| 3063 | 798 | } |
| 3064 | 799 | } |
| 3065 | 800 | #endif |
| ... | ... | @@ -3080,10 +815,7 @@ int main_loop(void *opaque) |
| 3080 | 815 | pic_set_irq(0, 1); |
| 3081 | 816 | pic_set_irq(0, 0); |
| 3082 | 817 | timer_irq_pending = 0; |
| 3083 | - /* XXX: RTC test */ | |
| 3084 | - if (cmos_data[RTC_REG_B] & 0x50) { | |
| 3085 | - pic_set_irq(8, 1); | |
| 3086 | - } | |
| 818 | + rtc_timer(); | |
| 3087 | 819 | #endif |
| 3088 | 820 | } |
| 3089 | 821 | /* XXX: add explicit timer */ |
| ... | ... | @@ -3199,7 +931,7 @@ static uint8_t *signal_stack; |
| 3199 | 931 | |
| 3200 | 932 | int main(int argc, char **argv) |
| 3201 | 933 | { |
| 3202 | - int c, ret, initrd_size, i, use_gdbstub, gdbstub_port, long_index; | |
| 934 | + int c, i, use_gdbstub, gdbstub_port, long_index; | |
| 3203 | 935 | int snapshot, linux_boot; |
| 3204 | 936 | struct sigaction act; |
| 3205 | 937 | struct itimerval itv; |
| ... | ... | @@ -3207,7 +939,6 @@ int main(int argc, char **argv) |
| 3207 | 939 | const char *initrd_filename; |
| 3208 | 940 | const char *hd_filename[MAX_DISKS], *fd_filename[MAX_FD]; |
| 3209 | 941 | const char *kernel_filename, *kernel_cmdline; |
| 3210 | - char buf[1024]; | |
| 3211 | 942 | DisplayState *ds = &display_state; |
| 3212 | 943 | |
| 3213 | 944 | /* we never want that malloc() uses mmap() */ |
| ... | ... | @@ -3438,92 +1169,7 @@ int main(int argc, char **argv) |
| 3438 | 1169 | cpu_single_env = env; |
| 3439 | 1170 | |
| 3440 | 1171 | init_ioports(); |
| 3441 | - | |
| 3442 | - /* allocate RAM */ | |
| 3443 | - cpu_register_physical_memory(0, ram_size, 0); | |
| 3444 | - | |
| 3445 | -#if defined(TARGET_I386) | |
| 3446 | - /* RAW PC boot */ | |
| 3447 | - | |
| 3448 | - /* BIOS load */ | |
| 3449 | - snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME); | |
| 3450 | - ret = load_image(buf, phys_ram_base + 0x000f0000); | |
| 3451 | - if (ret != 0x10000) { | |
| 3452 | - fprintf(stderr, "qemu: could not load PC bios '%s'\n", buf); | |
| 3453 | - exit(1); | |
| 3454 | - } | |
| 3455 | - | |
| 3456 | - /* VGA BIOS load */ | |
| 3457 | - snprintf(buf, sizeof(buf), "%s/%s", bios_dir, VGABIOS_FILENAME); | |
| 3458 | - ret = load_image(buf, phys_ram_base + 0x000c0000); | |
| 3459 | - | |
| 3460 | - /* setup basic memory access */ | |
| 3461 | - cpu_register_physical_memory(0xc0000, 0x10000, 0xc0000 | IO_MEM_ROM); | |
| 3462 | - cpu_register_physical_memory(0xf0000, 0x10000, 0xf0000 | IO_MEM_ROM); | |
| 3463 | - | |
| 3464 | - bochs_bios_init(); | |
| 3465 | - | |
| 3466 | - if (linux_boot) { | |
| 3467 | - uint8_t bootsect[512]; | |
| 3468 | - | |
| 3469 | - if (bs_table[0] == NULL) { | |
| 3470 | - fprintf(stderr, "A disk image must be given for 'hda' when booting a Linux kernel\n"); | |
| 3471 | - exit(1); | |
| 3472 | - } | |
| 3473 | - snprintf(buf, sizeof(buf), "%s/%s", bios_dir, LINUX_BOOT_FILENAME); | |
| 3474 | - ret = load_image(buf, bootsect); | |
| 3475 | - if (ret != sizeof(bootsect)) { | |
| 3476 | - fprintf(stderr, "qemu: could not load linux boot sector '%s'\n", | |
| 3477 | - buf); | |
| 3478 | - exit(1); | |
| 3479 | - } | |
| 3480 | - | |
| 3481 | - bdrv_set_boot_sector(bs_table[0], bootsect, sizeof(bootsect)); | |
| 3482 | - | |
| 3483 | - /* now we can load the kernel */ | |
| 3484 | - ret = load_kernel(kernel_filename, | |
| 3485 | - phys_ram_base + KERNEL_LOAD_ADDR, | |
| 3486 | - phys_ram_base + KERNEL_PARAMS_ADDR); | |
| 3487 | - if (ret < 0) { | |
| 3488 | - fprintf(stderr, "qemu: could not load kernel '%s'\n", | |
| 3489 | - kernel_filename); | |
| 3490 | - exit(1); | |
| 3491 | - } | |
| 3492 | - | |
| 3493 | - /* load initrd */ | |
| 3494 | - initrd_size = 0; | |
| 3495 | - if (initrd_filename) { | |
| 3496 | - initrd_size = load_image(initrd_filename, phys_ram_base + INITRD_LOAD_ADDR); | |
| 3497 | - if (initrd_size < 0) { | |
| 3498 | - fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", | |
| 3499 | - initrd_filename); | |
| 3500 | - exit(1); | |
| 3501 | - } | |
| 3502 | - } | |
| 3503 | - if (initrd_size > 0) { | |
| 3504 | - stl_raw(phys_ram_base + KERNEL_PARAMS_ADDR + 0x218, INITRD_LOAD_ADDR); | |
| 3505 | - stl_raw(phys_ram_base + KERNEL_PARAMS_ADDR + 0x21c, initrd_size); | |
| 3506 | - } | |
| 3507 | - pstrcpy(phys_ram_base + KERNEL_CMDLINE_ADDR, 4096, | |
| 3508 | - kernel_cmdline); | |
| 3509 | - stw_raw(phys_ram_base + KERNEL_PARAMS_ADDR + 0x20, 0xA33F); | |
| 3510 | - stw_raw(phys_ram_base + KERNEL_PARAMS_ADDR + 0x22, | |
| 3511 | - KERNEL_CMDLINE_ADDR - KERNEL_PARAMS_ADDR); | |
| 3512 | - /* loader type */ | |
| 3513 | - stw_raw(phys_ram_base + KERNEL_PARAMS_ADDR + 0x210, 0x01); | |
| 3514 | - } | |
| 3515 | -#elif defined(TARGET_PPC) | |
| 3516 | - /* allocate ROM */ | |
| 3517 | - // snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME); | |
| 3518 | - snprintf(buf, sizeof(buf), "%s", BIOS_FILENAME); | |
| 3519 | - printf("load BIOS at %p\n", phys_ram_base + 0x000f0000); | |
| 3520 | - ret = load_image(buf, phys_ram_base + 0x000f0000); | |
| 3521 | - if (ret != 0x10000) { | |
| 3522 | - fprintf(stderr, "qemu: could not load PPC bios '%s' (%d)\n%m\n", | |
| 3523 | - buf, ret); | |
| 3524 | - exit(1); | |
| 3525 | - } | |
| 3526 | -#endif | |
| 1172 | + cpu_calibrate_ticks(); | |
| 3527 | 1173 | |
| 3528 | 1174 | /* terminal init */ |
| 3529 | 1175 | if (nographic) { |
| ... | ... | @@ -3535,31 +1181,14 @@ int main(int argc, char **argv) |
| 3535 | 1181 | dumb_display_init(ds); |
| 3536 | 1182 | #endif |
| 3537 | 1183 | } |
| 3538 | - /* init basic PC hardware */ | |
| 3539 | - register_ioport_write(0x80, 1, ioport80_write, 1); | |
| 3540 | 1184 | |
| 3541 | - vga_initialize(ds, phys_ram_base + ram_size, ram_size, | |
| 3542 | - vga_ram_size); | |
| 3543 | -#if defined (TARGET_I386) | |
| 3544 | - cmos_init(); | |
| 3545 | -#endif | |
| 3546 | - pic_init(); | |
| 3547 | - pit_init(); | |
| 3548 | - serial_init(); | |
| 3549 | -#if defined (TARGET_I386) | |
| 3550 | - ne2000_init(); | |
| 3551 | -#endif | |
| 3552 | - ide_init(); | |
| 3553 | - kbd_init(); | |
| 3554 | - AUD_init(); | |
| 3555 | - DMA_init(); | |
| 3556 | -#if defined (TARGET_I386) | |
| 3557 | - SB16_init(); | |
| 3558 | -#endif | |
| 3559 | -#if defined (TARGET_PPC) | |
| 3560 | - PPC_end_init(); | |
| 1185 | +#if defined(TARGET_I386) | |
| 1186 | + pc_init(ram_size, vga_ram_size, boot_device, | |
| 1187 | + ds, fd_filename, snapshot, | |
| 1188 | + kernel_filename, kernel_cmdline, initrd_filename); | |
| 1189 | +#elif defined(TARGET_PPC) | |
| 1190 | + ppc_init(); | |
| 3561 | 1191 | #endif |
| 3562 | - fdctrl_register((unsigned char **)fd_filename, snapshot, boot_device); | |
| 3563 | 1192 | |
| 3564 | 1193 | /* setup cpu signal handlers for MMU / self modifying code handling */ |
| 3565 | 1194 | #if !defined(CONFIG_SOFTMMU) | ... | ... |
vl.h
| ... | ... | @@ -29,21 +29,25 @@ |
| 29 | 29 | /* vl.c */ |
| 30 | 30 | extern int reset_requested; |
| 31 | 31 | extern int64_t ticks_per_sec; |
| 32 | +extern int pit_min_timer_count; | |
| 32 | 33 | |
| 33 | 34 | typedef void (IOPortWriteFunc)(struct CPUState *env, uint32_t address, uint32_t data); |
| 34 | 35 | typedef uint32_t (IOPortReadFunc)(struct CPUState *env, uint32_t address); |
| 35 | 36 | |
| 36 | 37 | int register_ioport_read(int start, int length, IOPortReadFunc *func, int size); |
| 37 | 38 | int register_ioport_write(int start, int length, IOPortWriteFunc *func, int size); |
| 38 | -void pic_set_irq(int irq, int level); | |
| 39 | 39 | int64_t cpu_get_ticks(void); |
| 40 | +uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c); | |
| 40 | 41 | |
| 41 | -void kbd_put_keycode(int keycode); | |
| 42 | +void net_send_packet(int net_fd, const uint8_t *buf, int size); | |
| 42 | 43 | |
| 43 | -#define MOUSE_EVENT_LBUTTON 0x01 | |
| 44 | -#define MOUSE_EVENT_RBUTTON 0x02 | |
| 45 | -#define MOUSE_EVENT_MBUTTON 0x04 | |
| 46 | -void kbd_mouse_event(int dx, int dy, int dz, int buttons_state); | |
| 44 | +void hw_error(const char *fmt, ...); | |
| 45 | + | |
| 46 | +int load_image(const char *filename, uint8_t *addr); | |
| 47 | +extern const char *bios_dir; | |
| 48 | + | |
| 49 | +void pstrcpy(char *buf, int buf_size, const char *str); | |
| 50 | +char *pstrcat(char *buf, int buf_size, const char *s); | |
| 47 | 51 | |
| 48 | 52 | /* block.c */ |
| 49 | 53 | typedef struct BlockDriverState BlockDriverState; |
| ... | ... | @@ -139,4 +143,78 @@ void fdctrl_init (int irq_lvl, int dma_chann, int mem_mapped, uint32_t base, |
| 139 | 143 | char boot_device); |
| 140 | 144 | int fdctrl_disk_change (int idx, const unsigned char *filename, int ro); |
| 141 | 145 | |
| 146 | +/* ne2000.c */ | |
| 147 | + | |
| 148 | +#define MAX_ETH_FRAME_SIZE 1514 | |
| 149 | + | |
| 150 | +void ne2000_init(int base, int irq); | |
| 151 | +int ne2000_can_receive(void); | |
| 152 | +void ne2000_receive(uint8_t *buf, int size); | |
| 153 | + | |
| 154 | +extern int net_fd; | |
| 155 | + | |
| 156 | +/* pckbd.c */ | |
| 157 | + | |
| 158 | +void kbd_put_keycode(int keycode); | |
| 159 | + | |
| 160 | +#define MOUSE_EVENT_LBUTTON 0x01 | |
| 161 | +#define MOUSE_EVENT_RBUTTON 0x02 | |
| 162 | +#define MOUSE_EVENT_MBUTTON 0x04 | |
| 163 | +void kbd_mouse_event(int dx, int dy, int dz, int buttons_state); | |
| 164 | + | |
| 165 | +void kbd_init(void); | |
| 166 | + | |
| 167 | +/* mc146818rtc.c */ | |
| 168 | + | |
| 169 | +typedef struct RTCState { | |
| 170 | + uint8_t cmos_data[128]; | |
| 171 | + uint8_t cmos_index; | |
| 172 | + int irq; | |
| 173 | +} RTCState; | |
| 174 | + | |
| 175 | +extern RTCState rtc_state; | |
| 176 | + | |
| 177 | +void rtc_init(int base, int irq); | |
| 178 | +void rtc_timer(void); | |
| 179 | + | |
| 180 | +/* serial.c */ | |
| 181 | + | |
| 182 | +void serial_init(int base, int irq); | |
| 183 | +int serial_can_receive(void); | |
| 184 | +void serial_receive_byte(int ch); | |
| 185 | +void serial_receive_break(void); | |
| 186 | + | |
| 187 | +/* i8259.c */ | |
| 188 | + | |
| 189 | +void pic_set_irq(int irq, int level); | |
| 190 | +void pic_init(void); | |
| 191 | + | |
| 192 | +/* i8254.c */ | |
| 193 | + | |
| 194 | +#define PIT_FREQ 1193182 | |
| 195 | + | |
| 196 | +typedef struct PITChannelState { | |
| 197 | + int count; /* can be 65536 */ | |
| 198 | + uint16_t latched_count; | |
| 199 | + uint8_t rw_state; | |
| 200 | + uint8_t mode; | |
| 201 | + uint8_t bcd; /* not supported */ | |
| 202 | + uint8_t gate; /* timer start */ | |
| 203 | + int64_t count_load_time; | |
| 204 | + int64_t count_last_edge_check_time; | |
| 205 | +} PITChannelState; | |
| 206 | + | |
| 207 | +extern PITChannelState pit_channels[3]; | |
| 208 | + | |
| 209 | +void pit_init(void); | |
| 210 | +void pit_set_gate(PITChannelState *s, int val); | |
| 211 | +int pit_get_out(PITChannelState *s); | |
| 212 | +int pit_get_out_edges(PITChannelState *s); | |
| 213 | + | |
| 214 | +/* pc.c */ | |
| 215 | +void pc_init(int ram_size, int vga_ram_size, int boot_device, | |
| 216 | + DisplayState *ds, const char **fd_filename, int snapshot, | |
| 217 | + const char *kernel_filename, const char *kernel_cmdline, | |
| 218 | + const char *initrd_filename); | |
| 219 | + | |
| 142 | 220 | #endif /* VL_H */ | ... | ... |