1*4a5d661aSToomas Soome /*- 2*4a5d661aSToomas Soome * Copyright (c) 1998 Michael Smith <msmith@freebsd.org> 3*4a5d661aSToomas Soome * Copyright (c) 2007 Semihalf, Rafal Jaworowski <raj@semihalf.com> 4*4a5d661aSToomas Soome * All rights reserved. 5*4a5d661aSToomas Soome * 6*4a5d661aSToomas Soome * Redistribution and use in source and binary forms, with or without 7*4a5d661aSToomas Soome * modification, are permitted provided that the following conditions 8*4a5d661aSToomas Soome * are met: 9*4a5d661aSToomas Soome * 1. Redistributions of source code must retain the above copyright 10*4a5d661aSToomas Soome * notice, this list of conditions and the following disclaimer. 11*4a5d661aSToomas Soome * 2. Redistributions in binary form must reproduce the above copyright 12*4a5d661aSToomas Soome * notice, this list of conditions and the following disclaimer in the 13*4a5d661aSToomas Soome * documentation and/or other materials provided with the distribution. 14*4a5d661aSToomas Soome * 15*4a5d661aSToomas Soome * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16*4a5d661aSToomas Soome * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17*4a5d661aSToomas Soome * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18*4a5d661aSToomas Soome * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19*4a5d661aSToomas Soome * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20*4a5d661aSToomas Soome * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21*4a5d661aSToomas Soome * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22*4a5d661aSToomas Soome * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23*4a5d661aSToomas Soome * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24*4a5d661aSToomas Soome * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25*4a5d661aSToomas Soome * SUCH DAMAGE. 26*4a5d661aSToomas Soome */ 27*4a5d661aSToomas Soome 28*4a5d661aSToomas Soome #include <sys/cdefs.h> 29*4a5d661aSToomas Soome __FBSDID("$FreeBSD$"); 30*4a5d661aSToomas Soome #include <sys/param.h> 31*4a5d661aSToomas Soome 32*4a5d661aSToomas Soome #include <stand.h> 33*4a5d661aSToomas Soome #include <stdint.h> 34*4a5d661aSToomas Soome 35*4a5d661aSToomas Soome #include "api_public.h" 36*4a5d661aSToomas Soome #include "glue.h" 37*4a5d661aSToomas Soome #include "libuboot.h" 38*4a5d661aSToomas Soome 39*4a5d661aSToomas Soome /* 40*4a5d661aSToomas Soome * MD primitives supporting placement of module data 41*4a5d661aSToomas Soome */ 42*4a5d661aSToomas Soome 43*4a5d661aSToomas Soome #ifdef __arm__ 44*4a5d661aSToomas Soome #define KERN_ALIGN (2 * 1024 * 1024) 45*4a5d661aSToomas Soome #else 46*4a5d661aSToomas Soome #define KERN_ALIGN PAGE_SIZE 47*4a5d661aSToomas Soome #endif 48*4a5d661aSToomas Soome 49*4a5d661aSToomas Soome /* 50*4a5d661aSToomas Soome * Avoid low memory, u-boot puts things like args and dtb blobs there. 51*4a5d661aSToomas Soome */ 52*4a5d661aSToomas Soome #define KERN_MINADDR max(KERN_ALIGN, (1024 * 1024)) 53*4a5d661aSToomas Soome 54*4a5d661aSToomas Soome extern void _start(void); /* ubldr entry point address. */ 55*4a5d661aSToomas Soome 56*4a5d661aSToomas Soome /* 57*4a5d661aSToomas Soome * This is called for every object loaded (kernel, module, dtb file, etc). The 58*4a5d661aSToomas Soome * expected return value is the next address at or after the given addr which is 59*4a5d661aSToomas Soome * appropriate for loading the given object described by type and data. On each 60*4a5d661aSToomas Soome * call the addr is the next address following the previously loaded object. 61*4a5d661aSToomas Soome * 62*4a5d661aSToomas Soome * The first call is for loading the kernel, and the addr argument will be zero, 63*4a5d661aSToomas Soome * and we search for a big block of ram to load the kernel and modules. 64*4a5d661aSToomas Soome * 65*4a5d661aSToomas Soome * On subsequent calls the addr will be non-zero, and we just round it up so 66*4a5d661aSToomas Soome * that each object begins on a page boundary. 67*4a5d661aSToomas Soome */ 68*4a5d661aSToomas Soome uint64_t 69*4a5d661aSToomas Soome uboot_loadaddr(u_int type, void *data, uint64_t addr) 70*4a5d661aSToomas Soome { 71*4a5d661aSToomas Soome struct sys_info *si; 72*4a5d661aSToomas Soome uint64_t sblock, eblock, subldr, eubldr; 73*4a5d661aSToomas Soome uint64_t biggest_block, this_block; 74*4a5d661aSToomas Soome uint64_t biggest_size, this_size; 75*4a5d661aSToomas Soome int i; 76*4a5d661aSToomas Soome char *envstr; 77*4a5d661aSToomas Soome 78*4a5d661aSToomas Soome if (addr == 0) { 79*4a5d661aSToomas Soome /* 80*4a5d661aSToomas Soome * If the loader_kernaddr environment variable is set, blindly 81*4a5d661aSToomas Soome * honor it. It had better be right. We force interpretation 82*4a5d661aSToomas Soome * of the value in base-16 regardless of any leading 0x prefix, 83*4a5d661aSToomas Soome * because that's the U-Boot convention. 84*4a5d661aSToomas Soome */ 85*4a5d661aSToomas Soome envstr = ub_env_get("loader_kernaddr"); 86*4a5d661aSToomas Soome if (envstr != NULL) 87*4a5d661aSToomas Soome return (strtoul(envstr, NULL, 16)); 88*4a5d661aSToomas Soome 89*4a5d661aSToomas Soome /* 90*4a5d661aSToomas Soome * Find addr/size of largest DRAM block. Carve our own address 91*4a5d661aSToomas Soome * range out of the block, because loading the kernel over the 92*4a5d661aSToomas Soome * top ourself is a poor memory-conservation strategy. Avoid 93*4a5d661aSToomas Soome * memory at beginning of the first block of physical ram, 94*4a5d661aSToomas Soome * since u-boot likes to pass args and data there. Assume that 95*4a5d661aSToomas Soome * u-boot has moved itself to the very top of ram and 96*4a5d661aSToomas Soome * optimistically assume that we won't run into it up there. 97*4a5d661aSToomas Soome */ 98*4a5d661aSToomas Soome if ((si = ub_get_sys_info()) == NULL) 99*4a5d661aSToomas Soome panic("could not retrieve system info"); 100*4a5d661aSToomas Soome 101*4a5d661aSToomas Soome biggest_block = 0; 102*4a5d661aSToomas Soome biggest_size = 0; 103*4a5d661aSToomas Soome subldr = rounddown2((uintptr_t)_start, KERN_ALIGN); 104*4a5d661aSToomas Soome eubldr = roundup2((uint64_t)uboot_heap_end, KERN_ALIGN); 105*4a5d661aSToomas Soome for (i = 0; i < si->mr_no; i++) { 106*4a5d661aSToomas Soome if (si->mr[i].flags != MR_ATTR_DRAM) 107*4a5d661aSToomas Soome continue; 108*4a5d661aSToomas Soome sblock = roundup2((uint64_t)si->mr[i].start, 109*4a5d661aSToomas Soome KERN_ALIGN); 110*4a5d661aSToomas Soome eblock = rounddown2((uint64_t)si->mr[i].start + 111*4a5d661aSToomas Soome si->mr[i].size, KERN_ALIGN); 112*4a5d661aSToomas Soome if (biggest_size == 0) 113*4a5d661aSToomas Soome sblock += KERN_MINADDR; 114*4a5d661aSToomas Soome if (subldr >= sblock && subldr < eblock) { 115*4a5d661aSToomas Soome if (subldr - sblock > eblock - eubldr) { 116*4a5d661aSToomas Soome this_block = sblock; 117*4a5d661aSToomas Soome this_size = subldr - sblock; 118*4a5d661aSToomas Soome } else { 119*4a5d661aSToomas Soome this_block = eubldr; 120*4a5d661aSToomas Soome this_size = eblock - eubldr; 121*4a5d661aSToomas Soome } 122*4a5d661aSToomas Soome } else if (subldr < sblock && eubldr < eblock) { 123*4a5d661aSToomas Soome /* Loader is below or engulfs the sblock */ 124*4a5d661aSToomas Soome this_block = (eubldr < sblock) ? sblock : eubldr; 125*4a5d661aSToomas Soome this_size = eblock - this_block; 126*4a5d661aSToomas Soome } else { 127*4a5d661aSToomas Soome this_block = 0; 128*4a5d661aSToomas Soome this_size = 0; 129*4a5d661aSToomas Soome } 130*4a5d661aSToomas Soome if (biggest_size < this_size) { 131*4a5d661aSToomas Soome biggest_block = this_block; 132*4a5d661aSToomas Soome biggest_size = this_size; 133*4a5d661aSToomas Soome } 134*4a5d661aSToomas Soome } 135*4a5d661aSToomas Soome if (biggest_size == 0) 136*4a5d661aSToomas Soome panic("Not enough DRAM to load kernel\n"); 137*4a5d661aSToomas Soome #if 0 138*4a5d661aSToomas Soome printf("Loading kernel into region 0x%08jx-0x%08jx (%ju MiB)\n", 139*4a5d661aSToomas Soome (uintmax_t)biggest_block, 140*4a5d661aSToomas Soome (uintmax_t)biggest_block + biggest_size - 1, 141*4a5d661aSToomas Soome (uintmax_t)biggest_size / 1024 / 1024); 142*4a5d661aSToomas Soome #endif 143*4a5d661aSToomas Soome return (biggest_block); 144*4a5d661aSToomas Soome } 145*4a5d661aSToomas Soome return roundup2(addr, PAGE_SIZE); 146*4a5d661aSToomas Soome } 147*4a5d661aSToomas Soome 148*4a5d661aSToomas Soome ssize_t 149*4a5d661aSToomas Soome uboot_copyin(const void *src, vm_offset_t dest, const size_t len) 150*4a5d661aSToomas Soome { 151*4a5d661aSToomas Soome bcopy(src, (void *)dest, len); 152*4a5d661aSToomas Soome return (len); 153*4a5d661aSToomas Soome } 154*4a5d661aSToomas Soome 155*4a5d661aSToomas Soome ssize_t 156*4a5d661aSToomas Soome uboot_copyout(const vm_offset_t src, void *dest, const size_t len) 157*4a5d661aSToomas Soome { 158*4a5d661aSToomas Soome bcopy((void *)src, dest, len); 159*4a5d661aSToomas Soome return (len); 160*4a5d661aSToomas Soome } 161*4a5d661aSToomas Soome 162*4a5d661aSToomas Soome ssize_t 163*4a5d661aSToomas Soome uboot_readin(const int fd, vm_offset_t dest, const size_t len) 164*4a5d661aSToomas Soome { 165*4a5d661aSToomas Soome return (read(fd, (void *)dest, len)); 166*4a5d661aSToomas Soome } 167