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 (&sections[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