OSDN Git Service

* public snapshot of sid simulator
[pf3gnuchains/pf3gnuchains3x.git] / sid / component / loader / compLoader.cxx
1 // compLoader.cxx - object file loader component.  -*- C++ -*-
2
3 // Copyright (C) 1999, 2000 Red Hat.
4 // This file is part of SID and is licensed under the GPL.
5 // See the file COPYING.SID for conditions for redistribution.
6
7 #include <sidcomp.h>
8 #include <sidso.h>
9 #include <sidcomputil.h>
10 #include <sidattrutil.h>
11 #include <sidpinutil.h>
12 #include <sidbusutil.h>
13 #include <sidcpuutil.h>
14 #include <sidtypes.h>
15 #include <sidmiscutil.h>
16
17 #include <vector>
18 #include <string>
19 #include <cstdlib>
20 #include <ctime>
21 #include <cerrno>
22 #include <unistd.h>
23 #include <fstream>
24
25 extern "C" {
26 #include "elfload.h"
27 }
28
29 using std::vector;
30 using std::string;
31 using std::ostream;
32 using std::istream;
33 using std::ios;
34 using std::endl;
35 using std::cout;
36 using std::ifstream;
37 using std::cerr;
38
39 using sid::component;
40 using sid::bus;
41 using sid::host_int_1;
42 using sid::little_int_1;
43 using sid::host_int_4;
44 using sid::component_library;
45 using sid::COMPONENT_LIBRARY_MAGIC;
46
47 using sidutil::no_bus_component;
48 using sidutil::fixed_attribute_map_component;
49 using sidutil::fixed_pin_map_component;
50 using sidutil::fixed_accessor_map_component;
51 using sidutil::no_relation_component;
52 using sidutil::output_pin;
53 using sidutil::callback_pin;
54 using sidutil::string2stream;
55 using sidutil::stream2string;
56 using sidutil::make_attribute;
57 using sidutil::make_numeric_attribute;
58 using sidutil::parse_attribute;
59 using sidutil::std_error_string;
60
61 // ----------------------------------------------------------------------------
62
63
64 class generic_loader: public virtual component,
65                       protected no_bus_component,
66                       protected fixed_attribute_map_component,
67                       protected fixed_pin_map_component,
68                       protected fixed_accessor_map_component,
69                       protected no_relation_component
70 {
71 private:
72   callback_pin<generic_loader> doit_pin;
73
74 protected:
75   // entry point address
76   output_pin start_pc_pin;
77   // endianness as specified in ELF header.
78   // The value is one of sidutil::endian_*.
79   output_pin endian_pin;
80
81   // Signal this if something went wrong.
82   output_pin error_pin;
83
84   // loadable file names
85   bool verbose_p;
86   string load_file;
87
88   // accessors
89   bus* load_accessor;
90
91   // The load pin was triggered.
92   virtual void load_it (host_int_4) = 0;
93
94   // state control
95   friend ostream& operator << (ostream& o, const generic_loader& it);
96   friend istream& operator >> (istream& i, generic_loader& it);
97   string save_state() { return make_attribute(*this); }
98   sid::component::status restore_state(const string& state)
99     { return parse_attribute(state, *this); }
100
101 public:
102   generic_loader(): 
103     doit_pin(this, & generic_loader::load_it), 
104     verbose_p(false),
105     load_file("/dev/null"),
106     load_accessor(0)
107     {
108       add_pin("load!", & this->doit_pin);
109       add_pin("start-pc-set", & this->start_pc_pin);
110       add_pin("endian-set", & this->endian_pin);
111       add_pin("error", & this->error_pin);
112       add_accessor("load-accessor", & this->load_accessor);
113       add_attribute("file", & this->load_file, "setting");
114       add_attribute("verbose?", & this->verbose_p, "setting");
115       add_attribute_virtual ("state-snapshot", this,
116                              & generic_loader::save_state,
117                              & generic_loader::restore_state);
118     }
119     
120 };
121
122
123 ostream& 
124 operator << (ostream& out, const generic_loader& it)
125 {
126   out << "loader-state "
127       << string2stream(it.load_file) << " "
128       << it.verbose_p;
129
130   return out;
131 }
132
133
134 istream& 
135 operator >> (istream& in, generic_loader& it)
136 {
137   string coding;
138   in >> coding;
139   if (coding == "loader-state")
140     {
141       in >> stream2string(it.load_file)
142          >> it.verbose_p;
143     }
144   else
145     {
146       in.setstate(ios::badbit);
147     }
148
149   return in;
150 }
151
152
153
154 // ----------------------------------------------------------------------------
155
156
157 class elf_loader: public generic_loader
158 {
159   // static pointer to active instance (XXX: concurrency?)
160   static elf_loader* freeloader;
161
162   // callback function from C code in elfload.c
163   static int load_function(char* dest_addr, char* host_addr, int file_offset, int bytes);
164
165   // stream for current file  
166   ifstream* file;
167
168   void load_it (host_int_4)
169     {
170       if (this->load_accessor == 0)
171         {
172           cerr << "loader: error - target accessor not configured!" << endl;
173           this->error_pin.drive (0);
174           return;
175         }
176
177       if (this->verbose_p)
178         {
179           cout << "loader: Reading program " << this->load_file << endl;
180         }
181
182       assert(elf_loader::freeloader == 0);
183       this->file = new ifstream(this->load_file.c_str(), ios::binary | ios::in);
184       if(! this->file->good())
185         {
186           cerr << "loader: error opening " << load_file << ": "
187                << std_error_string() << endl;
188           return;
189         }
190
191       elf_loader::freeloader = this;
192       unsigned entry_point;
193       int little_endian_p;
194       int success_p = readElfFile(& elf_loader::load_function,
195                                   & entry_point, & little_endian_p);
196       elf_loader::freeloader = 0;
197
198       if (success_p)
199         {
200           // Tell anyone who's listening things we learned about the elf file.
201           this->start_pc_pin.drive((host_int_4) entry_point);
202           if (little_endian_p)
203             this->endian_pin.drive(sidutil::endian_little);
204           else
205             this->endian_pin.drive(sidutil::endian_big);
206         }
207       else
208         {
209           cerr << "loader: error loading " << load_file << endl;
210           this->error_pin.drive (0);
211         }
212
213       delete this->file;
214       this->file = 0;
215     }
216 };
217
218
219 // static variable
220 elf_loader* elf_loader::freeloader = 0;
221
222 // static function
223 int
224 elf_loader::load_function(char* dest_addr, char* host_addr, int file_offset, int bytes)
225 {
226   if (elf_loader::freeloader->verbose_p)
227     {
228       if(host_addr == 0)
229         cout << "loader: reading "
230              << make_numeric_attribute (bytes, ios::hex | ios::showbase)
231              << " bytes from file offset "
232              << make_numeric_attribute (file_offset, ios::hex | ios::showbase)
233              << " into target memory at "
234              << make_numeric_attribute ((void *)dest_addr, ios::hex | ios::showbase)
235              << endl;
236     }
237
238   elf_loader& l = * elf_loader::freeloader;
239   ifstream& f = * l.file;
240   bus* b = l.load_accessor;
241   assert (b);
242
243   // go to proper offset in file
244   f.seekg(file_offset);
245
246   // fetch lots of characters
247   for(int n=0; n<bytes; n++)
248     {
249       char c;
250       f.get(c);
251       if(! f.good())
252         {
253           cerr << "loader: error reading byte " << file_offset+n
254                << " from file " << l.load_file << endl;
255           return -1; // oops
256         }
257
258       if (host_addr) // read into host buffer
259         {
260           // cerr << "H:" << (void*)host_addr << ":" << hex << (int)c << dec << endl;
261           *host_addr++ = c;
262         }
263       else // read into target memory
264         {
265           host_int_4 a = (host_int_4)(dest_addr ++);
266           little_int_1 data = c;
267           host_int_4 addr = a;
268
269           bus::status s;
270           do // loop while memory getting ready
271             {
272               s = b->write(addr, data);
273             } while(s == bus::delayed);
274
275           if(s != bus::ok) // abort on error
276             {
277               cerr << "loader: write to accessor failed at address "
278                    << make_numeric_attribute (addr, ios::hex | ios::showbase)
279                    << ", status "
280                    << (int) s << endl;
281               return -1;
282             }
283           // else
284           //  cerr << "T:" << addr << ":" << data << endl;
285         }
286     }
287   return bytes;
288 }
289
290
291
292 // ----------------------------------------------------------------------------
293
294
295 static
296 vector<string>
297 compLoaderListTypes()
298 {
299   vector<string> types;
300   types.push_back("sw-load-elf");
301   return types;
302 }
303
304
305 static
306 component*
307 compLoaderCreate(const string& typeName)
308 {
309   if(typeName == "sw-load-elf")
310     return new elf_loader();
311   else
312     return 0;
313 }
314
315
316 static
317 void
318 compLoaderDelete(component* c)
319 {
320   delete dynamic_cast<elf_loader*>(c);
321 }
322
323
324 // static object
325 extern const component_library loader_component_library;
326
327 const component_library loader_component_library DLLEXPORT = 
328 {
329   COMPONENT_LIBRARY_MAGIC,
330   & compLoaderListTypes, 
331   & compLoaderCreate,
332   & compLoaderDelete
333 };