1 /* $NetBSD: load.cpp,v 1.15 2008/04/28 20:23:20 martin Exp $ */ 2 3 /*- 4 * Copyright (c) 2001 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by UCHIYAMA Yasushi. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <load.h> 33 #include <exec_coff.h> 34 #undef DPRINTF // trash coff_machdep.h 's define. 35 36 #include <console.h> 37 #include <memory.h> 38 #include <file.h> 39 40 #include <exec_elf.h> 41 42 Loader::Loader(Console *&cons, MemoryManager *&mem) 43 : _mem(mem), _cons(cons) 44 { 45 _file = 0; 46 _page_tag_start = 0; 47 } 48 49 LoaderOps 50 Loader::objectFormat(File &file) 51 { 52 union { 53 Elf_Ehdr elf; 54 coff_exechdr coff; 55 } header; 56 file.read(reinterpret_cast<void *>(&header), sizeof(header), 0); 57 58 if (header.elf.e_ident[EI_MAG0] == ELFMAG0 && 59 header.elf.e_ident[EI_MAG1] == ELFMAG1 && 60 header.elf.e_ident[EI_MAG2] == ELFMAG2 && 61 header.elf.e_ident[EI_MAG3] == ELFMAG3) 62 return LOADER_ELF; 63 #ifdef COFF_BADMAG 64 if (!COFF_BADMAG(&header.coff.f)) 65 return LOADER_COFF; 66 #endif // COFF_BADMAG 67 68 return LOADER_UNKNOWN; 69 } 70 71 BOOL 72 Loader::loadExtData(void) 73 { 74 size_t sz; 75 vaddr_t kv; 76 77 sz = _file->realsize(); 78 kv = ROUND(_kernend, static_cast <vsize_t>(KERNEL_PAGE_SIZE)); 79 80 DPRINTF((TEXT("[file system image]\n"))); 81 _load_segment(kv, sz, 0, sz); 82 83 return _load_success(); 84 } 85 86 void 87 Loader::loadEnd(void) 88 { 89 /* tag chain end */ 90 _load_segment_end(); 91 } 92 93 void 94 Loader::tagDump(int n) 95 { 96 #ifdef PAGE_LINK_DUMP 97 struct PageTag *p, *op; 98 int i = 0; 99 100 DPRINTF((TEXT("page tag start physical address: 0x%08x\n"), 101 _page_tag_start)); 102 p = reinterpret_cast <struct PageTag *>(_page_tag_start); 103 do { 104 if (i < n || p->src == ~0) 105 DPRINTF((TEXT("[%d] next 0x%08x src 0x%08x dst 0x%08x sz 0x%x\n"), 106 i, p->next, p->src, p->dst, p->sz)); 107 else if (i == n) 108 DPRINTF((TEXT("[...]\n"))); 109 op = p; 110 i++; 111 } while ((p = reinterpret_cast <struct PageTag *>(p->next)) != ~0); 112 113 DPRINTF((TEXT("[%d(last)] next 0x%08x src 0x%08x dst 0x%08x sz 0x%x\n"), 114 i - 1, op->next, op->src, op->dst, op->sz)); 115 #endif // PAGE_LINK_DUMP 116 } 117 118 paddr_t 119 Loader::tagStart(void) 120 { 121 return _page_tag_start; 122 } 123 124 void 125 Loader::_load_segment_start(void) 126 { 127 vaddr_t v; 128 paddr_t p; 129 130 _error = FALSE; 131 _nload_link = _n0clr_link = 0; 132 _tpsz = _mem->getTaggedPageSize(); 133 134 // start of chain. 135 if (!_mem->getTaggedPage(v, p, &_pvec_clr, _pvec_clr_paddr)) 136 _error = TRUE; 137 #ifdef PAGE_LINK_DUMP 138 _page_tag_start = (uint32_t)_pvec_clr; 139 #else 140 _page_tag_start = _pvec_clr_paddr; 141 #endif 142 _pvec_prev = _pvec_clr++; 143 _pvec_clr_paddr += sizeof(struct PageTag); 144 } 145 146 void 147 Loader::_load_segment_end(void) 148 { 149 _opvec_prev->next = ~0; // terminate 150 DPRINTF((TEXT("load link %d, zero clear link %d\n"), 151 _nload_link, _n0clr_link)); 152 } 153 154 void 155 Loader::_load_segment(vaddr_t kv, vsize_t memsz, off_t fileofs, size_t filesz) 156 { 157 int j, n; 158 vaddr_t kv_start = kv; 159 160 DPRINTF((TEXT("\t->load 0x%08x+0x%08x=0x%08x ofs=0x%08x+0x%x\n"), 161 kv, memsz, kv + memsz, fileofs, filesz)); 162 _kernend = kv + memsz; 163 164 if (filesz) { 165 n = filesz / _tpsz; 166 for (j = 0; j < n; j++) { 167 _opvec_prev = _pvec_prev; 168 _pvec_prev = _load_page(kv, fileofs, 169 _tpsz, _pvec_prev); 170 kv += _tpsz; 171 fileofs += _tpsz; 172 ++_nload_link; 173 } 174 size_t rest = filesz % _tpsz; 175 if (rest) { 176 _opvec_prev = _pvec_prev; 177 _pvec_prev = _load_page(kv, fileofs, rest, _pvec_prev); 178 ++_nload_link; 179 } 180 } 181 182 // zero clear tag 183 if (filesz < memsz) { 184 _pvec_prev->src = ~0; 185 _pvec_prev->dst = kv_start + filesz; 186 _pvec_prev->sz = memsz - filesz; 187 #ifdef PAGE_LINK_DUMP 188 _pvec_prev->next = (uint32_t)_pvec_clr; 189 #else 190 _pvec_prev->next = ptokv(_pvec_clr_paddr); 191 #endif 192 DPRINTF((TEXT("\t->zero 0x%08x+0x%08x=0x%08x\n"), 193 _pvec_prev->dst, _pvec_prev->sz, 194 _pvec_prev->dst + _pvec_prev->sz)); 195 _opvec_prev = _pvec_prev; 196 _pvec_prev = _pvec_clr++; 197 _pvec_clr_paddr += sizeof(struct PageTag); 198 ++_n0clr_link; 199 } 200 } 201 202 void 203 Loader::_load_memory(vaddr_t kv, vsize_t memsz, void *data) 204 { 205 struct PageTag *pvec; 206 paddr_t p, pvec_paddr; 207 vaddr_t v; 208 vaddr_t dst; 209 vsize_t remsz; 210 211 DPRINTF((TEXT("\t->load 0x%08x+0x%08x=0x%08x\n"), 212 kv, memsz, kv + memsz)); 213 214 dst = kv; 215 remsz = memsz; 216 while (remsz > 0) { 217 _opvec_prev = _pvec_prev; 218 if (!_mem->getTaggedPage(v, p, &pvec, pvec_paddr)) 219 _error = TRUE; 220 221 vsize_t tocopy = (remsz < _tpsz) ? remsz : _tpsz; 222 memcpy((void *)v, data, tocopy); 223 _pvec_prev->src = ptokv(p); 224 _pvec_prev->dst = dst; 225 _pvec_prev->sz = tocopy; 226 #ifdef PAGE_LINK_DUMP 227 _pvec_prev->next = (uint32_t)pvec; 228 #else 229 _pvec_prev->next = ptokv(pvec_paddr); 230 #endif 231 data = (char *)data + tocopy; 232 dst += tocopy; 233 remsz -= tocopy; 234 235 _pvec_prev = pvec; 236 ++_nload_link; 237 } 238 239 _kernend = kv + memsz; 240 } 241 242 struct PageTag * 243 Loader::_load_page(vaddr_t kv, off_t ofs, size_t sz, struct PageTag *prev) 244 { 245 struct PageTag *pvec; 246 paddr_t p, pvec_paddr; 247 vaddr_t v; 248 249 if (!_mem->getTaggedPage(v, p, &pvec, pvec_paddr)) 250 _error = TRUE; 251 _file->read((void *)v, sz, ofs); 252 prev->src = ptokv(p); 253 prev->dst = kv; 254 prev->sz = sz; 255 #ifdef PAGE_LINK_DUMP 256 prev->next = (uint32_t)pvec; 257 #else 258 prev->next = ptokv(pvec_paddr); 259 #endif 260 261 return pvec; 262 } 263