Loading hw/i8254.c +126 −46 Original line number Diff line number Diff line Loading @@ -43,6 +43,8 @@ #include "cpu.h" #include "vl.h" //#define DEBUG_PIT #define RW_STATE_LSB 0 #define RW_STATE_MSB 1 #define RW_STATE_WORD0 2 Loading @@ -52,12 +54,14 @@ PITChannelState pit_channels[3]; static void pit_irq_timer_update(PITChannelState *s, int64_t current_time); static int pit_get_count(PITChannelState *s) { uint64_t d; int counter; d = muldiv64(cpu_get_ticks() - s->count_load_time, PIT_FREQ, ticks_per_sec); d = muldiv64(qemu_get_clock(vm_clock) - s->count_load_time, PIT_FREQ, ticks_per_sec); switch(s->mode) { case 0: case 1: Loading @@ -77,12 +81,12 @@ static int pit_get_count(PITChannelState *s) } /* get pit output bit */ int pit_get_out(PITChannelState *s) int pit_get_out(PITChannelState *s, int64_t current_time) { uint64_t d; int out; d = muldiv64(cpu_get_ticks() - s->count_load_time, PIT_FREQ, ticks_per_sec); d = muldiv64(current_time - s->count_load_time, PIT_FREQ, ticks_per_sec); switch(s->mode) { default: case 0: Loading @@ -108,53 +112,51 @@ int pit_get_out(PITChannelState *s) return out; } /* get the number of 0 to 1 transitions we had since we call this function */ /* XXX: maybe better to use ticks precision to avoid getting edges twice if checks are done at very small intervals */ int pit_get_out_edges(PITChannelState *s) /* return -1 if no transition will occur. */ static int64_t pit_get_next_transition_time(PITChannelState *s, int64_t current_time) { uint64_t d1, d2; int64_t ticks; int ret, v; uint64_t d, next_time, base; int period2; ticks = cpu_get_ticks(); d1 = muldiv64(s->count_last_edge_check_time - s->count_load_time, PIT_FREQ, ticks_per_sec); d2 = muldiv64(ticks - s->count_load_time, PIT_FREQ, ticks_per_sec); s->count_last_edge_check_time = ticks; d = muldiv64(current_time - s->count_load_time, PIT_FREQ, ticks_per_sec); switch(s->mode) { default: case 0: if (d1 < s->count && d2 >= s->count) ret = 1; else ret = 0; break; case 1: ret = 0; if (d < s->count) next_time = s->count; else return -1; break; case 2: d1 /= s->count; d2 /= s->count; ret = d2 - d1; base = (d / s->count) * s->count; if ((d - base) == 0 && d != 0) next_time = base + s->count; else next_time = base + s->count + 1; break; case 3: v = s->count - ((s->count + 1) >> 1); d1 = (d1 + v) / s->count; d2 = (d2 + v) / s->count; ret = d2 - d1; base = (d / s->count) * s->count; period2 = ((s->count + 1) >> 1); if ((d - base) < period2) next_time = base + period2; else next_time = base + s->count; break; case 4: case 5: if (d1 < s->count && d2 >= s->count) ret = 1; if (d < s->count) next_time = s->count; else if (d == s->count) next_time = s->count + 1; else ret = 0; return -1; break; } return ret; /* convert to timer units */ next_time = s->count_load_time + muldiv64(next_time, ticks_per_sec, PIT_FREQ); return next_time; } /* val must be 0 or 1 */ Loading @@ -170,16 +172,16 @@ void pit_set_gate(PITChannelState *s, int val) case 5: if (s->gate < val) { /* restart counting on rising edge */ s->count_load_time = cpu_get_ticks(); s->count_last_edge_check_time = s->count_load_time; s->count_load_time = qemu_get_clock(vm_clock); pit_irq_timer_update(s, s->count_load_time); } break; case 2: case 3: if (s->gate < val) { /* restart counting on rising edge */ s->count_load_time = cpu_get_ticks(); s->count_last_edge_check_time = s->count_load_time; s->count_load_time = qemu_get_clock(vm_clock); pit_irq_timer_update(s, s->count_load_time); } /* XXX: disable/enable counting */ break; Loading @@ -191,14 +193,9 @@ static inline void pit_load_count(PITChannelState *s, int val) { if (val == 0) val = 0x10000; s->count_load_time = cpu_get_ticks(); s->count_last_edge_check_time = s->count_load_time; s->count_load_time = qemu_get_clock(vm_clock); s->count = val; if (s == &pit_channels[0] && val <= pit_min_timer_count) { fprintf(stderr, "\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", PIT_FREQ / pit_min_timer_count); } pit_irq_timer_update(s, s->count_load_time); } static void pit_ioport_write(void *opaque, uint32_t addr, uint32_t val) Loading @@ -222,6 +219,7 @@ static void pit_ioport_write(void *opaque, uint32_t addr, uint32_t val) s->mode = (val >> 1) & 7; s->bcd = val & 1; s->rw_state = access - 1 + RW_STATE_LSB; /* XXX: update irq timer ? */ break; } } else { Loading Loading @@ -279,18 +277,100 @@ static uint32_t pit_ioport_read(void *opaque, uint32_t addr) return ret; } void pit_init(int base) static void pit_irq_timer_update(PITChannelState *s, int64_t current_time) { int64_t expire_time; int irq_level; if (!s->irq_timer) return; expire_time = pit_get_next_transition_time(s, current_time); irq_level = pit_get_out(s, current_time); pic_set_irq(s->irq, irq_level); #ifdef DEBUG_PIT printf("irq_level=%d next_delay=%f\n", irq_level, (double)(expire_time - current_time) / ticks_per_sec); #endif s->next_transition_time = expire_time; if (expire_time != -1) qemu_mod_timer(s->irq_timer, expire_time); else qemu_del_timer(s->irq_timer); } static void pit_irq_timer(void *opaque) { PITChannelState *s = opaque; pit_irq_timer_update(s, s->next_transition_time); } static void pit_save(QEMUFile *f, void *opaque) { PITChannelState *s; int i; for(i = 0; i < 3; i++) { s = &pit_channels[i]; qemu_put_be32s(f, &s->count); qemu_put_be16s(f, &s->latched_count); qemu_put_8s(f, &s->rw_state); qemu_put_8s(f, &s->mode); qemu_put_8s(f, &s->bcd); qemu_put_8s(f, &s->gate); qemu_put_be64s(f, &s->count_load_time); if (s->irq_timer) { qemu_put_be64s(f, &s->next_transition_time); qemu_put_timer(f, s->irq_timer); } } } static int pit_load(QEMUFile *f, void *opaque, int version_id) { PITChannelState *s; int i; if (version_id != 1) return -EINVAL; for(i = 0; i < 3; i++) { s = &pit_channels[i]; qemu_get_be32s(f, &s->count); qemu_get_be16s(f, &s->latched_count); qemu_get_8s(f, &s->rw_state); qemu_get_8s(f, &s->mode); qemu_get_8s(f, &s->bcd); qemu_get_8s(f, &s->gate); qemu_get_be64s(f, &s->count_load_time); if (s->irq_timer) { qemu_get_be64s(f, &s->next_transition_time); qemu_get_timer(f, s->irq_timer); } } return 0; } void pit_init(int base, int irq) { PITChannelState *s; int i; for(i = 0;i < 3; i++) { s = &pit_channels[i]; if (i == 0) { /* the timer 0 is connected to an IRQ */ s->irq_timer = qemu_new_timer(vm_clock, pit_irq_timer, s); s->irq = irq; } s->mode = 3; s->gate = (i != 2); pit_load_count(s, 0); } register_savevm("i8254", base, 1, pit_save, pit_load, NULL); register_ioport_write(base, 4, 1, pit_ioport_write, NULL); register_ioport_read(base, 3, 1, pit_ioport_read, NULL); } Loading hw/i8259.c +56 −6 Original line number Diff line number Diff line Loading @@ -122,7 +122,7 @@ static int pic_get_irq(PicState *s) /* raise irq to CPU if necessary. must be called every time the active irq may change */ void pic_update_irq(void) static void pic_update_irq(void) { int irq2, irq; Loading Loading @@ -160,7 +160,6 @@ void pic_update_irq(void) #ifdef DEBUG_IRQ_LATENCY int64_t irq_time[16]; int64_t cpu_get_ticks(void); #endif #if defined(DEBUG_PIC) int irq_level[16]; Loading Loading @@ -376,11 +375,62 @@ uint32_t pic_intack_read(CPUState *env) return ret; } static void pic_save(QEMUFile *f, void *opaque) { PicState *s = opaque; qemu_put_8s(f, &s->last_irr); qemu_put_8s(f, &s->irr); qemu_put_8s(f, &s->imr); qemu_put_8s(f, &s->isr); qemu_put_8s(f, &s->priority_add); qemu_put_8s(f, &s->irq_base); qemu_put_8s(f, &s->read_reg_select); qemu_put_8s(f, &s->poll); qemu_put_8s(f, &s->special_mask); qemu_put_8s(f, &s->init_state); qemu_put_8s(f, &s->auto_eoi); qemu_put_8s(f, &s->rotate_on_auto_eoi); qemu_put_8s(f, &s->special_fully_nested_mode); qemu_put_8s(f, &s->init4); } static int pic_load(QEMUFile *f, void *opaque, int version_id) { PicState *s = opaque; if (version_id != 1) return -EINVAL; qemu_get_8s(f, &s->last_irr); qemu_get_8s(f, &s->irr); qemu_get_8s(f, &s->imr); qemu_get_8s(f, &s->isr); qemu_get_8s(f, &s->priority_add); qemu_get_8s(f, &s->irq_base); qemu_get_8s(f, &s->read_reg_select); qemu_get_8s(f, &s->poll); qemu_get_8s(f, &s->special_mask); qemu_get_8s(f, &s->init_state); qemu_get_8s(f, &s->auto_eoi); qemu_get_8s(f, &s->rotate_on_auto_eoi); qemu_get_8s(f, &s->special_fully_nested_mode); qemu_get_8s(f, &s->init4); return 0; } /* XXX: add generic master/slave system */ static void pic_init1(int io_addr, PicState *s) { register_ioport_write(io_addr, 2, 1, pic_ioport_write, s); register_ioport_read(io_addr, 2, 1, pic_ioport_read, s); register_savevm("i8259", io_addr, 1, pic_save, pic_load, s); } void pic_init(void) { register_ioport_write(0x20, 2, 1, pic_ioport_write, &pics[0]); register_ioport_read(0x20, 2, 1, pic_ioport_read, &pics[0]); register_ioport_write(0xa0, 2, 1, pic_ioport_write, &pics[1]); register_ioport_read(0xa0, 2, 1, pic_ioport_read, &pics[1]); pic_init1(0x20, &pics[0]); pic_init1(0xa0, &pics[1]); } hw/ne2000.c +1 −1 Original line number Diff line number Diff line Loading @@ -471,5 +471,5 @@ void ne2000_init(int base, int irq, NetDriverState *nd) ne2000_reset(s); add_fd_read_handler(nd->fd, ne2000_can_receive, ne2000_receive, s); qemu_add_fd_read_handler(nd->fd, ne2000_can_receive, ne2000_receive, s); } hw/pc.c +52 −26 Original line number Diff line number Diff line Loading @@ -58,50 +58,69 @@ int speaker_data_on; int dummy_refresh_clock; static fdctrl_t *floppy_controller; static RTCState *rtc_state; static void ioport80_write(void *opaque, uint32_t addr, uint32_t data) { } /* PC cmos mappings */ #define REG_EQUIPMENT_BYTE 0x14 #define REG_IBM_CENTURY_BYTE 0x32 #define REG_IBM_PS2_CENTURY_BYTE 0x37 static inline int to_bcd(RTCState *s, int a) { return ((a / 10) << 4) | (a % 10); } static void cmos_init(int ram_size, int boot_device) { RTCState *s = &rtc_state; RTCState *s = rtc_state; int val; int fd0, fd1, nb; time_t ti; struct tm *tm; /* various important CMOS locations needed by PC/Bochs bios */ /* set the CMOS date */ time(&ti); tm = gmtime(&ti); rtc_set_date(s, tm); val = to_bcd(s, (tm->tm_year / 100) + 19); rtc_set_memory(s, REG_IBM_CENTURY_BYTE, val); rtc_set_memory(s, REG_IBM_PS2_CENTURY_BYTE, val); s->cmos_data[REG_EQUIPMENT_BYTE] = 0x02; /* FPU is there */ s->cmos_data[REG_EQUIPMENT_BYTE] |= 0x04; /* PS/2 mouse installed */ /* various important CMOS locations needed by PC/Bochs bios */ /* memory size */ val = (ram_size / 1024) - 1024; if (val > 65535) val = 65535; s->cmos_data[0x17] = val; s->cmos_data[0x18] = val >> 8; s->cmos_data[0x30] = val; s->cmos_data[0x31] = val >> 8; rtc_set_memory(s, 0x17, val); rtc_set_memory(s, 0x18, val >> 8); rtc_set_memory(s, 0x30, val); rtc_set_memory(s, 0x31, val >> 8); val = (ram_size / 65536) - ((16 * 1024 * 1024) / 65536); if (val > 65535) val = 65535; s->cmos_data[0x34] = val; s->cmos_data[0x35] = val >> 8; rtc_set_memory(s, 0x34, val); rtc_set_memory(s, 0x35, val >> 8); switch(boot_device) { case 'a': case 'b': s->cmos_data[0x3d] = 0x01; /* floppy boot */ rtc_set_memory(s, 0x3d, 0x01); /* floppy boot */ break; default: case 'c': s->cmos_data[0x3d] = 0x02; /* hard drive boot */ rtc_set_memory(s, 0x3d, 0x02); /* hard drive boot */ break; case 'd': s->cmos_data[0x3d] = 0x03; /* CD-ROM boot */ rtc_set_memory(s, 0x3d, 0x03); /* CD-ROM boot */ break; } Loading @@ -110,35 +129,38 @@ static void cmos_init(int ram_size, int boot_device) fd0 = fdctrl_get_drive_type(floppy_controller, 0); fd1 = fdctrl_get_drive_type(floppy_controller, 1); s->cmos_data[0x10] = 0; val = 0; switch (fd0) { case 0: /* 1.44 Mb 3"5 drive */ s->cmos_data[0x10] |= 0x40; val |= 0x40; break; case 1: /* 2.88 Mb 3"5 drive */ s->cmos_data[0x10] |= 0x60; val |= 0x60; break; case 2: /* 1.2 Mb 5"5 drive */ s->cmos_data[0x10] |= 0x20; val |= 0x20; break; } switch (fd1) { case 0: /* 1.44 Mb 3"5 drive */ s->cmos_data[0x10] |= 0x04; val |= 0x04; break; case 1: /* 2.88 Mb 3"5 drive */ s->cmos_data[0x10] |= 0x06; val |= 0x06; break; case 2: /* 1.2 Mb 5"5 drive */ s->cmos_data[0x10] |= 0x02; val |= 0x02; break; } rtc_set_memory(s, 0x10, val); val = 0; nb = 0; if (fd0 < 3) nb++; Loading @@ -148,12 +170,16 @@ static void cmos_init(int ram_size, int boot_device) case 0: break; case 1: s->cmos_data[REG_EQUIPMENT_BYTE] |= 0x01; /* 1 drive, ready for boot */ val |= 0x01; /* 1 drive, ready for boot */ break; case 2: s->cmos_data[REG_EQUIPMENT_BYTE] |= 0x41; /* 2 drives, ready for boot */ val |= 0x41; /* 2 drives, ready for boot */ break; } val |= 0x02; /* FPU is there */ val |= 0x04; /* PS/2 mouse installed */ rtc_set_memory(s, REG_EQUIPMENT_BYTE, val); } static void speaker_ioport_write(void *opaque, uint32_t addr, uint32_t val) Loading @@ -165,7 +191,7 @@ static void speaker_ioport_write(void *opaque, uint32_t addr, uint32_t val) static uint32_t speaker_ioport_read(void *opaque, uint32_t addr) { int out; out = pit_get_out(&pit_channels[2]); out = pit_get_out(&pit_channels[2], qemu_get_clock(vm_clock)); dummy_refresh_clock ^= 1; return (speaker_data_on << 1) | pit_channels[2].gate | (out << 5) | (dummy_refresh_clock << 4); Loading Loading @@ -345,12 +371,12 @@ void pc_init(int ram_size, int vga_ram_size, int boot_device, vga_initialize(ds, phys_ram_base + ram_size, ram_size, vga_ram_size); rtc_init(0x70, 8); rtc_state = rtc_init(0x70, 8); register_ioport_read(0x61, 1, 1, speaker_ioport_read, NULL); register_ioport_write(0x61, 1, 1, speaker_ioport_write, NULL); pic_init(); pit_init(0x40); pit_init(0x40, 0); fd = serial_open_device(); serial_init(0x3f8, 4, fd); Loading hw/serial.c +1 −1 Original line number Diff line number Diff line Loading @@ -288,7 +288,7 @@ SerialState *serial_init(int base, int irq, int fd) register_ioport_read(base, 8, 1, serial_ioport_read, s); if (fd != 0) { add_fd_read_handler(fd, serial_can_receive1, serial_receive1, s); qemu_add_fd_read_handler(fd, serial_can_receive1, serial_receive1, s); s->out_fd = fd; } else { serial_console = s; Loading Loading
hw/i8254.c +126 −46 Original line number Diff line number Diff line Loading @@ -43,6 +43,8 @@ #include "cpu.h" #include "vl.h" //#define DEBUG_PIT #define RW_STATE_LSB 0 #define RW_STATE_MSB 1 #define RW_STATE_WORD0 2 Loading @@ -52,12 +54,14 @@ PITChannelState pit_channels[3]; static void pit_irq_timer_update(PITChannelState *s, int64_t current_time); static int pit_get_count(PITChannelState *s) { uint64_t d; int counter; d = muldiv64(cpu_get_ticks() - s->count_load_time, PIT_FREQ, ticks_per_sec); d = muldiv64(qemu_get_clock(vm_clock) - s->count_load_time, PIT_FREQ, ticks_per_sec); switch(s->mode) { case 0: case 1: Loading @@ -77,12 +81,12 @@ static int pit_get_count(PITChannelState *s) } /* get pit output bit */ int pit_get_out(PITChannelState *s) int pit_get_out(PITChannelState *s, int64_t current_time) { uint64_t d; int out; d = muldiv64(cpu_get_ticks() - s->count_load_time, PIT_FREQ, ticks_per_sec); d = muldiv64(current_time - s->count_load_time, PIT_FREQ, ticks_per_sec); switch(s->mode) { default: case 0: Loading @@ -108,53 +112,51 @@ int pit_get_out(PITChannelState *s) return out; } /* get the number of 0 to 1 transitions we had since we call this function */ /* XXX: maybe better to use ticks precision to avoid getting edges twice if checks are done at very small intervals */ int pit_get_out_edges(PITChannelState *s) /* return -1 if no transition will occur. */ static int64_t pit_get_next_transition_time(PITChannelState *s, int64_t current_time) { uint64_t d1, d2; int64_t ticks; int ret, v; uint64_t d, next_time, base; int period2; ticks = cpu_get_ticks(); d1 = muldiv64(s->count_last_edge_check_time - s->count_load_time, PIT_FREQ, ticks_per_sec); d2 = muldiv64(ticks - s->count_load_time, PIT_FREQ, ticks_per_sec); s->count_last_edge_check_time = ticks; d = muldiv64(current_time - s->count_load_time, PIT_FREQ, ticks_per_sec); switch(s->mode) { default: case 0: if (d1 < s->count && d2 >= s->count) ret = 1; else ret = 0; break; case 1: ret = 0; if (d < s->count) next_time = s->count; else return -1; break; case 2: d1 /= s->count; d2 /= s->count; ret = d2 - d1; base = (d / s->count) * s->count; if ((d - base) == 0 && d != 0) next_time = base + s->count; else next_time = base + s->count + 1; break; case 3: v = s->count - ((s->count + 1) >> 1); d1 = (d1 + v) / s->count; d2 = (d2 + v) / s->count; ret = d2 - d1; base = (d / s->count) * s->count; period2 = ((s->count + 1) >> 1); if ((d - base) < period2) next_time = base + period2; else next_time = base + s->count; break; case 4: case 5: if (d1 < s->count && d2 >= s->count) ret = 1; if (d < s->count) next_time = s->count; else if (d == s->count) next_time = s->count + 1; else ret = 0; return -1; break; } return ret; /* convert to timer units */ next_time = s->count_load_time + muldiv64(next_time, ticks_per_sec, PIT_FREQ); return next_time; } /* val must be 0 or 1 */ Loading @@ -170,16 +172,16 @@ void pit_set_gate(PITChannelState *s, int val) case 5: if (s->gate < val) { /* restart counting on rising edge */ s->count_load_time = cpu_get_ticks(); s->count_last_edge_check_time = s->count_load_time; s->count_load_time = qemu_get_clock(vm_clock); pit_irq_timer_update(s, s->count_load_time); } break; case 2: case 3: if (s->gate < val) { /* restart counting on rising edge */ s->count_load_time = cpu_get_ticks(); s->count_last_edge_check_time = s->count_load_time; s->count_load_time = qemu_get_clock(vm_clock); pit_irq_timer_update(s, s->count_load_time); } /* XXX: disable/enable counting */ break; Loading @@ -191,14 +193,9 @@ static inline void pit_load_count(PITChannelState *s, int val) { if (val == 0) val = 0x10000; s->count_load_time = cpu_get_ticks(); s->count_last_edge_check_time = s->count_load_time; s->count_load_time = qemu_get_clock(vm_clock); s->count = val; if (s == &pit_channels[0] && val <= pit_min_timer_count) { fprintf(stderr, "\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", PIT_FREQ / pit_min_timer_count); } pit_irq_timer_update(s, s->count_load_time); } static void pit_ioport_write(void *opaque, uint32_t addr, uint32_t val) Loading @@ -222,6 +219,7 @@ static void pit_ioport_write(void *opaque, uint32_t addr, uint32_t val) s->mode = (val >> 1) & 7; s->bcd = val & 1; s->rw_state = access - 1 + RW_STATE_LSB; /* XXX: update irq timer ? */ break; } } else { Loading Loading @@ -279,18 +277,100 @@ static uint32_t pit_ioport_read(void *opaque, uint32_t addr) return ret; } void pit_init(int base) static void pit_irq_timer_update(PITChannelState *s, int64_t current_time) { int64_t expire_time; int irq_level; if (!s->irq_timer) return; expire_time = pit_get_next_transition_time(s, current_time); irq_level = pit_get_out(s, current_time); pic_set_irq(s->irq, irq_level); #ifdef DEBUG_PIT printf("irq_level=%d next_delay=%f\n", irq_level, (double)(expire_time - current_time) / ticks_per_sec); #endif s->next_transition_time = expire_time; if (expire_time != -1) qemu_mod_timer(s->irq_timer, expire_time); else qemu_del_timer(s->irq_timer); } static void pit_irq_timer(void *opaque) { PITChannelState *s = opaque; pit_irq_timer_update(s, s->next_transition_time); } static void pit_save(QEMUFile *f, void *opaque) { PITChannelState *s; int i; for(i = 0; i < 3; i++) { s = &pit_channels[i]; qemu_put_be32s(f, &s->count); qemu_put_be16s(f, &s->latched_count); qemu_put_8s(f, &s->rw_state); qemu_put_8s(f, &s->mode); qemu_put_8s(f, &s->bcd); qemu_put_8s(f, &s->gate); qemu_put_be64s(f, &s->count_load_time); if (s->irq_timer) { qemu_put_be64s(f, &s->next_transition_time); qemu_put_timer(f, s->irq_timer); } } } static int pit_load(QEMUFile *f, void *opaque, int version_id) { PITChannelState *s; int i; if (version_id != 1) return -EINVAL; for(i = 0; i < 3; i++) { s = &pit_channels[i]; qemu_get_be32s(f, &s->count); qemu_get_be16s(f, &s->latched_count); qemu_get_8s(f, &s->rw_state); qemu_get_8s(f, &s->mode); qemu_get_8s(f, &s->bcd); qemu_get_8s(f, &s->gate); qemu_get_be64s(f, &s->count_load_time); if (s->irq_timer) { qemu_get_be64s(f, &s->next_transition_time); qemu_get_timer(f, s->irq_timer); } } return 0; } void pit_init(int base, int irq) { PITChannelState *s; int i; for(i = 0;i < 3; i++) { s = &pit_channels[i]; if (i == 0) { /* the timer 0 is connected to an IRQ */ s->irq_timer = qemu_new_timer(vm_clock, pit_irq_timer, s); s->irq = irq; } s->mode = 3; s->gate = (i != 2); pit_load_count(s, 0); } register_savevm("i8254", base, 1, pit_save, pit_load, NULL); register_ioport_write(base, 4, 1, pit_ioport_write, NULL); register_ioport_read(base, 3, 1, pit_ioport_read, NULL); } Loading
hw/i8259.c +56 −6 Original line number Diff line number Diff line Loading @@ -122,7 +122,7 @@ static int pic_get_irq(PicState *s) /* raise irq to CPU if necessary. must be called every time the active irq may change */ void pic_update_irq(void) static void pic_update_irq(void) { int irq2, irq; Loading Loading @@ -160,7 +160,6 @@ void pic_update_irq(void) #ifdef DEBUG_IRQ_LATENCY int64_t irq_time[16]; int64_t cpu_get_ticks(void); #endif #if defined(DEBUG_PIC) int irq_level[16]; Loading Loading @@ -376,11 +375,62 @@ uint32_t pic_intack_read(CPUState *env) return ret; } static void pic_save(QEMUFile *f, void *opaque) { PicState *s = opaque; qemu_put_8s(f, &s->last_irr); qemu_put_8s(f, &s->irr); qemu_put_8s(f, &s->imr); qemu_put_8s(f, &s->isr); qemu_put_8s(f, &s->priority_add); qemu_put_8s(f, &s->irq_base); qemu_put_8s(f, &s->read_reg_select); qemu_put_8s(f, &s->poll); qemu_put_8s(f, &s->special_mask); qemu_put_8s(f, &s->init_state); qemu_put_8s(f, &s->auto_eoi); qemu_put_8s(f, &s->rotate_on_auto_eoi); qemu_put_8s(f, &s->special_fully_nested_mode); qemu_put_8s(f, &s->init4); } static int pic_load(QEMUFile *f, void *opaque, int version_id) { PicState *s = opaque; if (version_id != 1) return -EINVAL; qemu_get_8s(f, &s->last_irr); qemu_get_8s(f, &s->irr); qemu_get_8s(f, &s->imr); qemu_get_8s(f, &s->isr); qemu_get_8s(f, &s->priority_add); qemu_get_8s(f, &s->irq_base); qemu_get_8s(f, &s->read_reg_select); qemu_get_8s(f, &s->poll); qemu_get_8s(f, &s->special_mask); qemu_get_8s(f, &s->init_state); qemu_get_8s(f, &s->auto_eoi); qemu_get_8s(f, &s->rotate_on_auto_eoi); qemu_get_8s(f, &s->special_fully_nested_mode); qemu_get_8s(f, &s->init4); return 0; } /* XXX: add generic master/slave system */ static void pic_init1(int io_addr, PicState *s) { register_ioport_write(io_addr, 2, 1, pic_ioport_write, s); register_ioport_read(io_addr, 2, 1, pic_ioport_read, s); register_savevm("i8259", io_addr, 1, pic_save, pic_load, s); } void pic_init(void) { register_ioport_write(0x20, 2, 1, pic_ioport_write, &pics[0]); register_ioport_read(0x20, 2, 1, pic_ioport_read, &pics[0]); register_ioport_write(0xa0, 2, 1, pic_ioport_write, &pics[1]); register_ioport_read(0xa0, 2, 1, pic_ioport_read, &pics[1]); pic_init1(0x20, &pics[0]); pic_init1(0xa0, &pics[1]); }
hw/ne2000.c +1 −1 Original line number Diff line number Diff line Loading @@ -471,5 +471,5 @@ void ne2000_init(int base, int irq, NetDriverState *nd) ne2000_reset(s); add_fd_read_handler(nd->fd, ne2000_can_receive, ne2000_receive, s); qemu_add_fd_read_handler(nd->fd, ne2000_can_receive, ne2000_receive, s); }
hw/pc.c +52 −26 Original line number Diff line number Diff line Loading @@ -58,50 +58,69 @@ int speaker_data_on; int dummy_refresh_clock; static fdctrl_t *floppy_controller; static RTCState *rtc_state; static void ioport80_write(void *opaque, uint32_t addr, uint32_t data) { } /* PC cmos mappings */ #define REG_EQUIPMENT_BYTE 0x14 #define REG_IBM_CENTURY_BYTE 0x32 #define REG_IBM_PS2_CENTURY_BYTE 0x37 static inline int to_bcd(RTCState *s, int a) { return ((a / 10) << 4) | (a % 10); } static void cmos_init(int ram_size, int boot_device) { RTCState *s = &rtc_state; RTCState *s = rtc_state; int val; int fd0, fd1, nb; time_t ti; struct tm *tm; /* various important CMOS locations needed by PC/Bochs bios */ /* set the CMOS date */ time(&ti); tm = gmtime(&ti); rtc_set_date(s, tm); val = to_bcd(s, (tm->tm_year / 100) + 19); rtc_set_memory(s, REG_IBM_CENTURY_BYTE, val); rtc_set_memory(s, REG_IBM_PS2_CENTURY_BYTE, val); s->cmos_data[REG_EQUIPMENT_BYTE] = 0x02; /* FPU is there */ s->cmos_data[REG_EQUIPMENT_BYTE] |= 0x04; /* PS/2 mouse installed */ /* various important CMOS locations needed by PC/Bochs bios */ /* memory size */ val = (ram_size / 1024) - 1024; if (val > 65535) val = 65535; s->cmos_data[0x17] = val; s->cmos_data[0x18] = val >> 8; s->cmos_data[0x30] = val; s->cmos_data[0x31] = val >> 8; rtc_set_memory(s, 0x17, val); rtc_set_memory(s, 0x18, val >> 8); rtc_set_memory(s, 0x30, val); rtc_set_memory(s, 0x31, val >> 8); val = (ram_size / 65536) - ((16 * 1024 * 1024) / 65536); if (val > 65535) val = 65535; s->cmos_data[0x34] = val; s->cmos_data[0x35] = val >> 8; rtc_set_memory(s, 0x34, val); rtc_set_memory(s, 0x35, val >> 8); switch(boot_device) { case 'a': case 'b': s->cmos_data[0x3d] = 0x01; /* floppy boot */ rtc_set_memory(s, 0x3d, 0x01); /* floppy boot */ break; default: case 'c': s->cmos_data[0x3d] = 0x02; /* hard drive boot */ rtc_set_memory(s, 0x3d, 0x02); /* hard drive boot */ break; case 'd': s->cmos_data[0x3d] = 0x03; /* CD-ROM boot */ rtc_set_memory(s, 0x3d, 0x03); /* CD-ROM boot */ break; } Loading @@ -110,35 +129,38 @@ static void cmos_init(int ram_size, int boot_device) fd0 = fdctrl_get_drive_type(floppy_controller, 0); fd1 = fdctrl_get_drive_type(floppy_controller, 1); s->cmos_data[0x10] = 0; val = 0; switch (fd0) { case 0: /* 1.44 Mb 3"5 drive */ s->cmos_data[0x10] |= 0x40; val |= 0x40; break; case 1: /* 2.88 Mb 3"5 drive */ s->cmos_data[0x10] |= 0x60; val |= 0x60; break; case 2: /* 1.2 Mb 5"5 drive */ s->cmos_data[0x10] |= 0x20; val |= 0x20; break; } switch (fd1) { case 0: /* 1.44 Mb 3"5 drive */ s->cmos_data[0x10] |= 0x04; val |= 0x04; break; case 1: /* 2.88 Mb 3"5 drive */ s->cmos_data[0x10] |= 0x06; val |= 0x06; break; case 2: /* 1.2 Mb 5"5 drive */ s->cmos_data[0x10] |= 0x02; val |= 0x02; break; } rtc_set_memory(s, 0x10, val); val = 0; nb = 0; if (fd0 < 3) nb++; Loading @@ -148,12 +170,16 @@ static void cmos_init(int ram_size, int boot_device) case 0: break; case 1: s->cmos_data[REG_EQUIPMENT_BYTE] |= 0x01; /* 1 drive, ready for boot */ val |= 0x01; /* 1 drive, ready for boot */ break; case 2: s->cmos_data[REG_EQUIPMENT_BYTE] |= 0x41; /* 2 drives, ready for boot */ val |= 0x41; /* 2 drives, ready for boot */ break; } val |= 0x02; /* FPU is there */ val |= 0x04; /* PS/2 mouse installed */ rtc_set_memory(s, REG_EQUIPMENT_BYTE, val); } static void speaker_ioport_write(void *opaque, uint32_t addr, uint32_t val) Loading @@ -165,7 +191,7 @@ static void speaker_ioport_write(void *opaque, uint32_t addr, uint32_t val) static uint32_t speaker_ioport_read(void *opaque, uint32_t addr) { int out; out = pit_get_out(&pit_channels[2]); out = pit_get_out(&pit_channels[2], qemu_get_clock(vm_clock)); dummy_refresh_clock ^= 1; return (speaker_data_on << 1) | pit_channels[2].gate | (out << 5) | (dummy_refresh_clock << 4); Loading Loading @@ -345,12 +371,12 @@ void pc_init(int ram_size, int vga_ram_size, int boot_device, vga_initialize(ds, phys_ram_base + ram_size, ram_size, vga_ram_size); rtc_init(0x70, 8); rtc_state = rtc_init(0x70, 8); register_ioport_read(0x61, 1, 1, speaker_ioport_read, NULL); register_ioport_write(0x61, 1, 1, speaker_ioport_write, NULL); pic_init(); pit_init(0x40); pit_init(0x40, 0); fd = serial_open_device(); serial_init(0x3f8, 4, fd); Loading
hw/serial.c +1 −1 Original line number Diff line number Diff line Loading @@ -288,7 +288,7 @@ SerialState *serial_init(int base, int irq, int fd) register_ioport_read(base, 8, 1, serial_ioport_read, s); if (fd != 0) { add_fd_read_handler(fd, serial_can_receive1, serial_receive1, s); qemu_add_fd_read_handler(fd, serial_can_receive1, serial_receive1, s); s->out_fd = fd; } else { serial_console = s; Loading