📄 emul_chirp.c
字号:
/* This file is part of the program psim. Copyright 1994, 1995, 1996, 1997, 2003 Andrew Cagney 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */#ifndef _EMUL_CHIRP_C_#define _EMUL_CHIRP_C_/* Note: this module is called via a table. There is no benefit in making it inline */#include "emul_generic.h"#include "emul_chirp.h"#ifdef HAVE_STRING_H#include <string.h>#else#ifdef HAVE_STRINGS_H#include <strings.h>#endif#endif#ifdef HAVE_UNISTD_H#include <unistd.h>#endif#ifndef STATIC_INLINE_EMUL_CHIRP#define STATIC_INLINE_EMUL_CHIRP STATIC_INLINE#endif/* EMULATION OpenFirmware - IEEE Standard for Boot (Initialization Configuration) Firmware. DESCRIPTION BUGS This code assumes that the memory node has #address-cells and #size-cells set to one. For future implementations, this may not be the case. *//* Descriptor of the open boot services being emulated */typedef int (chirp_handler) (os_emul_data *data, cpu *processor, unsigned_word cia);typedef struct _chirp_services { const char *name; chirp_handler *handler;} chirp_services;/* The OpenBoot emulation is, at any time either waiting for a client request or waiting on a client callback */typedef enum { serving, emulating, faulting,} chirp_emul_state;struct _os_emul_data { chirp_emul_state state; unsigned_word return_address; unsigned_word arguments; unsigned_word n_args; unsigned_word n_returns; chirp_services *service; device *root; chirp_services *services; /* configuration */ unsigned_word memory_size; unsigned_word real_base; unsigned_word real_size; unsigned_word virt_base; unsigned_word virt_size; int real_mode; int little_endian; int floating_point_available; int interrupt_prefix; unsigned_word load_base; /* hash table */ unsigned_word nr_page_table_entry_groups; unsigned_word htab_offset; unsigned_word htab_ra; unsigned_word htab_va; unsigned_word sizeof_htab; /* virtual address of htab */ unsigned_word stack_offset; unsigned_word stack_ra; unsigned_word stack_va; unsigned_word sizeof_stack; /* addresses of emulation instructions virtual/real */ unsigned_word code_offset; unsigned_word code_va; unsigned_word code_ra; unsigned_word sizeof_code; unsigned_word code_client_va; unsigned_word code_client_ra; unsigned_word code_callback_va; unsigned_word code_callback_ra; unsigned_word code_loop_va; unsigned_word code_loop_ra;};/* returns the name of the corresponding Ihandle */static const char *ihandle_name(device_instance *ihandle){ if (ihandle == NULL) return ""; else return device_name(device_instance_device(ihandle));}/* Read/write the argument list making certain that all values are converted to/from host byte order. In the below only n_args+n_returns is read/written */static intchirp_read_t2h_args(void *args, int sizeof_args, int n_args, int n_returns, os_emul_data *data, cpu *processor, unsigned_word cia){ unsigned_cell *words; int i; /* check against the number of arguments specified by the client program */ if ((n_args >= 0 && data->n_args != n_args) || (n_returns >= 0 && data->n_returns != n_returns)) { TRACE(trace_os_emul, ("%s - invalid nr of args - n_args=%ld, n_returns=%ld\n", data->service->name, (long)data->n_args, (long)data->n_returns)); return -1; } /* check that there is enough space */ if (sizeof(unsigned_cell) * (data->n_args + data->n_returns) > sizeof_args) return -1; /* bring in the data */ memset(args, 0, sizeof_args); emul_read_buffer(args, data->arguments + 3 * sizeof(unsigned_cell), sizeof(unsigned_cell) * (data->n_args + data->n_returns), processor, cia); /* convert all words to host format */ words = args; for (i = 0; i < (sizeof_args / sizeof(unsigned_cell)); i++) words[i] = T2H_cell(words[i]); return 0;}static voidchirp_write_h2t_args(void *args, int sizeof_args, os_emul_data *data, cpu *processor, unsigned_word cia){ int i; unsigned_cell *words; /* convert to target everything */ words = args; for (i = 0; i < (sizeof_args / sizeof(unsigned_cell)); i++) words[i] = H2T_cell(words[i]); /* bring in the data */ emul_write_buffer(args, data->arguments + 3 * sizeof(unsigned_cell), sizeof(unsigned_cell) * (data->n_args + data->n_returns), processor, cia);}/* OpenBoot emulation functions *//* client interface */static intchirp_emul_test(os_emul_data *data, cpu *processor, unsigned_word cia){ struct test_args { /*in*/ unsigned_cell name; /*string*/ /*out*/ unsigned_cell missing; } args; char name[32]; chirp_services *service = NULL; /* read in the arguments */ if (chirp_read_t2h_args(&args, sizeof(args), 1, 1, data, processor, cia)) return -1; emul_read_string(name, args.name, sizeof(name), processor, cia); TRACE(trace_os_emul, ("test - in - name=`%s'\n", name)); /* see if we know about the service */ service = data->services; while (service->name != NULL && strcmp(service->name, name) != 0) { service++; } if (service->name == NULL) args.missing = -1; else args.missing = 0; /* write the arguments back out */ TRACE(trace_os_emul, ("test - out - missing=%ld\n", (long)args.missing)); chirp_write_h2t_args(&args, sizeof(args), data, processor, cia); return 0;}/* Device tree */static intchirp_emul_peer(os_emul_data *data, cpu *processor, unsigned_word cia){ struct peer_args { /*in*/ unsigned_cell phandle; /*out*/ unsigned_cell sibling_phandle; } args; device *phandle; device *sibling_phandle = NULL; /* read in the arguments */ if (chirp_read_t2h_args(&args, sizeof(args), 1, 1, data, processor, cia)) return -1; phandle = external_to_device(data->root, args.phandle); TRACE(trace_os_emul, ("peer - in - phandle=0x%lx(0x%lx`%s')\n", (unsigned long)args.phandle, (unsigned long)phandle, (phandle == NULL ? "" : device_name(phandle)))); /* find the peer */ if (args.phandle == 0) { sibling_phandle = data->root; args.sibling_phandle = device_to_external(sibling_phandle); } else if (phandle == NULL) { sibling_phandle = NULL; args.sibling_phandle = -1; } else { sibling_phandle = device_sibling(phandle); if (sibling_phandle == NULL) args.sibling_phandle = 0; else args.sibling_phandle = device_to_external(sibling_phandle); } /* write the arguments back out */ TRACE(trace_os_emul, ("peer - out - sibling_phandle=0x%lx(0x%lx`%s')\n", (unsigned long)args.sibling_phandle, (unsigned long)sibling_phandle, (sibling_phandle == NULL ? "" : device_name(sibling_phandle)))); chirp_write_h2t_args(&args, sizeof(args), data, processor, cia); return 0;}static intchirp_emul_child(os_emul_data *data, cpu *processor, unsigned_word cia){ struct child_args { /*in*/ unsigned_cell phandle; /*out*/ unsigned_cell child_phandle; } args; device *phandle; device *child_phandle; /* read the arguments in */ if (chirp_read_t2h_args(&args, sizeof(args), 1, 1, data, processor, cia)) return -1; phandle = external_to_device(data->root, args.phandle); TRACE(trace_os_emul, ("child - in - phandle=0x%lx(0x%lx`%s')\n", (unsigned long)args.phandle, (unsigned long)phandle, (phandle == NULL ? "" : device_name(phandle)))); /* find a child */ if (args.phandle == 0 || phandle == NULL) { child_phandle = NULL; args.child_phandle = -1; } else { child_phandle = device_child(phandle); if (child_phandle == NULL) args.child_phandle = 0; else args.child_phandle = device_to_external(child_phandle); } /* write the result out */ TRACE(trace_os_emul, ("child - out - child_phandle=0x%lx(0x%lx`%s')\n", (unsigned long)args.child_phandle, (unsigned long)child_phandle, (child_phandle == NULL ? "" : device_name(child_phandle)))); chirp_write_h2t_args(&args, sizeof(args), data, processor, cia); return 0;}static intchirp_emul_parent(os_emul_data *data, cpu *processor, unsigned_word cia){ struct parent_args { /*in*/ unsigned_cell phandle; /*out*/ unsigned_cell parent_phandle; } args; device *phandle; device *parent_phandle; /* read the args in */ if (chirp_read_t2h_args(&args, sizeof(args), 1, 1, data, processor, cia)) return -1; phandle = external_to_device(data->root, args.phandle); TRACE(trace_os_emul, ("parent - in - phandle=0x%lx(0x%lx`%s')\n", (unsigned long)args.phandle, (unsigned long)phandle, (phandle == NULL ? "" : device_name(phandle)))); /* find a parent */ if (args.phandle == 0 || phandle == NULL) { parent_phandle = NULL; args.parent_phandle = -1; } else { parent_phandle = device_parent(phandle); if (parent_phandle == NULL) args.parent_phandle = 0; else args.parent_phandle = device_to_external(parent_phandle); } /* return the result */ TRACE(trace_os_emul, ("parent - out - parent_phandle=0x%lx(0x%lx`%s')\n", (unsigned long)args.parent_phandle, (unsigned long)parent_phandle, (parent_phandle == NULL ? "" : device_name(parent_phandle)))); chirp_write_h2t_args(&args, sizeof(args), data, processor, cia); return 0;}static intchirp_emul_instance_to_package(os_emul_data *data, cpu *processor, unsigned_word cia){ struct instance_to_package_args { /*in*/ unsigned_cell ihandle; /*out*/ unsigned_cell phandle; } args; device_instance *ihandle; device *phandle = NULL; /* read the args in */ if (chirp_read_t2h_args(&args, sizeof(args), 1, 1, data, processor, cia)) return -1; ihandle = external_to_device_instance(data->root, args.ihandle); TRACE(trace_os_emul, ("instance-to-package - in - ihandle=0x%lx(0x%lx`%s')\n", (unsigned long)args.ihandle, (unsigned long)ihandle, ihandle_name(ihandle))); /* find the corresponding phandle */ if (ihandle == NULL) { phandle = NULL; args.phandle = -1; } else { phandle = device_instance_device(ihandle); args.phandle = device_to_external(phandle); } /* return the result */ TRACE(trace_os_emul, ("instance-to-package - out - phandle=0x%lx(0x%lx`%s')\n", (unsigned long)args.phandle, (unsigned long)phandle, (phandle == NULL ? "" : device_name(phandle)))); chirp_write_h2t_args(&args, sizeof(args), data, processor, cia); return 0;}static intchirp_emul_getproplen(os_emul_data *data, cpu *processor, unsigned_word cia){ struct getproplen_args { /*in*/ unsigned_cell phandle; unsigned_cell name; /*out*/ unsigned_cell proplen; } args; char name[32]; device *phandle; /* read the args in */ if (chirp_read_t2h_args(&args, sizeof(args), 2, 1, data, processor, cia)) return -1; phandle = external_to_device(data->root, args.phandle); emul_read_string(name, args.name, sizeof(name), processor, cia); TRACE(trace_os_emul, ("getproplen - in - phandle=0x%lx(0x%lx`%s') name=`%s'\n", (unsigned long)args.phandle, (unsigned long)phandle, (phandle == NULL ? "" : device_name(phandle)), name)); /* find our prop and get its length */ if (args.phandle == 0 || phandle == NULL) { args.proplen = -1; } else { const device_property *prop = device_find_property(phandle, name); if (prop == (device_property*)0) { args.proplen = -1; } else { args.proplen = prop->sizeof_array; } } /* return the result */ TRACE(trace_os_emul, ("getproplen - out - proplen=%ld\n", (unsigned long)args.proplen)); chirp_write_h2t_args(&args, sizeof(args), data, processor, cia); return 0;}static intchirp_emul_getprop(os_emul_data *data, cpu *processor, unsigned_word cia){ struct getprop_args { /*in*/ unsigned_cell phandle; unsigned_cell name; unsigned_cell buf; unsigned_cell buflen; /*out*/ unsigned_cell size; } args; char name[32]; device *phandle; /* read in the args, the return is optional */ if (chirp_read_t2h_args(&args, sizeof(args), 4, -1, data, processor, cia)) return -1; phandle = external_to_device(data->root, args.phandle); emul_read_string(name, args.name,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -