Rev 3529 | Go to most recent revision | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 3529 | Rev 3759 | ||
---|---|---|---|
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> |
47 | #include <genarch/fb/fb.h> |
48 | #include <genarch/fb/visuals.h> |
48 | #include <genarch/fb/visuals.h> |
49 | 49 | ||
50 | /* Addresses of devices. */ |
50 | /* Addresses of devices. */ |
51 | #define QEMU_ICP_VIDEORAM 0x16000000 |
51 | #define QEMU_ICP_VIDEORAM 0x16000000 |
52 | #define QEMU_ICP_KBD 0x18000000 |
52 | #define QEMU_ICP_KBD 0x18000000 |
53 | #define QEMU_ICP_HALT_OFFSET 0x10 |
53 | #define QEMU_ICP_HALT_OFFSET 0x10 |
54 | #define QEMU_ICP_RTC 0x13000000 |
54 | #define QEMU_ICP_RTC 0x13000000 |
55 | #define QEMU_ICP_RTC_FREQ_OFFSET 0x100 |
55 | #define QEMU_ICP_RTC_FREQ_OFFSET 0x100 |
56 | #define QEMU_ICP_RTC_ACK_OFFSET 0x110 |
56 | #define QEMU_ICP_RTC_ACK_OFFSET 0x110 |
57 | #define QEMU_ICP_IRQC 0x14000000 |
57 | #define QEMU_ICP_IRQC 0x14000000 |
58 | #define QEMU_ICP_IRQC_MASK_OFFSET 0x8 |
58 | #define QEMU_ICP_IRQC_MASK_OFFSET 0xC |
59 | #define QEMU_ICP_IRQC_UNMASK_OFFSET 0xC |
59 | #define QEMU_ICP_IRQC_UNMASK_OFFSET 0x8 |
60 | #define QEMU_ICP_MP 0x11000000 |
60 | #define QEMU_ICP_MP 0x11000000 |
61 | #define QEMU_ICP_MP_MEMSIZE_OFFSET 0x0090 |
61 | #define QEMU_ICP_MP_MEMSIZE_OFFSET 0x0090 |
62 | #define QEMU_ICP_FB 0x94000 |
62 | #define QEMU_ICP_FB 0x94000 |
63 | 63 | ||
64 | #define ICP_VGA 0xC0000000 |
64 | #define ICP_VGA 0xC0000000 |
65 | #define ICP_CMCR 0x10000000 |
65 | #define ICP_CMCR 0x10000000 |
66 | 66 | ||
67 | /* IRQs */ |
67 | /* IRQs */ |
68 | #define QEMU_ICP_KBD_IRQ 3 |
68 | #define QEMU_ICP_KBD_IRQ 0x03 |
69 | #define QEMU_ICP_TIMER_IRQ 5 |
69 | #define QEMU_ICP_TIMER_IRQ 0x05 |
70 | 70 | ||
71 | static qemu_icp_hw_map_t qemu_icp_hw_map; |
71 | static qemu_icp_hw_map_t qemu_icp_hw_map; |
72 | static chardev_t console; |
72 | static chardev_t console; |
73 | static irq_t qemu_icp_console_irq; |
73 | static irq_t qemu_icp_console_irq; |
74 | static irq_t qemu_icp_timer_irq; |
74 | static irq_t qemu_icp_timer_irq; |
75 | 75 | ||
76 | static bool hw_map_init_called = false; |
76 | static bool hw_map_init_called = false; |
77 | static bool vga_init = false; |
77 | static bool vga_init = false; |
78 | 78 | ||
79 | static void qemu_icp_kbd_enable(chardev_t *dev); |
79 | static void qemu_icp_kbd_enable(chardev_t *dev); |
80 | static void qemu_icp_kbd_disable(chardev_t *dev); |
80 | static void qemu_icp_kbd_disable(chardev_t *dev); |
81 | static void qemu_icp_write(chardev_t *dev, const char ch); |
81 | static void qemu_icp_write(chardev_t *dev, const char ch); |
82 | static char qemu_icp_do_read(chardev_t *dev); |
82 | static char qemu_icp_do_read(chardev_t *dev); |
83 | void icp_vga_init(void); |
83 | void icp_vga_init(void); |
84 | 84 | ||
85 | static chardev_operations_t qemu_icp_ops = { |
85 | static chardev_operations_t qemu_icp_ops = { |
86 | .resume = qemu_icp_kbd_enable, |
86 | .resume = qemu_icp_kbd_enable, |
87 | .suspend = qemu_icp_kbd_disable, |
87 | .suspend = qemu_icp_kbd_disable, |
88 | .write = qemu_icp_write, |
88 | .write = qemu_icp_write, |
89 | .read = qemu_icp_do_read, |
89 | .read = qemu_icp_do_read, |
90 | }; |
90 | }; |
91 | 91 | ||
92 | /** Initializes the vga |
92 | /** Initializes the vga |
93 | * |
93 | * |
94 | */ |
94 | */ |
95 | void icp_vga_init(void) |
95 | void icp_vga_init(void) |
96 | { |
96 | { |
97 | *(uint32_t*)((char *)(qemu_icp_hw_map.cmcr)+0x14) = 0xA05F0000; |
97 | *(uint32_t*)((char *)(qemu_icp_hw_map.cmcr)+0x14) = 0xA05F0000; |
98 | *(uint32_t*)((char *)(qemu_icp_hw_map.cmcr)+0x1C) = 0x12C11000; |
98 | *(uint32_t*)((char *)(qemu_icp_hw_map.cmcr)+0x1C) = 0x12C11000; |
99 | *(uint32_t*)qemu_icp_hw_map.vga = 0x3F1F3F9C; |
99 | *(uint32_t*)qemu_icp_hw_map.vga = 0x3F1F3F9C; |
100 | *(uint32_t*)((char *)(qemu_icp_hw_map.vga) + 0x4) = 0x080B61DF; |
100 | *(uint32_t*)((char *)(qemu_icp_hw_map.vga) + 0x4) = 0x080B61DF; |
101 | *(uint32_t*)((char *)(qemu_icp_hw_map.vga) + 0x8) = 0x067F3800; |
101 | *(uint32_t*)((char *)(qemu_icp_hw_map.vga) + 0x8) = 0x067F3800; |
102 | *(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; |
103 | *(uint32_t *)((char *)(qemu_icp_hw_map.vga) + 0x1C) = 0x182B; |
103 | *(uint32_t *)((char *)(qemu_icp_hw_map.vga) + 0x1C) = 0x182B; |
104 | *(uint32_t*)((char *)(qemu_icp_hw_map.cmcr)+0xC) = 0x33805000; |
104 | *(uint32_t*)((char *)(qemu_icp_hw_map.cmcr)+0xC) = 0x33805000; |
105 | 105 | ||
106 | } |
106 | } |
107 | 107 | ||
108 | /** Returns the mask of active interrupts. */ |
108 | /** Returns the mask of active interrupts. */ |
109 | static inline uint32_t qemu_icp_irqc_get_sources(void) |
109 | static inline uint32_t qemu_icp_irqc_get_sources(void) |
110 | { |
110 | { |
111 | return *((uint32_t *) qemu_icp_hw_map.irqc); |
111 | return *((uint32_t *) qemu_icp_hw_map.irqc); |
112 | } |
112 | } |
113 | 113 | ||
114 | 114 | ||
115 | /** Masks interrupt. |
115 | /** Masks interrupt. |
116 | * |
116 | * |
117 | * @param irq interrupt number |
117 | * @param irq interrupt number |
118 | */ |
118 | */ |
119 | static inline void qemu_icp_irqc_mask(uint32_t irq) |
119 | static inline void qemu_icp_irqc_mask(uint32_t irq) |
120 | { |
120 | { |
121 | *((uint32_t *) qemu_icp_hw_map.irqc_mask) = irq; |
121 | *((uint32_t *) qemu_icp_hw_map.irqc_mask) = irq; |
122 | } |
122 | } |
123 | 123 | ||
124 | 124 | ||
125 | /** Unmasks interrupt. |
125 | /** Unmasks interrupt. |
126 | * |
126 | * |
127 | * @param irq interrupt number |
127 | * @param irq interrupt number |
128 | */ |
128 | */ |
129 | static inline void qemu_icp_irqc_unmask(uint32_t irq) |
129 | static inline void qemu_icp_irqc_unmask(uint32_t irq) |
130 | { |
130 | { |
131 | *((uint32_t *) qemu_icp_hw_map.irqc_unmask) = irq; |
131 | *((uint32_t *) qemu_icp_hw_map.irqc_unmask) |= irq; |
132 | } |
132 | } |
133 | 133 | ||
134 | /** Initializes the icp frame buffer */ |
134 | /** Initializes the icp frame buffer */ |
135 | void qemu_icp_fb_init(void) |
135 | void qemu_icp_fb_init(void) |
136 | { |
136 | { |
137 | fb_init(qemu_icp_get_fb_address(), 640, 480, 2560, VISUAL_BGR_8_8_8_0); |
137 | fb_init(qemu_icp_get_fb_address(), 640, 480, 2560, VISUAL_BGR_8_8_8_0); |
138 | } |
138 | } |
139 | 139 | ||
140 | /** Initializes #qemu_icp_hw_map. */ |
140 | /** Initializes #qemu_icp_hw_map. */ |
141 | void qemu_icp_hw_map_init(void) |
141 | void qemu_icp_hw_map_init(void) |
142 | { |
142 | { |
143 | 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); |
144 | 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); |
145 | 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); |
146 | 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); |
147 | 147 | ||
148 | 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; |
149 | 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; |
150 | 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; |
151 | qemu_icp_hw_map.irqc_unmask = qemu_icp_hw_map.irqc + |
151 | qemu_icp_hw_map.irqc_unmask = qemu_icp_hw_map.irqc + |
152 | QEMU_ICP_IRQC_UNMASK_OFFSET; |
152 | QEMU_ICP_IRQC_UNMASK_OFFSET; |
153 | qemu_icp_hw_map.cmcr = hw_map(ICP_CMCR, PAGE_SIZE); |
153 | qemu_icp_hw_map.cmcr = hw_map(ICP_CMCR, PAGE_SIZE); |
154 | qemu_icp_hw_map.vga = hw_map(ICP_VGA, PAGE_SIZE); |
154 | qemu_icp_hw_map.vga = hw_map(ICP_VGA, PAGE_SIZE); |
155 | 155 | ||
156 | //icp_vga_init(); |
156 | //icp_vga_init(); |
157 | 157 | ||
158 | hw_map_init_called = true; |
158 | hw_map_init_called = true; |
159 | } |
159 | } |
160 | 160 | ||
161 | 161 | ||
162 | /** Putchar that works with qemu_icp. |
162 | /** Putchar that works with qemu_icp. |
163 | * |
163 | * |
164 | * @param dev Not used. |
164 | * @param dev Not used. |
165 | * @param ch Characted to be printed. |
165 | * @param ch Characted to be printed. |
166 | */ |
166 | */ |
167 | static void qemu_icp_write(chardev_t *dev, const char ch) |
167 | static void qemu_icp_write(chardev_t *dev, const char ch) |
168 | { |
168 | { |
169 | *((char *) qemu_icp_hw_map.videoram) = ch; |
169 | *((char *) qemu_icp_hw_map.videoram) = ch; |
170 | } |
170 | } |
171 | 171 | ||
172 | /** Enables qemu_icp keyboard (interrupt unmasked). |
172 | /** Enables qemu_icp keyboard (interrupt unmasked). |
173 | * |
173 | * |
174 | * @param dev Not used. |
174 | * @param dev Not used. |
175 | * |
175 | * |
176 | * Called from getc(). |
176 | * Called from getc(). |
177 | */ |
177 | */ |
178 | static void qemu_icp_kbd_enable(chardev_t *dev) |
178 | static void qemu_icp_kbd_enable(chardev_t *dev) |
179 | { |
179 | { |
180 | qemu_icp_irqc_unmask(QEMU_ICP_KBD_IRQ); |
180 | qemu_icp_irqc_unmask(QEMU_ICP_KBD_IRQ); |
181 | } |
181 | } |
182 | 182 | ||
183 | /** Disables qemu_icp keyboard (interrupt masked). |
183 | /** Disables qemu_icp keyboard (interrupt masked). |
184 | * |
184 | * |
185 | * @param dev not used |
185 | * @param dev not used |
186 | * |
186 | * |
187 | * Called from getc(). |
187 | * Called from getc(). |
188 | */ |
188 | */ |
189 | static void qemu_icp_kbd_disable(chardev_t *dev) |
189 | static void qemu_icp_kbd_disable(chardev_t *dev) |
190 | { |
190 | { |
191 | qemu_icp_irqc_mask(QEMU_ICP_KBD_IRQ); |
191 | qemu_icp_irqc_mask(QEMU_ICP_KBD_IRQ); |
192 | } |
192 | } |
193 | 193 | ||
194 | /** Read character using polling, assume interrupts disabled. |
194 | /** Read character using polling, assume interrupts disabled. |
195 | * |
195 | * |
196 | * @param dev Not used. |
196 | * @param dev Not used. |
197 | */ |
197 | */ |
198 | static char qemu_icp_do_read(chardev_t *dev) |
198 | static char qemu_icp_do_read(chardev_t *dev) |
199 | { |
199 | { |
200 | char ch; |
200 | char ch; |
201 | 201 | ||
202 | while (1) { |
202 | while (1) { |
203 | ch = *((volatile char *) qemu_icp_hw_map.kbd); |
203 | ch = *((volatile char *) qemu_icp_hw_map.kbd); |
204 | if (ch) { |
204 | if (ch) { |
205 | if (ch == '\r') |
205 | if (ch == '\r') |
206 | return '\n'; |
206 | return '\n'; |
207 | if (ch == 0x7f) |
207 | if (ch == 0x7f) |
208 | return '\b'; |
208 | return '\b'; |
209 | return ch; |
209 | return ch; |
210 | } |
210 | } |
211 | } |
211 | } |
212 | } |
212 | } |
213 | 213 | ||
214 | /** Process keyboard interrupt. |
214 | /** Process keyboard interrupt. |
215 | * |
215 | * |
216 | * @param irq IRQ information. |
216 | * @param irq IRQ information. |
217 | * @param arg Not used. |
217 | * @param arg Not used. |
218 | */ |
218 | */ |
219 | static void qemu_icp_irq_handler(irq_t *irq, void *arg, ...) |
219 | static void qemu_icp_irq_handler(irq_t *irq, void *arg, ...) |
220 | { |
220 | { |
221 | if ((irq->notif_cfg.notify) && (irq->notif_cfg.answerbox)) { |
221 | if ((irq->notif_cfg.notify) && (irq->notif_cfg.answerbox)) { |
222 | ipc_irq_send_notif(irq); |
222 | ipc_irq_send_notif(irq); |
223 | } else { |
223 | } else { |
224 | char ch = 0; |
224 | char ch = 0; |
225 | 225 | ||
226 | ch = *((char *) qemu_icp_hw_map.kbd); |
226 | ch = *((char *) qemu_icp_hw_map.kbd); |
227 | if (ch == '\r') { |
227 | if (ch == '\r') { |
228 | ch = '\n'; |
228 | ch = '\n'; |
229 | } |
229 | } |
230 | if (ch == 0x7f) { |
230 | if (ch == 0x7f) { |
231 | ch = '\b'; |
231 | ch = '\b'; |
232 | } |
232 | } |
233 | chardev_push_character(&console, ch); |
233 | chardev_push_character(&console, ch); |
234 | } |
234 | } |
235 | } |
235 | } |
236 | 236 | ||
237 | static irq_ownership_t qemu_icp_claim(void) |
237 | static irq_ownership_t qemu_icp_claim(void) |
238 | { |
238 | { |
239 | return IRQ_ACCEPT; |
239 | return IRQ_ACCEPT; |
240 | } |
240 | } |
241 | 241 | ||
242 | 242 | ||
243 | /** Acquire console back for kernel. */ |
243 | /** Acquire console back for kernel. */ |
244 | void qemu_icp_grab_console(void) |
244 | void qemu_icp_grab_console(void) |
245 | { |
245 | { |
246 | ipl_t ipl = interrupts_disable(); |
246 | ipl_t ipl = interrupts_disable(); |
247 | spinlock_lock(&qemu_icp_console_irq.lock); |
247 | spinlock_lock(&qemu_icp_console_irq.lock); |
248 | qemu_icp_console_irq.notif_cfg.notify = false; |
248 | qemu_icp_console_irq.notif_cfg.notify = false; |
249 | spinlock_unlock(&qemu_icp_console_irq.lock); |
249 | spinlock_unlock(&qemu_icp_console_irq.lock); |
250 | interrupts_restore(ipl); |
250 | interrupts_restore(ipl); |
251 | } |
251 | } |
252 | 252 | ||
253 | /** Return console to userspace. */ |
253 | /** Return console to userspace. */ |
254 | void qemu_icp_release_console(void) |
254 | void qemu_icp_release_console(void) |
255 | { |
255 | { |
256 | ipl_t ipl = interrupts_disable(); |
256 | ipl_t ipl = interrupts_disable(); |
257 | spinlock_lock(&qemu_icp_console_irq.lock); |
257 | spinlock_lock(&qemu_icp_console_irq.lock); |
258 | if (qemu_icp_console_irq.notif_cfg.answerbox) { |
258 | if (qemu_icp_console_irq.notif_cfg.answerbox) { |
259 | qemu_icp_console_irq.notif_cfg.notify = true; |
259 | qemu_icp_console_irq.notif_cfg.notify = true; |
260 | } |
260 | } |
261 | spinlock_unlock(&qemu_icp_console_irq.lock); |
261 | spinlock_unlock(&qemu_icp_console_irq.lock); |
262 | interrupts_restore(ipl); |
262 | interrupts_restore(ipl); |
263 | } |
263 | } |
264 | 264 | ||
265 | /** Initializes console object representing qemu_icp console. |
265 | /** Initializes console object representing qemu_icp console. |
266 | * |
266 | * |
267 | * @param devno device number. |
267 | * @param devno device number. |
268 | */ |
268 | */ |
269 | void qemu_icp_console_init(devno_t devno) |
269 | void qemu_icp_console_init(devno_t devno) |
270 | { |
270 | { |
271 | chardev_initialize("qemu_icp_console", &console, &qemu_icp_ops); |
271 | chardev_initialize("qemu_icp_console", &console, &qemu_icp_ops); |
272 | stdin = &console; |
272 | stdin = &console; |
273 | stdout = &console; |
273 | stdout = &console; |
274 | 274 | ||
275 | irq_initialize(&qemu_icp_console_irq); |
275 | irq_initialize(&qemu_icp_console_irq); |
276 | qemu_icp_console_irq.devno = devno; |
276 | qemu_icp_console_irq.devno = devno; |
277 | qemu_icp_console_irq.inr = QEMU_ICP_KBD_IRQ; |
277 | qemu_icp_console_irq.inr = QEMU_ICP_KBD_IRQ; |
278 | qemu_icp_console_irq.claim = qemu_icp_claim; |
278 | qemu_icp_console_irq.claim = qemu_icp_claim; |
279 | qemu_icp_console_irq.handler = qemu_icp_irq_handler; |
279 | qemu_icp_console_irq.handler = qemu_icp_irq_handler; |
280 | irq_register(&qemu_icp_console_irq); |
280 | irq_register(&qemu_icp_console_irq); |
281 | 281 | ||
282 | qemu_icp_irqc_unmask(QEMU_ICP_KBD_IRQ); |
282 | qemu_icp_irqc_unmask(QEMU_ICP_KBD_IRQ); |
283 | 283 | ||
284 | sysinfo_set_item_val("kbd", NULL, true); |
284 | sysinfo_set_item_val("kbd", NULL, true); |
285 | sysinfo_set_item_val("kbd.devno", NULL, devno); |
285 | sysinfo_set_item_val("kbd.devno", NULL, devno); |
286 | sysinfo_set_item_val("kbd.inr", NULL, QEMU_ICP_KBD_IRQ); |
286 | sysinfo_set_item_val("kbd.inr", NULL, QEMU_ICP_KBD_IRQ); |
287 | 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); |
288 | } |
288 | } |
289 | 289 | ||
290 | /** Starts qemu_icp Real Time Clock device, which asserts regular interrupts. |
290 | /** Starts qemu_icp Real Time Clock device, which asserts regular interrupts. |
291 | * |
291 | * |
292 | * @param frequency Interrupts frequency (0 disables RTC). |
292 | * @param frequency Interrupts frequency (0 disables RTC). |
293 | */ |
293 | */ |
294 | static void qemu_icp_timer_start(uint32_t frequency) |
294 | static void qemu_icp_timer_start(uint32_t frequency) |
295 | { |
295 | { |
296 | *((uint32_t*) qemu_icp_hw_map.rtc_freq) = frequency; |
296 | *((uint32_t*) qemu_icp_hw_map.rtc_freq) = frequency; |
297 | } |
297 | } |
298 | 298 | ||
299 | static irq_ownership_t qemu_icp_timer_claim(void) |
299 | static irq_ownership_t qemu_icp_timer_claim(void) |
300 | { |
300 | { |
301 | return IRQ_ACCEPT; |
301 | return IRQ_ACCEPT; |
302 | } |
302 | } |
303 | 303 | ||
304 | /** Timer interrupt handler. |
304 | /** Timer interrupt handler. |
305 | * |
305 | * |
306 | * @param irq Interrupt information. |
306 | * @param irq Interrupt information. |
307 | * @param arg Not used. |
307 | * @param arg Not used. |
308 | */ |
308 | */ |
309 | 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, ...) |
310 | { |
310 | { |
311 | /* |
311 | /* |
312 | * We are holding a lock which prevents preemption. |
312 | * We are holding a lock which prevents preemption. |
313 | * Release the lock, call clock() and reacquire the lock again. |
313 | * Release the lock, call clock() and reacquire the lock again. |
314 | */ |
314 | */ |
315 | spinlock_unlock(&irq->lock); |
315 | spinlock_unlock(&irq->lock); |
316 | clock(); |
316 | clock(); |
317 | spinlock_lock(&irq->lock); |
317 | spinlock_lock(&irq->lock); |
318 | 318 | ||
319 | /* acknowledge tick */ |
319 | /* acknowledge tick */ |
320 | *((uint32_t*) qemu_icp_hw_map.rtc_ack) = 0; |
320 | *((uint32_t*) qemu_icp_hw_map.rtc_ack) = 0; |
321 | } |
321 | } |
322 | 322 | ||
323 | /** Initializes and registers timer interrupt handler. */ |
323 | /** Initializes and registers timer interrupt handler. */ |
324 | static void qemu_icp_timer_irq_init(void) |
324 | static void qemu_icp_timer_irq_init(void) |
325 | { |
325 | { |
326 | irq_initialize(&qemu_icp_timer_irq); |
326 | irq_initialize(&qemu_icp_timer_irq); |
327 | qemu_icp_timer_irq.devno = device_assign_devno(); |
327 | qemu_icp_timer_irq.devno = device_assign_devno(); |
328 | qemu_icp_timer_irq.inr = QEMU_ICP_TIMER_IRQ; |
328 | qemu_icp_timer_irq.inr = QEMU_ICP_TIMER_IRQ; |
329 | qemu_icp_timer_irq.claim = qemu_icp_timer_claim; |
329 | qemu_icp_timer_irq.claim = qemu_icp_timer_claim; |
330 | qemu_icp_timer_irq.handler = qemu_icp_timer_irq_handler; |
330 | qemu_icp_timer_irq.handler = qemu_icp_timer_irq_handler; |
331 | 331 | ||
332 | irq_register(&qemu_icp_timer_irq); |
332 | irq_register(&qemu_icp_timer_irq); |
333 | } |
333 | } |
334 | 334 | ||
335 | 335 | ||
336 | /** Starts timer. |
336 | /** Starts timer. |
337 | * |
337 | * |
338 | * Initiates regular timer interrupts after initializing |
338 | * Initiates regular timer interrupts after initializing |
339 | * corresponding interrupt handler. |
339 | * corresponding interrupt handler. |
340 | */ |
340 | */ |
341 | void qemu_icp_timer_irq_start(void) |
341 | void qemu_icp_timer_irq_start(void) |
342 | { |
342 | { |
343 | qemu_icp_timer_irq_init(); |
343 | qemu_icp_timer_irq_init(); |
344 | qemu_icp_timer_start(QEMU_ICP_TIMER_FREQ); |
344 | qemu_icp_timer_start(QEMU_ICP_TIMER_FREQ); |
345 | } |
345 | } |
346 | 346 | ||
347 | /** Returns the size of emulated memory. |
347 | /** Returns the size of emulated memory. |
348 | * |
348 | * |
349 | * @return Size in bytes. |
349 | * @return Size in bytes. |
350 | */ |
350 | */ |
351 | size_t qemu_icp_get_memory_size(void) |
351 | size_t qemu_icp_get_memory_size(void) |
352 | { |
352 | { |
353 | //return *((int *) (QEMU_ICP_MP + QEMU_ICP_MP_MEMSIZE_OFFSET)); |
353 | //return *((int *) (QEMU_ICP_MP + QEMU_ICP_MP_MEMSIZE_OFFSET)); |
354 | return 0x2000000; |
354 | return 0x2000000; |
355 | } |
355 | } |
356 | 356 | ||
357 | /** Prints a character. |
357 | /** Prints a character. |
358 | * |
358 | * |
359 | * @param ch Character to be printed. |
359 | * @param ch Character to be printed. |
360 | */ |
360 | */ |
361 | void qemu_icp_debug_putc(char ch) |
361 | void qemu_icp_debug_putc(char ch) |
362 | { |
362 | { |
363 | char *addr = 0; |
363 | char *addr = 0; |
364 | if (!hw_map_init_called) { |
364 | if (!hw_map_init_called) { |
365 | addr = (char *) QEMU_ICP_KBD; |
365 | addr = (char *) QEMU_ICP_KBD; |
366 | } else { |
366 | } else { |
367 | addr = (char *) qemu_icp_hw_map.videoram; |
367 | addr = (char *) qemu_icp_hw_map.videoram; |
368 | } |
368 | } |
369 | 369 | ||
370 | if (ch == '\n') |
370 | if (ch == '\n') |
371 | *(addr) = '\r'; |
371 | *(addr) = '\r'; |
372 | *(addr) = ch; |
372 | *(addr) = ch; |
373 | } |
373 | } |
374 | 374 | ||
375 | /** Stops qemu_icp. */ |
375 | /** Stops qemu_icp. */ |
376 | void qemu_icp_cpu_halt(void) |
376 | void qemu_icp_cpu_halt(void) |
377 | { |
377 | { |
378 | char * addr = 0; |
378 | char * addr = 0; |
379 | if (!hw_map_init_called) { |
379 | if (!hw_map_init_called) { |
380 | addr = (char *) QEMU_ICP_KBD; |
380 | addr = (char *) QEMU_ICP_KBD; |
381 | } else { |
381 | } else { |
382 | addr = (char *) qemu_icp_hw_map.videoram; |
382 | addr = (char *) qemu_icp_hw_map.videoram; |
383 | } |
383 | } |
384 | 384 | ||
385 | *(addr + QEMU_ICP_HALT_OFFSET) = '\0'; |
385 | *(addr + QEMU_ICP_HALT_OFFSET) = '\0'; |
386 | } |
386 | } |
387 | 387 | ||
388 | /** Gxemul specific interrupt exception handler. |
388 | /** Gxemul specific interrupt exception handler. |
389 | * |
389 | * |
390 | * Determines sources of the interrupt from interrupt controller and |
390 | * Determines sources of the interrupt from interrupt controller and |
391 | * calls high-level handlers for them. |
391 | * calls high-level handlers for them. |
392 | * |
392 | * |
393 | * @param exc_no Interrupt exception number. |
393 | * @param exc_no Interrupt exception number. |
394 | * @param istate Saved processor state. |
394 | * @param istate Saved processor state. |
395 | */ |
395 | */ |
396 | void qemu_icp_irq_exception(int exc_no, istate_t *istate) |
396 | void qemu_icp_irq_exception(int exc_no, istate_t *istate) |
397 | { |
397 | { |
398 | uint32_t sources = qemu_icp_irqc_get_sources(); |
398 | uint32_t sources = qemu_icp_irqc_get_sources(); |
399 | int i; |
399 | int i; |
400 | 400 | ||
401 | for (i = 0; i < QEMU_ICP_IRQC_MAX_IRQ; i++) { |
401 | for (i = 0; i < QEMU_ICP_IRQC_MAX_IRQ; i++) { |
402 | if (sources & (1 << i)) { |
402 | if (sources & (1 << i)) { |
403 | irq_t *irq = irq_dispatch_and_lock(i); |
403 | irq_t *irq = irq_dispatch_and_lock(i); |
404 | if (irq) { |
404 | if (irq) { |
405 | /* The IRQ handler was found. */ |
405 | /* The IRQ handler was found. */ |
406 | irq->handler(irq, irq->arg); |
406 | irq->handler(irq, irq->arg); |
407 | spinlock_unlock(&irq->lock); |
407 | spinlock_unlock(&irq->lock); |
408 | } else { |
408 | } else { |
409 | /* Spurious interrupt.*/ |
409 | /* Spurious interrupt.*/ |
410 | dprintf("cpu%d: spurious interrupt (inum=%d)\n", |
410 | dprintf("cpu%d: spurious interrupt (inum=%d)\n", |
411 | CPU->id, i); |
411 | CPU->id, i); |
412 | } |
412 | } |
413 | } |
413 | } |
414 | } |
414 | } |
415 | } |
415 | } |
416 | 416 | ||
417 | /** Returns address of framebuffer device. |
417 | /** Returns address of framebuffer device. |
418 | * |
418 | * |
419 | * @return Address of framebuffer device. |
419 | * @return Address of framebuffer device. |
420 | */ |
420 | */ |
421 | uintptr_t qemu_icp_get_fb_address(void) |
421 | uintptr_t qemu_icp_get_fb_address(void) |
422 | { |
422 | { |
423 | if (!vga_init) { |
423 | if (!vga_init) { |
424 | icp_vga_init(); |
424 | icp_vga_init(); |
425 | vga_init = true; |
425 | vga_init = true; |
426 | } |
426 | } |
427 | return (uintptr_t) QEMU_ICP_FB; |
427 | return (uintptr_t) QEMU_ICP_FB; |
428 | } |
428 | } |
429 | 429 | ||
430 | 430 | ||
431 | /** @} |
431 | /** @} |
432 | */ |
432 | */ |
433 | 433 |