summaryrefslogtreecommitdiff
path: root/ldso/ldso/bfin/dl-inlines.h
blob: 67f9ff6a351cb2ecbaeab4eae3be0cd80b0daef4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
/* Copyright (C) 2003, 2004 Red Hat, Inc.
 * Contributed by Alexandre Oliva <aoliva@redhat.com>
 * Copyright (C) 2006-2011 Analog Devices, Inc.
 *
 * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
 */

#include <bfin_sram.h>

#define __dl_loadaddr_unmap __dl_loadaddr_unmap

#include "../fdpic/dl-inlines.h"

void
__dl_loadaddr_unmap (struct elf32_fdpic_loadaddr loadaddr,
		     struct funcdesc_ht *funcdesc_ht)
{
  int i;

  for (i = 0; i < loadaddr.map->nsegs; i++)
    {
      struct elf32_fdpic_loadseg *segdata;
      ssize_t offs;
      segdata = loadaddr.map->segs + i;

      /* FIXME:
        A more cleaner way is to add type for struct elf32_fdpic_loadseg,
        and release the memory according to the type.
        Currently, we hardcode the memory address of L1 SRAM.  */
      if ((segdata->addr & 0xff800000) == 0xff800000)
       {
         _dl_sram_free ((void *)segdata->addr);
         continue;
       }

      offs = (segdata->p_vaddr & ADDR_ALIGN);
      _dl_munmap ((void*)segdata->addr - offs,
		  segdata->p_memsz + offs);
    }
  /* _dl_unmap is only called for dlopen()ed libraries, for which
     calling free() is safe, or before we've completed the initial
     relocation, in which case calling free() is probably pointless,
     but still safe.  */
  _dl_free (loadaddr.map);
  if (funcdesc_ht)
    htab_delete (funcdesc_ht);
}

static __always_inline int
__dl_is_special_segment (Elf32_Ehdr *epnt,
			 Elf32_Phdr *ppnt)
{
  if (ppnt->p_type != PT_LOAD)
    return 0;

  if ((epnt->e_flags & EF_BFIN_CODE_IN_L1)
      && !(ppnt->p_flags & PF_W)
      && (ppnt->p_flags & PF_X))
    return 1;

  if ((epnt->e_flags & EF_BFIN_DATA_IN_L1)
      && (ppnt->p_flags & PF_W)
      && !(ppnt->p_flags & PF_X))
    return 1;

  /* 0xfeb00000, 0xfec00000, 0xff700000, 0xff800000, 0xff900000,
     and 0xffa00000 are also used in GNU ld and linux kernel.
     They need to be kept synchronized.  */
  if (ppnt->p_vaddr == 0xff700000
      || ppnt->p_vaddr == 0xff800000
      || ppnt->p_vaddr == 0xff900000
      || ppnt->p_vaddr == 0xffa00000
      || ppnt->p_vaddr == 0xfeb00000
      || ppnt->p_vaddr == 0xfec00000)
    return 1;

  return 0;
}

static __always_inline char *
__dl_map_segment (Elf32_Ehdr *epnt,
		  Elf32_Phdr *ppnt,
		  int infile,
		  int flags)
{
  char *status, *tryaddr, *addr;
  size_t size;

  if (((epnt->e_flags & EF_BFIN_CODE_IN_L1) || ppnt->p_vaddr == 0xffa00000)
      && !(ppnt->p_flags & PF_W)
      && (ppnt->p_flags & PF_X)) {
    status = (char *) _dl_mmap
      (tryaddr = 0,
       size = (ppnt->p_vaddr & ADDR_ALIGN) + ppnt->p_filesz,
       LXFLAGS(ppnt->p_flags),
       flags | MAP_EXECUTABLE | MAP_DENYWRITE,
       infile, ppnt->p_offset & OFFS_ALIGN);
    if (_dl_mmap_check_error(status)
	|| (tryaddr && tryaddr != status))
      return NULL;
    addr = (char *) _dl_sram_alloc (ppnt->p_filesz, L1_INST_SRAM);
    if (addr != NULL)
      _dl_dma_memcpy (addr, status + (ppnt->p_vaddr & ADDR_ALIGN), ppnt->p_filesz);
    _dl_munmap (status, size);
    if (addr == NULL)
      _dl_dprintf(2, "%s:%i: L1 allocation failed\n", _dl_progname, __LINE__);
    return addr;
  }

  if (((epnt->e_flags & EF_BFIN_DATA_IN_L1)
       || ppnt->p_vaddr == 0xff700000
       || ppnt->p_vaddr == 0xff800000
       || ppnt->p_vaddr == 0xff900000)
      && (ppnt->p_flags & PF_W)
      && !(ppnt->p_flags & PF_X)) {
    if (ppnt->p_vaddr == 0xff800000)
      addr = (char *) _dl_sram_alloc (ppnt->p_memsz, L1_DATA_A_SRAM);
    else if (ppnt->p_vaddr == 0xff900000)
      addr = (char *) _dl_sram_alloc (ppnt->p_memsz, L1_DATA_B_SRAM);
    else
      addr = (char *) _dl_sram_alloc (ppnt->p_memsz, L1_DATA_SRAM);
    if (addr == NULL) {
      _dl_dprintf(2, "%s:%i: L1 allocation failed\n", _dl_progname, __LINE__);
    } else {
      if (_DL_PREAD (infile, addr, ppnt->p_filesz, ppnt->p_offset) != ppnt->p_filesz) {
        _dl_sram_free (addr);
        return NULL;
      }
      if (ppnt->p_filesz < ppnt->p_memsz)
       _dl_memset (addr + ppnt->p_filesz, 0, ppnt->p_memsz - ppnt->p_filesz);
    }
    return addr;
  }

  if (ppnt->p_vaddr == 0xfeb00000
      || ppnt->p_vaddr == 0xfec00000) {
    addr = (char *) _dl_sram_alloc (ppnt->p_memsz, L2_SRAM);
    if (addr == NULL) {
      _dl_dprintf(2, "%s:%i: L2 allocation failed\n", _dl_progname, __LINE__);
    } else {
      if (_DL_PREAD (infile, addr, ppnt->p_filesz, ppnt->p_offset) != ppnt->p_filesz) {
        _dl_sram_free (addr);
        return NULL;
      }
      if (ppnt->p_filesz < ppnt->p_memsz)
       _dl_memset (addr + ppnt->p_filesz, 0, ppnt->p_memsz - ppnt->p_filesz);
    }
    return addr;
  }

  return 0;
}