Merge from Etherboot 5.4
[people/xl0/gpxe-arm.git] / src / arch / ia64 / core / efi.c
1 #include "efi/efi.h"
2 #include "etherboot.h"
3 #include "elf.h"
4 #include "sal.h"
5 #include "pal.h"
6
7 #warning "Place a declaration of lookup_efi_nic somewhere useful"
8 EFI_NETWORK_INTERFACE_IDENTIFIER_INTERFACE *lookup_efi_nic(int index);
9
10 #warning "Place the declaraction of __call someplace more appropriate\n"
11 extern EFI_STATUS __call(void *,...);
12
13 /* Keep 16M free in case EFI needs to allocate some memory. 
14  * In the worst case this is only 1/8 the memory on an Itanium.
15  */
16 #define EFI_RESERVE_LOW_PAGES  ((8*1024*1024)/EFI_PAGE_SIZE)
17 #define EFI_RESERVE_HIGH_PAGES ((8*1024*1024)/EFI_PAGE_SIZE)
18
19 struct console_info {
20         uint16_t num_cols;
21         uint16_t num_rows;
22         uint16_t orig_x;
23         uint16_t orig_y;
24 };
25
26 struct efi_mem_map {
27         uint64_t        map_size;
28         uint64_t        map_key;
29         uint64_t        descriptor_size;
30         uint32_t              descriptor_version;
31         uint32_t              pad;
32         EFI_MEMORY_DESCRIPTOR map[64];
33 };
34
35 struct efi_info {
36         int flags;
37 #define READ_SYSTAB  1
38 #define READ_FPSWA   2
39 #define READ_MEMMAP  4  
40 #define READ_CONINFO 8
41         EFI_SYSTEM_TABLE *systab;
42         void *fpswa;
43         struct efi_mem_map mem_map;
44         struct console_info coninfo;
45 };
46
47
48 unsigned long io_base;
49
50 /* local globals */
51 static struct efi_info efi_info;
52 static EFI_HANDLE etherboot_handle;
53 static EFI_BOOT_SERVICES *boot_services;
54 static SIMPLE_TEXT_OUTPUT_INTERFACE *conout;
55 static SIMPLE_INPUT_INTERFACE *conin;
56 static void *mps_table;
57 static void *acpi20_table;
58 static void *smbios_table;
59 static void *nii_table;
60
61 /* local functions */
62
63 static EFI_STATUS efi_locate_handle(
64         EFI_LOCATE_SEARCH_TYPE search_type, 
65         EFI_GUID *protocol, void *search_key, 
66         UINTN *buffer_size, EFI_HANDLE *buffer)
67 {
68         if (!boot_services)
69                 return EFI_NOT_FOUND;
70         return __call(boot_services->LocateHandle, 
71                 search_type, protocol, search_key, buffer_size, buffer);
72 }
73
74 static EFI_STATUS efi_handle_protocol(EFI_HANDLE handle, EFI_GUID *protocol, void **interface)
75 {
76         if (!boot_services)
77                 return EFI_UNSUPPORTED;
78         return __call(boot_services->HandleProtocol, handle, protocol, interface);
79 }
80
81 static EFI_STATUS efi_locate_device_path(EFI_GUID *protocol, EFI_DEVICE_PATH **device_path,
82         EFI_HANDLE *device)
83 {
84         if (!boot_services)
85                 return EFI_NOT_FOUND;
86         return __call(boot_services->LocateDevicePath, protocol, device_path, device);
87 }
88
89 static EFI_STATUS efi_allocate_pages(EFI_ALLOCATE_TYPE type, EFI_MEMORY_TYPE memory_type, 
90         UINTN pages, EFI_PHYSICAL_ADDRESS *memory)
91 {
92         if (!boot_services)
93                 return EFI_OUT_OF_RESOURCES;
94         return __call(boot_services->AllocatePages,
95                 type, memory_type, pages, memory);
96 }
97
98 static EFI_STATUS efi_free_pages(EFI_PHYSICAL_ADDRESS memory, UINTN pages)
99 {
100         if(pages == 0)
101                 return EFI_SUCCESS;
102         if (!boot_services)
103                 return EFI_INVALID_PARAMETER;
104         return __call(boot_services->FreePages, memory, pages);
105 }
106
107 static EFI_STATUS efi_get_memory_map(UINTN *map_size, EFI_MEMORY_DESCRIPTOR *map,
108         UINTN *map_key, UINTN *descriptor_size, UINT32 *descriptor_version)
109 {
110         if (!boot_services)
111                 return EFI_INVALID_PARAMETER;
112         return __call(boot_services->GetMemoryMap,
113                 map_size, map, map_key, descriptor_size, descriptor_version);
114 }
115
116 static EFI_STATUS efi_free_pool(void *buffer)
117 {
118         if (!boot_services)
119                 return EFI_INVALID_PARAMETER;
120         return __call(boot_services->FreePool, buffer);
121 }
122 static EFI_STATUS efi_stall(UINTN microseconds)
123 {
124         if (!boot_services)
125                 return EFI_UNSUPPORTED;
126         return __call(boot_services->Stall, microseconds);
127 }
128
129 static EFI_STATUS efi_set_watchdog_timer(
130         UINTN timeout, UINT64 watchdog_code, UINTN data_size, CHAR16 *watchdog_data)
131 {
132         if (!boot_services)
133                 return EFI_UNSUPPORTED;
134         return __call(boot_services->SetWatchdogTimer,
135                 timeout, watchdog_code, data_size, watchdog_data);
136 }
137
138
139 static void efi_exit_boot_services(struct efi_mem_map *map)
140 {
141         EFI_STATUS status;
142         if (!boot_services)
143                 return;
144         status = __call(boot_services->ExitBootServices, 
145                 etherboot_handle, map->map_key);
146         if (status != EFI_SUCCESS) {
147                 printf("ExitBootServices failed: %lx\n", status);
148         }
149         conout = 0;
150         conin = 0;
151         boot_services = 0;
152 }
153
154 static void efi_free_memory(struct efi_mem_map *map)
155 {
156         EFI_MEMORY_DESCRIPTOR *desc, *tail;
157 #define next_desc(desc, size) ((EFI_MEMORY_DESCRIPTOR *)(((char *)(desc)) + (size)))
158         tail = next_desc(map->map, map->map_size);
159         for(desc = map->map; desc < tail; desc = next_desc(desc, map->descriptor_size)) {
160                 EFI_STATUS status;
161                 EFI_PHYSICAL_ADDRESS start, end;
162                 UINTN pages;
163                 int may_free;
164
165                 start = desc->PhysicalStart;
166                 pages = desc->NumberOfPages;
167                 end = start + pages * EFI_PAGE_SIZE;
168
169
170                 may_free = 0;
171                 /* The only canidates are Loader Code and Data */
172                 if ((desc->Type == EfiLoaderData) ||
173                         (desc->Type == EfiLoaderCode))
174                         may_free = 1;
175         
176                 /* Don't free anything etherboot lives in */
177                 if ((may_free) &&
178                         (start < virt_to_phys(_end)) &&
179                         (end > virt_to_phys(_text)))
180                         may_free = 0;
181
182                 /* Continue if it is not memory we want to free */
183                 if (!may_free)
184                         continue;
185
186                 status = efi_free_pages(start, pages);
187                 if (status != EFI_SUCCESS) {
188                         printf("free_pages: %lx\n", status);
189                 }
190         }
191 #undef next_desc
192 }
193
194 static void read_efi_mem_map(struct efi_mem_map *map)
195 {
196         EFI_STATUS status;
197         map->map_size = sizeof(map->map);
198         status = efi_get_memory_map(
199                 &map->map_size, map->map, &map->map_key,
200                 &map->descriptor_size, &map->descriptor_version);
201         if (status != EFI_SUCCESS) {
202                 printf("read_efi_mem_map failed: %lx\n", status);
203                 map->map_size = 0;
204         }
205         /* map->descriptor_size should only grow larger */
206         /* map->descriptor_version should only increase and retain
207          * a backward compatible format.
208          */
209 }
210
211 #if 0
212 static const char *efi_mem_type_name(uint32_t type)
213 {
214         const char *type_name;
215         if (type == EfiReservedMemoryType)
216                 type_name = "EfiReservedMemoryType     ";
217         else if (type == EfiLoaderCode)
218                 type_name = "EfiLoaderCode             ";
219         else if (type == EfiLoaderData)
220                 type_name = "EfiLoaderData             ";
221         else if (type == EfiBootServicesCode)
222                 type_name = "EfiBootServicesCode       ";
223         else if (type == EfiBootServicesData)
224                 type_name = "EfiBootServicesData       ";
225         else if (type == EfiRuntimeServicesCode)
226                 type_name = "EfiRuntimeServicesCode    ";
227         else if (type == EfiRuntimeServicesData)
228                 type_name = "EfiRuntimeServicesData    ";
229         else if (type == EfiConventionalMemory)
230                 type_name = "EfiConventionalMemory     ";
231         else if (type == EfiUnusableMemory)
232                 type_name = "EfiUnusableMemory         ";
233         else if (type == EfiACPIReclaimMemory)
234                 type_name = "EfiACPIReclaimMemory      ";
235         else if (type == EfiACPIMemoryNVS)
236                 type_name = "EfiACPIMemoryNVS          ";
237         else if (type == EfiMemoryMappedIO)
238                 type_name = "EfiMemoryMappedIO         ";
239         else if (type == EfiMemoryMappedIOPortSpace)
240                 type_name = "EfiMemoryMappedIOPortSpace";
241         else if (type == EfiPalCode)
242                 type_name = "EfiPalCode                ";
243         else
244                 type_name = "????                      ";
245         return type_name;
246 }
247
248 static void print_efi_mem_map(struct efi_mem_map *map)
249 {
250         EFI_MEMORY_DESCRIPTOR *desc, *end;
251 #define next_desc(desc, size) ((EFI_MEMORY_DESCRIPTOR *)(((char *)(desc)) + (size)))
252         end = next_desc(map->map, map->map_size);
253         for(desc = map->map; desc < end ; desc = next_desc(desc, map->descriptor_size)) {
254                 const char *mem_type;
255                 unsigned long start, end, virt, virt_end;
256                 uint64_t attr;
257                 mem_type = efi_mem_type_name(desc->Type);
258                 start = desc->PhysicalStart;
259                 end   = start + desc->NumberOfPages*EFI_PAGE_SIZE;
260                 virt  = desc->VirtualStart;
261                 virt_end = virt + desc->NumberOfPages*EFI_PAGE_SIZE;
262                 attr = desc->Attribute;
263                 printf( "mem: %hhx %s @ %#lx-%#lx",
264                         desc->Type, mem_type, start, end);
265                 if (attr & EFI_MEMORY_UC)
266                         printf("UC ");
267                 if (attr & EFI_MEMORY_WC)
268                         printf("WC ");
269                 if (attr & EFI_MEMORY_WT)
270                         printf("WT ");
271                 if (attr & EFI_MEMORY_WB)
272                         printf("WB ");
273                 if (attr & EFI_MEMORY_UCE)
274                         printf("UCE ");
275
276                 if (attr & EFI_MEMORY_WP)
277                         printf("WP ");
278                 if (attr & EFI_MEMORY_RP)
279                         printf("RP ");
280                 if (attr & EFI_MEMORY_XP)
281                         printf("XP ");
282                 
283                 if (attr & EFI_MEMORY_RUNTIME)
284                         printf("RUNTIME ");
285
286                 printf("\n");
287         }
288 #undef next_desc
289 }
290 #endif
291
292 static void efi_allocate_memory(struct efi_mem_map *map)
293 {
294         EFI_MEMORY_DESCRIPTOR *desc, *end;
295         unsigned long low_free, high_free;
296
297 #define next_desc(desc, size) ((EFI_MEMORY_DESCRIPTOR *)(((char *)(desc)) + (size)))
298         end = next_desc(map->map, map->map_size);
299         /* Find out how much memory is free */
300         low_free = high_free = 0;
301         for(desc = map->map; desc < end ; desc = next_desc(desc, map->descriptor_size)) {
302                 unsigned long start, middle, end;
303                 if (desc->Type != EfiConventionalMemory)
304                         continue;
305                 start = desc->PhysicalStart;
306                 end = desc->PhysicalStart + (desc->NumberOfPages*EFI_PAGE_SIZE);
307                 if (start < 0x100000000UL) {
308                         if (end > 0x100000000UL) {
309                                 middle = 0x10000000UL;
310                         } else {
311                                 middle = end;
312                         }
313                 } else {
314                         middle = start;
315                 }
316
317                 low_free += (middle - start)/EFI_PAGE_SIZE;
318                 high_free += (end - middle)/EFI_PAGE_SIZE;
319         }
320         /* O.k. Now allocate all of the conventional memory, reserving only a tiny
321          * fraction for efi.
322          */
323         for(desc = map->map; desc < end ; desc = next_desc(desc, map->descriptor_size)) {
324                 EFI_STATUS status;
325                 EFI_PHYSICAL_ADDRESS address;
326                 UINTN pages;
327                 unsigned long start, middle, end;
328                 unsigned long low_pages, high_pages;
329                 if (desc->Type != EfiConventionalMemory)
330                         continue;
331                 start = desc->PhysicalStart;
332                 end = desc->PhysicalStart + (desc->NumberOfPages*EFI_PAGE_SIZE);
333                 if (start < 0x100000000UL) {
334                         if (end > 0x100000000UL) {
335                                 middle = 0x10000000UL;
336                         } else {
337                                 middle = end;
338                         }
339                 } else {
340                         middle = start;
341                 }
342                 low_pages  = (middle - start)/EFI_PAGE_SIZE;
343                 high_pages = (end - middle)/EFI_PAGE_SIZE;
344                 if (low_pages && (low_free > EFI_RESERVE_LOW_PAGES)) {
345                         address = start;
346                         pages = low_pages;
347                         if ((low_free - pages) < EFI_RESERVE_LOW_PAGES) {
348                                 pages = low_free - EFI_RESERVE_LOW_PAGES;
349                         }
350                         status = efi_allocate_pages(
351                                 AllocateAddress, EfiLoaderData, pages, &address);
352                         if (status != EFI_SUCCESS) {
353                                 printf("allocate_pages @%lx for %ld pages failed: %ld\n", 
354                                         desc->PhysicalStart, pages, status);
355                         }
356                         low_free -= pages;
357                 }
358                 if (high_pages && (high_free > EFI_RESERVE_HIGH_PAGES)) {
359                         address = middle;
360                         pages = high_pages;
361                         if ((high_free - pages) < EFI_RESERVE_HIGH_PAGES) {
362                                 pages = high_free - EFI_RESERVE_HIGH_PAGES;
363                         }
364                         status = efi_allocate_pages(
365                                 AllocateAddress, EfiLoaderData, pages, &address);
366                         if (status != EFI_SUCCESS) {
367                                 printf("allocate_pages @%lx for %ld pages failed: %ld\n", 
368                                         desc->PhysicalStart, pages, status);
369                         }
370                         high_free -= pages;
371                 }
372         }
373 #undef next_desc
374 }
375
376 static void set_io_base(struct efi_mem_map *map)
377 {
378         EFI_MEMORY_DESCRIPTOR *desc, *end;
379
380         io_base = ia64_get_kr0(); /* Default to ar.kr0 */
381
382 #define next_desc(desc, size) ((EFI_MEMORY_DESCRIPTOR *)(((char *)(desc)) + (size)))
383         end = next_desc(map->map, map->map_size);
384
385         for(desc = map->map; desc < end ; desc = next_desc(desc, map->descriptor_size)) {
386                 if (desc->Type == EfiMemoryMappedIOPortSpace) {
387                         io_base = desc->PhysicalStart;
388                         break;
389                 }
390         }
391 #undef next_desc
392 }
393
394 #define MAX_EFI_DEVICES 32
395 static void efi_stop_nics(void)
396 {
397         static EFI_GUID simple_net_protocol = EFI_SIMPLE_NETWORK_PROTOCOL;
398         EFI_SIMPLE_NETWORK *simple;
399         EFI_STATUS status;
400         EFI_HANDLE handles[MAX_EFI_DEVICES];
401         EFI_HANDLE handle;
402         UINTN devices;
403         unsigned i;
404
405         if (!boot_services)
406                 return;
407         
408         devices = sizeof(handles);
409         status = efi_locate_handle(
410                 ByProtocol, &simple_net_protocol, 0, &devices, handles);
411         if (status != EFI_SUCCESS)
412                 return;
413         devices /= sizeof(handles[0]);
414         for(i = 0; i < devices; i++) {
415                 void *that;
416                 handle = handles[i];
417                 status = efi_handle_protocol(handle, &simple_net_protocol, &that);
418                 if (status != EFI_SUCCESS)
419                         continue;
420                 simple = that;
421                 if ((simple->Mode->State == EfiSimpleNetworkInitialized)) {
422                         status = __call(simple->Shutdown, simple);
423                         status = __call(simple->Stop, simple);
424                 }
425                 else if (simple->Mode->State == EfiSimpleNetworkStarted) {
426                         status = __call(simple->Stop, simple);
427                 }
428         }
429 }
430
431 static void efi_get_coninfo(struct console_info *info)
432 {
433         EFI_STATUS status;
434         UINTN cols, rows;
435
436         /* Initialize with some silly safe values */
437         info->num_cols = 80;
438         info->num_rows = 24;
439         info->orig_x   = 0;
440         info->orig_y   = 0;
441
442         status = EFI_UNSUPPORTED;
443         if (conout) {
444                 status = __call(conout->QueryMode, conout, conout->Mode->Mode, &cols, &rows);
445                 if (status) {
446                         printf("QueryMode Failed cannout get console parameters: %ld\n", status);
447                 } else {
448                         info->num_cols = cols;
449                         info->num_rows = rows;
450                         info->orig_x   = conout->Mode->CursorColumn;
451                         info->orig_y   = conout->Mode->CursorRow;
452                 }
453         }
454 }
455
456 static void *efi_get_fpswa(void)
457 {
458         static EFI_GUID fpswa_protocol = FPSWA_PROTOCOL;
459         EFI_STATUS status;
460         EFI_HANDLE fpswa_handle;
461         UINTN devices;
462         void *result;
463
464         /* The FPSWA is the Floating Point Software Assist driver,
465          * to some extent it makes sense but it has one large flaw.
466          * It fails to install an EFI Configuration table, so the
467          * OS does not need assistance from the bootloader to find it.
468          */
469         devices = sizeof(fpswa_handle);
470         status = efi_locate_handle(
471                 ByProtocol, &fpswa_protocol, 0, &devices, &fpswa_handle);
472         if (status != EFI_SUCCESS)
473                 return 0;
474         
475         status = efi_handle_protocol(
476                 fpswa_handle, &fpswa_protocol, &result);
477         if (status != EFI_SUCCESS)
478                 return 0;
479
480         return result;
481 }
482
483
484 /* Exported functions */
485
486
487 void arch_main(in_call_data_t *data, va_list params)
488 {
489         EFI_STATUS status;
490         unsigned char *note, *end;
491
492         /* IA64 doesn't have an in_call() implementation; start.S
493          * passes in this parameter directly on the stack instead of
494          * as part of the in_call_data_t structure or the parameter
495          * list.  params is unusable: don't attempt to access it.
496          */
497         struct Elf_Bhdr *ptr = (struct Elf_Bhdr *)data;
498
499         memset(&efi_info, 0, sizeof(efi_info));
500         note = ((char *)bhdr) + sizeof(*bhdr);
501         end  = ((char *)bhdr) + bhdr->b_size;
502         if (bhdr->b_signature != 0x0E1FB007) {
503                 printf("Bad bhdr(%lx) signature(%x)!\n",
504                         (unsigned long) bhdr, bhdr->b_signature);
505                 note = end = 0;
506         }
507         while(note < end) {
508                 Elf_Nhdr *hdr;
509                 unsigned char *n_name, *n_desc, *next;
510                 hdr = (Elf_Nhdr *)note;
511                 n_name = note + sizeof(*hdr);
512                 n_desc = n_name + ((hdr->n_namesz + 3) & ~3);
513                 next = n_desc + ((hdr->n_descsz + 3) & ~3);
514                 if (next > end) 
515                         break;
516 #if 0
517                 printf("n_type: %x n_name(%d): n_desc(%d): \n", 
518                         hdr->n_type, hdr->n_namesz, hdr->n_descsz);
519 #endif
520                 if ((hdr->n_namesz == 10) &&
521                         (memcmp(n_name, "Etherboot", 10) == 0)) {
522                         switch(hdr->n_type) {
523                         case EB_IA64_IMAGE_HANDLE:
524                         {
525                                 uint64_t *handlep = (void *)n_desc;
526                                 etherboot_handle = (EFI_HANDLE)(*handlep);
527                                 break;
528                         }
529                         case EB_IA64_SYSTAB:
530                         {
531                                 uint64_t *systabp = (void *)n_desc;
532                                 efi_info.systab = (void *)(*systabp);
533                                 efi_info.flags |= READ_SYSTAB;
534                                 break;
535                         }
536                         case EB_IA64_FPSWA:
537                         {
538                                 uint64_t*fpswap = (void *)n_desc;
539                                 efi_info.fpswa = (void *)(*fpswap);
540                                 efi_info.flags |= READ_FPSWA;
541                                 break;
542                         }
543                         case EB_IA64_CONINFO:
544                         {
545                                 struct console_info *coninfop = (void *)n_desc;
546                                 efi_info.coninfo = *coninfop;
547                                 efi_info.flags |= READ_CONINFO;
548                                 break;
549                         }
550                         case EB_IA64_MEMMAP:
551                         {
552                                 struct efi_mem_map *mem_mapp = (void *)n_desc;
553                                 efi_info.mem_map = *mem_mapp;
554                                 efi_info.flags |= READ_MEMMAP;
555                                 break;
556                         }
557                         default:
558                                 break;
559                         }
560                 }
561                 note = next;
562         }
563         if (!(efi_info.flags & READ_SYSTAB)) {
564                 printf("No EFI systab\n");
565                 return;
566         }
567         
568         /* If I have an efi memory map assume ExitBootServices has been called.
569          */
570 #warning "FIXME see if there is a better test for boot services still being active "
571         printf("FIXME Develop a better test for boot services still being active\n");
572         if (!(efi_info.flags & READ_MEMMAP)) {
573                 conout = efi_info.systab->ConOut;
574                 conin  = efi_info.systab->ConIn;
575                 boot_services = efi_info.systab->BootServices;
576         }
577
578         if (!(efi_info.flags & READ_CONINFO)) {
579                 efi_info.flags |= READ_CONINFO;
580                 efi_get_coninfo(&efi_info.coninfo);
581         }
582         if (!(efi_info.flags & READ_FPSWA)) {
583                 efi_info.flags |= READ_FPSWA;
584                 efi_info.fpswa = efi_get_fpswa();
585         }
586         if (!(efi_info.flags & READ_MEMMAP)) {
587                 efi_info.flags |= READ_MEMMAP;
588                 read_efi_mem_map(&efi_info.mem_map);
589                 /* Allocate all of the memory efi can spare */
590                 efi_allocate_memory(&efi_info.mem_map);
591                 /* Now refresh the memory map */
592                 read_efi_mem_map(&efi_info.mem_map);
593         }
594         /* Get the io_base for legacy i/o */
595         set_io_base(&efi_info.mem_map);
596
597         /* Attempt to disable the watchdog timer.. 
598          * Nothing useful can be done if this fails, so ignore the return code.
599          */
600         status = efi_set_watchdog_timer(0, 1, 0, 0);
601
602         /* Shutdown efi network drivers so efi doesn't get too confused */
603         efi_stop_nics();
604
605         if (efi_info.systab) {
606                 static const EFI_GUID mps_table_guid = MPS_TABLE_GUID;
607                 static const EFI_GUID acpi20_table_guid = ACPI_20_TABLE_GUID;
608                 static const EFI_GUID smbios_table_guid = SMBIOS_TABLE_GUID;
609                 static const EFI_GUID sal_system_table_guid = SAL_SYSTEM_TABLE_GUID;
610                 static const EFI_GUID nii_table_guid = EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL;
611                 EFI_SYSTEM_TABLE *systab;
612                 unsigned i;
613                 systab = efi_info.systab;
614                 for(i = 0; i < systab->NumberOfTableEntries; i++) {
615                         EFI_GUID *guid;
616                         void *table = systab->ConfigurationTable[i].VendorTable;
617                         guid = &systab->ConfigurationTable[i].VendorGuid;
618
619 #if 0
620                         printf("GUID: %x-%hx-%hx-%hhx-%hhx-%hhx-%hhx-%hhx-%hhx-%hhx-%hhx Table: %lx\n",
621                                 guid->Data1, guid->Data2, guid->Data3,
622                                 guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3],
623                                 guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7],
624                                 table);
625 #endif
626
627                         if (memcmp(guid, &mps_table_guid, 16) == 0) {
628                                 mps_table = table;
629                         }
630                         if (memcmp(guid, &acpi20_table_guid, 16) == 0) {
631                                 acpi20_table = table;
632                         }
633                         if (memcmp(guid, &smbios_table_guid, 16) == 0) {
634                                 smbios_table = table;
635                         }
636                         if (memcmp(guid, &sal_system_table_guid, 16) == 0) {
637                                 parse_sal_system_table(table);
638                         }
639                         if (memcmp(guid, &nii_table_guid, 16) == 0) {
640                                 nii_table = table;
641                         }
642                 }
643         }
644 }
645
646 void arch_on_exit(int status __unused)
647 {
648         if (!boot_services)
649                 return;
650         read_efi_mem_map(&efi_info.mem_map);
651         efi_free_memory(&efi_info.mem_map);
652 }
653
654 void arch_relocate_to(unsigned long addr)
655 {
656         EFI_PHYSICAL_ADDRESS address, end;
657         UINTN pages;
658         EFI_STATUS status;
659         
660         if (!boot_services)
661                 return;
662
663         /* Find the efi pages where the new etherboot will sit */
664         address = addr & ~(EFI_PAGE_SIZE -1);
665         end = (addr + (_end - _text) + EFI_PAGE_SIZE -1) & ~EFI_PAGE_SIZE;
666         pages = (end - address)/EFI_PAGE_SIZE;
667
668         /* Reallocate the memory for the new copy of etherboot as LoaderCode */
669         status = efi_free_pages(address, pages);
670         if (status != EFI_SUCCESS) {
671                 printf("efi_free_pages failed!: %lx\n", status);
672                 return;
673         }
674         status = efi_allocate_pages(AllocateAddress, EfiLoaderCode, pages, &address);
675         if (status != EFI_SUCCESS) {
676                 printf("efi_allocate_pages failed! %lx\n", status);
677                 return;
678         }
679 }
680
681
682 struct meminfo meminfo;
683 void get_memsizes(void)
684 {
685         EFI_MEMORY_DESCRIPTOR *desc, *end;
686         struct efi_mem_map *map;
687 #define next_desc(desc, size) ((EFI_MEMORY_DESCRIPTOR *)(((char *)(desc)) + (size)))
688
689         map = &efi_info.mem_map;
690         end = next_desc(map->map, map->map_size);
691
692         meminfo.map_count = 0;
693         for(desc = map->map; desc < end ; desc = next_desc(desc, map->descriptor_size)) {
694                 uint64_t start, size, end;
695                 unsigned long mem_k;
696                 
697                 start = desc->PhysicalStart;
698                 size  = desc->NumberOfPages*EFI_PAGE_SIZE;
699                 end   = start + size;
700
701                 if ((desc->Type != EfiLoaderCode) &&
702                         (desc->Type != EfiLoaderData)) {
703                         continue;
704                 }
705
706                 meminfo.map[meminfo.map_count].addr = start;
707                 meminfo.map[meminfo.map_count].size = size;
708                 meminfo.map[meminfo.map_count].type = E820_RAM;
709                 meminfo.map_count++;
710
711                 end >>= 10;
712                 mem_k = end;
713                 if (end & 0xFFFFFFFF00000000ULL) {
714                         mem_k = 0xFFFFFFFF;
715                 }
716                 /* Set the base basememsize */
717                 if ((mem_k <= 640) && (meminfo.basememsize <= mem_k)) {
718                         meminfo.basememsize = mem_k;
719                 }
720                 /* Set the total memsize */
721                 if ((mem_k >= 1024) && (meminfo.memsize <= (mem_k - 1024))) {
722                         meminfo.memsize = mem_k - 1024;
723                 }
724                 if (meminfo.map_count == E820MAX)
725                         break;
726         }
727 #undef next_desc
728 }
729
730
731 EFI_NETWORK_INTERFACE_IDENTIFIER_INTERFACE *lookup_efi_nic(int index)
732 {
733         static EFI_GUID protocol = EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL;
734         EFI_HANDLE handles[MAX_EFI_DEVICES];
735         EFI_STATUS status;
736         UINTN devices;
737         void *that;
738
739         if (!boot_services)
740                 return 0;
741         if (index < 0) {
742                 return 0;
743         }
744         devices = sizeof(handles);
745         status = efi_locate_handle(
746                 ByProtocol, &protocol, 0, &devices, handles);
747         if (status != EFI_SUCCESS)
748                 return 0;
749         devices /= sizeof(handles[0]);
750         if (index >= devices)
751                 return 0;
752         status = efi_handle_protocol(handles[index], &protocol, &that);
753         if (status != EFI_SUCCESS)
754                 return 0;
755         return that;
756 }
757
758 #if defined(CONSOLE_FIRMWARE)
759 void console_putc(int c)
760 {
761         CHAR16 str[2];
762         if (!conout)
763                 return;
764         str[0] = c;
765         str[1] = 0;
766         __call(conout->OutputString, conout, str);
767 }
768
769 static int efi_have_key = 0;
770 static int efi_key;
771 int console_ischar(void)
772 {
773         EFI_STATUS status;
774         EFI_INPUT_KEY new_key;
775         if (!conin)
776                 return 0;
777         if (efi_have_key) {
778                 return 1;
779         }
780         status = __call(conin->ReadKeyStroke, conin, &new_key);
781         if (status == EFI_SUCCESS) {
782                 if ((new_key.UnicodeChar >= 0) && (new_key.UnicodeChar < 0x7f)) {
783                         efi_have_key = 1;
784                         efi_key = new_key.UnicodeChar;
785                 }
786                 else if (new_key.ScanCode == 0x17) {
787                         efi_have_key = 1;
788                         efi_key = K_ESC;
789                 }
790         }
791         return efi_have_key;
792 }
793
794 int console_getc(void)
795 {
796         if (efi_have_key) {
797                 efi_have_key = 0;
798         }
799
800         return efi_key;
801 }
802 #endif /* CONSOLE_FIRMWARE */
803
804 #define NAME "Etherboot"
805 #define FIRMWARE "EFI"
806
807 #define SZ(X) ((sizeof(X)+3) & ~3)
808 #define CP(D,S) (memcpy(&(D), &(S), sizeof(S)))
809
810
811 struct elf_notes {
812         /* CAREFUL this structure is carefully arranged to avoid
813          * alignment problems.
814          */
815         /* The note header */
816         struct Elf_Bhdr hdr;
817         
818         /* First the Fixed sized entries that must be well aligned */
819
820         /* Insert a nop record so the next record is 64bit aligned */
821         Elf_Nhdr nf0;
822
823         /* Pointer to bootp data */
824         Elf_Nhdr nf1;
825         char     nf1_name[SZ(EB_PARAM_NOTE)];
826         uint64_t nf1_bootp_data;
827
828         /* Pointer to ELF header */
829         Elf_Nhdr nf2;
830         char     nf2_name[SZ(EB_PARAM_NOTE)];
831         uint64_t nf2_header;
832
833         /* The EFI systab pointer */
834         Elf_Nhdr nf3;
835         char     nf3_name[SZ(EB_PARAM_NOTE)];
836         uint64_t nf3_systab;
837
838         /* The FPSWA pointer */
839         Elf_Nhdr nf4;
840         char     nf4_name[SZ(EB_PARAM_NOTE)];
841         uint64_t nf4_fpswa;
842
843         /* The memory map */
844         Elf_Nhdr nf5;
845         char     nf5_name[SZ(EB_PARAM_NOTE)];
846         struct efi_mem_map nf5_map;
847
848         /* The console info, silly but elilo passes it... */
849         Elf_Nhdr nf6;
850         char     nf6_name[SZ(EB_PARAM_NOTE)];
851         struct console_info nf6_coninfo;
852
853         /* Then the variable sized data string data where alignment does not matter */
854
855         /* The bootloader name */
856         Elf_Nhdr nv1;
857         char     nv1_desc[SZ(NAME)];
858         /* The bootloader version */
859         Elf_Nhdr nv2;
860         char     nv2_desc[SZ(VERSION)];
861         /* The firmware type */
862         Elf_Nhdr nv3;
863         char     nv3_desc[SZ(FIRMWARE)];
864         /* Name of the loaded image */
865         Elf_Nhdr nv4;
866         char    nv4_loaded_image[128];
867         /* An empty command line */
868         Elf_Nhdr nv5;
869         char     nv5_cmdline[SZ("")];
870 };
871
872 #define ELF_NOTE_COUNT  (6+5)
873
874 static struct elf_notes notes;
875 struct Elf_Bhdr *prepare_boot_params(void *header)
876 {
877         /* Shutdown the boot services */
878         if (boot_services) {
879                 efi_get_coninfo(&efi_info.coninfo);
880                 read_efi_mem_map(&efi_info.mem_map);
881                 efi_exit_boot_services(&efi_info.mem_map);
882         }
883
884         memset(&notes, 0, sizeof(notes));
885         notes.hdr.b_signature = 0x0E1FB007;
886         notes.hdr.b_size      = sizeof(notes);
887         notes.hdr.b_checksum  = 0;
888         notes.hdr.b_records   = ELF_NOTE_COUNT;
889
890         /* Initialize the fixed length entries. */
891
892         /* Align the fixed length entries to a 64bit boundary */
893         notes.nf0.n_namesz = 0;
894         notes.nf0.n_descsz = 0;
895         notes.nf0.n_type   = EBN_NOP;
896
897         notes.nf1.n_namesz = sizeof(EB_PARAM_NOTE);
898         notes.nf1.n_descsz = sizeof(notes.nf1_bootp_data);
899         notes.nf1.n_type   = EB_BOOTP_DATA;
900         CP(notes.nf1_name,   EB_PARAM_NOTE);
901         notes.nf1_bootp_data = virt_to_phys(&bootp_data);
902
903         notes.nf2.n_namesz = sizeof(EB_PARAM_NOTE);
904         notes.nf2.n_descsz = sizeof(notes.nf2_header);
905         notes.nf2.n_type   = EB_HEADER;
906         CP(notes.nf2_name,   EB_PARAM_NOTE);
907         notes.nf2_header   = virt_to_phys(header);
908
909         notes.nf3.n_namesz = sizeof(EB_PARAM_NOTE);
910         notes.nf3.n_descsz = sizeof(notes.nf3_systab);
911         notes.nf3.n_type   = EB_IA64_SYSTAB;
912         CP(notes.nf3_name,   EB_PARAM_NOTE);
913         notes.nf3_systab   = (unsigned long)efi_info.systab;
914
915         notes.nf4.n_namesz = sizeof(EB_PARAM_NOTE);
916         notes.nf4.n_descsz = sizeof(notes.nf4_fpswa);
917         notes.nf4.n_type   = EB_IA64_FPSWA;
918         CP(notes.nf4_name,   EB_PARAM_NOTE);
919         notes.nf4_fpswa = (unsigned long)efi_info.fpswa;
920
921         notes.nf5.n_namesz = sizeof(EB_PARAM_NOTE);
922         notes.nf5.n_descsz = sizeof(notes.nf5_map);
923         notes.nf5.n_type   = EB_IA64_MEMMAP;
924         CP(notes.nf5_name,   EB_PARAM_NOTE);
925         notes.nf5_map      = efi_info.mem_map;
926
927         notes.nf6.n_namesz = sizeof(EB_PARAM_NOTE);
928         notes.nf6.n_descsz = sizeof(notes.nf6_coninfo);
929         notes.nf6.n_type   = EB_IA64_CONINFO;
930         CP(notes.nf6_name,   EB_PARAM_NOTE);
931         notes.nf6_coninfo  = efi_info.coninfo;
932
933         /* Initialize the variable length entries */
934         notes.nv1.n_namesz = 0;
935         notes.nv1.n_descsz = sizeof(NAME);
936         notes.nv1.n_type   = EBN_BOOTLOADER_NAME;
937         CP(notes.nv1_desc,   NAME);
938
939         notes.nv2.n_namesz = 0;
940         notes.nv2.n_descsz = sizeof(VERSION);
941         notes.nv2.n_type   = EBN_BOOTLOADER_VERSION;
942         CP(notes.nv2_desc,   VERSION);
943
944         notes.nv3.n_namesz = 0;
945         notes.nv3.n_descsz = sizeof(FIRMWARE);
946         notes.nv3.n_type   = EBN_FIRMWARE_TYPE;
947         CP(notes.nv3_desc,   FIRMWARE);
948
949         /* Attempt to pass the name of the loaded image */
950         notes.nv4.n_namesz = 0;
951         notes.nv4.n_descsz = sizeof(notes.nv4_loaded_image);
952         notes.nv4.n_type   = EBN_LOADED_IMAGE;
953         memcpy(&notes.nv4_loaded_image, KERNEL_BUF, sizeof(notes.nv4_loaded_image));
954
955         /* Pass an empty command line for now */
956         notes.nv5.n_namesz = 0;
957         notes.nv5.n_descsz = sizeof("");
958         notes.nv5.n_type   = EBN_COMMAND_LINE;
959         CP(notes.nv5_cmdline,   "");
960
961         notes.hdr.b_checksum = ipchksum(&notes, sizeof(notes));
962         /* Like UDP invert a 0 checksum to show that a checksum is present */
963         if (notes.hdr.b_checksum == 0) {
964                 notes.hdr.b_checksum = 0xffff;
965         }
966
967         return &notes.hdr;
968 }
969
970 int elf_start(unsigned long machine __unused, unsigned long entry, unsigned long params)
971 {
972         struct elf_notes *notes;
973         int result;
974         /* Since we can do both be polite and also pass the linux
975          * ia64_boot_param table.
976          */
977         static struct ia64_boot_param {
978                 uint64_t command_line;          /* physical address of command line arguments */
979                 uint64_t efi_systab;            /* physical address of EFI system table */
980                 uint64_t efi_memmap;            /* physical address of EFI memory map */
981                 uint64_t efi_memmap_size;               /* size of EFI memory map */
982                 uint64_t efi_memdesc_size;              /* size of an EFI memory map descriptor */
983                 uint32_t efi_memdesc_version;   /* memory descriptor version */
984                 struct {
985                         uint16_t num_cols;      /* number of columns on console output device */
986                         uint16_t num_rows;      /* number of rows on console output device */
987                         uint16_t orig_x;        /* cursor's x position */
988                         uint16_t orig_y;        /* cursor's y position */
989                 } console_info;
990                 uint64_t fpswa;         /* physical address of the fpswa interface */
991                 uint64_t initrd_start;
992                 uint64_t initrd_size;
993         } bp;
994
995         notes = phys_to_virt(params);
996         /* If I don't have notes don't attempt to start the image */
997         if (notes == 0) {
998                 return -2;
999         }
1000
1001         bp.command_line          = (unsigned long)&notes->nv5_cmdline;
1002         bp.efi_systab            = notes->nf3_systab;
1003         bp.efi_memmap            = (unsigned long)&notes->nf5_map.map;
1004         bp.efi_memmap_size       = notes->nf5_map.map_size;
1005         bp.efi_memdesc_size      = notes->nf5_map.descriptor_size;
1006         bp.efi_memdesc_version   = notes->nf5_map.descriptor_version;
1007         bp.console_info.num_cols = notes->nf6_coninfo.num_cols;
1008         bp.console_info.num_rows = notes->nf6_coninfo.num_rows;
1009         bp.console_info.orig_x   = notes->nf6_coninfo.orig_x;
1010         bp.console_info.orig_y   = notes->nf6_coninfo.orig_y;
1011         bp.fpswa                 = notes->nf4_fpswa;
1012         bp.initrd_start          = 0;
1013         bp.initrd_size           = 0;
1014
1015
1016         asm volatile(
1017                 ";;\n\t"
1018                 "mov r28=%2\n\t"
1019                 "mov out0=%3\n\t"
1020                 "br.call.sptk.few rp=%1\n\t"
1021                 "mov %0=r8\n\t"
1022                 : "=r" (result)
1023                 : "b"(entry), "r"(&bp),"r"(params)
1024                 );
1025         return result;
1026 }