source: trunk/softs/tsar_boot/src/reset_utils.c @ 701

Last change on this file since 701 was 701, checked in by cfuguet, 10 years ago

tsar_boot:

  • Important optimization in the reset_elf_loader function.
  • Implementation of pread function which uses bytes addressing to read disk.
  • pread function alternates between direct tranfer from disk to memory and from disk to a memory cache block based on alignment of byte address, i.e., when file offset is aligned to disk block (512 bytes), pread uses DMA capacity of disk to transfer directly to memory, otherwise it passes before by a memory cache block and then performs a memcpy to transfer data to final destination.
  • the cache block used by pread function, allows to treat succeeding reads on the same block without accessing the disk.
File size: 8.4 KB
Line 
1/**
2 * \file    : reset_utils.c
3 * \date    : August 2012
4 * \author  : Cesar Fuguet
5 *
6 * Definition of utilities functions used by the TSAR pre-loader
7 */
8
9#include <reset_utils.h>
10
11/*
12 * pread(size_t file_offset, void* buf, size_t nbyte, size_t offset)
13 *
14 * read from disk into buffer "nbyte" bytes from (file_offset + offset)
15 *
16 * \param file_offset: Disk relative offset of file
17 * \param buf: Destination buffer
18 * \param nbyte: Number of bytes to read
19 * \param offset: File relative offset
20 *
21 * \note Absolute disk offset (in bytes) is (file_offset + offset)
22 */
23int pread(size_t file_offset, void *buf, size_t nbyte, size_t offset) {
24    if (nbyte == 0) return 0;
25
26    /*
27     * Cache block data buffer and cached block index
28     */
29    static struct aligned_blk blk_buf;
30    static int blk_buf_idx = -1;
31
32    char *dst;
33    int offset_blk;
34    int unaligned_nbyte;
35    int read_nbyte;
36
37    dst = (char*) buf;
38
39    /*
40     * Offset parameter is relative to file, therefore compute disk relative
41     * offset (in bytes)
42     */
43    offset += file_offset;
44
45    /*
46     * Read unaligned bytes at start of segment passing by block cache
47     */
48    offset_blk = (offset / BLOCK_SIZE);
49    offset = (offset % BLOCK_SIZE);
50    unaligned_nbyte = BLOCK_SIZE - offset;
51    read_nbyte = 0;
52    if (offset) {
53        /*
54         * Check cache block hit: if miss, read new block else, use cache block
55         * data
56         */
57        if (offset_blk != blk_buf_idx) {
58            if (reset_ioc_read(offset_blk, (void*)&blk_buf, 1)) {
59                return -1; 
60            }
61        }
62        blk_buf_idx = offset_blk;
63        read_nbyte = (nbyte > unaligned_nbyte) ? unaligned_nbyte : nbyte; 
64        memcpy((void*)dst, (void*)&blk_buf.b[offset], read_nbyte);
65        nbyte -= read_nbyte;
66        offset_blk += 1;
67    }
68
69    /*
70     * Read aligned bytes directly to buffer
71     */
72    size_t nblk = nbyte / BLOCK_SIZE; 
73    if (nblk) {
74        if (reset_ioc_read(offset_blk, (void*)&dst[read_nbyte], nblk)) {
75            return -1;
76        }
77        read_nbyte += (nblk * BLOCK_SIZE);
78        nbyte -= read_nbyte;
79        offset_blk += nblk;
80    }
81
82    /*
83     * Read unaligned bytes at the end of segment passing by block cache
84     */
85    if (nbyte) {
86        if (reset_ioc_read(offset_blk, (void*)&blk_buf, 1)) {
87            return -1;
88        }
89        blk_buf_idx = offset_blk;
90        memcpy((void*)&dst[read_nbyte], (void*)&blk_buf, nbyte);
91        read_nbyte += nbyte;
92    }
93    return read_nbyte; 
94}
95
96/********************************************************************
97 * proctime()
98 *
99 * Returns processor local time.
100 ********************************************************************/
101inline unsigned int proctime() 
102{
103    unsigned int ret;
104    asm volatile ("mfc0   %0,        $9":"=r" (ret));
105    return ret;
106}
107
108/********************************************************************
109 * memcpy( _dst, _src, size )
110 *
111 * Transfer data between two memory buffers.
112 *
113 * \param _dst   : Destination buffer base address
114 * \param _src   : Source buffer base address
115 * \param size   : Number of bytes to transfer
116 *
117 ********************************************************************/
118void* memcpy(void *_dst, const void *_src, size_t n)
119{
120    unsigned int *dst = _dst;
121    const unsigned int *src = _src;
122    if ( !((unsigned int)dst & 3) && !((unsigned int)src & 3) )
123    {
124        while (n > 3) 
125        {
126            *dst++ = *src++;
127            n -= 4;
128        }
129    }
130
131    unsigned char *cdst = (unsigned char*) dst;
132    unsigned char *csrc = (unsigned char*) src;
133    while (n--) 
134    {
135        *cdst++ = *csrc++;
136    }
137    return _dst;
138}
139
140/********************************************************************
141 * memset( _dst, value, size )
142 *
143 * Initialize memory buffers with predefined value.
144 *
145 * \param _dst   : Destination buffer base address
146 * \param value  : Initialization value
147 * \param size   : Number of bytes to initialize
148 *
149 ********************************************************************/
150void* memset(void *_dst, int c, size_t len)
151{
152    if (len == 0) return _dst;
153
154    unsigned char val = (unsigned char) c;
155    unsigned int word = (val << 24) | (val << 16) | (val << 8 ) | val;
156
157    /*
158     * Write 4 bytes when destination buffer is aligned to 4 bytes
159     * and size is greater or equal to 4
160     */
161    unsigned int *dst = _dst;
162    if ( !((unsigned int)dst & 3) )
163    {
164        while (len > 3) 
165        {
166            *dst++ = word;
167            len -= 4;
168        }
169    }
170
171    /*
172     * Write 1 byte when destination buffer is not aligned to 4 bytes
173     * or size is smaller than 4
174     */
175    unsigned char* cdst = (unsigned char*) _dst;
176    while(len--)
177    {
178        *cdst++ = (unsigned char) c;
179    }
180
181    return _dst;
182}
183
184/********************************************************************
185 * check_elf_header(Elf32_Ehdr*)
186 *
187 * Verify that ELF file is valid and that the number of program
188 * headers does not exceed the defined maximum
189 *
190 * \param ehdr : ELF header pointer
191 *
192 ********************************************************************/
193void check_elf_header(Elf32_Ehdr *ehdr)
194{
195    /*
196     * Verification of ELF Magic Number
197     */
198    if ((ehdr->e_ident[EI_MAG0] != ELFMAG0) ||
199        (ehdr->e_ident[EI_MAG1] != ELFMAG1) ||
200        (ehdr->e_ident[EI_MAG2] != ELFMAG2) ||
201        (ehdr->e_ident[EI_MAG3] != ELFMAG3))
202    {
203        reset_puts("[RESET ERROR] Unrecognized file format (not an ELF format)\n");
204        reset_exit();
205    }
206
207    /*
208     * Verification of Program Headers table size. It must be
209     * smaller than the work size allocated for the
210     * elf_pht[PHDR_ARRAY_SIZE] array
211     */
212    if (ehdr->e_phnum > PHDR_ARRAY_SIZE)
213    {
214        reset_puts("[RESET ERROR] ELF PHDR table size too large\n");
215        reset_exit();
216    }
217}
218
219/********************************************************************
220 * reset_print_elf_phdr( elf_phdr_ptr )
221 *
222 * Print some fields of a ELF program header
223 *
224 * \param elf_phdr_ptr : Pointer to the ELF program header to print
225 *
226 ********************************************************************/
227void reset_print_elf_phdr(Elf32_Phdr * elf_phdr_ptr)
228{
229    reset_puts("- type   : ");
230    reset_putx(elf_phdr_ptr->p_type);
231    reset_puts("\n- offset : ");
232    reset_putx(elf_phdr_ptr->p_offset);
233    reset_puts("\n- vaddr  : ");
234    reset_putx(elf_phdr_ptr->p_vaddr);
235    reset_puts("\n- paddr  : ");
236    reset_putx(elf_phdr_ptr->p_paddr);
237    reset_puts("\n- filesz : ");
238    reset_putx(elf_phdr_ptr->p_filesz);
239    reset_puts("\n- memsz  : ");
240    reset_putx(elf_phdr_ptr->p_memsz);
241    reset_puts("\n- flags  : ");
242    reset_putx(elf_phdr_ptr->p_flags);
243    reset_puts("\n- align  : ");
244    reset_putx(elf_phdr_ptr->p_align);
245    reset_puts("\n");
246}
247
248
249/********************************************************************
250 * reset_mcc_inval()
251 *
252 * Invalidate all data cache lines corresponding to a memory buffer
253 * (identified by an address and a size) in L2 cache.
254 ********************************************************************/
255#if USE_IOB
256void reset_mcc_invalidate (const void * buffer, size_t size)
257{
258    addr_t *mcc_address = (addr_t*)MCC_PADDR_BASE;
259
260    // get the hard lock assuring exclusive access to MEMC
261    while (ioread32(&mcc_address[MCC_LOCK]));
262
263    // write invalidate paremeters on the memory cache this preloader
264    // use only the cluster 0 and then the HI bits are not used
265   
266    iowrite32(&mcc_address[MCC_ADDR_LO], (unsigned int) buffer);
267    iowrite32(&mcc_address[MCC_ADDR_HI], (unsigned int) 0);
268    iowrite32(&mcc_address[MCC_LENGTH] , (unsigned int) size);
269    iowrite32(&mcc_address[MCC_CMD]    , (unsigned int) MCC_CMD_INVAL);
270
271    // release the lock protecting MEMC
272    iowrite32(&mcc_address[MCC_LOCK], (unsigned int) 0);
273}
274#endif
275
276/********************************************************************
277 * reset_dcache_buf_invalidate()
278 *
279 * Invalidate all data cache lines corresponding to a memory buffer
280 * (identified by an address and a size) in L1 cache and L2 cache.
281 ********************************************************************/
282#if (CACHE_COHERENCE == 0) || USE_IOB
283void reset_buf_invalidate (const void * buffer, size_t line_size, size_t size)
284{
285    unsigned int i;
286
287    // iterate on cache lines
288    for (i = 0; i <= size; i += line_size) 
289    {
290        asm volatile(
291            " cache %0, %1"
292            :// no outputs
293            :"i" (0x11), "R" (*((unsigned char *) buffer + i))
294            );
295    }
296
297#if USE_IOB
298    reset_mcc_invalidate(buffer, size);
299#endif
300}
301#endif
302
303// vim: tabstop=4 : softtabstop=4 : shiftwidth=4 : expandtab
Note: See TracBrowser for help on using the repository browser.