OSDN Git Service

[bsp/ChangeLog]
[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 class generic_loader: public virtual component,
64                       protected no_bus_component,
65                       protected fixed_attribute_map_component,
66                       protected fixed_pin_map_component,
67                       protected fixed_accessor_map_component,
68                       protected no_relation_component
69 {
70 private:
71   callback_pin<generic_loader> doit_pin;
72
73 protected:
74   // entry point address
75   output_pin start_pc_pin;
76   // endianness as specified in ELF header.
77   // The value is one of sidutil::endian_*.
78   output_pin endian_pin;
79
80   // Signal this if something went wrong.
81   output_pin error_pin;
82
83   // loadable file names
84   bool verbose_p;
85   string load_file;
86
87   // accessors
88   bus* load_accessor_insn;
89   bus* load_accessor_data;
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_insn(0),
107     load_accessor_data(0)
108     {
109       add_pin("load!", & this->doit_pin);
110       add_pin("start-pc-set", & this->start_pc_pin);
111       add_pin("endian-set", & this->endian_pin);
112       add_pin("error", & this->error_pin);
113       add_accessor("load-accessor-insn", & this->load_accessor_insn);
114       add_accessor("load-accessor-data", & this->load_accessor_data);
115       add_attribute("file", & this->load_file, "setting");
116       add_attribute("verbose?", & this->verbose_p, "setting");
117       add_attribute_virtual ("state-snapshot", this,
118                              & generic_loader::save_state,
119                              & generic_loader::restore_state);
120     }
121     
122 };
123
124 ostream& 
125 operator << (ostream& out, const generic_loader& it)
126 {
127   out << "loader-state "
128       << string2stream(it.load_file) << " "
129       << it.verbose_p;
130
131   return out;
132 }
133
134
135 istream& 
136 operator >> (istream& in, generic_loader& it)
137 {
138   string coding;
139   in >> coding;
140   if (coding == "loader-state")
141     {
142       in >> stream2string(it.load_file)
143          >> it.verbose_p;
144     }
145   else
146     {
147       in.setstate(ios::badbit);
148     }
149
150   return in;
151 }
152
153 // ----------------------------------------------------------------------------
154
155 class elf_loader: public generic_loader
156 {
157   // static pointer to active instance (XXX: concurrency?)
158   static elf_loader* freeloader;
159
160   // callback function from C code in elfload.c
161   static int load_function(host_int_8 dest_addr, char* host_addr, host_int_8 file_offset, host_int_8 bytes, int insn_space);
162   static int verbose_function(char* s);
163
164   // stream for current file  
165   ifstream* file;
166
167   void load_it (host_int_4)
168     {
169       if (this->load_accessor_insn == 0 || this->load_accessor_data == 0)
170         {
171           cerr << "loader: error - target accessors not configured!" << endl;
172           this->error_pin.drive (0);
173           return;
174         }
175
176       if (this->verbose_p)
177         {
178           cout << "loader: Reading program " << this->load_file << endl;
179         }
180
181       assert(elf_loader::freeloader == 0);
182       this->file = new ifstream(this->load_file.c_str(), ios::binary | ios::in);
183       if (! this->file->good())
184         {
185           cerr << "loader: error opening " << load_file << ": "
186                << std_error_string() << endl;
187           return;
188         }
189
190       elf_loader::freeloader = this;
191       unsigned entry_point;
192       int little_endian_p;
193       int success_p = readElfFile(& elf_loader::load_function,
194                                   & entry_point, & little_endian_p);
195       elf_loader::freeloader = 0;
196
197       if (success_p)
198         {
199           // Tell anyone who's listening things we learned about the elf file.
200           this->start_pc_pin.drive((host_int_4) entry_point);
201           if (little_endian_p)
202             this->endian_pin.drive(sidutil::endian_little);
203           else
204             this->endian_pin.drive(sidutil::endian_big);
205         }
206       else
207         {
208           cerr << "loader: error loading " << load_file << endl;
209           this->error_pin.drive (0);
210         }
211
212       delete this->file;
213       this->file = 0;
214     }
215 };
216
217 // static variable
218 elf_loader* elf_loader::freeloader = 0;
219
220 // static function
221 int
222 elf_loader::load_function(host_int_8 dest_addr, char *host_addr, host_int_8 file_offset, host_int_8 bytes, int insn_space)
223 {
224   elf_loader& l = * elf_loader::freeloader;
225   string who = insn_space ? "instruction" : "data";
226
227   if (l.verbose_p)
228     {
229       if (host_addr == 0)
230         cout << "loader: reading "
231              << make_numeric_attribute (bytes, ios::hex | ios::showbase)
232              << " bytes from file offset "
233              << make_numeric_attribute (file_offset, ios::hex | ios::showbase)
234              << " into target " << who << " memory at "
235              << make_numeric_attribute ((void *)dest_addr, ios::hex | ios::showbase)
236              << endl;
237     }
238
239   ifstream& f = * l.file;
240   bus* b;
241
242   if (insn_space)
243     b = l.load_accessor_insn;
244   else
245     b = l.load_accessor_data;
246   assert (b);
247
248   // go to proper offset in file
249   f.seekg(file_offset);
250
251   // fetch lots of characters
252   for (int n = 0; n < bytes; n++)
253     {
254       char c;
255       f.get(c);
256       if (!f.good())
257         {
258           cerr << "loader: error reading byte " << file_offset+n
259                << " from file " << l.load_file << endl;
260           return -1; // oops
261         }
262
263       if (host_addr) // read into host buffer
264         {
265           // cerr << "H:" << (void*)host_addr << ":" << hex << (int)c << dec << endl;
266           *host_addr++ = c;
267         }
268       else // read into target memory
269         {
270           host_int_8 a = dest_addr++;
271           little_int_1 data = c;
272           host_int_4 addr = a;
273
274           bus::status s;
275
276           do // loop while memory getting ready
277             {
278               s = b->write(addr, data);
279             } while (s == bus::delayed);
280
281           if (s != bus::ok) // abort on error
282             {
283               cerr << "loader: write to " << who << " accessor failed at address "
284                    << make_numeric_attribute (addr, ios::hex | ios::showbase)
285                    << ", status "
286                    << (int) s << endl;
287               return -1;
288             }
289           // else
290           //  cerr << "T:" << addr << ":" << data << endl;
291         }
292     }
293   return bytes;
294 }
295
296 // ----------------------------------------------------------------------------
297
298 static
299 vector<string>
300 compLoaderListTypes()
301 {
302   vector<string> types;
303   types.push_back("sw-load-elf");
304   return types;
305 }
306
307 static
308 component*
309 compLoaderCreate(const string& typeName)
310 {
311   if (typeName == "sw-load-elf")
312     return new elf_loader();
313   else
314     return 0;
315 }
316
317 static
318 void
319 compLoaderDelete(component* c)
320 {
321   delete dynamic_cast<elf_loader*>(c);
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 };