15db28905STom Rini /* 25db28905STom Rini * (C) Copyright 2000-2009 35db28905STom Rini * Wolfgang Denk, DENX Software Engineering, wd@denx.de. 45db28905STom Rini * 55db28905STom Rini * SPDX-License-Identifier: GPL-2.0+ 65db28905STom Rini */ 75db28905STom Rini 85db28905STom Rini #include <common.h> 95db28905STom Rini #include <bootm.h> 105db28905STom Rini #include <command.h> 115db28905STom Rini #include <image.h> 125db28905STom Rini #include <lmb.h> 135db28905STom Rini #include <mapmem.h> 145db28905STom Rini 155db28905STom Rini DECLARE_GLOBAL_DATA_PTR; 165db28905STom Rini 175db28905STom Rini /* See Documentation/arm64/booting.txt in the Linux kernel */ 185db28905STom Rini struct Image_header { 195db28905STom Rini uint32_t code0; /* Executable code */ 205db28905STom Rini uint32_t code1; /* Executable code */ 215db28905STom Rini uint64_t text_offset; /* Image load offset, LE */ 225db28905STom Rini uint64_t image_size; /* Effective Image size, LE */ 235db28905STom Rini uint64_t res1; /* reserved */ 245db28905STom Rini uint64_t res2; /* reserved */ 255db28905STom Rini uint64_t res3; /* reserved */ 265db28905STom Rini uint64_t res4; /* reserved */ 275db28905STom Rini uint32_t magic; /* Magic number */ 285db28905STom Rini uint32_t res5; 295db28905STom Rini }; 305db28905STom Rini 315db28905STom Rini #define LINUX_ARM64_IMAGE_MAGIC 0x644d5241 325db28905STom Rini 335db28905STom Rini static int booti_setup(bootm_headers_t *images) 345db28905STom Rini { 355db28905STom Rini struct Image_header *ih; 365db28905STom Rini uint64_t dst; 375db28905STom Rini uint64_t image_size; 385db28905STom Rini 395db28905STom Rini ih = (struct Image_header *)map_sysmem(images->ep, 0); 405db28905STom Rini 415db28905STom Rini if (ih->magic != le32_to_cpu(LINUX_ARM64_IMAGE_MAGIC)) { 425db28905STom Rini puts("Bad Linux ARM64 Image magic!\n"); 435db28905STom Rini return 1; 445db28905STom Rini } 455db28905STom Rini 465db28905STom Rini if (ih->image_size == 0) { 475db28905STom Rini puts("Image lacks image_size field, assuming 16MiB\n"); 485db28905STom Rini image_size = 16 << 20; 495db28905STom Rini } else { 505db28905STom Rini image_size = le64_to_cpu(ih->image_size); 515db28905STom Rini } 525db28905STom Rini 535db28905STom Rini /* 545db28905STom Rini * If we are not at the correct run-time location, set the new 555db28905STom Rini * correct location and then move the image there. 565db28905STom Rini */ 575db28905STom Rini dst = gd->bd->bi_dram[0].start + le64_to_cpu(ih->text_offset); 585db28905STom Rini 595db28905STom Rini unmap_sysmem(ih); 605db28905STom Rini 615db28905STom Rini if (images->ep != dst) { 625db28905STom Rini void *src; 635db28905STom Rini 645db28905STom Rini debug("Moving Image from 0x%lx to 0x%llx\n", images->ep, dst); 655db28905STom Rini 665db28905STom Rini src = (void *)images->ep; 675db28905STom Rini images->ep = dst; 685db28905STom Rini memmove((void *)dst, src, image_size); 695db28905STom Rini } 705db28905STom Rini 715db28905STom Rini return 0; 725db28905STom Rini } 735db28905STom Rini 745db28905STom Rini /* 755db28905STom Rini * Image booting support 765db28905STom Rini */ 775db28905STom Rini static int booti_start(cmd_tbl_t *cmdtp, int flag, int argc, 785db28905STom Rini char * const argv[], bootm_headers_t *images) 795db28905STom Rini { 805db28905STom Rini int ret; 815db28905STom Rini struct Image_header *ih; 825db28905STom Rini 835db28905STom Rini ret = do_bootm_states(cmdtp, flag, argc, argv, BOOTM_STATE_START, 845db28905STom Rini images, 1); 855db28905STom Rini 865db28905STom Rini /* Setup Linux kernel Image entry point */ 875db28905STom Rini if (!argc) { 885db28905STom Rini images->ep = load_addr; 895db28905STom Rini debug("* kernel: default image load address = 0x%08lx\n", 905db28905STom Rini load_addr); 915db28905STom Rini } else { 925db28905STom Rini images->ep = simple_strtoul(argv[0], NULL, 16); 935db28905STom Rini debug("* kernel: cmdline image address = 0x%08lx\n", 945db28905STom Rini images->ep); 955db28905STom Rini } 965db28905STom Rini 975db28905STom Rini ret = booti_setup(images); 985db28905STom Rini if (ret != 0) 995db28905STom Rini return 1; 1005db28905STom Rini 1015db28905STom Rini ih = (struct Image_header *)map_sysmem(images->ep, 0); 1025db28905STom Rini 1035db28905STom Rini lmb_reserve(&images->lmb, images->ep, le32_to_cpu(ih->image_size)); 1045db28905STom Rini 1055db28905STom Rini unmap_sysmem(ih); 1065db28905STom Rini 1075db28905STom Rini /* 1085db28905STom Rini * Handle the BOOTM_STATE_FINDOTHER state ourselves as we do not 1095db28905STom Rini * have a header that provide this informaiton. 1105db28905STom Rini */ 1115db28905STom Rini if (bootm_find_images(flag, argc, argv)) 1125db28905STom Rini return 1; 1135db28905STom Rini 1145db28905STom Rini return 0; 1155db28905STom Rini } 1165db28905STom Rini 1175db28905STom Rini int do_booti(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 1185db28905STom Rini { 1195db28905STom Rini int ret; 1205db28905STom Rini 1215db28905STom Rini /* Consume 'booti' */ 1225db28905STom Rini argc--; argv++; 1235db28905STom Rini 1245db28905STom Rini if (booti_start(cmdtp, flag, argc, argv, &images)) 1255db28905STom Rini return 1; 1265db28905STom Rini 1275db28905STom Rini /* 1285db28905STom Rini * We are doing the BOOTM_STATE_LOADOS state ourselves, so must 1295db28905STom Rini * disable interrupts ourselves 1305db28905STom Rini */ 1315db28905STom Rini bootm_disable_interrupts(); 1325db28905STom Rini 1335db28905STom Rini images.os.os = IH_OS_LINUX; 1345db28905STom Rini ret = do_bootm_states(cmdtp, flag, argc, argv, 135*4943dc2fSCédric Schieli #ifdef CONFIG_SYS_BOOT_RAMDISK_HIGH 136*4943dc2fSCédric Schieli BOOTM_STATE_RAMDISK | 137*4943dc2fSCédric Schieli #endif 1385db28905STom Rini BOOTM_STATE_OS_PREP | BOOTM_STATE_OS_FAKE_GO | 1395db28905STom Rini BOOTM_STATE_OS_GO, 1405db28905STom Rini &images, 1); 1415db28905STom Rini 1425db28905STom Rini return ret; 1435db28905STom Rini } 1445db28905STom Rini 1455db28905STom Rini #ifdef CONFIG_SYS_LONGHELP 1465db28905STom Rini static char booti_help_text[] = 1475db28905STom Rini "[addr [initrd[:size]] [fdt]]\n" 1485db28905STom Rini " - boot arm64 Linux Image stored in memory\n" 1495db28905STom Rini "\tThe argument 'initrd' is optional and specifies the address\n" 1505db28905STom Rini "\tof an initrd in memory. The optional parameter ':size' allows\n" 1515db28905STom Rini "\tspecifying the size of a RAW initrd.\n" 1525db28905STom Rini #if defined(CONFIG_OF_LIBFDT) 1535db28905STom Rini "\tSince booting a Linux kernel requires a flat device-tree, a\n" 1545db28905STom Rini "\tthird argument providing the address of the device-tree blob\n" 1555db28905STom Rini "\tis required. To boot a kernel with a device-tree blob but\n" 1565db28905STom Rini "\twithout an initrd image, use a '-' for the initrd argument.\n" 1575db28905STom Rini #endif 1585db28905STom Rini ""; 1595db28905STom Rini #endif 1605db28905STom Rini 1615db28905STom Rini U_BOOT_CMD( 1625db28905STom Rini booti, CONFIG_SYS_MAXARGS, 1, do_booti, 1635db28905STom Rini "boot arm64 Linux Image image from memory", booti_help_text 1645db28905STom Rini ); 165