078d40650a2aca096be6704653f0549a65b7e544
[debian/elilo] / ia32 / system.c
1 /*
2  *  Copyright (C) 2001-2003 Hewlett-Packard Co.
3  *      Contributed by Stephane Eranian <eranian@hpl.hp.com>
4  *      Contributed by Mike Johnston <johnston@intel.com>
5  *      Contributed by Chris Ahna <christopher.j.ahna@intel.com>
6  *
7  * This file is part of the ELILO, the EFI Linux boot loader.
8  *
9  *  ELILO is free software; you can redistribute it and/or modify
10  *  it under the terms of the GNU General Public License as published by
11  *  the Free Software Foundation; either version 2, or (at your option)
12  *  any later version.
13  *
14  *  ELILO is distributed in the hope that it will be useful,
15  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  *  GNU General Public License for more details.
18  *
19  *  You should have received a copy of the GNU General Public License
20  *  along with ELILO; see the file COPYING.  If not, write to the Free
21  *  Software Foundation, 59 Temple Place - Suite 330, Boston, MA
22  *  02111-1307, USA.
23  *
24  * Please check out the elilo.txt for complete documentation on how
25  * to use this program.
26  */
27
28 /*
29  * This file contains all the IA-32 specific code expected by generic loader
30  */
31 #include <efi.h>
32 #include <efilib.h>
33
34 #include "elilo.h"
35 #include "loader.h"
36 #include "rmswitch.h"
37
38 extern loader_ops_t bzimage_loader, plain_loader, gzip_loader; 
39
40 /*
41  * Descriptor table base addresses & limits for Linux startup.
42  */
43
44 dt_addr_t gdt_addr = { 0x800, 0x94000 };
45 dt_addr_t idt_addr = { 0, 0 }; 
46
47 /*
48  * Initial GDT layout for Linux startup.
49  */
50
51 UINT16 init_gdt[] = {
52         /* gdt[0]: dummy */
53         0, 0, 0, 0, 
54         
55         /* gdt[1]: unused */
56         0, 0, 0, 0,
57
58         /* gdt[2]: code */
59         0xFFFF,         /* 4Gb - (0x100000*0x1000 = 4Gb) */
60         0x0000,         /* base address=0 */
61         0x9A00,         /* code read/exec */
62         0x00CF,         /* granularity=4096, 386 (+5th nibble of limit) */
63
64         /* gdt[3]: data */
65         0xFFFF,         /* 4Gb - (0x100000*0x1000 = 4Gb) */
66         0x0000,         /* base address=0 */
67         0x9200,         /* data read/write */
68         0x00CF,         /* granularity=4096, 386 (+5th nibble of limit) */
69 };
70
71 UINTN sizeof_init_gdt = sizeof init_gdt;
72
73 /*
74  * Highest available base memory address.
75  *
76  * For traditional kernels and loaders this is always at 0x90000.
77  * For updated kernels and loaders this is computed by taking the
78  * highest available base memory address and rounding down to the
79  * nearest 64 kB boundary and then subtracting 64 kB.
80  *
81  * A non-compressed kernel is automatically assumed to be an updated
82  * kernel.  A compressed kernel that has bit 6 (0x40) set in the
83  * loader_flags field is also assumed to be an updated kernel.
84  */
85
86 UINTN high_base_mem = 0x90000;
87
88 /*
89  * Highest available extended memory address.
90  *
91  * This is computed by taking the highest available extended memory
92  * address and rounding down to the nearest EFI_PAGE_SIZE (usually
93  * 4 kB) boundary.  
94  * This is only used for backward compatibility.
95  */
96
97 UINTN high_ext_mem = 32 * 1024 * 1024;
98
99 /* This starting address will hold true for all of the loader types for now */
100 VOID *kernel_start = (VOID *)DEFAULT_KERNEL_START;
101
102 /* The kernel may load elsewhere if EFI firmware reserves kernel_start */
103 VOID *kernel_load_address = (VOID *)DEFAULT_KERNEL_START;
104
105 VOID *initrd_start = NULL;
106 UINTN initrd_size = 0;
107
108 INTN
109 sysdeps_init(EFI_HANDLE dev)
110 {
111         DBG_PRT((L"sysdeps_init()\n"));
112
113         /*
114          * Register our loader(s)...
115          */
116
117         loader_register(&bzimage_loader);
118         loader_register(&plain_loader);         
119         loader_register(&gzip_loader); 
120         return 0;
121 }
122
123 /*
124  * initrd_get_addr()
125  *      Compute a starting address for the initial RAMdisk image.
126  *      For now, this image is placed immediately after the end of
127  *      the kernel memory.  Inside the start_kernel() code, the
128  *      RAMdisk image will be relocated to the top of available
129  *      extended memory.
130  */
131 INTN
132 sysdeps_initrd_get_addr(kdesc_t *kd, memdesc_t *imem)
133 {
134         DBG_PRT((L"initrd_get_addr()\n"));
135
136         if (!kd || !imem) {
137                 ERR_PRT((L"kd=" PTR_FMT " imem=" PTR_FMT, kd, imem));
138                 return -1;
139         }
140
141         VERB_PRT(3, Print(L"kstart=" PTR_FMT "  kentry=" PTR_FMT "  kend=" PTR_FMT "\n", 
142                 kd->kstart, kd->kentry, kd->kend));
143
144         imem->start_addr = kd->kend;
145
146         VERB_PRT(3, Print(L"initrd start_addr=" PTR_FMT " pgcnt=%d\n", 
147                 imem->start_addr, imem->pgcnt));
148
149         return 0;
150 }
151
152 VOID
153 sysdeps_free_boot_params(boot_params_t *bp)
154 {
155         mmap_desc_t md;
156
157         ZeroMem(&md, sizeof md);
158         md.md = (VOID *)bp->s.efi_mem_map;
159         free_memmap(&md);
160 }
161
162 static VOID find_bits(unsigned long mask, UINT8 *first, UINT8* len) {
163         unsigned char bit_pos = 0, bit_len = 0;
164         *first =0;
165         *len = 0;
166         if (mask == 0)
167                 return;
168         while (!(mask & 0x1)) {
169                 mask = mask >> 1;
170                 bit_pos++;
171         }
172         while (mask & 0x1) {
173                 mask = mask >> 1;
174                 bit_len++;
175         }
176         *first = bit_pos;
177         *len = bit_len;
178 }
179
180 /*
181  * Get video information.
182  */
183 static INTN get_video_info(boot_params_t * bp) {
184         EFI_GUID GopProtocol = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
185         EFI_GRAPHICS_OUTPUT_PROTOCOL *Gop_interface;
186         EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Gop_info;
187         EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE   *Gop_mode = NULL;
188         EFI_HANDLE *Gop_handle = NULL;
189         EFI_STATUS efi_status;
190         UINTN size = 0;
191         UINTN size1;
192         UINT8 i;
193
194         efi_status = uefi_call_wrapper(
195                         BS->LocateHandle,
196                         5,
197                         ByProtocol,
198                         &GopProtocol,
199                         NULL,
200                         &size,
201                         (VOID **)Gop_handle);
202
203         if (EFI_ERROR(efi_status) && efi_status != EFI_BUFFER_TOO_SMALL) {
204                 ERR_PRT((L"LocateHandle GopProtocol failed."));
205                 return -1;
206         }
207         Gop_handle = alloc(size, 0);
208         efi_status = uefi_call_wrapper(
209                         BS->LocateHandle,
210                         5,
211                         ByProtocol,
212                         &GopProtocol,
213                         NULL,
214                         &size,
215                         (VOID **)Gop_handle);
216         if (EFI_ERROR(efi_status)) {
217                 ERR_PRT((L"LocateHandle GopProtocol failed."));
218                 free(Gop_handle);
219                 return -1;
220         }
221
222         for (i=0; i < size/sizeof(EFI_HANDLE); i++) {
223                 Gop_handle += i;
224                 efi_status = uefi_call_wrapper(
225                                 BS->HandleProtocol,
226                                 3,
227                                 *Gop_handle,
228                                 &GopProtocol,
229                                 (VOID **) &Gop_interface);
230
231                 if (EFI_ERROR(efi_status)) {
232                         continue;
233                 }
234                 Gop_mode = Gop_interface->Mode;
235                 efi_status = uefi_call_wrapper(
236                                 Gop_interface->QueryMode,
237                                 4,
238                                 Gop_interface,
239                                 Gop_mode->Mode,
240                                 &size1,
241                                 &Gop_info);
242                 if (!EFI_ERROR(efi_status))
243                         break;
244                 if (EFI_ERROR(efi_status)) {
245                         continue;
246                 }
247         }
248         if (EFI_ERROR(efi_status) || i > (size/sizeof(EFI_HANDLE))) {
249                 ERR_PRT((L"HandleProtocol GopProtocol failed."));
250                 free(Gop_handle);
251                 return -1;
252         }
253
254         bp->s.is_vga = 0x70;
255         bp->s.orig_cursor_col = 0;
256         bp->s.orig_cursor_row = 0;
257         bp->s.orig_video_page = 0;
258         bp->s.orig_video_mode = 0;
259         bp->s.orig_video_cols = 0;
260         bp->s.orig_video_rows = 0;
261         bp->s.orig_ega_bx = 0;
262         bp->s.orig_video_points = 0;
263
264         bp->s.lfb_width = Gop_info->HorizontalResolution;
265         bp->s.lfb_height = Gop_info->VerticalResolution;
266         bp->s.lfb_base = Gop_mode->FrameBufferBase;
267         bp->s.lfb_size = Gop_mode->FrameBufferSize;
268         bp->s.lfb_pages = 1;
269         bp->s.vesa_seg = 0;
270         bp->s.vesa_off = 0;
271         if (Gop_info->PixelFormat == PixelRedGreenBlueReserved8BitPerColor) {
272                 bp->s.lfb_depth = 32;
273                 bp->s.lfb_red_size = 8;
274                 bp->s.lfb_red_pos = 0;
275                 bp->s.lfb_green_size = 8;
276                 bp->s.lfb_green_pos = 8;
277                 bp->s.lfb_blue_size = 8;
278                 bp->s.lfb_blue_pos = 16;
279                 bp->s.lfb_rsvd_size = 8;
280                 bp->s.lfb_rsvd_pos = 24;
281                 bp->s.lfb_line_len = Gop_info->PixelsPerScanLine * 4;
282
283         } else if (Gop_info->PixelFormat == PixelBlueGreenRedReserved8BitPerColor) {
284                 bp->s.lfb_depth = 32;
285                 bp->s.lfb_red_size = 8;
286                 bp->s.lfb_red_pos = 16;
287                 bp->s.lfb_green_size = 8;
288                 bp->s.lfb_green_pos = 8;
289                 bp->s.lfb_blue_size = 8;
290                 bp->s.lfb_blue_pos = 0;
291                 bp->s.lfb_rsvd_size = 8;
292                 bp->s.lfb_rsvd_pos = 24;
293                 bp->s.lfb_line_len = Gop_info->PixelsPerScanLine * 4;
294         } else if (Gop_info->PixelFormat == PixelBitMask) {
295                 find_bits(Gop_info->PixelInformation.RedMask,
296                           &bp->s.lfb_red_pos, &bp->s.lfb_red_size);
297                 find_bits(Gop_info->PixelInformation.GreenMask,
298                           &bp->s.lfb_green_pos, &bp->s.lfb_green_size);
299                 find_bits(Gop_info->PixelInformation.BlueMask,
300                           &bp->s.lfb_blue_pos, &bp->s.lfb_blue_size);
301                 find_bits(Gop_info->PixelInformation.ReservedMask,
302                           &bp->s.lfb_rsvd_pos, &bp->s.lfb_rsvd_size);
303                 bp->s.lfb_depth = bp->s.lfb_red_size + bp->s.lfb_green_size +
304                                   bp->s.lfb_blue_size + bp->s.lfb_rsvd_size;
305                 bp->s.lfb_line_len = (Gop_info->PixelsPerScanLine * bp->s.lfb_depth) / 8;
306         } else {
307                 bp->s.lfb_depth = 4;
308                 bp->s.lfb_red_size = 0;
309                 bp->s.lfb_red_pos = 0;
310                 bp->s.lfb_green_size = 0;
311                 bp->s.lfb_green_pos = 0;
312                 bp->s.lfb_blue_size = 0;
313                 bp->s.lfb_blue_pos = 0;
314                 bp->s.lfb_rsvd_size = 0;
315                 bp->s.lfb_rsvd_pos = 0;
316                 bp->s.lfb_line_len = bp->s.lfb_width / 2;
317         }
318         return 0;
319 }
320
321 /* Convert EFI memory map to E820 map for the operating system
322  * This code is based on a Linux kernel patch submitted by Edgar Hucek
323  */
324
325 /* Add a memory region to the e820 map */
326 static void add_memory_region (struct e820entry *e820_map,
327                                int *e820_nr_map,
328                                UINT64 start,
329                                UINT64 size,
330                                UINT32 type)
331 {
332         int x = *e820_nr_map;
333
334         if (x == E820_MAX) {
335                 Print(L"Too many entries in the memory map!\n");
336                 return;
337         }
338
339         if ((x > 0) && e820_map[x-1].addr + e820_map[x-1].size == start
340             && e820_map[x-1].type == type)
341                 e820_map[x-1].size += size;
342         else {
343                 e820_map[x].addr = start;
344                 e820_map[x].size = size;
345                 e820_map[x].type = type;
346                 (*e820_nr_map)++;
347         }
348 }
349
350 void fill_e820map(boot_params_t *bp, mmap_desc_t *mdesc)
351 {
352         int nr_map, e820_nr_map = 0, i;
353         UINT64 start, end, size;
354         EFI_MEMORY_DESCRIPTOR   *md, *p;
355         struct e820entry *e820_map;
356
357         nr_map = mdesc->map_size/mdesc->desc_size;
358         e820_map = (struct e820entry *)bp->s.e820_map;
359
360         for (i = 0, p = mdesc->md; i < nr_map; i++)
361         {
362                 md = p;
363                 switch (md->Type) {
364                 case EfiACPIReclaimMemory:
365                         add_memory_region(e820_map, &e820_nr_map,
366                                           md->PhysicalStart,
367                                           md->NumberOfPages << EFI_PAGE_SHIFT,
368                                           E820_ACPI);
369                         break;
370                 case EfiRuntimeServicesCode:
371                 case EfiRuntimeServicesData:
372                 case EfiReservedMemoryType:
373                 case EfiMemoryMappedIO:
374                 case EfiMemoryMappedIOPortSpace:
375                 case EfiUnusableMemory:
376                 case EfiPalCode:
377                         add_memory_region(e820_map, &e820_nr_map,
378                                           md->PhysicalStart,
379                                           md->NumberOfPages << EFI_PAGE_SHIFT,
380                                           E820_RESERVED);
381                         break;
382                 case EfiLoaderCode:
383                 case EfiLoaderData:
384                 case EfiBootServicesCode:
385                 case EfiBootServicesData:
386                 case EfiConventionalMemory:
387                         start = md->PhysicalStart;
388                         size = md->NumberOfPages << EFI_PAGE_SHIFT;
389                         end = start + size;
390                         /* Fix up for BIOS that claims RAM in 640K-1MB region */
391                         if (start < 0x100000ULL && end > 0xA0000ULL) {
392                                 if (start < 0xA0000ULL) {
393                                         /* start < 640K
394                                          * set memory map from start to 640K
395                                          */
396                                         add_memory_region(e820_map,
397                                                           &e820_nr_map,
398                                                           start,
399                                                           0xA0000ULL-start,
400                                                           E820_RAM);
401                                 }
402                                 if (end <= 0x100000ULL)
403                                         continue;
404                                 /* end > 1MB
405                                  * set memory map avoiding 640K to 1MB hole
406                                  */
407                                 start = 0x100000ULL;
408                                 size = end - start;
409                         }
410                         add_memory_region(e820_map, &e820_nr_map,
411                                           start, size, E820_RAM);
412                         break;
413                 case EfiACPIMemoryNVS:
414                         add_memory_region(e820_map, &e820_nr_map,
415                                           md->PhysicalStart,
416                                           md->NumberOfPages << EFI_PAGE_SHIFT,
417                                           E820_NVS);
418                         break;
419                 default:
420                         /* We should not hit this case */
421                         add_memory_region(e820_map, &e820_nr_map,
422                                           md->PhysicalStart,
423                                           md->NumberOfPages << EFI_PAGE_SHIFT,
424                                           E820_RESERVED);
425                         break;
426                 }
427                 p = NextMemoryDescriptor(p, mdesc->desc_size);
428         }
429         bp->s.e820_nrmap = e820_nr_map;
430 }
431
432 /*
433  * IA-32 specific boot parameters initialization routine
434  */
435 INTN
436 sysdeps_create_boot_params(
437         boot_params_t *bp,
438         CHAR8 *cmdline,
439         memdesc_t *initrd,
440         memdesc_t *vmcode, /* no use for ia32 now*/
441         UINTN *cookie)
442 {
443         mmap_desc_t mdesc;
444         EFI_STATUS efi_status;
445         UINTN rows, cols;
446         UINT8 row, col;
447         UINT8 mode;
448         UINT16 hdr_version;
449
450         DBG_PRT((L"fill_boot_params()\n"));
451
452         if (!bp || !cmdline || !initrd || !cookie) {
453                 ERR_PRT((L"bp=" PTR_FMT "  cmdline=" PTR_FMT "  initrd=" PTR_FMT " cookie=" PTR_FMT,
454                         bp, cmdline, initrd, cookie));
455
456                 if (param_start != NULL) {
457                         free(param_start);
458                         param_start = NULL;
459                         param_size = 0;
460                 }
461                 free_kmem();
462                 return -1;
463         }
464
465         /*
466          * Copy temporary boot sector and setup data storage to
467          * elilo allocated boot parameter storage.  We only need
468          * the first two sectors (1K).  The rest of the storage
469          * can be used by the command line.
470          */
471         if (param_start != NULL) {
472                 CopyMem(bp, param_start, 0x2000);
473                 free(param_start);
474                 param_start = NULL;
475                 param_size = 0;
476         }
477         /*
478          * Save off our header revision information.
479          */
480         hdr_version = (bp->s.hdr_major << 8) | bp->s.hdr_minor;
481
482         /*
483          * Clear out unused memory in boot sector image.
484          */
485         bp->s.unused_1 = 0;
486         bp->s.unused_2 = 0;
487         ZeroMem(bp->s.unused_3, sizeof bp->s.unused_3);
488         ZeroMem(bp->s.unused_4, sizeof bp->s.unused_4);
489         ZeroMem(&bp->s.unused_51, sizeof bp->s.unused_51);
490         ZeroMem(bp->s.unused_52, sizeof bp->s.unused_52);
491         bp->s.unused_6 = 0;
492         bp->s.unused_7 = 0;
493         ZeroMem(bp->s.unused_8, sizeof bp->s.unused_8);
494
495         /*
496          * Tell kernel this was loaded by an advanced loader type.
497          * If this field is zero, the initrd_start and initrd_size
498          * fields are ignored by the kernel.
499          */
500
501         bp->s.loader_type = LDRTYPE_ELILO;
502
503         /*
504          * Setup command line information.
505          */
506
507         bp->s.cmdline_magik = CMDLINE_MAGIK;
508         bp->s.cmdline_offset = (UINT8 *)cmdline - (UINT8 *)bp;
509
510         /* 
511          * Clear out the cmdline_addr field so the kernel can find 
512          * the cmdline.
513          */
514         bp->s.cmdline_addr = 0x0;
515
516         /*
517          * Setup hard drive parameters.
518          * %%TBD - It should be okay to zero fill the hard drive
519          * info buffers.  The kernel should do its own detection.
520          */
521
522         ZeroMem(bp->s.hd0_info, sizeof bp->s.hd0_info);
523         ZeroMem(bp->s.hd1_info, sizeof bp->s.hd1_info);
524
525         /*
526          * Memory info.
527          */
528
529         bp->s.alt_mem_k = high_ext_mem / 1024;
530
531         if (bp->s.alt_mem_k <= 65535) 
532                 bp->s.ext_mem_k = (UINT16)bp->s.alt_mem_k;
533         else 
534                 bp->s.ext_mem_k = 65535;
535
536         /*
537          * Initial RAMdisk and root device stuff.
538          */
539
540         DBG_PRT((L"initrd->start_addr=" PTR_FMT "  initrd->pgcnt=%d\n",
541                 initrd->start_addr, initrd->pgcnt));
542
543         /* These RAMdisk flags are not needed, just zero them. */
544         bp->s.ramdisk_flags = 0;
545
546         if (initrd->start_addr && initrd->pgcnt) {
547                 /* %%TBD - This will probably have to be changed. */
548                 bp->s.initrd_start = (UINT32)initrd->start_addr;
549                 bp->s.initrd_size = (UINT32)(initrd->size);
550
551                 /*
552                  * This is the RAMdisk root device for RedHat 2.2.x
553                  * kernels (major 0x01, minor 0x00).
554                  */
555
556                 bp->s.orig_root_dev = 0x0100;
557         } else {
558                 bp->s.initrd_start = 0;
559                 bp->s.initrd_size = 0;
560         }
561
562         /*
563          * APM BIOS info.
564          */
565         bp->s.apm_bios_ver = NO_APM_BIOS;
566         bp->s.bios_code_seg = 0;
567         bp->s.bios_entry_point = 0;
568         bp->s.bios_code_seg16 = 0;
569         bp->s.bios_data_seg = 0;
570         bp->s.apm_bios_flags = 0;
571         bp->s.bios_code_len = 0;
572         bp->s.bios_data_len = 0;
573
574         /*
575          * MCA BIOS info (misnomer).
576          */
577         bp->s.mca_info_len = 0;
578         ZeroMem(bp->s.mca_info_buf, sizeof bp->s.mca_info_buf);
579
580         /*
581          * Pointing device presence.  The kernel will detect this.
582          */
583         bp->s.aux_dev_info = NO_MOUSE;
584
585         /*
586          * EFI loader signature 
587          */
588         CopyMem(bp->s.efi_loader_sig, EFI_LOADER_SIG_IA32, 4);
589
590         /*
591          * Kernel entry point.
592          */
593         bp->s.kernel_start = (UINT32)kernel_start;
594
595         /*
596          * When changing stuff in the parameter structure compare
597          * the offsets of the fields with the offsets used in the
598          * boot sector and setup source files.
599          *   arch/i386/boot/bootsect.S
600          *   arch/i386/boot/setup.S
601          *   arch/i386/kernel/setup.c
602          *   include/asm-i386/setup.h (2.5/2.6)
603          */
604
605 #define CHECK_OFFSET(n, o, f) \
606 { \
607         UINTN p = (UINT8 *)&bp->s.n - (UINT8 *)bp; \
608         UINTN q = (UINTN)(o); \
609         if (p != q) { \
610                 test |= 1; \
611                 Print(L"%20a:  %3xh  %3xh  ", #n, p, q); \
612                 if (*f) { \
613                         Print(f, bp->s.n); \
614                 } \
615                 Print(L"\n"); \
616         } \
617 }
618
619 #define WAIT_FOR_KEY() \
620 { \
621         EFI_INPUT_KEY key; \
622         while (uefi_call_wrapper(ST->ConIn->ReadKeyStroke, 2, ST->ConIn, &key) != EFI_SUCCESS) { \
623                 ; \
624         } \
625 }
626         {
627                 UINTN test = 0;
628
629                 CHECK_OFFSET(orig_cursor_col, 0x00, L"%xh");
630                 CHECK_OFFSET(orig_cursor_row, 0x01, L"%xh");
631                 CHECK_OFFSET(ext_mem_k, 0x02, L"%xh");
632                 CHECK_OFFSET(orig_video_page, 0x04, L"%xh");
633                 CHECK_OFFSET(orig_video_mode, 0x06, L"%xh");
634                 CHECK_OFFSET(orig_video_cols, 0x07, L"%xh");
635                 CHECK_OFFSET(orig_ega_bx, 0x0A, L"%xh");
636                 CHECK_OFFSET(orig_video_rows, 0x0E, L"%xh");
637                 CHECK_OFFSET(is_vga, 0x0F, L"%xh");
638                 CHECK_OFFSET(orig_video_points, 0x10, L"%xh");
639                 CHECK_OFFSET(lfb_width, 0x12, L"%xh");
640                 CHECK_OFFSET(lfb_height, 0x14, L"%xh");
641                 CHECK_OFFSET(lfb_depth, 0x16, L"%xh");
642                 CHECK_OFFSET(lfb_base, 0x18, L"%xh");
643                 CHECK_OFFSET(lfb_size, 0x1C, L"%xh");
644                 CHECK_OFFSET(cmdline_magik, 0x20, L"%xh");
645                 CHECK_OFFSET(cmdline_offset, 0x22, L"%xh");
646                 CHECK_OFFSET(lfb_line_len, 0x24, L"%xh");
647                 CHECK_OFFSET(lfb_red_size, 0x26, L"%xh");
648                 CHECK_OFFSET(lfb_red_pos, 0x27, L"%xh");
649                 CHECK_OFFSET(lfb_green_size, 0x28, L"%xh");
650                 CHECK_OFFSET(lfb_green_pos, 0x29, L"%xh");
651                 CHECK_OFFSET(lfb_blue_size, 0x2A, L"%xh");
652                 CHECK_OFFSET(lfb_blue_pos, 0x2B, L"%xh");
653                 CHECK_OFFSET(lfb_rsvd_size, 0x2C, L"%xh");
654                 CHECK_OFFSET(lfb_rsvd_pos, 0x2D, L"%xh");
655                 CHECK_OFFSET(vesa_seg, 0x2E, L"%xh");
656                 CHECK_OFFSET(vesa_off, 0x30, L"%xh");
657                 CHECK_OFFSET(lfb_pages, 0x32, L"%xh");
658                 CHECK_OFFSET(lfb_reserved, 0x34, L"");
659                 CHECK_OFFSET(apm_bios_ver, 0x40, L"%xh");
660                 CHECK_OFFSET(bios_code_seg, 0x42, L"%xh");
661                 CHECK_OFFSET(bios_entry_point, 0x44, L"%xh");
662                 CHECK_OFFSET(bios_code_seg16, 0x48, L"%xh");
663                 CHECK_OFFSET(bios_data_seg, 0x4A, L"%xh");
664                 CHECK_OFFSET(apm_bios_flags, 0x4C, L"%xh");
665                 CHECK_OFFSET(bios_code_len, 0x4E, L"%xh");
666                 CHECK_OFFSET(bios_data_len, 0x52, L"%xh");
667                 CHECK_OFFSET(hd0_info, 0x80, L"");
668                 CHECK_OFFSET(hd1_info, 0x90, L"");
669                 CHECK_OFFSET(mca_info_len, 0xA0, L"%xh");
670                 CHECK_OFFSET(mca_info_buf, 0xA2, L"");
671                 CHECK_OFFSET(efi_loader_sig, 0x1C0, L"'%-4.4a'");
672                 CHECK_OFFSET(efi_sys_tbl, 0x1C4, L"%xh");
673                 CHECK_OFFSET(efi_mem_desc_size, 0x1C8, L"%xh");
674                 CHECK_OFFSET(efi_mem_desc_ver, 0x1CC, L"%xh");
675                 CHECK_OFFSET(efi_mem_map, 0x1D0, L"%xh");
676                 CHECK_OFFSET(efi_mem_map_size, 0x1D4, L"%xh");
677                 CHECK_OFFSET(loader_start, 0x1D8, L"%xh");
678                 CHECK_OFFSET(loader_size, 0x1DC, L"%xh");
679                 CHECK_OFFSET(alt_mem_k, 0x1E0, L"%xh");
680                 CHECK_OFFSET(e820_nrmap, 0x1E8, L"%xh");
681                 CHECK_OFFSET(setup_sectors, 0x1F1, L"%xh");
682                 CHECK_OFFSET(mount_root_rdonly, 0x1F2, L"%xh");
683                 CHECK_OFFSET(sys_size, 0x1F4, L"%xh");
684                 CHECK_OFFSET(swap_dev, 0x1F6, L"%xh");
685                 CHECK_OFFSET(ramdisk_flags, 0x1F8, L"%xh");
686                 CHECK_OFFSET(video_mode_flag, 0x1FA, L"%xh");
687                 CHECK_OFFSET(orig_root_dev, 0x1FC, L"%xh");
688                 CHECK_OFFSET(aux_dev_info, 0x1FF, L"%xh");
689                 CHECK_OFFSET(jump, 0x200, L"%xh");
690                 CHECK_OFFSET(setup_sig, 0x202, L"'%-4.4a'");
691                 CHECK_OFFSET(hdr_minor, 0x206, L"%xh");
692                 CHECK_OFFSET(hdr_major, 0x207, L"%xh");
693                 CHECK_OFFSET(rm_switch, 0x208, L"%xh");
694                 CHECK_OFFSET(start_sys_seg, 0x20C, L"%xh");
695                 CHECK_OFFSET(kernel_verstr_offset, 0x20E, L"%xh");
696                 CHECK_OFFSET(loader_type, 0x210, L"%xh");
697                 CHECK_OFFSET(loader_flags, 0x211, L"%xh");
698                 CHECK_OFFSET(setup_move_size, 0x212, L"%xh");
699                 CHECK_OFFSET(kernel_start, 0x214, L"%xh");
700                 CHECK_OFFSET(initrd_start, 0x218, L"%xh");
701                 CHECK_OFFSET(initrd_size, 0x21C, L"%xh");
702                 CHECK_OFFSET(bootsect_helper, 0x220, L"%xh");
703                 CHECK_OFFSET(heap_end_ptr, 0x224, L"%xh");
704                 CHECK_OFFSET(cmdline_addr, 0x228, L"%xh");
705                 CHECK_OFFSET(e820_map, 0x2D0, L"'%-2560.2560a'");
706
707                 if (test) {
708                         ERR_PRT((L"Boot sector and/or setup parameter alignment error."));
709                         free_kmem();
710                         return -1;
711                 }
712         }
713
714         /*
715          * Get video information.
716          * Do this last so that any other cursor positioning done
717          * in the fill routine gets accounted for.
718          */
719
720         if (!get_video_info(bp)) goto do_memmap;
721
722         efi_status = uefi_call_wrapper(
723                 ST->ConOut->QueryMode,
724                 4,
725                 ST->ConOut,
726                 ST->ConOut->Mode->Mode,
727                 &cols,
728                 &rows);
729
730         if (EFI_ERROR(efi_status)) {
731                 ERR_PRT((L"QueryMode failed.  Fake it."));
732                 mode = 3;
733                 rows = 25;
734                 cols = 80;
735                 row = 24;
736                 col = 0;
737         } else {
738                 mode = (UINT8)ST->ConOut->Mode->Mode;
739                 col = (UINT8)ST->ConOut->Mode->CursorColumn;
740                 row = (UINT8)ST->ConOut->Mode->CursorRow;
741         }
742
743         bp->s.orig_cursor_col = col;
744         bp->s.orig_cursor_row = row;
745         bp->s.orig_video_page = 0;
746         bp->s.orig_video_mode = mode;
747         bp->s.orig_video_cols = (UINT8)cols;
748         bp->s.orig_video_rows = (UINT8)rows;
749
750         bp->s.orig_ega_bx = 0;
751         bp->s.is_vga = 0;
752         bp->s.orig_video_points = 16; 
753
754         bp->s.lfb_width = 0;
755         bp->s.lfb_height = 0;
756         bp->s.lfb_depth = 0;
757         bp->s.lfb_base = 0;
758         bp->s.lfb_size = 0;
759         bp->s.lfb_line_len = 0;
760         bp->s.lfb_red_size = 0;
761         bp->s.lfb_red_pos = 0;
762         bp->s.lfb_green_size = 0;
763         bp->s.lfb_green_pos = 0;
764         bp->s.lfb_blue_size = 0;
765         bp->s.lfb_blue_pos = 0;
766         bp->s.lfb_rsvd_size = 0;
767         bp->s.lfb_rsvd_pos = 0;
768         bp->s.lfb_pages = 0;
769         bp->s.vesa_seg = 0;
770         bp->s.vesa_off = 0;
771
772 do_memmap:
773         /*
774          * Get memory map description and cookie for ExitBootServices()
775          */
776
777         if (get_memmap(&mdesc)) {
778                 ERR_PRT((L"Could not get memory map."));
779                 free_kmem();
780                 return -1;
781         }
782         *cookie = mdesc.cookie;
783         bp->s.efi_mem_map = (UINTN)mdesc.md;
784         bp->s.efi_mem_map_size = mdesc.map_size;
785         bp->s.efi_mem_desc_size = mdesc.desc_size;
786         bp->s.efi_mem_desc_ver = mdesc.desc_version;
787         bp->s.efi_sys_tbl = (UINTN)systab;
788         /* Now that we have EFI memory map, convert it to E820 map
789          * and update the bootparam accordingly
790          */
791         fill_e820map(bp, &mdesc);
792         
793         return 0;
794 }