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