| /* This file is part of the program psim. |
| |
| Copyright (C) 1994-1996, Andrew Cagney <cagney@highland.com.au> |
| |
| This program is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 3 of the License, or |
| (at your option) any later version. |
| |
| This program is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with this program; if not, see <http://www.gnu.org/licenses/>. |
| |
| */ |
| |
| |
| #ifndef _OS_EMUL_C_ |
| #define _OS_EMUL_C_ |
| |
| #include "cpu.h" |
| #include "idecode.h" |
| #include "os_emul.h" |
| |
| #include "emul_generic.h" |
| #include "emul_netbsd.h" |
| #include "emul_unix.h" |
| #include "emul_chirp.h" |
| #include "emul_bugapi.h" |
| |
| static const os_emul *(os_emulations[]) = { |
| &emul_chirp, |
| &emul_bugapi, |
| &emul_netbsd, |
| &emul_solaris, |
| &emul_linux, |
| 0 |
| }; |
| |
| |
| INLINE_OS_EMUL\ |
| (os_emul *) |
| os_emul_create(const char *file_name, |
| device *root) |
| { |
| const char *emulation_name = NULL; |
| bfd *image; |
| os_emul *chosen_emulation = NULL; |
| |
| bfd_init(); /* would never hurt */ |
| |
| /* open the file */ |
| image = bfd_openr(file_name, NULL); |
| if (image == NULL) { |
| bfd_perror(file_name); |
| error("nothing loaded\n"); |
| } |
| |
| /* check it is an executable */ |
| if (!bfd_check_format(image, bfd_object)) { |
| TRACE(trace_tbd, |
| ("FIXME - should check more than just bfd_check_format\n")); |
| TRACE(trace_os_emul, |
| ("%s not an executable, assumeing a device file\n", file_name)); |
| bfd_close(image); |
| image = NULL; |
| } |
| |
| /* if a device file, load that before trying the emulations on */ |
| if (image == NULL) { |
| psim_merge_device_file(root, file_name); |
| } |
| |
| /* see if the device tree already specifies the required emulation */ |
| if (tree_find_property(root, "/openprom/options/os-emul") != NULL) |
| emulation_name = |
| tree_find_string_property(root, "/openprom/options/os-emul"); |
| else |
| emulation_name = NULL; |
| |
| /* go through each emulation to see if they reconize it. FIXME - |
| should have some sort of imported table from a separate file */ |
| { |
| os_emul_data *emul_data; |
| const os_emul **possible_emulation; |
| chosen_emulation = NULL; |
| for (possible_emulation = os_emulations, emul_data = NULL; |
| *possible_emulation != NULL && emul_data == NULL; |
| possible_emulation++) { |
| emul_data = (*possible_emulation)->create(root, |
| image, |
| emulation_name); |
| if (emul_data != NULL) { |
| chosen_emulation = ZALLOC(os_emul); |
| *chosen_emulation = **possible_emulation; |
| chosen_emulation->data = emul_data; |
| } |
| } |
| } |
| |
| /* clean up */ |
| if (image != NULL) |
| bfd_close(image); |
| return chosen_emulation; |
| } |
| |
| INLINE_OS_EMUL\ |
| (void) |
| os_emul_init(os_emul *emulation, |
| int nr_cpus) |
| { |
| if (emulation != (os_emul*)0) |
| emulation->init(emulation->data, nr_cpus); |
| } |
| |
| INLINE_OS_EMUL\ |
| (void) |
| os_emul_system_call(cpu *processor, |
| unsigned_word cia) |
| { |
| os_emul *emulation = cpu_os_emulation(processor); |
| if (emulation != (os_emul*)0 && emulation->system_call != 0) |
| emulation->system_call(processor, cia, emulation->data); |
| else |
| error("System call emulation not available\n"); |
| } |
| |
| INLINE_OS_EMUL\ |
| (int) |
| os_emul_instruction_call(cpu *processor, |
| unsigned_word cia, |
| unsigned_word ra) |
| { |
| os_emul *emulation = cpu_os_emulation(processor); |
| if (emulation != (os_emul*)0 && emulation->instruction_call != 0) |
| return emulation->instruction_call(processor, cia, ra, emulation->data); |
| else |
| return 0; |
| } |
| |
| |
| #endif /* _OS_EMUL_C_ */ |