Fix high interrupt ISRs
[viridis.git] / kernel / platforms / efi / setup.c
1 /* vim: set ts=4 sw=4 sts=4 et : */
2
3 #include <kernel.h>
4 #include <stdarg.h>
5 #include <map.h>
6 #include <vsalloc.h>
7
8 #include <asm/boot.h>
9
10 #include "efi.h"
11 #include "vincent.h"    /* public domain 8x8 bitmap font */
12
13 static struct efi_mem_hdr *efi_memmap = NULL;
14 static struct efi_sys_table *system_table = NULL;
15
16 static struct efi_gop_mode *efi_gop_mode = NULL;
17 static struct efi_gop_info *efi_gop_info = NULL;
18
19 static u32 *efi_fb = NULL;
20 static u32 efi_curs_x, efi_curs_y;
21 static u32 efi_curs_max_x;
22 static u32 efi_curs_max_y;
23
24 extern u64 efi_gop_mode_phys;
25 extern u64 efi_gop_info_phys;
26
27 void efi_console_reset(struct platform *plat)
28 {
29     u64 pixels;
30     u64 i;
31
32     if (!efi_fb)
33         return;
34
35     pixels = efi_gop_info->pixels_per_scanline * efi_gop_info->v_res;
36     //pixels = efi_gop_info->pixels_per_scanline;
37
38     for (i = 0; i < pixels; i++)
39         efi_fb[i] = 0;
40
41     efi_curs_x = 0;
42     efi_curs_y = 0;
43     efi_curs_max_x = (efi_gop_info->h_res / EFI_FONT_W) - 1;
44     efi_curs_max_y = (efi_gop_info->v_res / EFI_FONT_H) - 1;
45 }
46
47 void efi_console_init(struct platform *plat)
48 {
49     u64 pages;
50
51     if ((!efi_gop_mode) || (!efi_gop_info))
52         return;
53
54     if (efi_gop_info->pixel_format == PixelBltOnly)
55         return;
56
57     pages = (efi_gop_mode->fb_size >> PAGE_SHIFT) + 1;
58
59     efi_fb = vsalloc("EFI GOP mem", 0, pages);
60
61     map_pages((u64) efi_fb, efi_gop_mode->fb_phys, pages);
62
63     efi_console_reset(plat);
64 }
65
66 static inline void __draw_one(u32 x, u32 y, u32 color)
67 {
68     efi_fb[y * efi_gop_info->pixels_per_scanline + x] = color;
69 }
70
71 static inline void __scroll_down(void)
72 {
73     memcpy(efi_fb, &efi_fb[efi_gop_info->pixels_per_scanline * EFI_FONT_H],
74             efi_gop_info->pixels_per_scanline * EFI_FONT_H * efi_curs_max_y * 4);
75     memset(&efi_fb[efi_gop_info->pixels_per_scanline * efi_curs_max_y * EFI_FONT_H],
76             0, efi_gop_info->pixels_per_scanline * EFI_FONT_H * 4);
77 }
78
79 #define TABSTOP 4
80
81 void efi_console_putch(struct platform *plat, char c)
82 {
83     unsigned char *letter;
84     int pixel_x, pixel_y;
85     int i, j;
86
87     if (c >= 128)
88         return;
89
90     if (c == '\n')
91         efi_curs_x = efi_curs_max_x;
92     else if (c == '\t')
93         efi_curs_x += TABSTOP - (efi_curs_x % TABSTOP);
94     else {
95         letter = vincent_data[(int) c];
96
97         pixel_x = efi_curs_x * EFI_FONT_W;
98         pixel_y = efi_curs_y * EFI_FONT_H;
99
100         for (i = 0; i < EFI_FONT_H; i++) {
101             unsigned char byte = letter[i];
102
103             for (j = 0; j < EFI_FONT_W; j++) {
104                 if (byte & 0x80)
105                     __draw_one(pixel_x, pixel_y, 0x00FFFFFF);
106                 pixel_x++;
107                 byte <<= 1;
108             }
109
110             pixel_x -= EFI_FONT_W;
111             pixel_y++;
112         }
113     }
114
115     efi_curs_x++;
116     if (efi_curs_x >= efi_curs_max_x) {
117         efi_curs_y++;
118         efi_curs_x = 0;
119     }
120
121     if (efi_curs_y > efi_curs_max_y) {
122         __scroll_down();
123         efi_curs_y = efi_curs_max_y;
124     }
125 }
126
127 /* efi_init, called after the memory map has been parsed and the page allocator
128  * and vsalloc have been init'd, we can use this to remap all of the runtime
129  * necessary memory and allow us to make EFI calls again.
130  */
131
132 void efi_init(struct platform *plat)
133 {
134     struct efi_mem_desc *cur = &efi_memmap->map[0];
135     u64 ret;
136
137     while (((u64) cur) < (((u64) &efi_memmap->map[0]) + efi_memmap->map_size)) {
138
139         /* All of this memory is reserved so our page allocator shouldn't
140          * be handing it out, and we're early enough we know the identity
141          * map of phys->virt is going to be free (since we reserved our
142          * kernel).
143          */
144
145         /* NOTE: It seems pretty clear in the spec that only EFI_MEMORY_RUNTIME
146          * marked map entries should be required, but for some reason BootServices
147          * junk is still required on some firmware (like my Thinkpad).
148          */
149
150         if ((cur->attributes & EFI_MEMORY_RUNTIME) ||
151                 (cur->type == EfiBootServicesCode) ||
152                 (cur->type == EfiBootServicesData)) {
153             cur->virt = cur->phys | EFI_RUNTIME;
154
155             if (cur->attributes & EFI_MEMORY_WB) {
156                 map_pages(cur->phys, cur->phys, cur->num_pages);
157                 map_pages(cur->virt, cur->phys, cur->num_pages);
158             } else {
159                 map_pages_nocache(cur->phys, cur->phys, cur->num_pages);
160                 map_pages_nocache(cur->virt, cur->phys, cur->num_pages);
161             }
162         } else
163             cur->virt = 0x0;
164
165         cur = (void *) (((u64) cur) + efi_memmap->descriptor_size);
166     }
167
168     /* Give the firmware the same structure it gave to us */
169     ret = EFI_CALL(system_table->runtime_services->set_virtual_address_map,
170             efi_memmap->map_size, efi_memmap->descriptor_size,
171             1, efi_memmap->map);
172
173     if (ret) {
174         printk("Set Virtual Address Map Failed!\n");
175         while(1);
176     }
177
178     /* The firmware has now updated its pointers, now we need to update ours
179      * before we destroy the identity mapping
180      */
181
182     system_table = (struct efi_sys_table *) (((u64) system_table) | EFI_RUNTIME);
183
184     /* Destroy the identity mapping */
185
186     cur = &efi_memmap->map[0];
187     while (((u64) cur) < (((u64) &efi_memmap->map[0]) + efi_memmap->map_size)) {
188         if (cur->virt)
189             unmap_pages(cur->phys, cur->num_pages);
190
191         cur = (void *) (((u64) cur) + efi_memmap->descriptor_size);
192     }
193 }
194
195 static union efi_guid acpi_guid = {
196     .guid = { 0xeb9d2d30, 0x2d88, 0x11d3,
197         { 0x9a, 0x16, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d }}
198 };
199
200 static union efi_guid efi_acpi_guid = {
201     .guid = { 0x8868e871, 0xe4f1, 0x11d3,
202         { 0xbc, 0x22, 0x00, 0x80, 0xc7, 0x3c, 0x88, 0x81 }}
203 };
204
205 void *efi_find_rsdp(struct platform *plat)
206 {
207     int i;
208
209     for (i = 0; i < system_table->num_entries; i++) {
210         if ((efi_guid_equal(&system_table->configuration_table[i].guid, &efi_acpi_guid)||
211              efi_guid_equal(&system_table->configuration_table[i].guid, &acpi_guid))) {
212             char *ret = vsalloc("ACPI", 0, 1);
213
214             if (!ret)
215                 return NULL;
216
217             map_page((u64) ret, (u64) system_table->configuration_table[i].table);
218
219             return (void *) ((u64) ret + PAGE_ALIGN_OFF((u64) system_table->configuration_table[i].table));
220         }
221     }
222     return NULL;
223 }
224
225 void efi_parse_memmap(struct platform *plat, struct plat_memmap *entry)
226 {
227     struct efi_mem_desc *cur = entry->next;
228
229     if (!cur)
230         cur = &efi_memmap->map[0];
231
232     entry->start = cur->phys;
233     entry->end = cur->phys + (cur->num_pages << PAGE_SHIFT);
234
235     if (cur->type == EfiConventionalMemory)
236         entry->type = PLAT_MEMMAP_FREE;
237     else
238         entry->type = PLAT_MEMMAP_RESV;
239
240     entry->next = (void *) (((u64) cur) + efi_memmap->descriptor_size);
241     if (((u64) entry->next) >= (((u64) &efi_memmap->map[0]) + efi_memmap->map_size))
242         entry->next = NULL;
243 }
244
245 int efi_probe(struct platform *plat, struct boot_header *header)
246 {
247     if (!(header->flags & BOOT_EFI))
248         return 0;
249
250     system_table = (struct efi_sys_table *) header->info_address;
251
252     efi_memmap = (struct efi_mem_hdr *) (VIRT_BASE | header->memmap_address);
253
254     if (!(header->flags & BOOT_NOVID)) {
255         efi_gop_mode = (struct efi_gop_mode *) (VIRT_BASE | ((u64) &efi_gop_mode_phys));
256         efi_gop_info = (struct efi_gop_info *) (VIRT_BASE | ((u64) &efi_gop_info_phys));
257     }
258
259     return 1;
260 }