FileLoader_bout.cc Source File

Back to the index.

FileLoader_bout.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2009-2018 Anders Gavare. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6  *
7  * 1. Redistributions of source code must retain the above copyright
8  * notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  * notice, this list of conditions and the following disclaimer in the
11  * documentation and/or other materials provided with the distribution.
12  * 3. The name of the author may not be used to endorse or promote products
13  * derived from this software without specific prior written permission.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27 
28 #include <assert.h>
29 #include <string.h>
30 #include <fstream>
31 #include <iomanip>
32 
33 using std::setw;
34 using std::setfill;
35 using std::ifstream;
36 
37 #include "AddressDataBus.h"
39 #include "FileLoader_bout.h"
40 
41 #include "thirdparty/exec_bout.h"
42 
43 
44 FileLoader_bout::FileLoader_bout(const string& filename)
45  : FileLoaderImpl(filename)
46 {
47 }
48 
49 
50 string FileLoader_bout::DetectFileType(unsigned char *buf, size_t buflen, float& matchness) const
51 {
52  matchness = 0.9;
53 
54  if (buflen >= 0x2c && buf[0] == 0x0d && buf[1] == 0x01 && buf[2] == 0x00 && buf[3] == 0x00) {
55  return "b.out_i960_little";
56  }
57 
58  if (buflen >= 0x2c && buf[0] == 0x00 && buf[1] == 0x00 && buf[2] == 0x01 && buf[3] == 0x0d) {
59  return "b.out_i960_big";
60  }
61 
62  matchness = 0.0;
63  return "";
64 }
65 
66 
67 static uint32_t unencode32(uint8_t *p, Endianness endianness)
68 {
69  uint32_t res;
70 
71  if (endianness == BigEndian)
72  res = p[3] + (p[2] << 8) + (p[1] << 16) + (p[0] << 24);
73  else
74  res = p[0] + (p[1] << 8) + (p[2] << 16) + (p[3] << 24);
75 
76  return res;
77 }
78 
79 
80 bool FileLoader_bout::LoadIntoComponent(refcount_ptr<Component> component, ostream& messages) const
81 {
82  AddressDataBus* bus = component->AsAddressDataBus();
83  if (bus == NULL) {
84  messages << "Target is not an AddressDataBus.\n";
85  return false;
86  }
87 
88  ifstream file(Filename().c_str());
89  if (!file.is_open()) {
90  messages << "Unable to read file.\n";
91  return false;
92  }
93 
94  unsigned char buf[65536];
95 
96  memset(buf, 0, sizeof(buf));
97  file.seekg(0, std::ios_base::end);
98  uint64_t totalSize = file.tellg();
99  file.seekg(0, std::ios_base::beg);
100  file.read((char *)buf, totalSize < sizeof(buf)? totalSize : sizeof(buf));
101  size_t amountRead = file.gcount();
102 
103  float matchness;
104  string format = DetectFileType(buf, amountRead, matchness);
105 
106  if (format == "") {
107  messages << "Unknown b.out format.\n";
108  return false;
109  }
110 
111  file.seekg(0, std::ios_base::beg);
112 
113  StateVariable* var = component->GetVariable("bigendian");
114  if (var == NULL) {
115  messages << "Target does not have the 'bigendian' variable,"
116  " which is needed to\n"
117  "load b.out files.\n";
118  return false;
119  }
120 
121  Endianness endianness = LittleEndian;
122  if (format == "b.out_i960_big")
123  endianness = BigEndian;
124 
125  struct bout_exec header;
126  uint32_t entry;
127 
128  file.read((char *)&header, sizeof(header));
129  if (file.gcount() != sizeof(header)) {
130  messages << "The file is too small to be a b.out.\n";
131  return false;
132  }
133 
134  entry = unencode32((unsigned char*)&header.a_entry, endianness);
135 
136  uint32_t textaddr = unencode32((unsigned char*)&header.a_tload, endianness);
137  uint32_t textsize = unencode32((unsigned char*)&header.a_text, endianness);
138 
139  uint32_t dataaddr = unencode32((unsigned char*)&header.a_dload, endianness);
140  uint32_t datasize = unencode32((unsigned char*)&header.a_data, endianness);
141 
142  int32_t symbsize = unencode32((unsigned char*)&header.a_syms, endianness);
143 
144  messages.flags(std::ios::hex);
145  messages << "b.out: entry point 0x";
146  messages << setw(8) << setfill('0') << (uint32_t) entry << "\n";
147 
148  messages.flags(std::ios::dec);
149  messages << "text + data = " << textsize << " + " << datasize << " bytes\n";
150 
151  // Load text:
152  uint32_t vaddr = textaddr;
153  while (textsize != 0) {
154  int len = textsize > sizeof(buf) ? sizeof(buf) : textsize;
155  file.read((char *)buf, len);
156  len = file.gcount();
157  if (len < 1)
158  break;
159 
160  // Write to the bus, one byte at a time.
161  for (int k=0; k<len; ++k) {
162  bus->AddressSelect(vaddr);
163  if (!bus->WriteData(buf[k])) {
164  messages.flags(std::ios::hex);
165  messages << "Failed to write data to virtual "
166  "address 0x" << vaddr << "\n";
167  return false;
168  }
169 
170  ++ vaddr;
171  }
172 
173  textsize -= len;
174  }
175 
176  if (textsize != 0) {
177  messages << "Failed to read the entire file.\n";
178  return false;
179  }
180 
181  // Load data:
182  vaddr = dataaddr;
183  while (datasize != 0) {
184  int len = datasize > sizeof(buf) ? sizeof(buf) : datasize;
185  file.read((char *)buf, len);
186  len = file.gcount();
187  if (len < 1)
188  break;
189 
190  // Write to the bus, one byte at a time.
191  for (int k=0; k<len; ++k) {
192  bus->AddressSelect(vaddr);
193  if (!bus->WriteData(buf[k])) {
194  messages.flags(std::ios::hex);
195  messages << "Failed to write data to virtual "
196  "address 0x" << vaddr << "\n";
197  return false;
198  }
199 
200  ++ vaddr;
201  }
202 
203  datasize -= len;
204  }
205 
206  if (datasize != 0) {
207  messages << "Failed to read the entire file.\n";
208  return false;
209  }
210 
211 #if 0
212  // TODO: Symbols. Similar to a.out?
213 
214  SymbolRegistry* symbolRegistry = NULL;
215  CPUComponent* cpu = component->AsCPUComponent();
216  if (cpu != NULL)
217  symbolRegistry = &cpu->GetSymbolRegistry();
218 
219  // Symbols:
220  if (symbolRegistry != NULL && symbsize > 0) {
221  messages.flags(std::ios::dec);
222  messages << "symbols: " << symbsize << " bytes at 0x";
223  messages.flags(std::ios::hex);
224  messages << file.tellg() << "\n";
225 
226  vector<char> symbolData;
227  symbolData.resize(symbsize);
228  file.read(&symbolData[0], symbsize);
229  if (file.gcount() != symbsize) {
230  messages << "Failed to read all symbols.\n";
231  return false;
232  }
233 
234  off_t oldpos = file.tellg();
235  file.seekg(0, std::ios_base::end);
236  size_t strings_len = (off_t)file.tellg() - oldpos;
237  file.seekg(oldpos, std::ios_base::beg);
238 
239  messages.flags(std::ios::dec);
240  messages << "strings: " << strings_len << " bytes at 0x";
241  messages.flags(std::ios::hex);
242  messages << file.tellg() << "\n";
243 
244  vector<char> symbolStrings;
245  // Note: len + 1 for a nul terminator, for safety.
246  symbolStrings.resize(strings_len + 1);
247  file.read(&symbolStrings[0], strings_len);
248  if (file.gcount() != strings_len) {
249  messages << "Failed to read all strings.\n";
250  return false;
251  }
252 
253  assert(sizeof(struct aout_symbol) == 12);
254 
255  int nsymbols = 0;
256 
257  struct aout_symbol* aout_symbol_ptr = (struct aout_symbol *) (void*) &symbolData[0];
258  int n_symbols = symbsize / sizeof(struct aout_symbol);
259  for (int i = 0; i < n_symbols; i++) {
260  uint32_t index = unencode32((unsigned char*)&aout_symbol_ptr[i].strindex, endianness);
261  uint32_t type = unencode32((unsigned char*)&aout_symbol_ptr[i].type, endianness);
262  uint32_t addr = unencode32((unsigned char*)&aout_symbol_ptr[i].addr, endianness);
263 
264  // TODO: These bits probably mean different things for
265  // different b.out formats. For OpenBSD/m88k at least,
266  // this bit (0x01000000) seems to mean "a normal symbol".
267  if (!(type & 0x01000000))
268  continue;
269 
270  // ... and the rectangle drawing demo says
271  // "_my_memset" at addr 1020, type 5020000
272  // "rectangles_m88k_O2.o" at addr 1020, type 1f000000
273  if ((type & 0x1f000000) == 0x1f000000)
274  continue;
275 
276  if (index >= (uint32_t)strings_len) {
277  messages << "symbol " << i << " has invalid string index\n";
278  continue;
279  }
280 
281  string symbol = ((char*) &symbolStrings[0]) + index;
282  if (symbol == "")
283  continue;
284 
285  // messages << "\"" << symbol << "\" at addr " << addr
286  // << ", type " << type << "\n";
287 
288  // Add this symbol to the symbol registry:
289  symbolRegistry->AddSymbol(symbol, addr);
290  ++ nsymbols;
291  }
292 
293  messages.flags(std::ios::dec);
294  messages << nsymbols << " symbols read\n";
295  }
296 #endif
297 
298  // Set the CPU's entry point.
299  stringstream ss;
300  ss << (int64_t)(int32_t)entry;
301  component->SetVariableValue("pc", ss.str());
302 
303  return true;
304 }
305 
306 
307 /*****************************************************************************/
308 
309 
310 #ifdef WITHUNITTESTS
311 
312 #include "ComponentFactory.h"
313 
314 static void Test_FileLoader_bout_Constructor()
315 {
316  FileLoader_bout boutLoader("test/FileLoader_B.OUT_i960");
317 }
318 
320 {
321  UNITTEST(Test_FileLoader_bout_Constructor);
322 
323  // TODO
324 }
325 
326 #endif
A registry for loaded symbols.
virtual CPUComponent * AsCPUComponent()
Returns the component&#39;s CPUComponent interface.
Definition: Component.cc:360
StateVariable * GetVariable(const string &name)
Gets a pointer to a state variable.
Definition: Component.cc:949
void AddSymbol(const string &symbol, uint64_t vaddr)
Adds a symbol to the registry.
string DetectFileType(unsigned char *buf, size_t buflen, float &matchness) const
Attempt to detect file type.
const string & Filename() const
bool LoadIntoComponent(refcount_ptr< Component > component, ostream &messages) const
Loads the file into a Component.
virtual bool WriteData(const uint8_t &data, Endianness endianness=BigEndian)=0
Writes 8-bit data to the currently selected address.
b.out binary loader.
Endianness
Definition: misc.h:156
uint32_t strindex
Definition: file_aout.cc:43
An interface for implementing components that read/write data via an address bus. ...
A file loader.
#define UNITTESTS(class)
Helper for unit test case execution.
Definition: UnitTest.h:184
FileLoader_bout(const string &filename)
SymbolRegistry & GetSymbolRegistry()
Gets a reference to the CPU&#39;s symbol registry.
Definition: CPUComponent.h:63
uint32_t addr
Definition: cpu.h:326
StateVariables make up the persistent state of Component objects.
Definition: StateVariable.h:67
A base-class for processors Component implementations.
Definition: CPUComponent.h:43
virtual void AddressSelect(uint64_t address)=0
Place an address on the bus.
bool SetVariableValue(const string &name, const string &expression)
Sets a variable to a new value.
Definition: Component.cc:1030
virtual AddressDataBus * AsAddressDataBus()
Returns the component&#39;s AddressDataBus interface, if any.
Definition: Component.cc:367
Definition: symbol.h:37
uint32_t type
Definition: file_aout.cc:44
#define UNITTEST(functionname)
Helper for unit test case execution.
Definition: UnitTest.h:217

Generated on Sun Sep 30 2018 16:05:18 for GXemul by doxygen 1.8.13