Commit 81732d1926fd50283e12b0abdcbbe8242c8bb29c
1 parent
aa6ad6fe
Implement user mode for timers
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3337 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
3 changed files
with
78 additions
and
21 deletions
hw/slavio_timer.c
| ... | ... | @@ -47,6 +47,8 @@ do { printf("TIMER: " fmt , ##args); } while (0) |
| 47 | 47 | * |
| 48 | 48 | */ |
| 49 | 49 | |
| 50 | +#define MAX_CPUS 16 | |
| 51 | + | |
| 50 | 52 | typedef struct SLAVIO_TIMERState { |
| 51 | 53 | qemu_irq irq; |
| 52 | 54 | ptimer_state *timer; |
| ... | ... | @@ -54,10 +56,13 @@ typedef struct SLAVIO_TIMERState { |
| 54 | 56 | uint64_t limit; |
| 55 | 57 | int stopped; |
| 56 | 58 | int mode; // 0 = processor, 1 = user, 2 = system |
| 59 | + struct SLAVIO_TIMERState *slave[MAX_CPUS]; | |
| 60 | + uint32_t slave_mode; | |
| 57 | 61 | } SLAVIO_TIMERState; |
| 58 | 62 | |
| 59 | 63 | #define TIMER_MAXADDR 0x1f |
| 60 | 64 | #define TIMER_SIZE (TIMER_MAXADDR + 1) |
| 65 | +#define CPU_TIMER_SIZE 0x10 | |
| 61 | 66 | |
| 62 | 67 | // Update count, set irq, update expire_time |
| 63 | 68 | // Convert from ptimer countdown units |
| ... | ... | @@ -120,7 +125,7 @@ static uint32_t slavio_timer_mem_readl(void *opaque, target_phys_addr_t addr) |
| 120 | 125 | break; |
| 121 | 126 | case 4: |
| 122 | 127 | // read user/system mode |
| 123 | - ret = s->mode & 1; | |
| 128 | + ret = s->slave_mode; | |
| 124 | 129 | break; |
| 125 | 130 | default: |
| 126 | 131 | ret = 0; |
| ... | ... | @@ -141,10 +146,20 @@ static void slavio_timer_mem_writel(void *opaque, target_phys_addr_t addr, uint3 |
| 141 | 146 | saddr = (addr & TIMER_MAXADDR) >> 2; |
| 142 | 147 | switch (saddr) { |
| 143 | 148 | case 0: |
| 144 | - // set limit, reset counter | |
| 149 | + if (s->mode == 1) { | |
| 150 | + // set user counter limit MSW, reset counter | |
| 151 | + qemu_irq_lower(s->irq); | |
| 152 | + s->limit &= 0xfffffe00ULL; | |
| 153 | + s->limit |= (uint64_t)val << 32; | |
| 154 | + if (!s->limit) | |
| 155 | + s->limit = 0x7ffffffffffffe00ULL; | |
| 156 | + ptimer_set_limit(s->timer, s->limit >> 9, 1); | |
| 157 | + break; | |
| 158 | + } | |
| 159 | + // set limit, reset counter | |
| 145 | 160 | reload = 1; |
| 146 | - qemu_irq_lower(s->irq); | |
| 147 | - // fall through | |
| 161 | + qemu_irq_lower(s->irq); | |
| 162 | + // fall through | |
| 148 | 163 | case 2: |
| 149 | 164 | // set limit without resetting counter |
| 150 | 165 | s->limit = val & 0x7ffffe00ULL; |
| ... | ... | @@ -152,6 +167,17 @@ static void slavio_timer_mem_writel(void *opaque, target_phys_addr_t addr, uint3 |
| 152 | 167 | s->limit = 0x7ffffe00ULL; |
| 153 | 168 | ptimer_set_limit(s->timer, s->limit >> 9, reload); |
| 154 | 169 | break; |
| 170 | + case 1: | |
| 171 | + // set user counter limit LSW, reset counter | |
| 172 | + if (s->mode == 1) { | |
| 173 | + qemu_irq_lower(s->irq); | |
| 174 | + s->limit &= 0x7fffffff00000000ULL; | |
| 175 | + s->limit |= val & 0xfffffe00ULL; | |
| 176 | + if (!s->limit) | |
| 177 | + s->limit = 0x7ffffffffffffe00ULL; | |
| 178 | + ptimer_set_limit(s->timer, s->limit >> 9, 1); | |
| 179 | + } | |
| 180 | + break; | |
| 155 | 181 | case 3: |
| 156 | 182 | // start/stop user counter |
| 157 | 183 | if (s->mode == 1) { |
| ... | ... | @@ -167,13 +193,24 @@ static void slavio_timer_mem_writel(void *opaque, target_phys_addr_t addr, uint3 |
| 167 | 193 | break; |
| 168 | 194 | case 4: |
| 169 | 195 | // bit 0: user (1) or system (0) counter mode |
| 170 | - if (s->mode == 0 || s->mode == 1) | |
| 171 | - s->mode = val & 1; | |
| 172 | - if (s->mode == 1) { | |
| 173 | - qemu_irq_lower(s->irq); | |
| 174 | - s->limit = -1ULL; | |
| 196 | + { | |
| 197 | + unsigned int i; | |
| 198 | + | |
| 199 | + for (i = 0; i < MAX_CPUS; i++) { | |
| 200 | + if (val & (1 << i)) { | |
| 201 | + qemu_irq_lower(s->slave[i]->irq); | |
| 202 | + s->slave[i]->limit = -1ULL; | |
| 203 | + s->slave[i]->mode = 1; | |
| 204 | + } else { | |
| 205 | + s->slave[i]->mode = 0; | |
| 206 | + } | |
| 207 | + ptimer_stop(s->slave[i]->timer); | |
| 208 | + ptimer_set_limit(s->slave[i]->timer, s->slave[i]->limit >> 9, | |
| 209 | + 1); | |
| 210 | + ptimer_run(s->slave[i]->timer, 0); | |
| 211 | + } | |
| 212 | + s->slave_mode = val & ((1 << MAX_CPUS) - 1); | |
| 175 | 213 | } |
| 176 | - ptimer_set_limit(s->timer, s->limit >> 9, 1); | |
| 177 | 214 | break; |
| 178 | 215 | default: |
| 179 | 216 | break; |
| ... | ... | @@ -240,7 +277,8 @@ static void slavio_timer_reset(void *opaque) |
| 240 | 277 | qemu_irq_lower(s->irq); |
| 241 | 278 | } |
| 242 | 279 | |
| 243 | -void slavio_timer_init(target_phys_addr_t addr, qemu_irq irq, int mode) | |
| 280 | +static SLAVIO_TIMERState *slavio_timer_init(target_phys_addr_t addr, | |
| 281 | + qemu_irq irq, int mode) | |
| 244 | 282 | { |
| 245 | 283 | int slavio_timer_io_memory; |
| 246 | 284 | SLAVIO_TIMERState *s; |
| ... | ... | @@ -248,7 +286,7 @@ void slavio_timer_init(target_phys_addr_t addr, qemu_irq irq, int mode) |
| 248 | 286 | |
| 249 | 287 | s = qemu_mallocz(sizeof(SLAVIO_TIMERState)); |
| 250 | 288 | if (!s) |
| 251 | - return; | |
| 289 | + return s; | |
| 252 | 290 | s->irq = irq; |
| 253 | 291 | s->mode = mode; |
| 254 | 292 | bh = qemu_bh_new(slavio_timer_irq, s); |
| ... | ... | @@ -257,8 +295,29 @@ void slavio_timer_init(target_phys_addr_t addr, qemu_irq irq, int mode) |
| 257 | 295 | |
| 258 | 296 | slavio_timer_io_memory = cpu_register_io_memory(0, slavio_timer_mem_read, |
| 259 | 297 | slavio_timer_mem_write, s); |
| 260 | - cpu_register_physical_memory(addr, TIMER_SIZE, slavio_timer_io_memory); | |
| 298 | + if (mode < 2) | |
| 299 | + cpu_register_physical_memory(addr, CPU_TIMER_SIZE, slavio_timer_io_memory); | |
| 300 | + else | |
| 301 | + cpu_register_physical_memory(addr, TIMER_SIZE, | |
| 302 | + slavio_timer_io_memory); | |
| 261 | 303 | register_savevm("slavio_timer", addr, 2, slavio_timer_save, slavio_timer_load, s); |
| 262 | 304 | qemu_register_reset(slavio_timer_reset, s); |
| 263 | 305 | slavio_timer_reset(s); |
| 306 | + | |
| 307 | + return s; | |
| 308 | +} | |
| 309 | + | |
| 310 | +void slavio_timer_init_all(target_phys_addr_t base, qemu_irq master_irq, | |
| 311 | + qemu_irq *cpu_irqs) | |
| 312 | +{ | |
| 313 | + SLAVIO_TIMERState *master; | |
| 314 | + unsigned int i; | |
| 315 | + | |
| 316 | + master = slavio_timer_init(base + 0x10000ULL, master_irq, 2); | |
| 317 | + | |
| 318 | + for (i = 0; i < MAX_CPUS; i++) { | |
| 319 | + master->slave[i] = slavio_timer_init(base + (target_phys_addr_t) | |
| 320 | + (i * TARGET_PAGE_SIZE), | |
| 321 | + cpu_irqs[i], 0); | |
| 322 | + } | |
| 264 | 323 | } | ... | ... |
hw/sun4m.c
| ... | ... | @@ -380,13 +380,10 @@ static void *sun4m_hw_init(const struct hwdef *hwdef, int RAM_size, |
| 380 | 380 | |
| 381 | 381 | nvram = m48t59_init(slavio_irq[0], hwdef->nvram_base, 0, |
| 382 | 382 | hwdef->nvram_size, 8); |
| 383 | - for (i = 0; i < MAX_CPUS; i++) { | |
| 384 | - slavio_timer_init(hwdef->counter_base + | |
| 385 | - (target_phys_addr_t)(i * TARGET_PAGE_SIZE), | |
| 386 | - slavio_cpu_irq[i], 0); | |
| 387 | - } | |
| 388 | - slavio_timer_init(hwdef->counter_base + 0x10000ULL, | |
| 389 | - slavio_irq[hwdef->clock1_irq], 2); | |
| 383 | + | |
| 384 | + slavio_timer_init_all(hwdef->counter_base, slavio_irq[hwdef->clock1_irq], | |
| 385 | + slavio_cpu_irq); | |
| 386 | + | |
| 390 | 387 | slavio_serial_ms_kbd_init(hwdef->ms_kb_base, slavio_irq[hwdef->ms_kb_irq]); |
| 391 | 388 | // Slavio TTYA (base+4, Linux ttyS0) is the first Qemu serial device |
| 392 | 389 | // Slavio TTYB (base+0, Linux ttyS1) is the second Qemu serial device | ... | ... |
vl.h
| ... | ... | @@ -1287,7 +1287,8 @@ int load_aout(const char *filename, uint8_t *addr); |
| 1287 | 1287 | int load_uboot(const char *filename, target_ulong *ep, int *is_linux); |
| 1288 | 1288 | |
| 1289 | 1289 | /* slavio_timer.c */ |
| 1290 | -void slavio_timer_init(target_phys_addr_t addr, qemu_irq irq, int mode); | |
| 1290 | +void slavio_timer_init_all(target_phys_addr_t base, qemu_irq master_irq, | |
| 1291 | + qemu_irq *cpu_irqs); | |
| 1291 | 1292 | |
| 1292 | 1293 | /* slavio_serial.c */ |
| 1293 | 1294 | SerialState *slavio_serial_init(target_phys_addr_t base, qemu_irq irq, | ... | ... |