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, | ... | ... |