1 // compLoader.cxx - object file loader component. -*- C++ -*-
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.
9 #include <sidcomputil.h>
10 #include <sidattrutil.h>
11 #include <sidpinutil.h>
12 #include <sidbusutil.h>
13 #include <sidcpuutil.h>
15 #include <sidmiscutil.h>
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;
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;
61 // ----------------------------------------------------------------------------
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
72 callback_pin<generic_loader> doit_pin;
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;
81 // Signal this if something went wrong.
84 // loadable file names
91 // The load pin was triggered.
92 virtual void load_it (host_int_4) = 0;
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); }
103 doit_pin(this, & generic_loader::load_it),
105 load_file("/dev/null"),
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);
124 operator << (ostream& out, const generic_loader& it)
126 out << "loader-state "
127 << string2stream(it.load_file) << " "
135 operator >> (istream& in, generic_loader& it)
139 if (coding == "loader-state")
141 in >> stream2string(it.load_file)
146 in.setstate(ios::badbit);
154 // ----------------------------------------------------------------------------
157 class elf_loader: public generic_loader
159 // static pointer to active instance (XXX: concurrency?)
160 static elf_loader* freeloader;
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);
165 // stream for current file
168 void load_it (host_int_4)
170 if (this->load_accessor == 0)
172 cerr << "loader: error - target accessor not configured!" << endl;
173 this->error_pin.drive (0);
179 cout << "loader: Reading program " << this->load_file << endl;
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())
186 cerr << "loader: error opening " << load_file << ": "
187 << std_error_string() << endl;
191 elf_loader::freeloader = this;
192 unsigned entry_point;
194 int success_p = readElfFile(& elf_loader::load_function,
195 & entry_point, & little_endian_p);
196 elf_loader::freeloader = 0;
200 // Tell anyone who's listening things we learned about the elf file.
201 this->start_pc_pin.drive((host_int_4) entry_point);
203 this->endian_pin.drive(sidutil::endian_little);
205 this->endian_pin.drive(sidutil::endian_big);
209 cerr << "loader: error loading " << load_file << endl;
210 this->error_pin.drive (0);
220 elf_loader* elf_loader::freeloader = 0;
224 elf_loader::load_function(char* dest_addr, char* host_addr, int file_offset, int bytes)
226 if (elf_loader::freeloader->verbose_p)
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)
238 elf_loader& l = * elf_loader::freeloader;
239 ifstream& f = * l.file;
240 bus* b = l.load_accessor;
243 // go to proper offset in file
244 f.seekg(file_offset);
246 // fetch lots of characters
247 for(int n=0; n<bytes; n++)
253 cerr << "loader: error reading byte " << file_offset+n
254 << " from file " << l.load_file << endl;
258 if (host_addr) // read into host buffer
260 // cerr << "H:" << (void*)host_addr << ":" << hex << (int)c << dec << endl;
263 else // read into target memory
265 host_int_4 a = (host_int_4)(dest_addr ++);
266 little_int_1 data = c;
270 do // loop while memory getting ready
272 s = b->write(addr, data);
273 } while(s == bus::delayed);
275 if(s != bus::ok) // abort on error
277 cerr << "loader: write to accessor failed at address "
278 << make_numeric_attribute (addr, ios::hex | ios::showbase)
284 // cerr << "T:" << addr << ":" << data << endl;
292 // ----------------------------------------------------------------------------
297 compLoaderListTypes()
299 vector<string> types;
300 types.push_back("sw-load-elf");
307 compLoaderCreate(const string& typeName)
309 if(typeName == "sw-load-elf")
310 return new elf_loader();
318 compLoaderDelete(component* c)
320 delete dynamic_cast<elf_loader*>(c);
325 extern const component_library loader_component_library;
327 const component_library loader_component_library DLLEXPORT =
329 COMPONENT_LIBRARY_MAGIC,
330 & compLoaderListTypes,