OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-old/] [gdb-6.8/] [gdb/] [target-memory.c] - Blame information for rev 840

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 24 jeremybenn
/* Parts of target interface that deal with accessing memory and memory-like
2
   objects.
3
 
4
   Copyright (C) 2006, 2007, 2008 Free Software Foundation, Inc.
5
 
6
   This file is part of GDB.
7
 
8
   This program is free software; you can redistribute it and/or modify
9
   it under the terms of the GNU General Public License as published by
10
   the Free Software Foundation; either version 3 of the License, or
11
   (at your option) any later version.
12
 
13
   This program is distributed in the hope that it will be useful,
14
   but WITHOUT ANY WARRANTY; without even the implied warranty of
15
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
   GNU General Public License for more details.
17
 
18
   You should have received a copy of the GNU General Public License
19
   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
20
 
21
#include "defs.h"
22
#include "vec.h"
23
#include "target.h"
24
#include "memory-map.h"
25
 
26
#include "gdb_assert.h"
27
 
28
#include <stdio.h>
29
#include <sys/time.h>
30
 
31
static int
32
compare_block_starting_address (const void *a, const void *b)
33
{
34
  const struct memory_write_request *a_req = a;
35
  const struct memory_write_request *b_req = b;
36
 
37
  if (a_req->begin < b_req->begin)
38
    return -1;
39
  else if (a_req->begin == b_req->begin)
40
    return 0;
41
  else
42
    return 1;
43
}
44
 
45
/* Adds to RESULT all memory write requests from BLOCK that are
46
   in [BEGIN, END) range.
47
 
48
   If any memory request is only partially in the specified range,
49
   that part of the memory request will be added.  */
50
 
51
static void
52
claim_memory (VEC(memory_write_request_s) *blocks,
53
              VEC(memory_write_request_s) **result,
54
              ULONGEST begin,
55
              ULONGEST end)
56
{
57
  int i;
58
  ULONGEST claimed_begin;
59
  ULONGEST claimed_end;
60
  struct memory_write_request *r;
61
 
62
  for (i = 0; VEC_iterate (memory_write_request_s, blocks, i, r); ++i)
63
    {
64
      /* If the request doesn't overlap [BEGIN, END), skip it.  We
65
         must handle END == 0 meaning the top of memory; we don't yet
66
         check for R->end == 0, which would also mean the top of
67
         memory, but there's an assertion in
68
         target_write_memory_blocks which checks for that.  */
69
 
70
      if (begin >= r->end)
71
        continue;
72
      if (end != 0 && end <= r->begin)
73
        continue;
74
 
75
      claimed_begin = max (begin, r->begin);
76
      if (end == 0)
77
        claimed_end = r->end;
78
      else
79
        claimed_end = min (end, r->end);
80
 
81
      if (claimed_begin == r->begin && claimed_end == r->end)
82
        VEC_safe_push (memory_write_request_s, *result, r);
83
      else
84
        {
85
          struct memory_write_request *n =
86
            VEC_safe_push (memory_write_request_s, *result, NULL);
87
          *n = *r;
88
          n->begin = claimed_begin;
89
          n->end = claimed_end;
90
          n->data += claimed_begin - r->begin;
91
        }
92
    }
93
}
94
 
95
/* Given a vector of struct memory_write_request objects in BLOCKS,
96
   add memory requests for flash memory into FLASH_BLOCKS, and for
97
   regular memory to REGULAR_BLOCKS.  */
98
 
99
static void
100
split_regular_and_flash_blocks (VEC(memory_write_request_s) *blocks,
101
                                VEC(memory_write_request_s) **regular_blocks,
102
                                VEC(memory_write_request_s) **flash_blocks)
103
{
104
  struct mem_region *region;
105
  CORE_ADDR cur_address;
106
 
107
  /* This implementation runs in O(length(regions)*length(blocks)) time.
108
     However, in most cases the number of blocks will be small, so this does
109
     not matter.
110
 
111
     Note also that it's extremely unlikely that a memory write request
112
     will span more than one memory region, however for safety we handle
113
     such situations.  */
114
 
115
  cur_address = 0;
116
  while (1)
117
    {
118
      VEC(memory_write_request_s) **r;
119
      region = lookup_mem_region (cur_address);
120
 
121
      r = region->attrib.mode == MEM_FLASH ? flash_blocks : regular_blocks;
122
      cur_address = region->hi;
123
      claim_memory (blocks, r, region->lo, region->hi);
124
 
125
      if (cur_address == 0)
126
        break;
127
    }
128
}
129
 
130
/* Given an ADDRESS, if BEGIN is non-NULL this function sets *BEGIN
131
   to the start of the flash block containing the address.  Similarly,
132
   if END is non-NULL *END will be set to the address one past the end
133
   of the block containing the address.  */
134
 
135
static void
136
block_boundaries (CORE_ADDR address, CORE_ADDR *begin, CORE_ADDR *end)
137
{
138
  struct mem_region *region;
139
  unsigned blocksize;
140
 
141
  region = lookup_mem_region (address);
142
  gdb_assert (region->attrib.mode == MEM_FLASH);
143
  blocksize = region->attrib.blocksize;
144
  if (begin)
145
    *begin = address / blocksize * blocksize;
146
  if (end)
147
    *end = (address + blocksize - 1) / blocksize * blocksize;
148
}
149
 
150
/* Given the list of memory requests to be WRITTEN, this function
151
   returns write requests covering each group of flash blocks which must
152
   be erased.  */
153
 
154
static VEC(memory_write_request_s) *
155
blocks_to_erase (VEC(memory_write_request_s) *written)
156
{
157
  unsigned i;
158
  struct memory_write_request *ptr;
159
 
160
  VEC(memory_write_request_s) *result = NULL;
161
 
162
  for (i = 0; VEC_iterate (memory_write_request_s, written, i, ptr); ++i)
163
    {
164
      CORE_ADDR begin, end;
165
 
166
      block_boundaries (ptr->begin, &begin, 0);
167
      block_boundaries (ptr->end - 1, 0, &end);
168
 
169
      if (!VEC_empty (memory_write_request_s, result)
170
          && VEC_last (memory_write_request_s, result)->end >= begin)
171
        {
172
          VEC_last (memory_write_request_s, result)->end = end;
173
        }
174
      else
175
        {
176
          struct memory_write_request *n =
177
            VEC_safe_push (memory_write_request_s, result, NULL);
178
          memset (n, 0, sizeof (struct memory_write_request));
179
          n->begin = begin;
180
          n->end = end;
181
        }
182
    }
183
 
184
  return result;
185
}
186
 
187
/* Given ERASED_BLOCKS, a list of blocks that will be erased with
188
   flash erase commands, and WRITTEN_BLOCKS, the list of memory
189
   addresses that will be written, compute the set of memory addresses
190
   that will be erased but not rewritten (e.g. padding within a block
191
   which is only partially filled by "load").  */
192
 
193
static VEC(memory_write_request_s) *
194
compute_garbled_blocks (VEC(memory_write_request_s) *erased_blocks,
195
                        VEC(memory_write_request_s) *written_blocks)
196
{
197
  VEC(memory_write_request_s) *result = NULL;
198
 
199
  unsigned i, j;
200
  unsigned je = VEC_length (memory_write_request_s, written_blocks);
201
  struct memory_write_request *erased_p;
202
 
203
  /* Look at each erased memory_write_request in turn, and
204
     see what part of it is subsequently written to.
205
 
206
     This implementation is O(length(erased) * length(written)).  If
207
     the lists are sorted at this point it could be rewritten more
208
     efficiently, but the complexity is not generally worthwhile.  */
209
 
210
  for (i = 0;
211
       VEC_iterate (memory_write_request_s, erased_blocks, i, erased_p);
212
       ++i)
213
    {
214
      /* Make a deep copy -- it will be modified inside the loop, but
215
         we don't want to modify original vector.  */
216
      struct memory_write_request erased = *erased_p;
217
 
218
      for (j = 0; j != je;)
219
        {
220
          struct memory_write_request *written
221
            = VEC_index (memory_write_request_s,
222
                         written_blocks, j);
223
 
224
          /* Now try various cases.  */
225
 
226
          /* If WRITTEN is fully to the left of ERASED, check the next
227
             written memory_write_request.  */
228
          if (written->end <= erased.begin)
229
            {
230
              ++j;
231
              continue;
232
            }
233
 
234
          /* If WRITTEN is fully to the right of ERASED, then ERASED
235
             is not written at all.  WRITTEN might affect other
236
             blocks.  */
237
          if (written->begin >= erased.end)
238
            {
239
              VEC_safe_push (memory_write_request_s, result, &erased);
240
              goto next_erased;
241
            }
242
 
243
          /* If all of ERASED is completely written, we can move on to
244
             the next erased region.  */
245
          if (written->begin <= erased.begin
246
              && written->end >= erased.end)
247
            {
248
              goto next_erased;
249
            }
250
 
251
          /* If there is an unwritten part at the beginning of ERASED,
252
             then we should record that part and try this inner loop
253
             again for the remainder.  */
254
          if (written->begin > erased.begin)
255
            {
256
              struct memory_write_request *n =
257
                VEC_safe_push (memory_write_request_s, result, NULL);
258
              memset (n, 0, sizeof (struct memory_write_request));
259
              n->begin = erased.begin;
260
              n->end = written->begin;
261
              erased.begin = written->begin;
262
              continue;
263
            }
264
 
265
          /* If there is an unwritten part at the end of ERASED, we
266
             forget about the part that was written to and wait to see
267
             if the next write request writes more of ERASED.  We can't
268
             push it yet.  */
269
          if (written->end < erased.end)
270
            {
271
              erased.begin = written->end;
272
              ++j;
273
              continue;
274
            }
275
        }
276
 
277
      /* If we ran out of write requests without doing anything about
278
         ERASED, then that means it's really erased.  */
279
      VEC_safe_push (memory_write_request_s, result, &erased);
280
 
281
    next_erased:
282
      ;
283
    }
284
 
285
  return result;
286
}
287
 
288
static void
289
cleanup_request_data (void *p)
290
{
291
  VEC(memory_write_request_s) **v = p;
292
  struct memory_write_request *r;
293
  int i;
294
 
295
  for (i = 0; VEC_iterate (memory_write_request_s, *v, i, r); ++i)
296
    xfree (r->data);
297
}
298
 
299
static void
300
cleanup_write_requests_vector (void *p)
301
{
302
  VEC(memory_write_request_s) **v = p;
303
  VEC_free (memory_write_request_s, *v);
304
}
305
 
306
int
307
target_write_memory_blocks (VEC(memory_write_request_s) *requests,
308
                            enum flash_preserve_mode preserve_flash_p,
309
                            void (*progress_cb) (ULONGEST, void *))
310
{
311
  struct cleanup *back_to = make_cleanup (null_cleanup, NULL);
312
  VEC(memory_write_request_s) *blocks = VEC_copy (memory_write_request_s,
313
                                                  requests);
314
  unsigned i;
315
  int err = 0;
316
  struct memory_write_request *r;
317
  VEC(memory_write_request_s) *regular = NULL;
318
  VEC(memory_write_request_s) *flash = NULL;
319
  VEC(memory_write_request_s) *erased, *garbled;
320
 
321
  /* END == 0 would represent wraparound: a write to the very last
322
     byte of the address space.  This file was not written with that
323
     possibility in mind.  This is fixable, but a lot of work for a
324
     rare problem; so for now, fail noisily here instead of obscurely
325
     later.  */
326
  for (i = 0; VEC_iterate (memory_write_request_s, requests, i, r); ++i)
327
    gdb_assert (r->end != 0);
328
 
329
  make_cleanup (cleanup_write_requests_vector, &blocks);
330
 
331
  /* Sort the blocks by their start address.  */
332
  qsort (VEC_address (memory_write_request_s, blocks),
333
         VEC_length (memory_write_request_s, blocks),
334
         sizeof (struct memory_write_request), compare_block_starting_address);
335
 
336
  /* Split blocks into list of regular memory blocks,
337
     and list of flash memory blocks. */
338
  make_cleanup (cleanup_write_requests_vector, &regular);
339
  make_cleanup (cleanup_write_requests_vector, &flash);
340
  split_regular_and_flash_blocks (blocks, &regular, &flash);
341
 
342
  /* If a variable is added to forbid flash write, even during "load",
343
     it should be checked here.  Similarly, if this function is used
344
     for other situations besides "load" in which writing to flash
345
     is undesirable, that should be checked here.  */
346
 
347
  /* Find flash blocks to erase.  */
348
  erased = blocks_to_erase (flash);
349
  make_cleanup (cleanup_write_requests_vector, &erased);
350
 
351
  /* Find what flash regions will be erased, and not overwritten; then
352
     either preserve or discard the old contents.  */
353
  garbled = compute_garbled_blocks (erased, flash);
354
  make_cleanup (cleanup_request_data, &garbled);
355
  make_cleanup (cleanup_write_requests_vector, &garbled);
356
 
357
  if (!VEC_empty (memory_write_request_s, garbled))
358
    {
359
      if (preserve_flash_p == flash_preserve)
360
        {
361
          struct memory_write_request *r;
362
 
363
          /* Read in regions that must be preserved and add them to
364
             the list of blocks we read.  */
365
          for (i = 0; VEC_iterate (memory_write_request_s, garbled, i, r); ++i)
366
            {
367
              gdb_assert (r->data == NULL);
368
              r->data = xmalloc (r->end - r->begin);
369
              err = target_read_memory (r->begin, r->data, r->end - r->begin);
370
              if (err != 0)
371
                goto out;
372
 
373
              VEC_safe_push (memory_write_request_s, flash, r);
374
            }
375
 
376
          qsort (VEC_address (memory_write_request_s, flash),
377
                 VEC_length (memory_write_request_s, flash),
378
                 sizeof (struct memory_write_request), compare_block_starting_address);
379
        }
380
    }
381
 
382
  /* We could coalesce adjacent memory blocks here, to reduce the
383
     number of write requests for small sections.  However, we would
384
     have to reallocate and copy the data pointers, which could be
385
     large; large sections are more common in loadable objects than
386
     large numbers of small sections (although the reverse can be true
387
     in object files).  So, we issue at least one write request per
388
     passed struct memory_write_request.  The remote stub will still
389
     have the opportunity to batch flash requests.  */
390
 
391
  /* Write regular blocks.  */
392
  for (i = 0; VEC_iterate (memory_write_request_s, regular, i, r); ++i)
393
    {
394
      LONGEST len;
395
 
396
      len = target_write_with_progress (&current_target,
397
                                        TARGET_OBJECT_MEMORY, NULL,
398
                                        r->data, r->begin, r->end - r->begin,
399
                                        progress_cb, r->baton);
400
      if (len < (LONGEST) (r->end - r->begin))
401
        {
402
          /* Call error?  */
403
          err = -1;
404
          goto out;
405
        }
406
    }
407
 
408
  if (!VEC_empty (memory_write_request_s, erased))
409
    {
410
      /* Erase all pages.  */
411
      for (i = 0; VEC_iterate (memory_write_request_s, erased, i, r); ++i)
412
        target_flash_erase (r->begin, r->end - r->begin);
413
 
414
      /* Write flash data.  */
415
      for (i = 0; VEC_iterate (memory_write_request_s, flash, i, r); ++i)
416
        {
417
          LONGEST len;
418
 
419
          len = target_write_with_progress (&current_target,
420
                                            TARGET_OBJECT_FLASH, NULL,
421
                                            r->data, r->begin, r->end - r->begin,
422
                                            progress_cb, r->baton);
423
          if (len < (LONGEST) (r->end - r->begin))
424
            error (_("Error writing data to flash"));
425
        }
426
 
427
      target_flash_done ();
428
    }
429
 
430
 out:
431
  do_cleanups (back_to);
432
 
433
  return err;
434
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.