1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Copyright (c) 2011 The Chromium OS Authors. 4 */ 5 6 #include <common.h> 7 #include <dm.h> 8 #include <errno.h> 9 #include <linux/libfdt.h> 10 #include <os.h> 11 #include <asm/io.h> 12 #include <asm/setjmp.h> 13 #include <asm/state.h> 14 #include <dm/root.h> 15 16 DECLARE_GLOBAL_DATA_PTR; 17 18 /* Enable access to PCI memory with map_sysmem() */ 19 static bool enable_pci_map; 20 21 #ifdef CONFIG_PCI 22 /* Last device that was mapped into memory, and length of mapping */ 23 static struct udevice *map_dev; 24 unsigned long map_len; 25 #endif 26 27 void sandbox_exit(void) 28 { 29 /* Do this here while it still has an effect */ 30 os_fd_restore(); 31 if (state_uninit()) 32 os_exit(2); 33 34 if (dm_uninit()) 35 os_exit(2); 36 37 /* This is considered normal termination for now */ 38 os_exit(0); 39 } 40 41 /* delay x useconds */ 42 void __udelay(unsigned long usec) 43 { 44 struct sandbox_state *state = state_get_current(); 45 46 if (!state->skip_delays) 47 os_usleep(usec); 48 } 49 50 int cleanup_before_linux(void) 51 { 52 return 0; 53 } 54 55 int cleanup_before_linux_select(int flags) 56 { 57 return 0; 58 } 59 60 /** 61 * is_in_sandbox_mem() - Checks if a pointer is within sandbox's emulated DRAM 62 * 63 * This provides a way to check if a pointer is owned by sandbox (and is within 64 * its RAM) or not. Sometimes pointers come from a test which conceptually runs 65 * output sandbox, potentially with direct access to the C-library malloc() 66 * function, or the sandbox stack (which is not actually within the emulated 67 * DRAM. 68 * 69 * Such pointers obviously cannot be mapped into sandbox's DRAM, so we must 70 * detect them an process them separately, by recording a mapping to a tag, 71 * which we can use to map back to the pointer later. 72 * 73 * @ptr: Pointer to check 74 * @return true if this is within sandbox emulated DRAM, false if not 75 */ 76 static bool is_in_sandbox_mem(const void *ptr) 77 { 78 return (const uint8_t *)ptr >= gd->arch.ram_buf && 79 (const uint8_t *)ptr < gd->arch.ram_buf + gd->ram_size; 80 } 81 82 /** 83 * phys_to_virt() - Converts a sandbox RAM address to a pointer 84 * 85 * Sandbox uses U-Boot addresses from 0 to the size of DRAM. These index into 86 * the emulated DRAM buffer used by sandbox. This function converts such an 87 * address to a pointer into this buffer, which can be used to access the 88 * memory. 89 * 90 * If the address is outside this range, it is assumed to be a tag 91 */ 92 void *phys_to_virt(phys_addr_t paddr) 93 { 94 struct sandbox_mapmem_entry *mentry; 95 struct sandbox_state *state; 96 97 /* If the address is within emulated DRAM, calculate the value */ 98 if (paddr < gd->ram_size) 99 return (void *)(gd->arch.ram_buf + paddr); 100 101 /* 102 * Otherwise search out list of tags for the correct pointer previously 103 * created by map_to_sysmem() 104 */ 105 state = state_get_current(); 106 list_for_each_entry(mentry, &state->mapmem_head, sibling_node) { 107 if (mentry->tag == paddr) { 108 debug("%s: Used map from %lx to %p\n", __func__, 109 (ulong)paddr, mentry->ptr); 110 return mentry->ptr; 111 } 112 } 113 114 printf("%s: Cannot map sandbox address %lx (SDRAM from 0 to %lx)\n", 115 __func__, (ulong)paddr, (ulong)gd->ram_size); 116 os_abort(); 117 118 /* Not reached */ 119 return NULL; 120 } 121 122 struct sandbox_mapmem_entry *find_tag(const void *ptr) 123 { 124 struct sandbox_mapmem_entry *mentry; 125 struct sandbox_state *state = state_get_current(); 126 127 list_for_each_entry(mentry, &state->mapmem_head, sibling_node) { 128 if (mentry->ptr == ptr) { 129 debug("%s: Used map from %p to %lx\n", __func__, ptr, 130 mentry->tag); 131 return mentry; 132 } 133 } 134 return NULL; 135 } 136 137 phys_addr_t virt_to_phys(void *ptr) 138 { 139 struct sandbox_mapmem_entry *mentry; 140 141 /* 142 * If it is in emulated RAM, don't bother looking for a tag. Just 143 * calculate the pointer using the provides offset into the RAM buffer. 144 */ 145 if (is_in_sandbox_mem(ptr)) 146 return (phys_addr_t)((uint8_t *)ptr - gd->arch.ram_buf); 147 148 mentry = find_tag(ptr); 149 if (!mentry) { 150 /* Abort so that gdb can be used here */ 151 printf("%s: Cannot map sandbox address %p (SDRAM from 0 to %lx)\n", 152 __func__, ptr, (ulong)gd->ram_size); 153 os_abort(); 154 } 155 debug("%s: Used map from %p to %lx\n", __func__, ptr, mentry->tag); 156 157 return mentry->tag; 158 } 159 160 void *map_physmem(phys_addr_t paddr, unsigned long len, unsigned long flags) 161 { 162 #if defined(CONFIG_PCI) && !defined(CONFIG_SPL_BUILD) 163 unsigned long plen = len; 164 void *ptr; 165 166 map_dev = NULL; 167 if (enable_pci_map && !pci_map_physmem(paddr, &len, &map_dev, &ptr)) { 168 if (plen != len) { 169 printf("%s: Warning: partial map at %x, wanted %lx, got %lx\n", 170 __func__, (uint)paddr, len, plen); 171 } 172 map_len = len; 173 return ptr; 174 } 175 #endif 176 177 return phys_to_virt(paddr); 178 } 179 180 void unmap_physmem(const void *ptr, unsigned long flags) 181 { 182 #ifdef CONFIG_PCI 183 if (map_dev) { 184 pci_unmap_physmem(ptr, map_len, map_dev); 185 map_dev = NULL; 186 } 187 #endif 188 } 189 190 phys_addr_t map_to_sysmem(const void *ptr) 191 { 192 struct sandbox_mapmem_entry *mentry; 193 194 /* 195 * If it is in emulated RAM, don't bother creating a tag. Just return 196 * the offset into the RAM buffer. 197 */ 198 if (is_in_sandbox_mem(ptr)) 199 return (u8 *)ptr - gd->arch.ram_buf; 200 201 /* 202 * See if there is an existing tag with this pointer. If not, set up a 203 * new one. 204 */ 205 mentry = find_tag(ptr); 206 if (!mentry) { 207 struct sandbox_state *state = state_get_current(); 208 209 mentry = malloc(sizeof(*mentry)); 210 if (!mentry) { 211 printf("%s: Error: Out of memory\n", __func__); 212 os_exit(ENOMEM); 213 } 214 mentry->tag = state->next_tag++; 215 mentry->ptr = (void *)ptr; 216 list_add_tail(&mentry->sibling_node, &state->mapmem_head); 217 debug("%s: Added map from %p to %lx\n", __func__, ptr, 218 (ulong)mentry->tag); 219 } 220 221 /* 222 * Return the tag as the address to use. A later call to map_sysmem() 223 * will return ptr 224 */ 225 return mentry->tag; 226 } 227 228 void sandbox_set_enable_pci_map(int enable) 229 { 230 enable_pci_map = enable; 231 } 232 233 void flush_dcache_range(unsigned long start, unsigned long stop) 234 { 235 } 236 237 void invalidate_dcache_range(unsigned long start, unsigned long stop) 238 { 239 } 240 241 int sandbox_read_fdt_from_file(void) 242 { 243 struct sandbox_state *state = state_get_current(); 244 const char *fname = state->fdt_fname; 245 void *blob; 246 loff_t size; 247 int err; 248 int fd; 249 250 blob = map_sysmem(CONFIG_SYS_FDT_LOAD_ADDR, 0); 251 if (!state->fdt_fname) { 252 err = fdt_create_empty_tree(blob, 256); 253 if (!err) 254 goto done; 255 printf("Unable to create empty FDT: %s\n", fdt_strerror(err)); 256 return -EINVAL; 257 } 258 259 err = os_get_filesize(fname, &size); 260 if (err < 0) { 261 printf("Failed to file FDT file '%s'\n", fname); 262 return err; 263 } 264 fd = os_open(fname, OS_O_RDONLY); 265 if (fd < 0) { 266 printf("Failed to open FDT file '%s'\n", fname); 267 return -EACCES; 268 } 269 if (os_read(fd, blob, size) != size) { 270 os_close(fd); 271 return -EIO; 272 } 273 os_close(fd); 274 275 done: 276 gd->fdt_blob = blob; 277 278 return 0; 279 } 280 281 ulong timer_get_boot_us(void) 282 { 283 static uint64_t base_count; 284 uint64_t count = os_get_nsec(); 285 286 if (!base_count) 287 base_count = count; 288 289 return (count - base_count) / 1000; 290 } 291