1 /* 2 * bootstub 32 bit entry setting routings 3 * 4 * Copyright (C) 2008-2010 Intel Corporation. 5 * Author: Alek Du <alek.du (at) intel.com> 6 * 7 * This program is free software; you can redistribute it and/or modify it 8 * under the terms and conditions of the GNU General Public License, 9 * version 2, as published by the Free Software Foundation. 10 * 11 * This program is distributed in the hope it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 14 * more details. 15 * 16 * You should have received a copy of the GNU General Public License along with 17 * this program; if not, write to the Free Software Foundation, Inc., 18 * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. 19 * 20 */ 21 22 #include "types.h" 23 #include "bootstub.h" 24 #include "bootparam.h" 25 #include "spi-uart.h" 26 #include "ssp-uart.h" 27 #include "mb.h" 28 #include "sfi.h" 29 #include <bootimg.h> 30 31 #include <stdint.h> 32 #include <stddef.h> 33 #include "imr_toc.h" 34 35 #define PAGE_SIZE_MASK 0xFFF 36 #define MASK_1K 0x3FF 37 #define PAGE_ALIGN_FWD(x) ((x + PAGE_SIZE_MASK) & ~PAGE_SIZE_MASK) 38 #define PAGE_ALIGN_BACK(x) ((x) & ~PAGE_SIZE_MASK) 39 40 #define IMR_START_ADDRESS(x) (((x) & 0xFFFFFFFC) << 8) 41 #define IMR_END_ADDRESS(x) ((x == 0) ? (x) : ((((x) & 0xFFFFFFFC) << 8) | MASK_1K)) 42 43 #define IMR6_START_ADDRESS IMR_START_ADDRESS(*((u32 *)0xff108160)) 44 #define IMR6_END_ADDRESS IMR_END_ADDRESS(*((u32 *)0xff108164)) 45 #define IMR7_START_ADDRESS IMR_START_ADDRESS(*((u32 *)0xff108170)) 46 #define IMR7_END_ADDRESS IMR_END_ADDRESS(*((u32 *)0xff108174)) 47 48 #define FATAL_HANG() { asm("cli"); while (1) { asm("nop"); } } 49 50 extern int no_uart_used; 51 52 extern imr_toc_t imr6_toc; 53 static u32 imr7_size; 54 55 static u32 sps_load_adrs; 56 57 static memory_map_t mb_mmap[E820MAX]; 58 u32 mb_magic, mb_info; 59 60 struct gdt_ptr { 61 u16 len; 62 u32 ptr; 63 } __attribute__((packed)); 64 65 static void *memcpy(void *dest, const void *src, size_t count) 66 { 67 char *tmp = dest; 68 const char *s = src; 69 size_t _count = count / 4; 70 71 while (_count--) { 72 *(long *)tmp = *(long *)s; 73 tmp += 4; 74 s += 4; 75 } 76 count %= 4; 77 while (count--) 78 *tmp++ = *s++; 79 return dest; 80 } 81 82 static void *memset(void *s, unsigned char c, size_t count) 83 { 84 char *xs = s; 85 size_t _count = count / 4; 86 unsigned long _c = c << 24 | c << 16 | c << 8 | c; 87 88 while (_count--) { 89 *(long *)xs = _c; 90 xs += 4; 91 } 92 count %= 4; 93 while (count--) 94 *xs++ = c; 95 return s; 96 } 97 98 static size_t strnlen(const char *s, size_t maxlen) 99 { 100 const char *es = s; 101 while (*es && maxlen) { 102 es++; 103 maxlen--; 104 } 105 106 return (es - s); 107 } 108 109 static const char *strnchr(const char *s, int c, size_t maxlen) 110 { 111 int i; 112 for (i = 0; i < maxlen && *s != c; s++, i++) 113 ; 114 return s; 115 } 116 117 int strncmp(const char *cs, const char *ct, size_t count) 118 { 119 unsigned char c1, c2; 120 121 while (count) { 122 c1 = *cs++; 123 c2 = *ct++; 124 if (c1 != c2) 125 return c1 < c2 ? -1 : 1; 126 if (!c1) 127 break; 128 count--; 129 } 130 return 0; 131 } 132 133 static inline int is_image_aosp(unsigned char *magic) 134 { 135 return !strncmp((char *)magic, (char *)BOOT_MAGIC, sizeof(BOOT_MAGIC)-1); 136 } 137 138 static void setup_boot_params(struct boot_params *bp, struct setup_header *sh) 139 { 140 bp->screen_info.orig_video_mode = 0; 141 bp->screen_info.orig_video_lines = 0; 142 bp->screen_info.orig_video_cols = 0; 143 bp->alt_mem_k = 128*1024; // hard coded 128M mem here, since SFI will override it 144 memcpy(&bp->hdr, sh, sizeof (struct setup_header)); 145 bp->hdr.type_of_loader = 0xff; //bootstub is unknown bootloader for kernel :) 146 bp->hdr.hardware_subarch = X86_SUBARCH_MRST; 147 } 148 149 static u32 bzImage_setup(struct boot_params *bp, struct setup_header *sh) 150 { 151 void *cmdline = (void *)BOOT_CMDLINE_OFFSET; 152 struct boot_img_hdr *aosp = (struct boot_img_hdr *)AOSP_HEADER_ADDRESS; 153 size_t cmdline_len, extra_cmdline_len; 154 u8 *initramfs, *ptr; 155 156 if (is_image_aosp(aosp->magic)) { 157 ptr = (u8*)aosp->kernel_addr; 158 cmdline_len = strnlen((const char *)aosp->cmdline, sizeof(aosp->cmdline)); 159 extra_cmdline_len = strnlen((const char *)aosp->extra_cmdline, sizeof(aosp->extra_cmdline)); 160 161 /* 162 * Copy the command + extra command line to be after bootparams 163 * so that it won't be overwritten by the kernel executable. 164 */ 165 memset(cmdline, 0, sizeof(aosp->cmdline) + sizeof(aosp->extra_cmdline)); 166 memcpy(cmdline, (const void *)aosp->cmdline, cmdline_len); 167 memcpy(cmdline + cmdline_len, (const void *)aosp->extra_cmdline, extra_cmdline_len); 168 169 bp->hdr.ramdisk_size = aosp->ramdisk_size; 170 171 initramfs = (u8 *)aosp->ramdisk_addr; 172 } else { 173 ptr = (u8*)BZIMAGE_OFFSET; 174 cmdline_len = strnlen((const char *)CMDLINE_OFFSET, CMDLINE_SIZE); 175 /* 176 * Copy the command line to be after bootparams so that it won't be 177 * overwritten by the kernel executable. 178 */ 179 memset(cmdline, 0, CMDLINE_SIZE); 180 memcpy(cmdline, (const void *)CMDLINE_OFFSET, cmdline_len); 181 182 bp->hdr.ramdisk_size = *(u32 *)INITRD_SIZE_OFFSET; 183 184 initramfs = (u8 *)BZIMAGE_OFFSET + *(u32 *)BZIMAGE_SIZE_OFFSET; 185 } 186 187 bp->hdr.cmd_line_ptr = BOOT_CMDLINE_OFFSET; 188 bp->hdr.cmdline_size = cmdline_len; 189 #ifndef BUILD_RAMDUMP 190 bp->hdr.ramdisk_image = (bp->alt_mem_k*1024 - bp->hdr.ramdisk_size) & 0xFFFFF000; 191 192 if (*initramfs) { 193 bs_printk("Relocating initramfs to high memory ...\n"); 194 memcpy((u8*)bp->hdr.ramdisk_image, initramfs, bp->hdr.ramdisk_size); 195 } else { 196 bs_printk("Won't relocate initramfs, are you in SLE?\n"); 197 } 198 #else 199 bp->hdr.ramdisk_image = (u32) initramfs; 200 #endif 201 202 while (1){ 203 if (*(u32 *)ptr == SETUP_SIGNATURE && *(u32 *)(ptr+4) == 0) 204 break; 205 ptr++; 206 } 207 ptr+=4; 208 return (((unsigned int)ptr+511)/512)*512; 209 } 210 211 static inline void cpuid(u32 op, u32 regs[4]) 212 { 213 __asm__ volatile ( 214 "mov %%ebx, %%edi\n" 215 "cpuid\n" 216 "xchg %%edi, %%ebx\n" 217 : "=a"(regs[0]), "=D"(regs[1]), "=c"(regs[2]), "=d"(regs[3]) 218 : "a"(op) 219 ); 220 } 221 222 enum cpuid_regs { 223 CR_EAX = 0, 224 CR_ECX, 225 CR_EDX, 226 CR_EBX 227 }; 228 229 int mid_identify_cpu(void) 230 { 231 u32 regs[4]; 232 233 cpuid(1, regs); 234 235 switch ( regs[CR_EAX] & CPUID_MASK ) { 236 237 case PENWELL_FAMILY: 238 return MID_CPU_CHIP_PENWELL; 239 case CLOVERVIEW_FAMILY: 240 return MID_CPU_CHIP_CLOVERVIEW; 241 case VALLEYVIEW2_FAMILY: 242 return MID_CPU_CHIP_VALLEYVIEW2; 243 case TANGIER_FAMILY: 244 return MID_CPU_CHIP_TANGIER; 245 case ANNIEDALE_FAMILY: 246 return MID_CPU_CHIP_ANNIEDALE; 247 default: 248 return MID_CPU_CHIP_OTHER; 249 } 250 } 251 252 static void setup_spi(void) 253 { 254 if (!(*(int *)SPI_TYPE)) { 255 switch ( mid_identify_cpu() ) { 256 257 case MID_CPU_CHIP_PENWELL: 258 *(int *)SPI_TYPE = SPI_1; 259 bs_printk("PNW detected\n"); 260 break; 261 262 case MID_CPU_CHIP_CLOVERVIEW: 263 *(int *)SPI_TYPE = SPI_1; 264 bs_printk("CLV detected\n"); 265 break; 266 267 case MID_CPU_CHIP_TANGIER: 268 *(int *)SPI_TYPE = SPI_2; 269 bs_printk("MRD detected\n"); 270 break; 271 272 case MID_CPU_CHIP_ANNIEDALE: 273 *(int *)SPI_TYPE = SPI_2; 274 bs_printk("ANN detected\n"); 275 break; 276 277 case MID_CPU_CHIP_VALLEYVIEW2: 278 case MID_CPU_CHIP_OTHER: 279 default: 280 no_uart_used = 1; 281 } 282 } 283 } 284 285 static void setup_gdt(void) 286 { 287 static const u64 boot_gdt[] __attribute__((aligned(16))) = { 288 /* CS: code, read/execute, 4 GB, base 0 */ 289 [GDT_ENTRY_BOOT_CS] = GDT_ENTRY(0xc09b, 0, 0xfffff), 290 /* DS: data, read/write, 4 GB, base 0 */ 291 [GDT_ENTRY_BOOT_DS] = GDT_ENTRY(0xc093, 0, 0xfffff), 292 }; 293 static struct gdt_ptr gdt; 294 295 gdt.len = sizeof(boot_gdt)-1; 296 gdt.ptr = (u32)&boot_gdt; 297 298 asm volatile("lgdtl %0" : : "m" (gdt)); 299 } 300 301 static void setup_idt(void) 302 { 303 static const struct gdt_ptr null_idt = {0, 0}; 304 asm volatile("lidtl %0" : : "m" (null_idt)); 305 } 306 307 static void vxe_fw_setup(void) 308 { 309 u8 *vxe_fw_image; 310 u32 vxe_fw_size; 311 u32 vxe_fw_load_adrs; 312 313 vxe_fw_size = *(u32*)VXE_FW_SIZE_OFFSET; 314 /* do we have a VXE FW image? */ 315 if (vxe_fw_size == 0) 316 return; 317 318 /* Do we have enough room to load the image? */ 319 if (vxe_fw_size > imr6_toc.entries[IMR_TOC_ENTRY_VXE_FW].size) { 320 bs_printk("FATAL ERROR: VXE FW image size is too large for IMR\n"); 321 FATAL_HANG(); 322 } 323 324 vxe_fw_image = (u8 *)( 325 BZIMAGE_OFFSET 326 + *(u32 *)BZIMAGE_SIZE_OFFSET 327 + *(u32 *)INITRD_SIZE_OFFSET 328 ); 329 330 vxe_fw_load_adrs = IMR6_START_ADDRESS + imr6_toc.entries[IMR_TOC_ENTRY_VXE_FW].start_offset; 331 memcpy((u8 *)vxe_fw_load_adrs, vxe_fw_image, vxe_fw_size); 332 } 333 334 static void load_imr_toc(u32 imr, u32 imrsize, imr_toc_t *toc, u32 tocsize) 335 { 336 if (imr == 0 || imrsize == 0 || toc == NULL || tocsize == 0 || imrsize < tocsize ) 337 { 338 bs_printk("FATAL ERROR: TOC size is too large for IMR\n"); 339 FATAL_HANG(); 340 } 341 memcpy((u8 *)imr, (u8 *)toc, tocsize); 342 } 343 344 345 static u32 xen_multiboot_setup(void) 346 { 347 u32 *magic, *xen_image, i; 348 char *src, *dst; 349 u32 xen_size; 350 u32 xen_jump_adrs; 351 static module_t modules[3]; 352 static multiboot_info_t mb = { 353 .flags = MBI_CMDLINE | MBI_MODULES | MBI_MEMMAP | MBI_DRIVES, 354 .mmap_addr = (u32)mb_mmap, 355 .mods_count = 3, 356 .mods_addr = (u32)modules, 357 }; 358 359 xen_size = *(u32 *)XEN_SIZE_OFFSET; 360 /* do we have a xen image? */ 361 if (xen_size == 0) { 362 return 0; 363 } 364 365 /* Compute the actual offset of the Xen image */ 366 xen_image = (u32*)( 367 BZIMAGE_OFFSET 368 + *(u32 *)BZIMAGE_SIZE_OFFSET 369 + *(u32 *)INITRD_SIZE_OFFSET 370 + *(u32 *)VXE_FW_SIZE_OFFSET 371 + *(u32 *)SEC_PLAT_SVCS_SIZE_OFFSET 372 ); 373 374 /* the multiboot signature should be located in the first 8192 bytes */ 375 for (magic = xen_image; magic < xen_image + 2048; magic++) 376 if (*magic == MULTIBOOT_HEADER_MAGIC) 377 break; 378 if (*magic != MULTIBOOT_HEADER_MAGIC) { 379 return 0; 380 } 381 382 mb.cmdline = (u32)strnchr((char *)CMDLINE_OFFSET, '$', CMDLINE_SIZE) + 1; 383 dst = (char *)mb.cmdline + strnlen((const char *)mb.cmdline, CMDLINE_SIZE) - 1; 384 *dst = ' '; 385 dst++; 386 src = (char *)CMDLINE_OFFSET; 387 for (i = 0 ;i < strnlen((const char *)CMDLINE_OFFSET, CMDLINE_SIZE);i++) { 388 if (!strncmp(src, "capfreq=", 8)) { 389 while (*src != ' ' && *src != 0) { 390 *dst = *src; 391 dst++; 392 src++; 393 } 394 break; 395 } 396 src++; 397 } 398 399 /* fill in the multiboot module information: dom0 kernel + initrd + Platform Services Image */ 400 modules[0].mod_start = BZIMAGE_OFFSET; 401 modules[0].mod_end = BZIMAGE_OFFSET + *(u32 *)BZIMAGE_SIZE_OFFSET; 402 modules[0].string = CMDLINE_OFFSET; 403 404 modules[1].mod_start = modules[0].mod_end ; 405 modules[1].mod_end = modules[1].mod_start + *(u32 *)INITRD_SIZE_OFFSET; 406 modules[1].string = 0; 407 408 modules[2].mod_start = sps_load_adrs; 409 modules[2].mod_end = modules[2].mod_start + *(u32 *)SEC_PLAT_SVCS_SIZE_OFFSET; 410 modules[2].string = 0; 411 412 mb.drives_addr = IMR6_START_ADDRESS + imr6_toc.entries[IMR_TOC_ENTRY_XEN_EXTRA].start_offset; 413 mb.drives_length = imr6_toc.entries[IMR_TOC_ENTRY_XEN_EXTRA].size; 414 415 for(i = 0; i < E820MAX; i++) 416 if (!mb_mmap[i].size) 417 break; 418 mb.mmap_length = i * sizeof(memory_map_t); 419 420 /* relocate xen to start address */ 421 if (xen_size > imr7_size) { 422 bs_printk("FATAL ERROR: Xen image size is too large for IMR\n"); 423 FATAL_HANG(); 424 } 425 xen_jump_adrs = IMR7_START_ADDRESS; 426 memcpy((u8 *)xen_jump_adrs, xen_image, xen_size); 427 428 mb_info = (u32)&mb; 429 mb_magic = MULTIBOOT_BOOTLOADER_MAGIC; 430 431 return (u32)xen_jump_adrs; 432 } 433 434 static void sec_plat_svcs_setup(void) 435 { 436 u8 *sps_image; 437 u32 sps_size; 438 439 sps_size = PAGE_ALIGN_FWD(*(u32*)SEC_PLAT_SVCS_SIZE_OFFSET); 440 /* do we have a SPS image? */ 441 if (sps_size == 0) 442 return; 443 444 /* Do we have enough room to load the image? */ 445 if (sps_size > imr7_size) { 446 bs_printk("FATAL ERROR: SPS image size is too large for IMR\n"); 447 FATAL_HANG(); 448 } 449 450 sps_image = (u8 *)( 451 BZIMAGE_OFFSET 452 + *(u32 *)BZIMAGE_SIZE_OFFSET 453 + *(u32 *)INITRD_SIZE_OFFSET 454 + *(u32 *)VXE_FW_SIZE_OFFSET 455 ); 456 457 /* load SPS image (with assumed CHAABI Mailboxes suffixed) */ 458 /* at bottom of IMR7 */ 459 /* Must be page-aligned or Xen will panic */ 460 sps_load_adrs = PAGE_ALIGN_BACK(IMR7_START_ADDRESS + imr7_size - sps_size); 461 memcpy((u8 *)sps_load_adrs, sps_image, sps_size); 462 463 /* reduce remaining size for Xen image size check */ 464 imr7_size -= sps_size; 465 } 466 467 int bootstub(void) 468 { 469 u32 jmp; 470 struct boot_img_hdr *aosp = (struct boot_img_hdr *)AOSP_HEADER_ADDRESS; 471 struct boot_params *bp = (struct boot_params *)BOOT_PARAMS_OFFSET; 472 struct setup_header *sh; 473 u32 imr_size; 474 int nr_entries; 475 476 if (is_image_aosp(aosp->magic)) { 477 sh = (struct setup_header *)((unsigned int)aosp->kernel_addr + \ 478 (unsigned int)offsetof(struct boot_params,hdr)); 479 /* disable the bs_printk through SPI/UART */ 480 *(int *)SPI_UART_SUPPRESSION = 1; 481 *(int *)SPI_TYPE = SPI_2; 482 } else 483 sh = (struct setup_header *)SETUP_HEADER_OFFSET; 484 485 setup_idt(); 486 setup_gdt(); 487 setup_spi(); 488 bs_printk("Bootstub Version: 1.4 ...\n"); 489 490 memset(bp, 0, sizeof (struct boot_params)); 491 492 if (mid_identify_cpu() == MID_CPU_CHIP_VALLEYVIEW2) { 493 nr_entries = get_e820_by_bios(bp->e820_map); 494 bp->e820_entries = (nr_entries > 0) ? nr_entries : 0; 495 } else { 496 sfi_setup_mmap(bp, mb_mmap); 497 } 498 499 if ((mid_identify_cpu() != MID_CPU_CHIP_TANGIER) && (mid_identify_cpu() != MID_CPU_CHIP_ANNIEDALE)) { 500 if ((IMR6_END_ADDRESS > IMR6_START_ADDRESS) && (IMR7_END_ADDRESS > IMR7_START_ADDRESS)) { 501 imr_size = PAGE_ALIGN_FWD(IMR6_END_ADDRESS - IMR6_START_ADDRESS); 502 load_imr_toc(IMR6_START_ADDRESS, imr_size, &imr6_toc, sizeof(imr6_toc)); 503 vxe_fw_setup(); 504 sfi_add_e820_entry(bp, mb_mmap, IMR6_START_ADDRESS, imr_size, E820_RESERVED); 505 506 imr7_size = PAGE_ALIGN_FWD(IMR7_END_ADDRESS - IMR7_START_ADDRESS); 507 sec_plat_svcs_setup(); 508 sfi_add_e820_entry(bp, mb_mmap, IMR7_START_ADDRESS, imr7_size, E820_RESERVED); 509 } else { 510 *(u32 *)XEN_SIZE_OFFSET = 0; /* Don't allow Xen to boot */ 511 } 512 } else { 513 *(u32 *)XEN_SIZE_OFFSET = 0; /* Don't allow Xen to boot */ 514 } 515 516 setup_boot_params(bp, sh); 517 518 jmp = xen_multiboot_setup(); 519 if (!jmp) { 520 bs_printk("Using bzImage to boot\n"); 521 jmp = bzImage_setup(bp, sh); 522 } else 523 bs_printk("Using multiboot image to boot\n"); 524 525 bs_printk("Jump to kernel 32bit entry\n"); 526 return jmp; 527 } 528 529 void bs_printk(const char *str) 530 { 531 if (*(int *)SPI_UART_SUPPRESSION) 532 return; 533 534 switch (*(int *)SPI_TYPE) { 535 536 case SPI_1: 537 bs_spi_printk(str); 538 break; 539 540 case SPI_2: 541 bs_ssp_printk(str); 542 break; 543 } 544 } 545