1 /* Load executable files into virtual machine's memory.
2 Copyright 2004 Brian R. Gaeke.
3
4 This file is part of VMIPS.
5
6 VMIPS is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the
8 Free Software Foundation; either version 2 of the License, or (at your
9 option) any later version.
10
11 VMIPS is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 for more details.
15
16 You should have received a copy of the GNU General Public License along
17 with VMIPS; if not, write to the Free Software Foundation, Inc.,
18 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
19
20 #include <string>
21 #include <cstring>
22 #include <cerrno>
23 #include <cstdio>
24 #include "vmips.h"
25 #include "cpzeroreg.h"
26 #include "memorymodule.h"
27 #include "error.h"
28
29 struct coff_file_header
30 {
31 unsigned short magic;
32 unsigned short no_sections;
33 char extras[20];
34 /* traditional header stuff follows: */
35 unsigned long text_size;
36 unsigned long data_size;
37 unsigned long bss_size;
38 unsigned long entry_addr;
39 unsigned long text_start;
40 unsigned long data_start;
41 unsigned long bss_start;
42 char extras2[20];
43 unsigned long gp_value;
44 };
45
46 struct coff_section_header
47 {
48 char section_name[8];
49 unsigned long section_phys_addr;
50 unsigned long section_virt_addr;
51 unsigned long section_size;
52 unsigned long section_file_loc;
53 char extras[16];
54 };
55
56 struct coff_info
57 {
58 struct coff_file_header file_header;
59 unsigned long text_addr;
60 unsigned long text_offset;
61 unsigned long text_size;
62 unsigned long data_addr;
63 unsigned long data_offset;
64 unsigned long data_size;
65 unsigned long bss_addr;
66 unsigned long bss_size;
67 };
68
69 #define MIPSEBMAGIC 0x0160
70 #define MIPSELMAGIC 0x0162
71
good_ecoff_magic(struct coff_file_header * fhdr)72 static inline bool good_ecoff_magic (struct coff_file_header *fhdr) {
73 return ((fhdr->magic == MIPSEBMAGIC) || (fhdr->magic == MIPSELMAGIC));
74 }
75
file_is_ecoff(FILE * fp)76 static bool file_is_ecoff (FILE *fp) {
77 fseek (fp, 0, SEEK_SET);
78 coff_file_header hdr;
79 if (fread (&hdr, sizeof (coff_file_header), 1, fp) != 1)
80 return false;
81 return good_ecoff_magic (&hdr);
82 }
83
file_is_elf(FILE * fp)84 static bool file_is_elf (FILE *fp) {
85 fseek (fp, 0, SEEK_SET);
86 char buf[4];
87 if (fread (&buf, sizeof(char), 4, fp) != 4)
88 return false;
89 return (buf[0] == 0x7f) && (buf[1] == 'E') && (buf[2] == 'L')
90 && (buf[3] == 'F');
91 }
92
93 /// Translate vaddr to a physical address, then return a host-machine
94 /// pointer to where it is in the simulated machine's RAM. vaddr must be in
95 /// one of the non-mapped kernel-mode segments (KSEG0 or KSEG1), and it must
96 /// be within the bounds of the simulated machine's physical RAM. Otherwise
97 /// a null pointer is returned.
98 ///
translate_to_host_ram_pointer(uint32 vaddr)99 char *vmips::translate_to_host_ram_pointer (uint32 vaddr) {
100 // Translate vaddr to physical address.
101 uint32 paddr;
102 if ((vaddr & KSEG_SELECT_MASK) == KSEG0) {
103 paddr = vaddr - KSEG0_CONST_TRANSLATION;
104 } else if ((vaddr & KSEG_SELECT_MASK) == KSEG1) {
105 paddr = vaddr - KSEG1_CONST_TRANSLATION;
106 } else {
107 error ("Virtual address 0x%x is not in KSEG0 or KSEG1", vaddr);
108 return 0;
109 }
110
111 // Get pointer to where physaddr is in RAM and return it.
112 if (memmod->incorporates(paddr)) {
113 return (char *) memmod->getAddress() + (paddr - memmod->getBase());
114 } else {
115 error ("Virtual address 0x%x is not within physical RAM", vaddr);
116 return 0;
117 }
118 }
119
load_ecoff(FILE * fp)120 bool vmips::load_ecoff (FILE *fp) {
121 coff_section_header *sections = 0;
122 bool rv = true;
123 try {
124
125 if (fseek (fp, 0, SEEK_SET) < 0)
126 throw std::string ("Can't seek to file header");
127 coff_info header;
128 if (fread (&header.file_header, sizeof (coff_file_header), 1, fp) != 1)
129 throw std::string ("Can't read file header");
130
131 if (fseek (fp, 76, SEEK_SET) < 0)
132 throw std::string ("Can't seek to section headers");
133 int nsects = header.file_header.no_sections;
134 sections = new coff_section_header[nsects];
135 for (int i = 0; i < nsects; ++i)
136 if (fread (§ions[i], sizeof (coff_section_header), 1, fp) != 1)
137 throw std::string ("Can't read section headers");
138
139 coff_section_header *section = sections;
140 for (int i = 0; i < header.file_header.no_sections; i++) {
141 if (strlen(section->section_name) != 0) {
142 if (strcmp(section->section_name, ".text") == 0) {
143 header.text_addr = section->section_virt_addr;
144 header.text_offset = section->section_file_loc;
145 header.text_size = section->section_size;
146 } else if (strcmp(section->section_name, ".data") == 0) {
147 header.data_addr = section->section_virt_addr;
148 header.data_offset = section->section_file_loc;
149 header.data_size = section->section_size;
150 } else if (strcmp(section->section_name, ".bss") == 0) {
151 header.bss_addr = section->section_virt_addr;
152 header.bss_size = section->section_size;
153 }
154 }
155 section++;
156 }
157 printf
158 ("size: text %lx data %lx bss %lx entry %lx\n"
159 "base: text %lx data %lx bss %lx\n" "gp: %lx\n",
160 header.file_header.text_size, header.file_header.data_size,
161 header.file_header.bss_size, header.file_header.entry_addr,
162 header.file_header.text_start, header.file_header.data_start,
163 header.file_header.bss_start, header.file_header.gp_value);
164 printf ("sections: .text@0x%x, %u bytes, at file offset %u\n",
165 (unsigned int) header.text_addr, (unsigned int) header.text_size,
166 (unsigned int) header.text_offset);
167 printf (" .data@0x%x, %u bytes, at file offset %u\n",
168 (unsigned int) header.data_addr, (unsigned int) header.data_size,
169 (unsigned int) header.data_offset);
170 printf (" .bss@0x%x, %u bytes\n", (unsigned int) header.bss_addr,
171 (unsigned int) header.bss_size);
172 putchar ('\n');
173
174 char *text_area_dst = translate_to_host_ram_pointer (header.text_addr);
175 char *data_area_dst = translate_to_host_ram_pointer (header.data_addr);
176 char *bss_area_dst = translate_to_host_ram_pointer (header.bss_addr);
177 printf ("host ptrs; text=%p data=%p bss=%p\n", text_area_dst, data_area_dst,
178 bss_area_dst);
179
180 if (fseek (fp, header.text_offset, SEEK_SET) < 0)
181 throw std::string ("Can't seek to text offset");
182 if (fread (text_area_dst, 1, header.text_size, fp) != header.text_size)
183 throw std::string ("Can't read text");
184 if (fseek (fp, header.data_offset, SEEK_SET) < 0)
185 throw std::string ("Can't seek to data offset");
186 if (fread (data_area_dst, 1, header.data_size, fp) != header.data_size)
187 throw std::string ("Can't read data");
188 memset (bss_area_dst, 0, header.bss_size);
189 //cpu->debug_set_pc (header.file_header.entry_addr);
190
191 } catch (std::string &errorstr) {
192 error ("%s", errorstr.c_str ());
193 rv = false;
194 }
195
196 fclose (fp);
197 if (sections) delete sections;
198 return rv;
199 }
200
load_elf(FILE * fp)201 bool vmips::load_elf (FILE *fp) {
202 error ("Can't load elf files yet");
203 fclose (fp);
204 return false;
205 }
206
207 bool
setup_exe()208 vmips::setup_exe ()
209 {
210 // Open executable file.
211 if (strcmp (opt_execname, "none") == 0)
212 return true;
213 FILE *fp = fopen (opt_execname, "rb");
214 if (!fp) {
215 error ("Could not open executable `%s': %s", opt_execname,
216 strerror (errno));
217 return false;
218 }
219 if (file_is_ecoff (fp)) {
220 return load_ecoff (fp);
221 } else if (file_is_elf (fp)) {
222 return load_elf (fp);
223 } else {
224 error ("Could not determine type of executable `%s'", opt_execname);
225 return false;
226 }
227 }
228
229