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