Rev 3528 | Go to most recent revision | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 3528 | Rev 3529 | ||
---|---|---|---|
1 | /* |
1 | /* |
2 | * Copyright (c) 2007 Michal Kebrt, Petr Stepan |
2 | * Copyright (c) 2007 Michal Kebrt, Petr Stepan |
3 | * All rights reserved. |
3 | * All rights reserved. |
4 | * |
4 | * |
5 | * Redistribution and use in source and binary forms, with or without |
5 | * Redistribution and use in source and binary forms, with or without |
6 | * modification, are permitted provided that the following conditions |
6 | * modification, are permitted provided that the following conditions |
7 | * are met: |
7 | * are met: |
8 | * |
8 | * |
9 | * - Redistributions of source code must retain the above copyright |
9 | * - Redistributions of source code must retain the above copyright |
10 | * notice, this list of conditions and the following disclaimer. |
10 | * notice, this list of conditions and the following disclaimer. |
11 | * - Redistributions in binary form must reproduce the above copyright |
11 | * - Redistributions in binary form must reproduce the above copyright |
12 | * notice, this list of conditions and the following disclaimer in the |
12 | * notice, this list of conditions and the following disclaimer in the |
13 | * documentation and/or other materials provided with the distribution. |
13 | * documentation and/or other materials provided with the distribution. |
14 | * - The name of the author may not be used to endorse or promote products |
14 | * - The name of the author may not be used to endorse or promote products |
15 | * derived from this software without specific prior written permission. |
15 | * derived from this software without specific prior written permission. |
16 | * |
16 | * |
17 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
17 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
18 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
18 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
19 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
19 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
20 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
20 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
21 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
21 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
22 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
22 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
23 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
23 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
24 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
24 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
25 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
25 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
26 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
26 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
27 | */ |
27 | */ |
28 | 28 | ||
29 | /** @addtogroup arm32qemu_icp |
29 | /** @addtogroup arm32qemu_icp |
30 | * @{ |
30 | * @{ |
31 | */ |
31 | */ |
32 | /** @file |
32 | /** @file |
33 | * @brief QEMU icp drivers. |
33 | * @brief QEMU icp drivers. |
34 | */ |
34 | */ |
35 | 35 | ||
36 | #include <interrupt.h> |
36 | #include <interrupt.h> |
37 | #include <ipc/irq.h> |
37 | #include <ipc/irq.h> |
38 | #include <console/chardev.h> |
38 | #include <console/chardev.h> |
39 | #include <arch/drivers/qemu.h> |
39 | #include <arch/drivers/qemu.h> |
40 | #include <console/console.h> |
40 | #include <console/console.h> |
41 | #include <sysinfo/sysinfo.h> |
41 | #include <sysinfo/sysinfo.h> |
42 | #include <print.h> |
42 | #include <print.h> |
43 | #include <ddi/device.h> |
43 | #include <ddi/device.h> |
44 | #include <mm/page.h> |
44 | #include <mm/page.h> |
45 | #include <arch/machine.h> |
45 | #include <arch/machine.h> |
46 | #include <arch/debug/print.h> |
46 | #include <arch/debug/print.h> |
- | 47 | #include <genarch/fb/fb.h> |
|
- | 48 | #include <genarch/fb/visuals.h> |
|
47 | 49 | ||
48 | /* Addresses of devices. */ |
50 | /* Addresses of devices. */ |
49 | #define QEMU_ICP_VIDEORAM 0x16000000 |
51 | #define QEMU_ICP_VIDEORAM 0x16000000 |
50 | #define QEMU_ICP_KBD 0x18000000 |
52 | #define QEMU_ICP_KBD 0x18000000 |
51 | #define QEMU_ICP_HALT_OFFSET 0x10 |
53 | #define QEMU_ICP_HALT_OFFSET 0x10 |
52 | #define QEMU_ICP_RTC 0x13000000 |
54 | #define QEMU_ICP_RTC 0x13000000 |
53 | #define QEMU_ICP_RTC_FREQ_OFFSET 0x100 |
55 | #define QEMU_ICP_RTC_FREQ_OFFSET 0x100 |
54 | #define QEMU_ICP_RTC_ACK_OFFSET 0x110 |
56 | #define QEMU_ICP_RTC_ACK_OFFSET 0x110 |
55 | #define QEMU_ICP_IRQC 0x14000000 |
57 | #define QEMU_ICP_IRQC 0x14000000 |
56 | #define QEMU_ICP_IRQC_MASK_OFFSET 0x8 |
58 | #define QEMU_ICP_IRQC_MASK_OFFSET 0x8 |
57 | #define QEMU_ICP_IRQC_UNMASK_OFFSET 0xC |
59 | #define QEMU_ICP_IRQC_UNMASK_OFFSET 0xC |
58 | #define QEMU_ICP_MP 0x11000000 |
60 | #define QEMU_ICP_MP 0x11000000 |
59 | #define QEMU_ICP_MP_MEMSIZE_OFFSET 0x0090 |
61 | #define QEMU_ICP_MP_MEMSIZE_OFFSET 0x0090 |
60 | #define QEMU_ICP_FB 0x94000 |
62 | #define QEMU_ICP_FB 0x94000 |
61 | 63 | ||
62 | #define ICP_VGA 0xC0000000 |
64 | #define ICP_VGA 0xC0000000 |
63 | #define ICP_CMCR 0x10000000 |
65 | #define ICP_CMCR 0x10000000 |
64 | 66 | ||
65 | /* IRQs */ |
67 | /* IRQs */ |
66 | #define QEMU_ICP_KBD_IRQ 3 |
68 | #define QEMU_ICP_KBD_IRQ 3 |
67 | #define QEMU_ICP_TIMER_IRQ 5 |
69 | #define QEMU_ICP_TIMER_IRQ 5 |
68 | 70 | ||
69 | static qemu_icp_hw_map_t qemu_icp_hw_map; |
71 | static qemu_icp_hw_map_t qemu_icp_hw_map; |
70 | static chardev_t console; |
72 | static chardev_t console; |
71 | static irq_t qemu_icp_console_irq; |
73 | static irq_t qemu_icp_console_irq; |
72 | static irq_t qemu_icp_timer_irq; |
74 | static irq_t qemu_icp_timer_irq; |
73 | 75 | ||
74 | static bool hw_map_init_called = false; |
76 | static bool hw_map_init_called = false; |
75 | static bool vga_init = false; |
77 | static bool vga_init = false; |
76 | 78 | ||
77 | static void qemu_icp_kbd_enable(chardev_t *dev); |
79 | static void qemu_icp_kbd_enable(chardev_t *dev); |
78 | static void qemu_icp_kbd_disable(chardev_t *dev); |
80 | static void qemu_icp_kbd_disable(chardev_t *dev); |
79 | static void qemu_icp_write(chardev_t *dev, const char ch); |
81 | static void qemu_icp_write(chardev_t *dev, const char ch); |
80 | static char qemu_icp_do_read(chardev_t *dev); |
82 | static char qemu_icp_do_read(chardev_t *dev); |
81 | void icp_vga_init(void); |
83 | void icp_vga_init(void); |
82 | 84 | ||
83 | static chardev_operations_t qemu_icp_ops = { |
85 | static chardev_operations_t qemu_icp_ops = { |
84 | .resume = qemu_icp_kbd_enable, |
86 | .resume = qemu_icp_kbd_enable, |
85 | .suspend = qemu_icp_kbd_disable, |
87 | .suspend = qemu_icp_kbd_disable, |
86 | .write = qemu_icp_write, |
88 | .write = qemu_icp_write, |
87 | .read = qemu_icp_do_read, |
89 | .read = qemu_icp_do_read, |
88 | }; |
90 | }; |
89 | 91 | ||
90 | /** Initializes the vga |
92 | /** Initializes the vga |
91 | * |
93 | * |
92 | */ |
94 | */ |
93 | void icp_vga_init(void) |
95 | void icp_vga_init(void) |
94 | { |
96 | { |
95 | *(uint32_t*)((char *)(qemu_icp_hw_map.cmcr)+0x14) = 0xA05F0000; |
97 | *(uint32_t*)((char *)(qemu_icp_hw_map.cmcr)+0x14) = 0xA05F0000; |
96 | *(uint32_t*)((char *)(qemu_icp_hw_map.cmcr)+0x1C) = 0x12C11000; |
98 | *(uint32_t*)((char *)(qemu_icp_hw_map.cmcr)+0x1C) = 0x12C11000; |
97 | *(uint32_t*)qemu_icp_hw_map.vga = 0x3F1F3F9C; |
99 | *(uint32_t*)qemu_icp_hw_map.vga = 0x3F1F3F9C; |
98 | *(uint32_t*)((char *)(qemu_icp_hw_map.vga) + 0x4) = 0x080B61DF; |
100 | *(uint32_t*)((char *)(qemu_icp_hw_map.vga) + 0x4) = 0x080B61DF; |
99 | *(uint32_t*)((char *)(qemu_icp_hw_map.vga) + 0x8) = 0x067F3800; |
101 | *(uint32_t*)((char *)(qemu_icp_hw_map.vga) + 0x8) = 0x067F3800; |
100 | *(uint32_t*)((char *)(qemu_icp_hw_map.vga) + 0x10) = QEMU_ICP_FB; |
102 | *(uint32_t*)((char *)(qemu_icp_hw_map.vga) + 0x10) = QEMU_ICP_FB; |
101 | *(uint32_t *)((char *)(qemu_icp_hw_map.vga) + 0x1C) = 0x182B; |
103 | *(uint32_t *)((char *)(qemu_icp_hw_map.vga) + 0x1C) = 0x182B; |
102 | *(uint32_t*)((char *)(qemu_icp_hw_map.cmcr)+0xC) = 0x33805000; |
104 | *(uint32_t*)((char *)(qemu_icp_hw_map.cmcr)+0xC) = 0x33805000; |
103 | 105 | ||
104 | } |
106 | } |
105 | 107 | ||
106 | /** Returns the mask of active interrupts. */ |
108 | /** Returns the mask of active interrupts. */ |
107 | static inline uint32_t qemu_icp_irqc_get_sources(void) |
109 | static inline uint32_t qemu_icp_irqc_get_sources(void) |
108 | { |
110 | { |
109 | return *((uint32_t *) qemu_icp_hw_map.irqc); |
111 | return *((uint32_t *) qemu_icp_hw_map.irqc); |
110 | } |
112 | } |
111 | 113 | ||
112 | 114 | ||
113 | /** Masks interrupt. |
115 | /** Masks interrupt. |
114 | * |
116 | * |
115 | * @param irq interrupt number |
117 | * @param irq interrupt number |
116 | */ |
118 | */ |
117 | static inline void qemu_icp_irqc_mask(uint32_t irq) |
119 | static inline void qemu_icp_irqc_mask(uint32_t irq) |
118 | { |
120 | { |
119 | *((uint32_t *) qemu_icp_hw_map.irqc_mask) = irq; |
121 | *((uint32_t *) qemu_icp_hw_map.irqc_mask) = irq; |
120 | } |
122 | } |
121 | 123 | ||
122 | 124 | ||
123 | /** Unmasks interrupt. |
125 | /** Unmasks interrupt. |
124 | * |
126 | * |
125 | * @param irq interrupt number |
127 | * @param irq interrupt number |
126 | */ |
128 | */ |
127 | static inline void qemu_icp_irqc_unmask(uint32_t irq) |
129 | static inline void qemu_icp_irqc_unmask(uint32_t irq) |
128 | { |
130 | { |
129 | *((uint32_t *) qemu_icp_hw_map.irqc_unmask) = irq; |
131 | *((uint32_t *) qemu_icp_hw_map.irqc_unmask) = irq; |
130 | } |
132 | } |
131 | 133 | ||
- | 134 | /** Initializes the icp frame buffer */ |
|
- | 135 | void qemu_icp_fb_init(void) |
|
- | 136 | { |
|
- | 137 | fb_init(qemu_icp_get_fb_address(), 640, 480, 2560, VISUAL_BGR_8_8_8_0); |
|
- | 138 | } |
|
132 | 139 | ||
133 | /** Initializes #qemu_icp_hw_map. */ |
140 | /** Initializes #qemu_icp_hw_map. */ |
134 | void qemu_icp_hw_map_init(void) |
141 | void qemu_icp_hw_map_init(void) |
135 | { |
142 | { |
136 | qemu_icp_hw_map.videoram = hw_map(QEMU_ICP_VIDEORAM, PAGE_SIZE); |
143 | qemu_icp_hw_map.videoram = hw_map(QEMU_ICP_VIDEORAM, PAGE_SIZE); |
137 | qemu_icp_hw_map.kbd = hw_map(QEMU_ICP_KBD, PAGE_SIZE); |
144 | qemu_icp_hw_map.kbd = hw_map(QEMU_ICP_KBD, PAGE_SIZE); |
138 | qemu_icp_hw_map.rtc = hw_map(QEMU_ICP_RTC, PAGE_SIZE); |
145 | qemu_icp_hw_map.rtc = hw_map(QEMU_ICP_RTC, PAGE_SIZE); |
139 | qemu_icp_hw_map.irqc = hw_map(QEMU_ICP_IRQC, PAGE_SIZE); |
146 | qemu_icp_hw_map.irqc = hw_map(QEMU_ICP_IRQC, PAGE_SIZE); |
140 | 147 | ||
141 | qemu_icp_hw_map.rtc_freq = qemu_icp_hw_map.rtc + QEMU_ICP_RTC_FREQ_OFFSET; |
148 | qemu_icp_hw_map.rtc_freq = qemu_icp_hw_map.rtc + QEMU_ICP_RTC_FREQ_OFFSET; |
142 | qemu_icp_hw_map.rtc_ack = qemu_icp_hw_map.rtc + QEMU_ICP_RTC_ACK_OFFSET; |
149 | qemu_icp_hw_map.rtc_ack = qemu_icp_hw_map.rtc + QEMU_ICP_RTC_ACK_OFFSET; |
143 | qemu_icp_hw_map.irqc_mask = qemu_icp_hw_map.irqc + QEMU_ICP_IRQC_MASK_OFFSET; |
150 | qemu_icp_hw_map.irqc_mask = qemu_icp_hw_map.irqc + QEMU_ICP_IRQC_MASK_OFFSET; |
144 | qemu_icp_hw_map.irqc_unmask = qemu_icp_hw_map.irqc + |
151 | qemu_icp_hw_map.irqc_unmask = qemu_icp_hw_map.irqc + |
145 | QEMU_ICP_IRQC_UNMASK_OFFSET; |
152 | QEMU_ICP_IRQC_UNMASK_OFFSET; |
146 | qemu_icp_hw_map.cmcr = hw_map(ICP_CMCR, PAGE_SIZE); |
153 | qemu_icp_hw_map.cmcr = hw_map(ICP_CMCR, PAGE_SIZE); |
147 | qemu_icp_hw_map.vga = hw_map(ICP_VGA, PAGE_SIZE); |
154 | qemu_icp_hw_map.vga = hw_map(ICP_VGA, PAGE_SIZE); |
148 | 155 | ||
149 | //icp_vga_init(); |
156 | //icp_vga_init(); |
150 | 157 | ||
151 | hw_map_init_called = true; |
158 | hw_map_init_called = true; |
152 | } |
159 | } |
153 | 160 | ||
154 | 161 | ||
155 | /** Putchar that works with qemu_icp. |
162 | /** Putchar that works with qemu_icp. |
156 | * |
163 | * |
157 | * @param dev Not used. |
164 | * @param dev Not used. |
158 | * @param ch Characted to be printed. |
165 | * @param ch Characted to be printed. |
159 | */ |
166 | */ |
160 | static void qemu_icp_write(chardev_t *dev, const char ch) |
167 | static void qemu_icp_write(chardev_t *dev, const char ch) |
161 | { |
168 | { |
162 | *((char *) qemu_icp_hw_map.videoram) = ch; |
169 | *((char *) qemu_icp_hw_map.videoram) = ch; |
163 | } |
170 | } |
164 | 171 | ||
165 | /** Enables qemu_icp keyboard (interrupt unmasked). |
172 | /** Enables qemu_icp keyboard (interrupt unmasked). |
166 | * |
173 | * |
167 | * @param dev Not used. |
174 | * @param dev Not used. |
168 | * |
175 | * |
169 | * Called from getc(). |
176 | * Called from getc(). |
170 | */ |
177 | */ |
171 | static void qemu_icp_kbd_enable(chardev_t *dev) |
178 | static void qemu_icp_kbd_enable(chardev_t *dev) |
172 | { |
179 | { |
173 | qemu_icp_irqc_unmask(QEMU_ICP_KBD_IRQ); |
180 | qemu_icp_irqc_unmask(QEMU_ICP_KBD_IRQ); |
174 | } |
181 | } |
175 | 182 | ||
176 | /** Disables qemu_icp keyboard (interrupt masked). |
183 | /** Disables qemu_icp keyboard (interrupt masked). |
177 | * |
184 | * |
178 | * @param dev not used |
185 | * @param dev not used |
179 | * |
186 | * |
180 | * Called from getc(). |
187 | * Called from getc(). |
181 | */ |
188 | */ |
182 | static void qemu_icp_kbd_disable(chardev_t *dev) |
189 | static void qemu_icp_kbd_disable(chardev_t *dev) |
183 | { |
190 | { |
184 | qemu_icp_irqc_mask(QEMU_ICP_KBD_IRQ); |
191 | qemu_icp_irqc_mask(QEMU_ICP_KBD_IRQ); |
185 | } |
192 | } |
186 | 193 | ||
187 | /** Read character using polling, assume interrupts disabled. |
194 | /** Read character using polling, assume interrupts disabled. |
188 | * |
195 | * |
189 | * @param dev Not used. |
196 | * @param dev Not used. |
190 | */ |
197 | */ |
191 | static char qemu_icp_do_read(chardev_t *dev) |
198 | static char qemu_icp_do_read(chardev_t *dev) |
192 | { |
199 | { |
193 | char ch; |
200 | char ch; |
194 | 201 | ||
195 | while (1) { |
202 | while (1) { |
196 | ch = *((volatile char *) qemu_icp_hw_map.kbd); |
203 | ch = *((volatile char *) qemu_icp_hw_map.kbd); |
197 | if (ch) { |
204 | if (ch) { |
198 | if (ch == '\r') |
205 | if (ch == '\r') |
199 | return '\n'; |
206 | return '\n'; |
200 | if (ch == 0x7f) |
207 | if (ch == 0x7f) |
201 | return '\b'; |
208 | return '\b'; |
202 | return ch; |
209 | return ch; |
203 | } |
210 | } |
204 | } |
211 | } |
205 | } |
212 | } |
206 | 213 | ||
207 | /** Process keyboard interrupt. |
214 | /** Process keyboard interrupt. |
208 | * |
215 | * |
209 | * @param irq IRQ information. |
216 | * @param irq IRQ information. |
210 | * @param arg Not used. |
217 | * @param arg Not used. |
211 | */ |
218 | */ |
212 | static void qemu_icp_irq_handler(irq_t *irq, void *arg, ...) |
219 | static void qemu_icp_irq_handler(irq_t *irq, void *arg, ...) |
213 | { |
220 | { |
214 | if ((irq->notif_cfg.notify) && (irq->notif_cfg.answerbox)) { |
221 | if ((irq->notif_cfg.notify) && (irq->notif_cfg.answerbox)) { |
215 | ipc_irq_send_notif(irq); |
222 | ipc_irq_send_notif(irq); |
216 | } else { |
223 | } else { |
217 | char ch = 0; |
224 | char ch = 0; |
218 | 225 | ||
219 | ch = *((char *) qemu_icp_hw_map.kbd); |
226 | ch = *((char *) qemu_icp_hw_map.kbd); |
220 | if (ch == '\r') { |
227 | if (ch == '\r') { |
221 | ch = '\n'; |
228 | ch = '\n'; |
222 | } |
229 | } |
223 | if (ch == 0x7f) { |
230 | if (ch == 0x7f) { |
224 | ch = '\b'; |
231 | ch = '\b'; |
225 | } |
232 | } |
226 | chardev_push_character(&console, ch); |
233 | chardev_push_character(&console, ch); |
227 | } |
234 | } |
228 | } |
235 | } |
229 | 236 | ||
230 | static irq_ownership_t qemu_icp_claim(void) |
237 | static irq_ownership_t qemu_icp_claim(void) |
231 | { |
238 | { |
232 | return IRQ_ACCEPT; |
239 | return IRQ_ACCEPT; |
233 | } |
240 | } |
234 | 241 | ||
235 | 242 | ||
236 | /** Acquire console back for kernel. */ |
243 | /** Acquire console back for kernel. */ |
237 | void qemu_icp_grab_console(void) |
244 | void qemu_icp_grab_console(void) |
238 | { |
245 | { |
239 | ipl_t ipl = interrupts_disable(); |
246 | ipl_t ipl = interrupts_disable(); |
240 | spinlock_lock(&qemu_icp_console_irq.lock); |
247 | spinlock_lock(&qemu_icp_console_irq.lock); |
241 | qemu_icp_console_irq.notif_cfg.notify = false; |
248 | qemu_icp_console_irq.notif_cfg.notify = false; |
242 | spinlock_unlock(&qemu_icp_console_irq.lock); |
249 | spinlock_unlock(&qemu_icp_console_irq.lock); |
243 | interrupts_restore(ipl); |
250 | interrupts_restore(ipl); |
244 | } |
251 | } |
245 | 252 | ||
246 | /** Return console to userspace. */ |
253 | /** Return console to userspace. */ |
247 | void qemu_icp_release_console(void) |
254 | void qemu_icp_release_console(void) |
248 | { |
255 | { |
249 | ipl_t ipl = interrupts_disable(); |
256 | ipl_t ipl = interrupts_disable(); |
250 | spinlock_lock(&qemu_icp_console_irq.lock); |
257 | spinlock_lock(&qemu_icp_console_irq.lock); |
251 | if (qemu_icp_console_irq.notif_cfg.answerbox) { |
258 | if (qemu_icp_console_irq.notif_cfg.answerbox) { |
252 | qemu_icp_console_irq.notif_cfg.notify = true; |
259 | qemu_icp_console_irq.notif_cfg.notify = true; |
253 | } |
260 | } |
254 | spinlock_unlock(&qemu_icp_console_irq.lock); |
261 | spinlock_unlock(&qemu_icp_console_irq.lock); |
255 | interrupts_restore(ipl); |
262 | interrupts_restore(ipl); |
256 | } |
263 | } |
257 | 264 | ||
258 | /** Initializes console object representing qemu_icp console. |
265 | /** Initializes console object representing qemu_icp console. |
259 | * |
266 | * |
260 | * @param devno device number. |
267 | * @param devno device number. |
261 | */ |
268 | */ |
262 | void qemu_icp_console_init(devno_t devno) |
269 | void qemu_icp_console_init(devno_t devno) |
263 | { |
270 | { |
264 | chardev_initialize("qemu_icp_console", &console, &qemu_icp_ops); |
271 | chardev_initialize("qemu_icp_console", &console, &qemu_icp_ops); |
265 | stdin = &console; |
272 | stdin = &console; |
266 | stdout = &console; |
273 | stdout = &console; |
267 | 274 | ||
268 | irq_initialize(&qemu_icp_console_irq); |
275 | irq_initialize(&qemu_icp_console_irq); |
269 | qemu_icp_console_irq.devno = devno; |
276 | qemu_icp_console_irq.devno = devno; |
270 | qemu_icp_console_irq.inr = QEMU_ICP_KBD_IRQ; |
277 | qemu_icp_console_irq.inr = QEMU_ICP_KBD_IRQ; |
271 | qemu_icp_console_irq.claim = qemu_icp_claim; |
278 | qemu_icp_console_irq.claim = qemu_icp_claim; |
272 | qemu_icp_console_irq.handler = qemu_icp_irq_handler; |
279 | qemu_icp_console_irq.handler = qemu_icp_irq_handler; |
273 | irq_register(&qemu_icp_console_irq); |
280 | irq_register(&qemu_icp_console_irq); |
274 | 281 | ||
275 | qemu_icp_irqc_unmask(QEMU_ICP_KBD_IRQ); |
282 | qemu_icp_irqc_unmask(QEMU_ICP_KBD_IRQ); |
276 | 283 | ||
277 | sysinfo_set_item_val("kbd", NULL, true); |
284 | sysinfo_set_item_val("kbd", NULL, true); |
278 | sysinfo_set_item_val("kbd.devno", NULL, devno); |
285 | sysinfo_set_item_val("kbd.devno", NULL, devno); |
279 | sysinfo_set_item_val("kbd.inr", NULL, QEMU_ICP_KBD_IRQ); |
286 | sysinfo_set_item_val("kbd.inr", NULL, QEMU_ICP_KBD_IRQ); |
280 | sysinfo_set_item_val("kbd.address.virtual", NULL, qemu_icp_hw_map.kbd); |
287 | sysinfo_set_item_val("kbd.address.virtual", NULL, qemu_icp_hw_map.kbd); |
281 | } |
288 | } |
282 | 289 | ||
283 | /** Starts qemu_icp Real Time Clock device, which asserts regular interrupts. |
290 | /** Starts qemu_icp Real Time Clock device, which asserts regular interrupts. |
284 | * |
291 | * |
285 | * @param frequency Interrupts frequency (0 disables RTC). |
292 | * @param frequency Interrupts frequency (0 disables RTC). |
286 | */ |
293 | */ |
287 | static void qemu_icp_timer_start(uint32_t frequency) |
294 | static void qemu_icp_timer_start(uint32_t frequency) |
288 | { |
295 | { |
289 | *((uint32_t*) qemu_icp_hw_map.rtc_freq) = frequency; |
296 | *((uint32_t*) qemu_icp_hw_map.rtc_freq) = frequency; |
290 | } |
297 | } |
291 | 298 | ||
292 | static irq_ownership_t qemu_icp_timer_claim(void) |
299 | static irq_ownership_t qemu_icp_timer_claim(void) |
293 | { |
300 | { |
294 | return IRQ_ACCEPT; |
301 | return IRQ_ACCEPT; |
295 | } |
302 | } |
296 | 303 | ||
297 | /** Timer interrupt handler. |
304 | /** Timer interrupt handler. |
298 | * |
305 | * |
299 | * @param irq Interrupt information. |
306 | * @param irq Interrupt information. |
300 | * @param arg Not used. |
307 | * @param arg Not used. |
301 | */ |
308 | */ |
302 | static void qemu_icp_timer_irq_handler(irq_t *irq, void *arg, ...) |
309 | static void qemu_icp_timer_irq_handler(irq_t *irq, void *arg, ...) |
303 | { |
310 | { |
304 | /* |
311 | /* |
305 | * We are holding a lock which prevents preemption. |
312 | * We are holding a lock which prevents preemption. |
306 | * Release the lock, call clock() and reacquire the lock again. |
313 | * Release the lock, call clock() and reacquire the lock again. |
307 | */ |
314 | */ |
308 | spinlock_unlock(&irq->lock); |
315 | spinlock_unlock(&irq->lock); |
309 | clock(); |
316 | clock(); |
310 | spinlock_lock(&irq->lock); |
317 | spinlock_lock(&irq->lock); |
311 | 318 | ||
312 | /* acknowledge tick */ |
319 | /* acknowledge tick */ |
313 | *((uint32_t*) qemu_icp_hw_map.rtc_ack) = 0; |
320 | *((uint32_t*) qemu_icp_hw_map.rtc_ack) = 0; |
314 | } |
321 | } |
315 | 322 | ||
316 | /** Initializes and registers timer interrupt handler. */ |
323 | /** Initializes and registers timer interrupt handler. */ |
317 | static void qemu_icp_timer_irq_init(void) |
324 | static void qemu_icp_timer_irq_init(void) |
318 | { |
325 | { |
319 | irq_initialize(&qemu_icp_timer_irq); |
326 | irq_initialize(&qemu_icp_timer_irq); |
320 | qemu_icp_timer_irq.devno = device_assign_devno(); |
327 | qemu_icp_timer_irq.devno = device_assign_devno(); |
321 | qemu_icp_timer_irq.inr = QEMU_ICP_TIMER_IRQ; |
328 | qemu_icp_timer_irq.inr = QEMU_ICP_TIMER_IRQ; |
322 | qemu_icp_timer_irq.claim = qemu_icp_timer_claim; |
329 | qemu_icp_timer_irq.claim = qemu_icp_timer_claim; |
323 | qemu_icp_timer_irq.handler = qemu_icp_timer_irq_handler; |
330 | qemu_icp_timer_irq.handler = qemu_icp_timer_irq_handler; |
324 | 331 | ||
325 | irq_register(&qemu_icp_timer_irq); |
332 | irq_register(&qemu_icp_timer_irq); |
326 | } |
333 | } |
327 | 334 | ||
328 | 335 | ||
329 | /** Starts timer. |
336 | /** Starts timer. |
330 | * |
337 | * |
331 | * Initiates regular timer interrupts after initializing |
338 | * Initiates regular timer interrupts after initializing |
332 | * corresponding interrupt handler. |
339 | * corresponding interrupt handler. |
333 | */ |
340 | */ |
334 | void qemu_icp_timer_irq_start(void) |
341 | void qemu_icp_timer_irq_start(void) |
335 | { |
342 | { |
336 | qemu_icp_timer_irq_init(); |
343 | qemu_icp_timer_irq_init(); |
337 | qemu_icp_timer_start(QEMU_ICP_TIMER_FREQ); |
344 | qemu_icp_timer_start(QEMU_ICP_TIMER_FREQ); |
338 | } |
345 | } |
339 | 346 | ||
340 | /** Returns the size of emulated memory. |
347 | /** Returns the size of emulated memory. |
341 | * |
348 | * |
342 | * @return Size in bytes. |
349 | * @return Size in bytes. |
343 | */ |
350 | */ |
344 | size_t qemu_icp_get_memory_size(void) |
351 | size_t qemu_icp_get_memory_size(void) |
345 | { |
352 | { |
346 | //return *((int *) (QEMU_ICP_MP + QEMU_ICP_MP_MEMSIZE_OFFSET)); |
353 | //return *((int *) (QEMU_ICP_MP + QEMU_ICP_MP_MEMSIZE_OFFSET)); |
347 | return 0x2000000; |
354 | return 0x2000000; |
348 | } |
355 | } |
349 | 356 | ||
350 | /** Prints a character. |
357 | /** Prints a character. |
351 | * |
358 | * |
352 | * @param ch Character to be printed. |
359 | * @param ch Character to be printed. |
353 | */ |
360 | */ |
354 | void qemu_icp_debug_putc(char ch) |
361 | void qemu_icp_debug_putc(char ch) |
355 | { |
362 | { |
356 | char *addr = 0; |
363 | char *addr = 0; |
357 | if (!hw_map_init_called) { |
364 | if (!hw_map_init_called) { |
358 | addr = (char *) QEMU_ICP_KBD; |
365 | addr = (char *) QEMU_ICP_KBD; |
359 | } else { |
366 | } else { |
360 | addr = (char *) qemu_icp_hw_map.videoram; |
367 | addr = (char *) qemu_icp_hw_map.videoram; |
361 | } |
368 | } |
362 | 369 | ||
363 | if (ch == '\n') |
370 | if (ch == '\n') |
364 | *(addr) = '\r'; |
371 | *(addr) = '\r'; |
365 | *(addr) = ch; |
372 | *(addr) = ch; |
366 | } |
373 | } |
367 | 374 | ||
368 | /** Stops qemu_icp. */ |
375 | /** Stops qemu_icp. */ |
369 | void qemu_icp_cpu_halt(void) |
376 | void qemu_icp_cpu_halt(void) |
370 | { |
377 | { |
371 | char * addr = 0; |
378 | char * addr = 0; |
372 | if (!hw_map_init_called) { |
379 | if (!hw_map_init_called) { |
373 | addr = (char *) QEMU_ICP_KBD; |
380 | addr = (char *) QEMU_ICP_KBD; |
374 | } else { |
381 | } else { |
375 | addr = (char *) qemu_icp_hw_map.videoram; |
382 | addr = (char *) qemu_icp_hw_map.videoram; |
376 | } |
383 | } |
377 | 384 | ||
378 | *(addr + QEMU_ICP_HALT_OFFSET) = '\0'; |
385 | *(addr + QEMU_ICP_HALT_OFFSET) = '\0'; |
379 | } |
386 | } |
380 | 387 | ||
381 | /** Gxemul specific interrupt exception handler. |
388 | /** Gxemul specific interrupt exception handler. |
382 | * |
389 | * |
383 | * Determines sources of the interrupt from interrupt controller and |
390 | * Determines sources of the interrupt from interrupt controller and |
384 | * calls high-level handlers for them. |
391 | * calls high-level handlers for them. |
385 | * |
392 | * |
386 | * @param exc_no Interrupt exception number. |
393 | * @param exc_no Interrupt exception number. |
387 | * @param istate Saved processor state. |
394 | * @param istate Saved processor state. |
388 | */ |
395 | */ |
389 | void qemu_icp_irq_exception(int exc_no, istate_t *istate) |
396 | void qemu_icp_irq_exception(int exc_no, istate_t *istate) |
390 | { |
397 | { |
391 | uint32_t sources = qemu_icp_irqc_get_sources(); |
398 | uint32_t sources = qemu_icp_irqc_get_sources(); |
392 | int i; |
399 | int i; |
393 | 400 | ||
394 | for (i = 0; i < QEMU_ICP_IRQC_MAX_IRQ; i++) { |
401 | for (i = 0; i < QEMU_ICP_IRQC_MAX_IRQ; i++) { |
395 | if (sources & (1 << i)) { |
402 | if (sources & (1 << i)) { |
396 | irq_t *irq = irq_dispatch_and_lock(i); |
403 | irq_t *irq = irq_dispatch_and_lock(i); |
397 | if (irq) { |
404 | if (irq) { |
398 | /* The IRQ handler was found. */ |
405 | /* The IRQ handler was found. */ |
399 | irq->handler(irq, irq->arg); |
406 | irq->handler(irq, irq->arg); |
400 | spinlock_unlock(&irq->lock); |
407 | spinlock_unlock(&irq->lock); |
401 | } else { |
408 | } else { |
402 | /* Spurious interrupt.*/ |
409 | /* Spurious interrupt.*/ |
403 | dprintf("cpu%d: spurious interrupt (inum=%d)\n", |
410 | dprintf("cpu%d: spurious interrupt (inum=%d)\n", |
404 | CPU->id, i); |
411 | CPU->id, i); |
405 | } |
412 | } |
406 | } |
413 | } |
407 | } |
414 | } |
408 | } |
415 | } |
409 | 416 | ||
410 | /** Returns address of framebuffer device. |
417 | /** Returns address of framebuffer device. |
411 | * |
418 | * |
412 | * @return Address of framebuffer device. |
419 | * @return Address of framebuffer device. |
413 | */ |
420 | */ |
414 | uintptr_t qemu_icp_get_fb_address(void) |
421 | uintptr_t qemu_icp_get_fb_address(void) |
415 | { |
422 | { |
416 | if (!vga_init) { |
423 | if (!vga_init) { |
417 | icp_vga_init(); |
424 | icp_vga_init(); |
418 | vga_init = true; |
425 | vga_init = true; |
419 | } |
426 | } |
420 | return (uintptr_t) QEMU_ICP_FB; |
427 | return (uintptr_t) QEMU_ICP_FB; |
421 | } |
428 | } |
422 | 429 | ||
423 | 430 | ||
424 | /** @} |
431 | /** @} |
425 | */ |
432 | */ |
426 | 433 |