From: Nick Clifton Date: Thu, 8 Jan 1998 11:12:39 +0000 (+0000) Subject: Applied patches from Tony.Thompson@arm.com to implement the Angel remote X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=3a9c3d120fe4b7cd24f75f275e4b1034577ce056;p=binutils-gdb.git Applied patches from Tony.Thompson@arm.com to implement the Angel remote debugging interface and resurrected associated RDI files. --- diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 4a920227a88..fe86b0504c5 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,15 @@ +Thu Jan 8 11:03:59 1998 Nick Clifton + + * remote-rdp.c: Applied patches submitted by Tony.Thompson@arm.com + to implement the Angel remote debugging interface. + + * Makefile.in: Add build rules for remote-rdi.c and + rdi-share/libangsd.a + + * configure.tgt: Updated from source on branch. + * config/arm/tm-arm.h: Updated from source on branch. + * arm-tdep.c: Updated from source on branch. + Mon Jan 5 20:21:59 1998 Mark Alexander * monitor.h (MO_PRINT_PROGRAM_OUTPUT): Define. diff --git a/gdb/Makefile.in b/gdb/Makefile.in index 7f6e1de8807..c56503f9952 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -163,6 +163,10 @@ WIN32LIBS = @WIN32LIBS@ ENABLE_GDBTK= @ENABLE_GDBTK@ ENABLE_IDE= @ENABLE_IDE@ +LIBGUI = ../libgui/src/libgui.a + +GUI_CFLAGS_X = -I$(srcdir)/../libgui/src + IDE_CFLAGS_X = -I$(srcdir)/../libide/src \ `if [ x"$(ENABLE_IDE)" != x ] ; then \ echo -DIDE -I$(srcdir)/../ilu/runtime/mainloop;\ @@ -179,7 +183,7 @@ IDE_DEPS = ../ilu/runtime/mainloop/libilu-Tk.a \ ../ilu/runtime/c/libilu-c.a ../ilu/runtime/kernel/libilu.a IDE=$(IDE_X) -IDE_CFLAGS=$(IDE_CFLAGS_X) +IDE_CFLAGS=$(GUI_CFLAGS_X) $(IDE_CFLAGS_X) #end-sanitize-gdbtk ENABLE_CFLAGS= @ENABLE_CFLAGS@ @@ -1359,6 +1363,19 @@ remote-adapt.o: remote-adapt.c $(wait_h) $(defs_h) $(gdbcore_h) \ remote-array.o: remote-array.c $(wait_h) $(defs_h) $(gdbcore_h) target.h \ gdb_string.h $(command_h) serial.h monitor.h $(remote_utils_h) +remote-rdi.o: remote-rdi.c $(wait_h) $(defs_h) $(gdbcore_h) \ + $(inferior_h) gdb_string.h + +rdi-share/libangsd.a: force + @dir=rdi-share; \ + if [ -f ./$${dir}/Makefile ] ; then \ + r=`pwd`; export r; \ + srcroot=`cd $(srcdir); pwd`; export srcroot; \ + (cd $${dir}; $(MAKE) $(FLAGS_TO_PASS) all); \ + else \ + true; \ + fi + remote-rdp.o: remote-rdp.c $(wait_h) $(defs_h) $(gdbcore_h) \ $(inferior_h) gdb_string.h diff --git a/gdb/configure.tgt b/gdb/configure.tgt index 6739d08fe1e..3c29d73ced6 100644 --- a/gdb/configure.tgt +++ b/gdb/configure.tgt @@ -48,7 +48,17 @@ alpha-*-linux*) gdb_target=alpha-linux ;; arc-*-*) gdb_target=arc ;; -arm-*-* | thumb-*-*) gdb_target=arm ;; +arm-*-* | thumb-*-*) gdb_target=arm + + # rdi doesn't work for wingdb yet + case $gdb_host in + windows) ;; + *) + configdirs="$configdirs rdi-share" + CONFIG_OBS="$CONFIG_OBS remote-rdi.o rdi-share/libangsd.a" + ;; + esac + ;; c1-*-*) gdb_target=convex ;; c2-*-*) gdb_target=convex ;; diff --git a/gdb/rdi-share/Makefile.in b/gdb/rdi-share/Makefile.in new file mode 100644 index 00000000000..45a92049688 --- /dev/null +++ b/gdb/rdi-share/Makefile.in @@ -0,0 +1,165 @@ +prefix = /usr/local + +program_transform_name = +exec_prefix = $(prefix) +bindir = $(exec_prefix)/bin +libdir = $(exec_prefix)/lib +tooldir = $(libdir)/$(target_alias) + +datadir = $(prefix)/share +mandir = $(prefix)/man +man1dir = $(mandir)/man1 +man2dir = $(mandir)/man2 +man3dir = $(mandir)/man3 +man4dir = $(mandir)/man4 +man5dir = $(mandir)/man5 +man6dir = $(mandir)/man6 +man7dir = $(mandir)/man7 +man8dir = $(mandir)/man8 +man9dir = $(mandir)/man9 +infodir = $(prefix)/info +includedir = $(prefix)/include + +ARM_RELEASE='"Berkeley Licence for Cygnus"' + +SHELL = /bin/sh + +INSTALL = `cd $(srcdir)/../..;pwd`/install.sh -c +INSTALL_PROGRAM = $(INSTALL) +INSTALL_DATA = $(INSTALL) +INSTALL_XFORM = $(INSTALL) -t='$(program_transform_name)' +INSTALL_XFORM1 = $(INSTALL_XFORM) -b=.1 + +AR = ar +AR_FLAGS = qv +RANLIB = ranlib + +LD = ld + +# If you are compiling with GCC, make sure that either 1) You use the +# -traditional flag, or 2) You have the fixed include files where GCC +# can reach them. Otherwise the ioctl calls in inflow.c +# will be incorrectly compiled. The "fixincludes" script in the gcc +# distribution will fix your include files up. +#CC=cc +#CC=gcc -traditional +GCC=gcc + +# Directory containing source files. Don't clean up the spacing, +# this exact string is matched for by the "configure" script. +srcdir = . + +# It is also possible that you will need to add -I/usr/include/sys to the +# CFLAGS section if your system doesn't have fcntl.h in /usr/include (which +# is where it should be according to Posix). + +# Set this up with gcc if you have gnu ld and the loader will print out +# line numbers for undefinded refs. +#CC-LD=gcc -static +CC-LD=${CC} + +# All the includes used for CFLAGS and for lint. +# -I. for config files. +# -I${srcdir} possibly for regex.h also. +# -I${srcdir}/config for more generic config files. +INCLUDE_CFLAGS = -I. -I${srcdir} + +# M{H,T}_CFLAGS, if defined, has host- and target-dependent CFLAGS +# from the config/ directory. +GLOBAL_CFLAGS = ${MT_CFLAGS} ${MH_CFLAGS} -DRETRANS -DARM_RELEASE=$(ARM_RELEASE) +#PROFILE_CFLAGS = -pg + +# CFLAGS is specifically reserved for setting from the command line +# when running make. I.E. "make CFLAGS=-Wmissing-prototypes". +CFLAGS = -g + +# INTERNAL_CFLAGS is the aggregate of all other *CFLAGS macros. +INTERNAL_CFLAGS = ${CFLAGS} ${GLOBAL_CFLAGS} ${PROFILE_CFLAGS} \ + ${BFD_CFLAGS} ${MMALLOC_CFLAGS} ${INCLUDE_CFLAGS} + +# LDFLAGS is specifically reserved for setting from the command line +# when running make. + +# Host and target-dependent makefile fragments come in here. +#### +# End of host and target-dependent makefile fragments + +# All source files that go into linking GDB remote server. + +SFILES = $(srcdir)/ + +DEPFILES = + +SOURCES = $(SFILES) $(ALLDEPFILES) +TAGFILES = $(SOURCES) ${HFILES} ${ALLPARAM} ${POSSLIBS} + +OBS = hostchan.o drivers.o devsw.o rx.o tx.o params.o hsys.o crc.o \ +logging.o msgbuild.o ardi.o serdrv.o serpardr.o etherdrv.o bytesex.o \ +unixcomm.o + +# Prevent Sun make from putting in the machine type. Setting +# TARGET_ARCH to nothing works for SunOS 3, 4.0, but not for 4.1. +.c.o: + ${CC} -c ${INTERNAL_CFLAGS} $< + +all: libangsd.a + +libangsd.a: $(OBS) + rm -f libangsd.a + $(AR) $(AR_FLAGS) libangsd.a $(OBS) + $(RANLIB) libangsd.a + +# Traditionally "install" depends on "all". But it may be useful +# not to; for example, if the user has made some trivial change to a +# source file and doesn't care about rebuilding or just wants to save the +# time it takes for make to check that all is up to date. +# install-only is intended to address that need. +install: all install-only +install-only: + +uninstall: + +installcheck: +check: +info dvi: +install-info: +clean-info: + +config.status: + @echo "You must configure rdi-share. Look at the README file for details." + @false + +clean: + rm -f *.o ${ADD_FILES} *~ + rm -f gdbserver core make.log + +distclean: clean + rm -f config.status + rm -f Makefile + +maintainer-clean realclean: clean + rm -f config.status + rm -f Makefile + +Makefile: $(srcdir)/Makefile.in $(host_makefile_frag) $(target_makefile_frag) + $(SHELL) ./config.status + +force: + +# GNU Make has an annoying habit of putting *all* the Makefile variables +# into the environment, unless you include this target as a circumvention. +# Rumor is that this will be fixed (and this target can be removed) +# in GNU Make 4.0. +.NOEXPORT: + +# GNU Make 3.63 has a different problem: it keeps tacking command line +# overrides onto the definition of $(MAKE). This variable setting +# will remove them. +MAKEOVERRIDES= + +## This is ugly, but I don't want GNU make to put these variables in +## the environment. Older makes will see this as a set of targets +## with no dependencies and no actions. +unexport CHILLFLAGS CHILL_LIB CHILL_FOR_TARGET : + +# This is the end of "Makefile.in". diff --git a/gdb/rdi-share/README.CYGNUS b/gdb/rdi-share/README.CYGNUS new file mode 100644 index 00000000000..4bf06c93c3d --- /dev/null +++ b/gdb/rdi-share/README.CYGNUS @@ -0,0 +1,6 @@ +This is a version of ARM's RDI library which has been been put under a +free software license. + +See ARM's Software Development Tools Reference Manual (Remote +Debugging chapter), and the file gdb/remote-rdi.c for information +about how to use it. diff --git a/gdb/rdi-share/adp.h b/gdb/rdi-share/adp.h new file mode 100644 index 00000000000..099fa4db149 --- /dev/null +++ b/gdb/rdi-share/adp.h @@ -0,0 +1,2528 @@ +/* + * Copyright (C) 1995 Advanced RISC Machines Limited. All rights reserved. + * + * This software may be freely used, copied, modified, and distributed + * provided that the above copyright notice is preserved in all copies of the + * software. + */ + +/* -*-C-*- + * + * $Revision$ + * $Date$ + * + * + * + * INTRODUCTION + * ------------ + * The early RDP message definitions were held in an ARM Ltd "armdbg" + * source file. Since the relevant header files were not exported + * publicly as part of an ARM Ltd core tools release, it was a problem + * for developers manipulating the target side of the protocol. + * + * For Angel, this new (ANSI 'C' clean) header file defines the ADP + * protocol. The header should be useable by both host and target + * systems, thus avoiding problems that can arise from duplicate + * definitions. Care has been taken in the construction of this header + * file to avoid any host/target differences. + * + * MESSAGE FORMAT + * -------------- + * Format of the "data" section of debug and boot agent messages. This is + * the standard ADP (Angel Debug Protocol) message format: + * + * unsigned32 reason - Main debug reason code. + * unsigned32 debugID - Information describing host debug world; + * - private to host and used in any target initiated + * messages. + * unsigned32 OSinfo1 \ Target OS information to identify process/thread + * unsigned32 OSinfo2 / memory/world, etc. These two fields are target + * defined. + * byte args[n] - Data for message "reason" code. + * + * NOTE: The message format is the same for single threaded debugging, + * except that the "OSinfo" fields should be -1 (0xFFFFFFFF). Even + * single-threaded debugging *MAY* have different host specified + * debugID values, so the Angel debug system will preserve the "debugID" + * information for replies, and the relevant asynchronous target-to-host + * messages. The "debugID" is defined by the host-end of the + * protocol, and is used by the host to ensure that messages are + * routed to the correct handler program/veneer. + * + * The reason there are two target specified "OSinfo" words is because + * thread identifiers may not be unique when processes/tasks have + * private virtual address spaces. It allows more flexibility when + * supporting multi-threaded or O/S aware debugging. + * + * NOTE: The reason that there is no "size" information, is that the + * message IDs themselves encode the format of any arguments. Also it + * would be a duplication of information used by the physical + * transport layer (which is distinct from this logical message + * layer). Any routing of messages through programs, hosts, + * etc. should be performed at the physical layer, or the boundaries + * between physical layers. i.e. packet received on socket in host, + * and transferred to serial packet for passing on down the line. + * + * NOTE: Pointers aren't passed in messages because they are dangerous in + * a multi-threaded environment. + * + * ADP REASON CODE + * --------------- + * The message reason codes contain some information that ties them to + * the channel and direction that the message will be used with. This + * will ensure that even if the message "#define name" is not + * completely descriptive, the message reason code is. + * + * b31 = direction. 0=Host-to-Target; 1=Target-to-Host; + * b30-28 = debug agent multi-threaded control (see below) + * b27-24 = reserved. should be zero. + * b23-16 = channelid. The fixed Angel channel number + * (see "channels.h"). + * b15-0 = message reason code. + * + * It is unfortunate that to aid the error-checking capabilities of + * the Angel communications we have changed the message numbers from + * the original ARM Ltd RDP. However this also has benefits, in that + * the Angel work is meant to be a clean break. + * + * However, it isn't so bad since even though the numbers are + * different, the majority of the reason codes have exactly the same + * functionality as the original RDP messages. + * + * NOTES + * ----- + * It would be ideal to use "rpcgen" (or some equivalent) to + * automatically maintain compatibility between the target and host + * ends of the protocol. However, ARM Ltd expressed that the message + * handling should be hand-coded, to avoid dependance on external + * tools. + * + * All other channels have undefined data formats and are purely + * application defined. The C library "_sys_" support will provide a + * veneer to perform message block operations as required. + * + * It is IMPLIED that all of the ADP messages will fit within the + * buffer DATASIZE. This has a minimum value, calculated from + * BUFFERMINSIZE. + * + * All messages are passed and received to the channel system in little + * endian order (ie. use little endian order when writing a word as + * a sequence of bytes within a message). + * + * A reply / acknowledgement to an ADP message is always sent and has the + * same reason code as the original except that the TtoH / HtoT bit is + * reversed. This makes it simple to check that the reply really + * is a reply to the message which was just sent! [Boot Channel messages + * also require that this protocol is used]. + */ + +#ifndef angel_adp_h +#define angel_adp_h + +#include "chandefs.h" + + +/* + * Buffer minimum sizes + */ + +/* the minimum target internal size */ +#define ADP_BUFFER_MIN_SIZE (256) + +/* a word is always reserved for internal use in the target */ +#define ADP_BUFFER_MAX_INTERNAL (sizeof(word)) + +/* the minimum available data portion */ +#define ADP_BUFFER_MIN_DATASIZE \ + (ADP_BUFFER_MIN_SIZE - ADP_BUFFER_MAX_INTERNAL - CHAN_HEADER_SIZE) + +/* + * the space taken up by the standard ADP header + * (reason, debugID, OSinfo1, OSinfo2) + */ +#define ADP_DEFAULT_HEADER_SIZE (4*sizeof(word)) + + +/* 8bit ADP version identification */ +#define ADPVSN (0x03) +/* This value can be used to identify the protocol version supported + * by target or host systems. This version number should only be + * changed if the protocol undergoes a non-backward compatible + * change. It should *NOT* be used to reflect extensions to the + * protocol. Such extensions can be added to the existing protocol + * version by allocating new reason codes, and by extending the + * ADP_Info message to identify new features. + */ + +/* The following value is used in the OSinfo fields for + * single-threaded messages, or where the host wants to alter the + * global CPU state. NOTE: The "debugID" field should always be + * defined by the host, and returned in target initiated messages. The + * only exception to this rule is the ADP_Booted message at the + * start-of-day. + */ +#define ADP_HandleUnknown (-1) + +/****************************************************************** + * + * ADP reason code subfields + * + */ + +/* The following bits are used to describe the basic direction of + * messages. This allows some extra checking of message validity to be + * performed, as well as providing a description of the message that + * may not be available in the "cpp" macro: + */ +#define HtoT ((unsigned)0 << 31) /* Host-to-Target message */ +#define TtoH ((unsigned)1 << 31) /* Target-to-Host message */ + +/* The following bits are used to control how the target system + * executes whilst processing messages. This allows for O/S specific + * host-based debug programs to interrogate system structures whilst + * ensuring that the access is atomic within the constraints imposed + * by the target O/S. + * + * NOTE: That only the channel is inserted into the reason code + * automatically. Thus both direction and multi thread control bits + * must be added by the host / target. + */ +/* Disable FIQ whilst processing message */ +#define DisableFIQ (1 << 30) +/* Disable IRQ whilst processing message */ +#define DisableIRQ (1 << 29) +/* Disable O/S pre-emption whilst processing message */ +#define DisablePreemption (1 << 28) + +/* The channel identification number is held in the reason code as a + * check: + */ +#define ADPCHANNEL(b) (((b) & 0xFF) << 16) + +/* The following macro constructs the reason code number, from the + * various fields - note that the direction is NOT inlcuded since + * this depends on whether the Host or Target system is including + * this file! + */ +#define ADPREASON(c,r) (ADPCHANNEL(c) | ((r) & 0xFFFF)) + +/* This macros is used when constructing manifests for sub-reason + * codes. At the moment it is identical to the main reason macro. If + * desired we could add a new bit that explicitly identifies the value + * as a sub-reason code, where the corresponding bit in the main + * message ID would be zero. + */ +#define ADPSUBREASON(c,r) (ADPCHANNEL(c) | ((r) & 0xFFFF)) + +/* All other undefined bits are reserved, and should be zero. */ + + + +/***************************************************************** + * + * channel_BOOT messages + * + */ + +/* The BOOT agent only supports a few messages. They are used purely + * to control the "start-of-day" connection to a host program. All + * Angel systems with host communications *MUST* provide the BOOT + * agent, even if they don't have support for either the single- or + * multi-threaded debug agents. + * + * The way the BOOT channel will be used on startup will be as follows: + * + * a) Target board is powered up before host debugger is invoked + * + * After switching on the target and initialisation is completed the + * target will send an ADP_Booted or ADP_Reset message. The debugger + * has not been started yet so this message will not be received. In + * a serial world this makes it important that any buffers on the host + * side are flushed during initialisation of the debugger, and in an + * Ethernet world it makes it important that the target can cope with the + * message not being received. + * + * Eventually the Debugger will be started up and will send an + * ADP_Reboot or ADP_Reset request. The target will respond to this with + * an ADP_Reboot or ADP_Reset acknowldege and will then reboot, finally + * sending an ADP_Rebooted when it has done all it needs to do (very little + * in the case of ADP_Reset, but completely rebooting in the case of + * ADP_Reboot). Note that it is important that an ADP_Rebooted message is + * sent so that the Debugger does not attempt to send any data after it has + * made a request to ADP_Reboot and before it receives an ADP_Rebooted, as + * data can be lost be the target during this time. + * + * The target and host are now ready to start a debug session. + * + * b) Target board is powered up after host debugger is invoked + * + * The debugger will send an ADP_Reboot or ADP_Reset request, but will + * receive no reply until the target is powered up. +/ * + * When the target is powered up then it will send an ADP_Rebooted + * message to the debugger. The debugger should accept this message + * even though it has received no ADP_Reboot or ADP_Reset acknowldege message + * from the target. + * + * The target and host are now ready to start a debug session. + * + * + * If at any point during the bootup sequence and ADP messages are + * sent down the S_DBG channel then they should be responded to with a + * RDI_NotInitialised error. [This should never happen however]. + * + * An ADP_Boot or ADP Rebooted message should be accepted at + * any point, since it is possible for a catastrophe to occur (such as + * disconnecteing the host and target during a debug message) which + * requires that one or other end be reset. + * + */ + +/* + * A list of parameter types - for now just baud rate + */ +typedef enum ADP_Parameter { + AP_PARAMS_START = 0xC000, + AP_BAUD_RATE = AP_PARAMS_START, + /* extra parameters go in here */ +#ifdef TEST_PARAMS + AP_CAFE_MENU, /* extra just for testing */ +#endif + AP_PARAMS_END +} ADP_Parameter; + +#define AP_NUM_PARAMS (AP_PARAMS_END - AP_PARAMS_START) + +/* + * Parameter types should have associated semantics which can be represented + * within one word per parameter, or an associated enum for choices. + * + * AP_BAUD_RATE: the word contains the exact baud rate, eg. 9600, 38400. + */ + +/* this is not strictly necessary, but it's an example */ +typedef enum ADP_BaudRate { + AB_9600 = 9600, + AB_19200 = 19200, + AB_38400 = 38400, + AB_57600 = 57600, + AB_115200 = 115200 +} ADP_BaudRate; + +#define AB_NUM_BAUD_RATES 5 /* this is more useful, for sizing arrays */ + +/* This must be set to the max number of options per parameter type */ +#define AP_MAX_OPTIONS (AB_NUM_BAUD_RATES) + + +#define ADP_Booted ADPREASON(CI_TBOOT,0) +/* This message is sent by the target after the Angel system has been + * initialised. This message also contains information describing the + * Angel world. The information can then be used to check that the + * target debug agent and source debugger are compatible. + * + * Message arguments: + * word Angel message default buffer size. + * word Angel message large buffer size (may be same as default) + * word Angel version ; inc. type (e.g. boot ROM) See (1) + * word ADP version. See (2) + * word ARM Architecture info See (3) + * word ARM CPU information ; including target endianness. See (4) + * word Target hardware status. See (5) + * word Number of bytes in banner message + * bytes Startup banner message (single-threaded readable + * descriptive text - NOT NULL terminated). + * + * Reply: + * word status + * + * 'status' returns RDIError_NoError for success, and otherwise + * indicates an error. + */ + +/* Angel version word [Reference(1)] : */ +/* Angel version number is a 16bit BCD value */ +#define ADP_ANGELVSN_MASK (0x0000FFFF) +#define ADP_ANGELVSN_SHIFT (0) + +/* Type of Angel system */ +#define ADP_ANGELVSN_TYPE_MASK (0x00FF0000) +#define ADP_ANGELVSN_TYPE_SHIFT (16) + +typedef enum { + ADP_AngelType_bootROM, /* Simple ROM system providing download capability */ + ADP_AngelType_appROM, /* ROM based application */ + ADP_AngelType_appDLOAD,/* Downloaded Angel based application */ + ADP_AngelType_Last /* Unknown type. This typedef can be extended */ + /* but if the host and target vsns differ */ + /* Then one will spot that it dies not understand */ +} ADP_Angel_Types ; /* this field and can whinge appropriately */ + +/* First unknown ADP_AngelType */ +#define ADP_ANGELVSN_UNKTYPE_MASK (0xFF000000) +#define ADP_ANGELVSN_UNKYPE_SHIFT (24) + +/* Currently only 8 bits are used in the word: */ +/* ADP protocol supported by target [Reference (2)] */ +#define ADP_ANGELVSN_ADP_MASK (0x000000FF) +#define ADP_ANGELVSN_ADP_SHIFT (0) + +/* ARM Architecture info: [Reference (3)] */ +/* ARM Architecture Verson of target CPU */ +#define ADP_ARM_ARCH_VSN_MASK (0x000000FF) +#define ADP_ARM_ARCH_VSN_SHIFT (0) +/* Does the processor support the Thumb Instruction Set */ +#define ADP_ARM_ARCH_THUMB (0x80000000) +/* Does the processor support Long Multiplies */ +#define ADP_ARM_ARCH_LONGMUL (0x40000000) +/* All other flags are current undefined, and should be zero. */ + +/* The following flags describe the feature set of the processor: */ +/* Set if cpu supports little-endian model [Reference (4)] */ +#define ADP_CPU_LE (1 << 0) +/* Set if cpu supports big-endian model */ +#define ADP_CPU_BE (1 << 1) +/* Set if processor has a cache */ +#define ADP_CPU_CACHE (1 << 2) +/* Set if processor has a MMU */ +#define ADP_CPU_MMU (1 << 3) +/* All other flags are current undefined, and should be zero. */ + +/* The following flags reflect current Target hardware status: */ +/* [Reference (5)] */ +/* 0 = no MMU or MMU off; 1 = MMU on */ +#define ADP_CPU_MMUOn (1 << 29) +/* 0 = no cache or cache off; 1 = cache on */ +#define ADP_CPU_CacheOn (1 << 30) +/* 0 = little-endian; 1 = big-endian */ +#define ADP_CPU_BigEndian (1U << 31) +/* All other flags are current undefined, and should be zero. */ + + +#ifdef LINK_RECOVERY + +#define ADP_TargetResetIndication ADPREASON(CI_TBOOT, 1) +/* + * If parameter negotiation is enabled at the target, it configures itself + * to various likely parameter settings and sends this message at each + * configuration. The message describes the default settings, and after + * sending at each configuration the target sets itself to the defaults + * it has just broadcast, to await either an ack on TBOOT or a request + * or reset indication on HBOOT. + * + * If the host receives this message successfully, it should reset to the + * indicated parameters and send a reply. + * + * Message arguments: + * word status (always 0, makes body same as + * ADP_ParamNegotiate response) + * word n-parameters + * n-parameters * { + * word ADP_Parameter + * word parameter-value + * } + * + * Reply: + * - empty acknowledgement + */ + +#endif /* def LINK_RECOVERY */ + +typedef enum ADP_Boot_Ack { + AB_NORMAL_ACK, /* will comply, immediate booted message */ + AB_LATE_ACK, /* will comply, late startup */ + AB_ERROR /* cannot comply */ +} ADP_Boot_Ack; + +/* If the host sets neither of these in the word sent on a Reset / Reboot + * then it doesn;t care about the endianess of the target + */ +#define ADP_BootHostFeature_LittleEnd 0x80000000 +#define ADP_BootHostFeature_BigEnd 0x40000000 + +#define ADP_Reboot ADPREASON(CI_HBOOT,2) +/* This message is sent when the host wants the target system to be + * completely reset, back to the boot monitor Angel. This is the + * method of the host forcing a cold-reboot. + * Note that an acknowledgement message will be sent immediately and + * that this must be sent before the target can reset. + * + * The parameter to this function is a bitset of host supported + * features. (in fact the same as ADP_Reset below. This can be used by + * the target system to avoid using debug channel bandwidth raising + * messages that will be ignored by the host. + * + * Parameters: + * word host supported features (see above) + * + * Reply: + * word status, one of enum ADP_Boot_Ack above. + * + * Currently there are no such features defined, so the word indicating + * host supported features should be set to 0. + */ + + + +#define ADP_Reset ADPREASON(CI_HBOOT,3) +/* This message is a request from the host, which should eventually + * result in the "ADP_Booted" message being sent by the target. + * Note that an acknowledgement message will be sent immediately and + * that this must be sent before the target can reset. + * This reset message is *ALWAYS* treated as a warm boot, with the target + * preserving as much state as possible. + * + * The parameter to this function is a bitset of host supported + * features. This can be used by the target system to avoid using + * debug channel bandwitdth raising messages that will be ignored by + * the host. + * + * Parameters: + * word host supported features (see above) + * + * Reply: + * word status, one of enum ADP_Boot_Ack above. + * + * Currently there are no such features defined, so the word indicating + * host supported features should be set to 0. + */ + + +#ifdef LINK_RECOVERY + +#define ADP_HostResetIndication ADPREASON(CI_HBOOT, 4) +/* + * This is as for ADP_TargetResetIndication, but is sent by the host when + * it first starts up in case the target is listening at a non-default + * setting. Having sent at various configurations, the host then listens + * at the defaults it has just broadcast, to await either an ack on HBOOT + * or a reset indication on TBOOT. + * + * For arguments and reply, see ADP_TargetResetIndication. + */ + +#endif /* def LINK_RECOVERY */ + + +#define ADP_ParamNegotiate ADPREASON(CI_HBOOT, 5) +/* + * The host sends this messages to negotiate new parameters with the target. + * For each parameter the host specifies a range of possibilities, starting + * with the most favoured. All possible combinations of parameters + * must be valid. + * + * If the target can operate at a combination of the offered parameters, + * it will reply with the parameters it is willing to use. AFTER sending + * the reply, the target switches to this combination. On receiving the + * reply, the host will switch to the new combination and send a LinkCheck + * message (see below). + * + * If the target cannot operate at any combination of the offered parameters, + * it will reply with an error status. + * + * Message arguments: + * word n-parameter-blocks + * n-parameter-blocks * { + * word ADP_Parameter + * word n-options + * n-options * { word parameter-value } + * } + * + * Reply: + * word status + * if (status == RDIError_NoError) { + * word n-parameters + * n-parameters * { + * word ADP_Parameter + * word chosen-value + * } + * } + */ + +#define ADP_LinkCheck ADPREASON(CI_HBOOT, 6) +/* + * This should be the first message that the host sends after a successful + * parameter negotiation. It is really just a 'ping'. + * + * Message arguments: + * - empty message + * + * Reply: + * - empty acknowledgement + */ + + +/******************************************************************** + * + * CI_HADP messages + * + */ + +#define ADP_HADPUnrecognised ADPREASON(CI_HADP,0) +/* This message is unusual in that it is normally sent in reply to + * another message which is not understood. This is an exception + * to the normal protocol which says that a reply must have the + * same base reason code as the original. There is a single reply + * parameter which is the reason code which was not understood. + * + * As well as being a reply this message can also be sent and will + * return as if this message were unrecognised! + * + * Parameters: + * none + * + * Reply: + * word reason code which was not recognised + */ + + +#define ADP_Info ADPREASON(CI_HADP,1) +/* This is the new ADP information message. It is used to interrogate + * the target debug agent. It provides information on the processor, + * as well as the state of the debug world. This allows the host to + * configure itself to the capabilities of the target. + * + * We try not to use feature bitsets, since we could quickly run out + * of known bits. Thus when the feature set is extended, this can be + * done in a couple of supported ways: + * + * If an undivided reason code is to be added (no reason subcodes) + * then add a new ADP_Info code which responds with a flag indicating + * whether that feature is supported by the target. If this has not + * even been implemented then the reply will be ADP_HADPUnrecognised + * + * If a reason code which is subdivided into reason subcodes is + * added then reason subcode 0 should be set aside to indicate + * whether the functionality of that reason code is supported + * by the target. If it is not even implemented then the reply will + * be ADP_Unrecognised. + * + * The first parameter to ADP_Info is a reason subcode, and subsequent + * parameters are defined by that subcode + * + * Parameters: + * word reason subcode + * other arguments as reason subcode determines. + * + * Reply: + * word reason subcode + * other argument as reason subcode determines + */ + +/* ADP_Info reason subcodes: */ + + + +#define ADP_Info_NOP ADPSUBREASON(CI_HADP,0) +/* ADP_Info_NOP + * ------------ + * Summary: This message is used to check for ADP_Info being supported. + * + * Arguments: + * Send: () + * Return: (word status) + * + * 'status' returns RDIError_NoError for success, non-zero indicates an error. + * If an error is returned then there is no handler for the ADP_Info + * message. The normal action will be to return an OK status. + */ + + +#define ADP_Info_Target ADPSUBREASON(CI_HADP,1) +/* ADP_Info_Target + * --------------- + * Summary: + * This reason code is used to interrogate target system details. + * + * Arguments: + * Send: () + * Return: (word status, word bitset, word model) + * + * 'status' is RDIError_NoError to indicate OK, or non-zero to indicate + * some sort of error. + * 'bitset' is described in more detail below, and is mostly compatible + * with the old RDI/RDP system to avoid gratuitous changes to the debugger + * toolbox. + * 'model' is the target hardware ID word, as returned by the ADP_Booted + * message. + * + * NOTE: The minimum and maximum protocol levels are no longer supported. + * It is the Angel view that debugging complexity should be shifted to the + * host if at all possible. This means that the host debugger should + * always try to configure itself to the features available in the target + * debug agent. This can be done by checking individual messages, rather + * than by a blanket version number dictating the feature set. + */ + +/* 'bitset':- */ +/* Target speed in instructions per second = 10**(bits0..3). */ +#define ADP_Info_Target_LogSpeedMask (0xF) + +/* Target is running on [0 = emulator / 1 = hardware] */ +#define ADP_Info_Target_HW (1 << 4) + +/* Bits 5..10 are currently undefined and should be zero. */ +/* Other bis are kept the same as the RDP in order to */ +/* eliminate the need to change the position of some bits */ + +/* If set then the debug agent can be reloaded. */ +#define ADP_Info_Target_CanReloadAgent (1 << 11) + +/* Can request AngelBufferSize information. */ +#define ADP_Info_Target_CanInquireBufferSize (1 << 12) + +/* Bit 13 is no longer required as it inquired whether + * a special RDP Interrupt code was supported + */ + +/* Debug agent can perform profiling. */ +#define ADP_Info_Target_Profiling (1 << 14) + +/* Debug agent can support Thumb code. */ +#define ADP_Info_Target_Thumb (1 << 15) + +/* Bit 16 was the communications channel check. + * This is always available on Angel systems. + */ + +#define ADP_Info_Points ADPSUBREASON(CI_HADP,2) +/* ADP_Info_Points + * --------------- + * Summary: Returns a 32bit wide bitset of break- and watch-point + * features supported by the target debug agent. + * + * Arguments: + * Send: () + * Return: (word status, word breakinfo) + * + * 'status' returns RDIError_NoError on success or non-zero to indicate + * some sort of error. + * 'breakinfo' is a 32bit wide bitset described in detail below. Note + * that only bits 1..12 are used. + */ + +/* 'breakinfo':- */ +/* Can trap on address equality. */ +#define ADP_Info_Points_Comparison (1 << 0) + +/* Can trap on address range. */ +#define ADP_Info_Points_Range (1 << 1) + +/* Can trap on 8bit memory reads. */ +#define ADP_Info_Points_ReadByteWatch (1 << 2) + +/* Can trap on 16bit memory reads. */ +#define ADP_Info_Points_ReadHalfWatch (1 << 3) + +/* Can trap on 32bit memory reads. */ +#define ADP_Info_Points_ReadWordWatch (1 << 4) + +/* Can trap on 8bit write accesses. */ +#define ADP_Info_Points_WriteByteWatch (1 << 5) + +/* Can trap on 16bit write accesses. */ +#define ADP_Info_Points_WriteHalfWatch (1 << 6) + +/* Can trap on 32bit write accesses. */ +#define ADP_Info_Points_WriteWordWatch (1 << 7) + +/* Like range, but based on address bitmask<. */ +#define ADP_Info_Points_Mask (1 << 8) + +/* Multi-threaded support only - thread specific breakpoints. */ +#define ADP_Info_Points_ThreadBreak (1 << 9) + +/* Multi-threaded support only - thread specific watchpoints. */ +#define ADP_Info_Points_ThreadWatch (1 << 10) + +/* Allows conditional breakpoints. */ +#define ADP_Info_Points_Conditionals (1 << 11) + +/* Break- and watch-points can be interrogated */ +#define ADP_Info_Points_Status (1 << 12) + + +#define ADP_Info_Step ADPSUBREASON(CI_HADP,3) +/* ADP_Info_Step + * ------------- + * Summary: Returns a 32bit wide bitmask of the single-stepping + * capabilities of the target debug agent. + * + * Arguments: + * Send: () + * Return: (word status, word stepinfo) + * + * 'status' returns RDIError_NoError on success, or non-zero to indicate + * some kind of error. + * 'stepinfo' is a 32bit wide bitmask described in detail below. Note that + * only 3 bits are used. + */ + +/* 'stepinfo':- */ +/* Single-stepping of more than one instruction is possible. */ +#define ADP_Info_Step_Multiple (1 << 0) + +/* Single-stepping until next direct PC change is possible. */ +#define ADP_Info_Step_PCChange (1 << 1) + +/* Single-stepping of a single instruction is possible. */ +#define ADP_Info_Step_Single (1 << 2) + + +#define ADP_Info_MMU ADPSUBREASON(CI_HADP,4) +/* ADP_Info_MMU + * ------------ + * Summary: Returns information about the memory management system (if + * any). + * + * Arguments: + * Send: () + * Return: (word status, word meminfo) + * + * 'status' returns RDIError_NoError to indicate success or non-zero to + * indicate some kind of error. + * 'meminfo' should be a 32bit unique ID, or zero if there is no MMU + * support on the target. + */ + + +#define ADP_Info_SemiHosting ADPSUBREASON(CI_HADP,5) +/* ADP_Info_SemiHosting + * -------------------- + * Summary: This message is used to check whether semi-hosting info calls + * are available on the target. + * + * Arguments: + * Send: () + * Return: (word status) + * + * 'status' returns RDIError_NoError if semi-hosting info calls are available, + * non-zero otherwise. + */ + + +#define ADP_Info_CoPro ADPSUBREASON(CI_HADP,6) +/* ADP_Info_CoPro + * -------------- + * Summary: This message checks whether CoProcessor info calls are + * supported. + * + * Arguments: + * Send: () + * Return: (word status) + * + * 'status' returns RDIError_NoError to indicate these facilities + * are supported, non-zero otherwise. + */ + + +#define ADP_Info_Cycles ADPSUBREASON(CI_HADP,7) +/* ADP_Info_Cycles + * --------------- + * Summary: Returns the number of instructions and cycles executed since + * the target was initialised. + * + * Arguments: + * Send: () + * Return: (word status, word ninstr, word Scycles, word Ncycles, + * word Icycles, word Ccycles, word Fcycles) + * + * 'status' is RDIError_NoError to indicate success, or non-zero if there + * is no target support for gathering cycle count information. + * 'ninstr' is the number of instructions executed. + * 'Scycles' is the number of S-cycles executed. + * 'Ncycles' is the number of N-cycles executed. + * 'Icycles' is the number of I-cycles executed. + * 'Ccycles' is the number of C-cycles executed. + * 'Fcycles' is the number of F-cycles executed. + */ + + +#define ADP_Info_DescribeCoPro ADPSUBREASON(CI_HADP,8) +/* ADP_Info_DescribeCoPro + * ---------------------- + * Summary: Describe the registers of a coprocessor. Use only if + * ADP_Info_CoPro return RDIError_NoError. + * + * Arguments: + * Send: Arguments of the form: + * (byte cpno, byte rmin, byte rmax, byte nbytes, byte access, + * byte cprt_r_b0, byte cprt_r_b1, byte cprt_w_b0, byte cprt_w_b1) + * And a terminating byte = 0xff. Must be within maximum buffer size. + * Return: (word status) + * + * 'cpno' is the number of the coprocessor to be described. + * 'rmin' is the bottom of a range of registers with the same description. + * 'rmax' is the top of a range of registers with the same description. + * 'nbytes' is the size of the register. + * 'access' describes access to the register and is described in more detail + * below. + * + * If bit 2 of access is set:- + * 'cprt_r0' provides bits 0 to 7, and + * 'cprt_r1' provides bits 16 to 23 of a CPRT instruction to read the + * register. + * 'cprt_w0' provides bits 0 to 7, and + * 'cprt_w1' provides bits 16 to 23 of a CPRT instruction to write the + * register. + * + * Otherwise, 'cprt_r0' provides bits 12 to 15, and 'cprt_r1' bit 22 of CPDT + * instructions to read and write the register ('cprt_w0' and 'cprt_w1' are + * junk). + */ + +/* 'access':- */ +/* Readable. */ +#define ADP_Info_DescribeCoPro_Readable (1 << 0) + +/* Writeable. */ +#define ADP_Info_DescribeCoPro_Writeable (1 << 1) + +/* Registers read or written via CPDT instructions (else CPRT) with this + bit set. */ +#define ADP_Info_DescribeCoPro_CPDT (1 << 2) + +#define ADP_Info_RequestCoProDesc ADPSUBREASON(CI_HADP,9) +/* ADP_Info_RequestCoProDesc + * ------------------------- + * Summary: Requests a description of the registers of a coprocessor. Use + * only if ADP_Info_CoPro return RDIError_NoError. + * + * Arguments: + * Send: (byte cpno) + * Return: Arguments of the form:- + * (word status, byte rmin, byte rmax, byte nbytes, byte access) + * Followed by a terminating byte = 0xFF. Must be within maximum + * buffer size. + * 'cpno' is the number of the coprocessor to describe. + * 'status' is RDIError_NoError to indicate success, non-zero otherwise. + * 'rmin' is the bottom of a range of registers with the same description. + * 'rmax' is the top of a range of registers with the same description. + * 'nbytes' is the size in bytes of the register(s). + * 'access' is as above in ADP_Info_DescribeCoPro. + */ + + +#define ADP_Info_AngelBufferSize ADPSUBREASON(CI_HADP,10) +/* ADP_Info_AngelBufferSize + * ------------------------ + * Summary: Returns the Angel buffer sizes. + * + * Arguments: + * Send: () + * Return: (word status, word defaultsize, word maxsize) + * + * 'status' returns RDIError_NoError to indicate success or non-zero to + * indicate some kind of error. + * 'defaultsize' is the default Angel ADP buffer size in bytes. This is + * at least 256 bytes. + * 'maxsize' is the largest Angel ADP buffer size in bytes. This will be + * greater than or equal to defaultsize. The target will accept ADP messages + * of up to this length for download, etc. + * + * Was DownLoadSize in RDP/RDI world. This is the amount that the target + * should transmit in a single operation. This should now be the Angel + * buffer size. This information is also given in the ADP_Booted message. + * + * NOTE: The value returned should be the DATASIZE and *NOT* BUFFERDEFSIZE. + * This is needed to ensure that the transport protocol information + * can be wrapped around the data. + */ + +#define ADP_Info_ChangeableSHSWI ADPSUBREASON(CI_HADP,11) +/* ADP_Info_ChangeableSHSWI + * ------------------------ + * Summary: This message is used to check whether it is possible to change + * which SWI's are used for semihosting. + * + * Arguments: + * Send: () + * Return: (word status) + * + * 'status' returns RDIError_NoError if semi-hosting info calls are available, + * non-zero otherwise. + */ + +#define ADP_Info_CanTargetExecute ADPSUBREASON(CI_HADP,12) +/* ADP_Info_CanTargetExecute + * ------------------------- + * Summary: This message is used to see if the target is currently in + * an executable state. Typically this is called after the debugger + * initialises. If a non-error statis is returned then the user is + * allowed to 'go' immediately. + * + * Arguments: + * Send: () + * Return: (word status) + * + * 'status' returns RDIError_NoError if target is ready to execute. + * other values indicate why it cannot execute. + */ + +#define ADP_Info_AgentEndianess ADPSUBREASON(CI_HADP,13) +/* ADP_Info_AgentEndianess + * ------------------------- + * Summary: This message is used to determine the endianess of the + * debug agent + * Arguments: + * Send: () + * Return: (word status) + * + * status should be RDIError_LittleEndian or RDIError_BigEndian + * any other value indicates the target does not support this + * request, so the debugger will have to make a best guess, which + * probably means only allow little endian loadagenting. + */ + + +#define ADP_Control ADPREASON(CI_HADP,2) +/* This message allows for the state of the debug agent to be + * manipulated by the host. + */ + +/* The following are sub reason codes to ADP control, the first parameter + * is the sub reason code which defines the format of subsequent parameters. + * + * word sub reason code + */ + +#define ADP_Ctrl_NOP ADPSUBREASON(CI_HADP,0) +/* ADP_Ctrl_NOP + * ------------ + * Summary: This message is used to check that ADP_Ctrl messages are + * supported. + * + * Arguments: + * Send: () + * Return: (word status) + * + * 'status' is RDIError_NoError to indicate ADP_Ctrl messages are + * supported, non-zero otherwise. + */ + +#define ADP_Ctrl_VectorCatch ADPSUBREASON(CI_HADP,1) +/* ADP_Ctrl_VectorCatch + * -------------------- + * Summary: Specifies which hardware exceptions should be reported to the + * debugger. + * + * Arguments: + * Send: (word bitmap) + * Return: (word status) + * + * 'bitmap' is a bit-mask of exceptions to be reported, described in more + * detail below. A set bit indicates that the exception should be + * reported to the debugger, a clear bit indicates that the corresponding + * exception vector should be taken. + * 'status' is RDIError_NoError to indicate success, non-zero otherwise. + */ + +/* 'bitmap':- */ +/* Reset(branch through zero). */ +#define ADP_Ctrl_VectorCatch_BranchThroughZero (1 << 0) + +/* Undefined Instruction. */ +#define ADP_Ctrl_VectorCatch_UndefinedInstr (1 << 1) + +/* Software Interrupt. */ +#define ADP_Ctrl_VectorCatch_SWI (1 << 2) + +/* Prefetch Abort. */ +#define ADP_Ctrl_VectorCatch_PrefetchAbort (1 << 3) + +/* Data Abort. */ +#define ADP_Ctrl_VectorCatch_DataAbort (1 << 4) + +/* Address Exception. */ +#define ADP_Ctrl_VectorCatch_AddressException (1 << 5) + +/* Interrupt Request. */ +#define ADP_Ctrl_VectorCatch_IRQ (1 << 6) + +/* Fast Interrupt Request. */ +#define ADP_Ctrl_VectorCatch_FIQ (1 << 7) + +/* Error. */ +#define ADP_Ctrl_VectorCatch_Error (1 << 8) + + +#define ADP_Ctrl_PointStatus_Watch ADPSUBREASON(CI_HADP,2) +/* ADP_Ctrl_PointStatus_Watch + * -------------------------- + * Summary: Returns the hardware resource number and the type of that + * resource when given a watchpoint handle. Should only be called if + * the value returned by ADP_Info_Points had ADP_Info_Points_Status set. + * + * Arguments: + * Send: (word handle) + * Return: (word status, word hwresource, word type) + * + * 'handle' is a handle to a watchpoint. + * 'status' is RDIError_NoError to indicate success, non-zero otherwise. + * 'hwresource' is the hardware resource number. !!!!! + * 'type' is the type of the resource. + */ + + +#define ADP_Ctrl_PointStatus_Break ADPSUBREASON(CI_HADP,3) +/* ADP_Ctrl_PointStatus_Break + * -------------------------- + * Summary: Returns the hardware resource number and the type of that + * resource when given a breakpoint handle. Should only be called if + * the value returned by ADP_Info_Points had ADP_Info_Points_Status set. + * + * Arguments: + * Send: (word handle) + * Return: (word status, word hwresource, word type) + * + * 'handle' is a handle to a breakpoint. + * 'status' is RDIError_NoError to indicate success, non-zero otherwise. + * 'hwresource' is the hardware resource number. + * 'type' is the type of the resource. + */ + +#define ADP_Ctrl_SemiHosting_SetState ADPSUBREASON(CI_HADP,4) +/* ADP_Ctrl_SemiHosting_SetState + * ----------------------------- + * Summary: Sets whether or not semi-hosting is enabled. + * + * Arguments: + * Send: (word semihostingstate) + * Return: (word status) + * + * 'semihostingstate' sets semi-hosting to enabled if zero, otherwise + * it disables semi-hosting. + * 'status' is RDIError_NoError to indicate success, non-zero otherwise. + * + * NOTE: This should only be called if ADP_Info_SemiHosting didn't return + * an error. + */ + + +#define ADP_Ctrl_SemiHosting_GetState ADPSUBREASON(CI_HADP,5) +/* ADP_Ctrl_SemiHosting_GetState + * ----------------------------- + * Summary: Reads whether or not semi-hosting is enabled. + * + * Arguments: + * Send: () + * Return: (word status, word semihostingstate) + * + * 'status' is RDIError_NoError to indicate success, non-zero otherwise. + * 'semihostingstate' is zero if semi-hosting is enabled, non-zero otherwise. + * + * NOTE: This should only be called if ADP_Info_SemiHosting didn't return + * an error. + */ + + +#define ADP_Ctrl_SemiHosting_SetVector ADPSUBREASON(CI_HADP,6) +/* ADP_Ctrl_SemiHosting_SetVector + * ------------------------------ + * Summary: Sets the semi-hosting vector. + * + * Arguments: + * Send: (word semihostingvector) + * Return: (word status) + * + * 'semihostingvector' holds the value the vector is to be set to. + * 'status' is RDIError_NoError to indicate success, non-zero otherwise. + * + * NOTE: This should only be called if ADP_Info_SemiHosting didn't return + * an error. + */ + + +#define ADP_Ctrl_SemiHosting_GetVector ADPSUBREASON(CI_HADP,7) +/* ADP_Ctrl_SemiHosting_GetVector + * ------------------------------ + * Summary: Gets the value of the semi-hosting vector. + * + * Arguments: + * Send: () + * Return: (word status, word semihostingvector) + * + * 'status' is RDIError_NoError to indicate success, non-zero otherwise. + * 'semihostingvector' holds the value of the vector. + * + * NOTE: This should only be called if ADP_Info_SemiHosting didn't return + * an error. + */ + + +#define ADP_Ctrl_Log ADPSUBREASON(CI_HADP,8) +/* ADP_Ctrl_Log + * ------------ + * Summary: Returns the logging state. + * + * Arguments: + * Send: () + * Return: (word status, word logsetting) + * + * 'status' is RDIError_NoError to indicate success, non-zero otherwise. + * 'logsetting' is a bitmap specifying the level of logging desired, + * described in more detail below. The bits can be ORed together + */ + +/* 'logsetting':- */ + +/* No logging. */ +#define ADP_Ctrl_Log_NoLogging (0) +/* RDI level logging. */ +#define ADP_Ctrl_Log_RDI (1 << 0) +/* ADP byte level logging. */ +#define ADP_Ctrl_Log_ADP (1 << 1) + + +#define ADP_Ctrl_SetLog ADPSUBREASON(CI_HADP,9) +/* ADP_Ctrl_SetLog + * --------------- + * Summary: Sets the logging state. + * + * Arguments: + * Send: (word logsetting) + * Return: (word status) + * + * 'logsetting' is the same as in ADP_Ctrl_Log above. + * 'status' is RDIError_NoError to indicate success, non-zero otherwise. + */ + +#define ADP_Ctrl_SemiHosting_SetARMSWI ADPSUBREASON(CI_HADP,10) +/* ADP_Ctrl_SemiHosting_SetARMSWI + * ------------------------------ + * Summary: Sets the number of the ARM SWI used for semihosting + * + * Arguments: + * Send: (word ARM_SWI_number) + * Return: (word status) + * + * The debug agent will interpret ARM SWI's with the SWI number specified + * as semihosting SWI's. + * 'status' is RDIError_NoError to indicate success, non-zero otherwise. + * + * NOTE: This should only be called if ADP_Info_ChangeableSHSWI didn't return + * an error. + */ + + +#define ADP_Ctrl_SemiHosting_GetARMSWI ADPSUBREASON(CI_HADP,11) +/* ADP_Ctrl_SemiHosting_GetARMSWI + * ------------------------------ + * Summary: Reads the number of the ARM SWI used for semihosting + * + * Arguments: + * Send: () + * Return: (word status, word ARM_SWI_number) + * + * 'status' is RDIError_NoError to indicate success, non-zero otherwise. + * ARM_SWI_number is the SWI number which is used for semihosting. + * + * NOTE: This should only be called if ADP_Info_SemiHosting didn't return + * an error. + */ + +#define ADP_Ctrl_SemiHosting_SetThumbSWI ADPSUBREASON(CI_HADP,12) +/* ADP_Ctrl_SemiHosting_SetThumbSWI + * -------------------------------- + * Summary: Sets the number of the Thumb SWI used for semihosting + * + * Arguments: + * Send: (word Thumb_SWI_number) + * Return: (word status) + * + * The debug agent will interpret Thumb SWI's with the SWI number specified + * as semihosting SWI's. + * 'status' is RDIError_NoError to indicate success, non-zero otherwise. + * + * NOTE: This should only be called if ADP_Info_ChangeableSHSWI didn't return + * an error. + */ + + +#define ADP_Ctrl_SemiHosting_GetThumbSWI ADPSUBREASON(CI_HADP,13) +/* ADP_Ctrl_SemiHosting_GetThumbSWI + * -------------------------------- + * Summary: Reads the number of the Thumb SWI used for semihosting + * + * Arguments: + * Send: () + * Return: (word status, word ARM_Thumb_number) + * + * 'status' is RDIError_NoError to indicate success, non-zero otherwise. + * Thumb_SWI_number is the SWI number which is used for semihosting. + * + * NOTE: This should only be called if ADP_Info_SemiHosting didn't return + * an error. + */ + + +#define ADP_Ctrl_Download_Supported ADPSUBREASON(CI_HADP,14) +/* ADP_Ctrl_Download_Supported + * --------------------------- + * Summary: Can configuration be downloaded? + * + * Arguments: + * Send: () + * Return: (word status) + * + * 'status' is RDIError_NoError if the configuration can be downloaded, + * non-zero otherwise. + * + * NOTE: Equivalent to RDIInfo_DownLoad. + */ + + +#define ADP_Ctrl_Download_Data ADPSUBREASON(CI_HADP,15) +/* ADP_Ctrl_Download_Data + * ---------------------- + * Summary: Loads configuration data. + * + * Arguments: + * Send: (word nbytes, words data) + * Return: (word status) + * + * 'nbytes' is the number of *bytes* being sent. + * 'data' is the configuration data. NOTE: data must not cause the buffer + * size to exceed the maximum allowed buffer size. + * 'status' is RDIError_NoError to indicate success, non-zero otherwise. + * + * NOTE: Equivalent to RDP_LoadConfigData. Should only be used if + * ADP_ICEM_AddConfig didn't return an error. + */ + + +#define ADP_Ctrl_Download_Agent ADPSUBREASON(CI_HADP,16) +/* ADP_Ctrl_Download_Agent + * ----------------------- + * Summary: Prepares Debug Agent to receive configuration data which it + * should interpret as a new version of the Debug Agent code. + * + * Arguments: + * Send: (word loadaddress, word size) + * Return: (word status) + * + * 'loadaddress' is the address where the new Debug Agent code should be + * loaded. + * 'size' is the number of bytes of Debug Agent code to be loaded. + * 'status' is RDIError_NoError to indicate success, non-zero otherwise. + * + * NOTE: Equivalent to RDP_LoadAgent. The data will be downloaded using + * ADP_Ctrl_Download_Data. The new agent is started with ADP_Ctrl_Start_Agent + */ + + +#define ADP_Ctrl_Start_Agent ADPSUBREASON(CI_HADP,17) +/* ADP_Ctrl_Start_Agent + * ----------------------- + * Summary: Instruct Debug Agent to begin execution of new agent, + * which has been downloaded by ADP_Ctrl_Download_Agent. + * + * Arguments: + * Send: (word startaddress) + * Return: (word status) + * + * 'startaddress' is the address where the new Debug Agent code should be + * entered, and must satisfy: + * (loadaddress <= startaddress <= (loadaddress + size)) + * where 'loadaddress' and 'size' were specified in the + * ADP_Ctrl_Download_Agent message. + * + * 'status' is RDIError_NoError to indicate success, non-zero otherwise. + */ + + +#define ADP_Ctrl_SetTopMem ADPSUBREASON(CI_HADP,18) +/* ADP_Ctrl_SetTopMem + * ------------------ + * Summary: Sets the top of memory for ICEman2 systems, so that the C Library + * can allocate the stack in the correct place on startup. + * + * Arguments: + * Send: (word mem_top) + * Return: (word status) + * + * This request should only be supported by ICEman2. Standard Angel systems + * should return an error (unrecognised is fine). + */ + + +#define ADP_Read ADPREASON(CI_HADP,3) +#define ADP_ReadHeaderSize (ADP_DEFAULT_HEADER_SIZE + 2*sizeof(word)) + +/* ADP_Read + * -------- + * Summary: Request for a transer of memory contents from the target to the + * debugger. + * + * Arguments: + * Send: (word address, word nbytes) + * Return: (word status, word rnbytes [, bytes data]) + * + * 'address' is the address from which memory transer should start. + * 'nbytes' is the number of bytes to transfer. + * 'status' is RDIError_NoError to indicate success, non-zero otherwise. + * 'rnbytes' holds the number of requested bytes NOT read (i.e. zero + * indicates success, non-zero indicates an error). + * 'data' is the number of bytes requested minus 'rnbytes'. + */ + + + +#define ADP_Write ADPREASON(CI_HADP,4) +#define ADP_WriteHeaderSize (ADP_DEFAULT_HEADER_SIZE + 2*sizeof(word)) + +/* ADP_Write + * --------- + * Summary: Request for a transfer of memory contents from the debugger to + * the target. + * + * Arguments: + * Send: (word address, word nbytes, bytes data) + * Return: (word status [, word rnbytes]) + * + * 'address' is the address from which memory transer should start. + * 'nbytes' is the number of bytes to transfer. + * 'data' holds the bytes to be transferred. + * 'status' is RDIError_NoError to indicate success, non-zero otherwise. + * 'rnbytes' holds the number of requested bytes NOT written (i.e. zero + * indicates success, non-zero indicates an error) if status indicated an + * error. + */ + + + +#define ADP_CPUread ADPREASON(CI_HADP,5) +/* ADP_CPUread + * ----------- + * Summary: This is a request to read values in the CPU. + * + * Arguments: + * Send: (byte mode, word mask) + * Return: (word status, words data) + * + * 'mode' defines the processor mode from which the transfer should be made. + * It is described in more detail below. + * 'mask' indicates which registers should be transferred. Setting a bit to + * one will cause the designated register to be transferred. The details + * of mask are specified below. + * 'status' is RDIError_NoError to indicate success, non-zero otherwise. + * 'data' holds the values of the registers on successful completion, + * otherwise it just holds rubbish. The lowest numbered register is + * transferred first. NOTE: data must not cause the buffer size to exceed + * the maximum allowed buffer size. + */ + +/* 'mode':- */ +/* The mode number is the same as the mode number used by an ARM; a value of + 255 indicates the current mode. */ +#define ADP_CPUmode_Current (255) + +/* 26bit user mode. */ +#define ADP_CPUread_26bitUser (0x0) + +/* 26bit FIQ mode. */ +#define ADP_CPUread_26bitFIQ (0x1) + +/* 26bit IRQ mode. */ +#define ADP_CPUread_26bitIRQ (0x2) + +/* 26bit Supervisor mode. */ +#define ADP_CPUread_26bitSVC (0x3) + +/* 32bit user mode. */ +#define ADP_CPUread_32bitUser (0x10) + +/* 32bit FIQ mode. */ +#define ADP_CPUread_32bitFIQ (0x11) + +/* 32bit IRQ mode. */ +#define ADP_CPUread_32bitIRQ (0x12) + +/* 32bit Supervisor mode. */ +#define ADP_CPUread_32bitSVC (0x13) + +/* 32bit Abort mode. */ +#define ADP_CPUread_32bitAbort (0x17) + +/* 32bit Undefined mode. */ +#define ADP_CPUread_32bitUndef (0x1B) + +/* #32bit System mode - Added in Architecture 4 ARMs e.g.ARM7TDMI */ +#define ADP_CPUread_32bitSystem (0x1F) + +/* 'mask':- */ +/* Request registers RO-R14. */ +#define ADP_CPUread_RegsMask (0x7FFF) + +/* Request Program Counter (including mode and flag bits in 26-bit modes. */ +#define ADP_CPUread_PCmode (1 << 15) + +/* Request Program Counter (without mode and flag bits in 26-bit modes. */ +#define ADP_CPUread_PCnomode (1 << 16) + +/* Requests the transfer of the CPSR */ +#define ADP_CPUread_CPSR (1 << 17) + +/* In processor modes with an SPSR(non-user modes), bit 19 requests its + transfer */ +#define ADP_CPUread_SPSR (1 << 18) + + + +#define ADP_CPUwrite ADPREASON(CI_HADP,6) +/* ADP_CPUwrite + * ------------ + * Summary: This is a request to write values to the CPU. + * + * Arguments: + * Send: (byte mode, word mask, words data) + * Return: (word status) + * + * 'mode' defines the processor mode to which the transfer should be made. + * The mode number is the same as the mode number used by ARM; a value of + * 255 indicates the current mode. See ADP_CPUread above for more detail. + * 'mask' indicates which registers should be transferred. Setting a bit to + * one will cause the designated register to be transferred. The details + * of mask are specified above in ADP_CPUread. + * 'data' holds the values of the registers to be transferred. The first + * value is written to the lowest numbered register. NOTE: data must not + * cause the buffer size to exceed the maximum allowed buffer size. + * 'status' is RDIError_NoError to indicate success, non-zero otherwise. + */ + + + +#define ADP_CPread ADPREASON(CI_HADP,7) +/* ADP_CPread + * ---------- + * Summary: This message requests a co-processors internal state. + * + * Arguments: + * Send: (byte CPnum, word mask) + * Return: (word status, words data) + * + * 'CPnum' is the number of the co-processor to transfer values from. + * 'mask' specifies which registers to transfer and is co-processor + * specific. + * 'status' is RDIError_NoError to indicate success, non-zero otherwise. + * 'data' holds the registers specified in 'mask' if successful, otherwise + * just rubbish. The lowest numbered register is transferred first. + * NOTE: data must not cause the buffer size to exceed the maximum allowed + * buffer size. + */ + + + +#define ADP_CPwrite ADPREASON(CI_HADP,8) +/* ADP_CPwrite + * ----------- + * Summary: This message requests a write to a co-processors internal state. + * + * Arguments: + * Send: (byte CPnum, word mask, words data) + * Return: (word status) + * + * 'CPnum' is the number of the co-processor to transfer values to. + * 'mask' specifies which registers to transfer and is co-processor + * specific. + * 'data' holds the values to transfer to the registers specified in 'mask'. + * The first value is written to the lowest numbered register. + * NOTE: data must not cause the buffer size to exceed the maximum allowed + * buffer size. + * 'status' is RDIError_NoError to indicate success, non-zero otherwise. + */ + + + +#define ADP_SetBreak ADPREASON(CI_HADP,9) +/* ADP_SetBreak + * ------------ + * Summary: Sets a breakpoint. + * + * Arguments: + * Send: (word address, byte type [, word bound]) + * Return: (word status, word pointhandle, word raddress, word rbound) + * + * 'address' is the address of the instruction to set the breakpoint on. + * 'type' specifies the sort of breakpoint and is described in more detail + * below. + * 'bound' is included if the least significant 4 bits of type are set to + * 5 or above (see below for more detail). + * 'status' is RDIError_NoError to indicate success, non-zero otherwise. + * 'pointhandle' returns a handle to the breakpoint, it will be valid if bit + * 7 of 'type' is set. See below for more detail. + * 'raddress' is valid depending on 'type', see below for more detail. + * 'rbound' is valid depending on 'type', see below for more detail. + */ + +/* 'type':- */ +/* The least significant 4 bits define the sort of breakpoint to set:- */ +/* Halt if the pc is equal to 'address'. */ +#define ADP_SetBreak_EqualsAddress (0) + +/* Halt if the pc is greater than 'address'. */ +#define ADP_SetBreak_GreaterAddress (1) + +/* Halt if the pc is greater than or equal to 'address'. */ +#define ADP_SetBreak_GEqualsAddress (2) + +/* Halt if the pc is less than 'address'. */ +#define ADP_SetBreak_LessAddress (3) + +/* Halt if the pc is less than or equal to 'address'. */ +#define ADP_SetBreak_LEqualsAddress (4) + +/* Halt if the pc is in the range from 'address' to 'bound' inclusive. */ +#define ADP_SetBreak_Range (5) + +/* Halt if the pc is not in the range from 'address' to 'bound' inclusive. */ +#define ADP_SetBreak_NotRange (6) + +/* Halt if (pc & 'bound') = 'address'. */ +#define ADP_SetBreak_AndBound (7) + +/* Bits 5,6 and 7 are used as follows :- */ +/* If set this indicates that the breakpoint is on a 16bit (Thumb) + instruction rather than a 32bit (ARM) instruction. */ +#define ADP_SetBreak_Thumb (1 << 4) + +/* This requests that the breakpoint should be conditional (execution halts + only if the breakpointed instruction is executed, not if it is + conditionally skipped). If bit 5 is not set, execution halts whenever + the breakpointed instruction is reached (whether executed or skipped). */ +#define ADP_SetBreak_Cond (1 << 5) + +/* This requests a dry run: the breakpoint is not set and the 'raddress', and + if appropriate the 'rbound', that would be used, are returned (for + comparison and range breakpoints the address and bound used need not be + exactly as requested). A RDIError_NoError 'status' byte indicates that + resources are currently available to set the breakpoint, non-zero + indicates an error. RDIError_NoMorePoints indicates that the required + breakpoint resources are not currently available. */ +#define ADP_SetBreak_DryRun (1 << 6) + +/* If the request is successful, but there are no more breakpoint registers + (of the requested type), then the value RDIError_NoMorePoints is + returned. */ + +/* If a breakpoint is set on a location which already has a breakpoint, the + first breakpoint will be removed before the new breakpoint is set. */ + + + +#define ADP_ClearBreak ADPREASON(CI_HADP,10) +/* ADP_ClearBreak + * -------------- + * Summary: Clears a breakpoint. + * + * Arguments: + * Send: (word pointhandle) + * Return: (word status) + * + * 'pointhandle' is a handle returned by a previous ADP_SetBreak. + * 'status' is RDIError_NoError to indicate success, non-zero otherwise. + */ + + +#define ADP_SetWatch ADPREASON(CI_HADP,11) +/* ADP_SetWatch + * ------------ + * Summary: Sets a watchpoint. + * + * Arguments: + * Send: (word address, byte type, byte datatype [,word bound]) + * Return: (word status, word pointhandle, word raddress, word rbound) + * + * 'address' is the address at which to set the watchpoint. + * 'type' is the type of watchpoint to set and is described in detail below. + * 'datatype' defines the sort of data access to watch for and is described + * in more detail below. + * 'bound' is included depending on the value of type (see description of + * type below). + * 'status' is RDIError_NoError to indicate success, non-zero otherwise. + * 'pointhandle' is valid depending on the value of type (see description + * of type below). + * 'raddress' is valid depending on the value of type (see description + * of type below). + * 'rbound' is valid depending on the value of type (see description + * of type below). + */ + +/* 'type':- */ +/* The least significant 4 bits of 'type' define the sort of watchpoint to + set:- */ +/* Halt on a data access to the address equal to 'address'. */ +#define ADP_SetWatch_EqualsAddress (0) + +/* Halt on a data access to an address greater than 'address'. */ +#define ADP_SetWatch_GreaterAddress (1) + +/* Halt on a data access to an address greater than or equal to 'address'. */ +#define ADP_SetWatch_GEqualsAddress (2) + +/* Halt on a data access to an address less than 'address'. */ +#define ADP_SetWatch_LessAddress (3) + +/* Halt on a data access to an address less than or equal to 'address'. */ +#define ADP_SetWatch_LEqualsAddress (4) + +/* Halt on a data access to an address in the range from 'address' to + 'bound' inclusive. */ +#define ADP_SetWatch_Range (5) + +/* Halt on a data access to an address not in the range from 'address' to + 'bound' inclusive. */ +#define ADP_SetWatch_NotRange (6) + +/* Halt if (data-access-address & 'bound')='address'. */ +#define ADP_SetWatch_AndBound (7) + +/* Bits 6 and 7 of 'type' also have further significance:- + NOTE: they must not be simulataneously set. */ + +/* Bit 6 of 'type' set: Requests a dry run: the watchpoint is not set and + the 'address' and, if appropriate, the 'bound', that would be used are + returned (for range and comparison watchpoints, the 'address' and 'bound' + used need not be exactly as requested). A RDIError_NoError status byte + indicates that resources are currently available to set the watchpoint; + RDIError_NoMorePoints indicates that the required watchpoint resources + are not currently available. */ + +/* Bit 7 of 'type' set: Requests that a handle should be returned for the + watchpoint by which it will be identified subsequently. If bit 7 is + set, a handle will be returned ('pointhandle'), whether or not the + request succeeds or fails (but, obviously, it will only be meaningful + if the request succeesd). */ + +/* 'datatype':- */ +/* The 'datatype' argument defines the sort of data access to watch for, + values can be summed or ORed together to halt on any set of sorts of + memory access. */ + +/* Watch for byte reads. */ +#define ADP_SetWatch_ByteReads (1) + +/* Watch for half-word reads. */ +#define ADP_SetWatch_HalfWordReads (2) + +/* Watch for word reads. */ +#define ADP_SetWatch_WordReads (4) + +/* Watch for half-word reads. */ +#define ADP_SetWatch_ByteWrites (8) + +/* Watch for half-word reads. */ +#define ADP_SetWatch_HalfWordWrites (16) + +/* Watch for half-word reads. */ +#define ADP_SetWatch_WordWrites (32) + +/* On successful completion a RDIError_NoError 'status' byte is returned. On + unsuccessful completion, a non-zero error code byte is returned. If the + request is successful, but there are now no more watchpoint registers + (of the requested type), then the value RDIError_NoMorePoints is + returned. */ + +/* If a watchpoint is set on a location which already has a watchpoint, the + first watchpoint will be removed before the new watchpoint is set. */ + + +#define ADP_ClearWatch ADPREASON(CI_HADP,12) +/* ADP_ClearWatch + * -------------- + * Summary: Clears a watchpoint. + * + * Arguments: + * Send: (word pointhandle) + * Return: (word status) + * + * 'pointhandle' is a handle to a watchpoint returned by a previous + * ADP_SetWatch. + * 'status' is RDIError_NoError to indicate success, non-zero otherwise. + */ + + + +#define ADP_Execute ADPREASON(CI_HADP,13) +/* ADP_Execute + * ----------- + * Summary: This message requests that the target starts executing from + * the stored CPU state. + * + * Arguments: + * Send: () + * Return: (word status) + * + * 'status' is RDIError_NoError to indicate success, non-zero otherwise. + * The message will *ALWAYS* respond immediately with an ACK (unlike the + * old RDI definition, which allowed asynchronous message replies). + * + * Execution will stop when allowed system events occur. The host will + * be notified via a ADP_Stopped message (described below). + */ + + + +#define ADP_Step ADPREASON(CI_HADP,14) +/* ADP_Step + * -------- + * Summary: Execute 'ninstr' instructions. + * + * Arguments: + * Send: (word ninstr) + * Return: (word status) + * + * 'ninstr' is the number of instructions to execute, starting at the + * address currently loaded into the CPU program counter. If it is zero, + * the target should execute instructions upto the next instruction that + * explicitly alters the Program Counter. i.e. a branch or ALU operation + * with the PC as the destination. + * 'status' is RDIError_NoError to indicate success, non-zero otherwise. + * + * The ADP_Step function (unlike the earlier RDI system) will *ALWAYS* + * return an ACK immediately. A subsequent ADP_Stopped message will be + * delivered from the target to the host when the ADP_Step operation + * has completed. + */ + + + +#define ADP_InterruptRequest ADPREASON(CI_HADP,15) +/* ADP_InterruptRequest + * -------------------- + * Summary: Interrupt execution. + * + * Arguments: + * Send: () + * Return: (word status) + * + * 'status' is RDIError_NoError to indicate success, non-zero otherwise. + * On receiving this message the target should attempt to stop execution. + */ + + + +#define ADP_HW_Emulation ADPREASON(CI_HADP,16) +/* ADP_HW_Emulation + * ---------------- + * The first parameter to ADP_HW_Emulation is a Reason Subcode, and + * subsequent parameters are defined by that subcode + * + * word reason subcode + * other arguments as reason subcode determines + * + */ + +/* ADP__HW_Emulation sub-reason codes: */ + +#define ADP_HW_Emul_Supported ADPSUBREASON(CI_HADP,0) +/* ADP_HW_Emul_Supported + * --------------------- + * Summary: Enquires whether calls to the next 4 messages are available + * (MemoryAccess, MemoryMap, Set_CPUspeed, ReadClock). + * + * Arguments: + * Send: () + * Return: (word status) + * + * 'status' is RDIError_NoError to indicate the messages are available, + * non-zero otherwise. + * + * NOTE: Equivalent to RDI_Info_Memory_Stats. + */ + + +#define ADP_HW_Emul_MemoryAccess ADPSUBREASON(CI_HADP,1) +/* ADP_HW_Emul_MemoryAccess + * ------------------------ + * Summary: Get memory access information for memory block with specified + * handle. + * + * Arguments: + * Send: (word handle) + * Return: (word status, word nreads, word nwrites, word sreads, + * word swrites, word ns, word s) + * + * 'handle' is a handle to a memory block. + * 'status' is RDIError_NoError to indicate success, non-zero otherwise. + * 'nreads' is the number of non-sequential reads. + * 'nwrites' is the number of non-sequential writes. + * 'sreads' is the number of sequential reads. + * 'swrites' is the number of sequential writes. + * 'ns' is time in nano seconds. + * 's' is time in seconds. + * + * NOTE: Equivalent to RDIMemory_Access. + */ + + +#define ADP_HW_Emul_MemoryMap ADPSUBREASON(CI_HADP,2) +/* ADP_HW_Emul_MemoryMap + * --------------------- + * Summary: Sets memory characteristics. + * + * Arguments: + * Send: (word n, + Then 'n' sets of arguments of the form:- + word handle, word start, word limit, byte width, + byte access, word Nread_ns, word Nwrite_ns, word Sread_ns, + word Swrite_ns) + * Return: (word status) + * + * 'n' is the number of sets of arguments. + * 'handle' is a handle to the region. + * 'start' is the start of this region. + * 'limit' is the limit of this region. + * 'width' is the memory width, described in detail below. + * 'access' is described in detail below. + * 'Nread_ns' is the access time for N read cycles in nano seconds. + * 'Nwrite_ns' is the access time for N write cycles in nano seconds. + * 'Sread_ns' is the access time for S read cycles in nano seconds. + * 'Swrite_ns' is the access time for S write cycles in nano seconds. + * 'status' is RDIError_NoError to indicate success, non-zero otherwise. + * NOTE: Equivalent to RDIMemory_Map. + */ + +/* 'width':- */ +/* 8 bit memory width. */ +#define ADP_HW_Emul_MemoryMap_Width8 (0) + +/* 16 bit memory width. */ +#define ADP_HW_Emul_MemoryMap_Width16 (1) + +/* 32 bit memory width. */ +#define ADP_HW_Emul_MemoryMap_Width32 (2) + +/* 'access':- */ +/* Bit 0 - read access. */ +#define ADP_HW_Emul_MemoryMap_Access_Read (1 << 0) + +/* Bit 1 - write access. */ +#define ADP_HW_Emul_MemoryMap_Access_Write (1 << 1) + +/* Bit 2 - latched 32 bit memory. */ +#define ADP_HW_Emul_MemoryMap_Access_Latched (1 << 2) + + +#define ADP_HW_Emul_SetCPUSpeed ADPSUBREASON(CI_HADP,3) +/* ADP_HW_Emul_SetCPUSpeed + * ----------------------- + * Summary: Sets the speed of the CPU. + * + * Arguments: + * Send: (word speed) + * Return: (word status) + * + * 'speed' is the CPU speed in nano seconds. + * 'status' is RDIError_NoError to indicate success, non-zero otherwise. + * + * NOTE: Equivalent to RDISet_CPUSpeed. + */ + + +#define ADP_HW_Emul_ReadClock ADPSUBREASON(CI_HADP,4) +/* ADP_HW_Emul_ReadClock + * --------------------- + * Summary: Reads simulated time. + * + * Arguments: + * Send: () + * Return: (word status, word ns, word s) + * + * 'status' is RDIError_NoError to indicate success, non-zero otherwise. + * 'ns' is time in nano seconds. + * 's' is time in seconds. + * + * NOTE: Equivalent to RDIRead_Clock. + */ + + +#define ADP_ICEbreakerHADP ADPREASON(CI_HADP,17) + +/* The first parameter to ADP_ICEbreaker is a Reason Subcode, and + * subsequent parameters are defined by that subcode + * + * word reason subcode + * other arguments as reason subcode determines + * + */ + +/* ADP_ICEbreaker sub-reason codes: */ + +#define ADP_ICEB_Exists ADPSUBREASON(CI_HADP,0) +/* ADP_ICEB_Exists + * --------------- + * Summary: Is there an ICEbreaker in the system? + * + * Arguments: + * Send: () + * Return: (word status) + * + * 'status' is RDIError_NoError to indicate there is an ICEbreaker, + * non-zero otherwise. + */ + + +#define ADP_ICEB_GetLocks ADPSUBREASON(CI_HADP,1) +/* ADP_ICEB_GetLocks + * ----------------- + * Summary: Returns which ICEbreaker registers are locked. + * + * Arguments: + * Send: () + * Return: (word status, word lockedstate) + * + * 'status' is RDIError_NoError to indicate success, non-zero otherwise. + * 'lockedstate' is a bitmap if the ICEbreaker registers locked against use + * by IceMan (because explicitly written by the user). Bit n represents + * hardware breakpoint n, and if set the register is locked. + * + * NOTE: Equivalent to RDIIcebreaker_GetLocks. Should only be used if + * ADP_ICEB_Exists didn't return an error. + */ + + +#define ADP_ICEB_SetLocks ADPSUBREASON(CI_HADP,2) +/* ADP_ICEB_SetLocks + * ----------------- + * Summary: Sets which ICEbreaker registers are locked. + * + * Arguments: + * Send: (word lockedstate) + * Return: (word status) + * + * 'lockedstate' is the same as in ADP_ICEB_GetLocks above. + * 'status' is RDIError_NoError to indicate success, non-zero otherwise. + * + * NOTE: Equivalent to RDIIcebreaker_SetLocks. Should only be used if + * ADP_ICEB_Exists didn't return an error. + */ + + +#define ADP_ICEB_CC_Exists ADPSUBREASON(CI_HADP,3) +/* ADP_ICEB_CC_Exists + * ------------------ + * Summary: Is there an ICEbreaker Comms Channel? + * + * Arguments: + * Send: () + * Return: (word status) + * + * 'status' is RDIError_NoError to indicate there is a Comms Channel, + * non-zero otherwise. + * + * NOTE: Should only be used if ADP_ICEB_Exists didn't return an error. + */ + + +#define ADP_ICEB_CC_Connect_ToHost ADPSUBREASON(CI_HADP,4) +/* ADP_ICEB_CC_Connect_ToHost + * -------------------------- + * Summary: Connect Comms Channel in ToHost direction. + * + * Arguments: + * Send: (byte connect) + * Return: (word status) + * + * 'connect' !!!!! + * 'status' is RDIError_NoError to indicate success, non-zero otherwise. + * + * NOTE: Equivalent to RDICommsChannel_ToHost. Should only be used if + * ADP_ICEB_CC_Exists didn't return an error. + */ + + +#define ADP_ICEB_CC_Connect_FromHost ADPSUBREASON(CI_HADP,5) +/* ADP_ICEB_CC_Connect_FromHost + * ---------------------------- + * Summary: Connect Comms Channel in FromHost direction. + * + * Arguments: + * Send: (byte connect) + * Return: (word status) + * + * 'connect' is the same as in ADP_ICEB_CC_Connect_ToHost above. + * 'status' is RDIError_NoError to indicate success, non-zero otherwise. + * + * NOTE: Equivalent to RDICommsChannel_FromHost. Should only be used if + * ADP_ICEB_CC_Exists didn't return an error. + */ + + +#define ADP_ICEman ADPREASON(CI_HADP,18) + +/* The first parameter to ADP_ICEman is a Reason Subcode, and + * subsequent parameters are defined by that subcode + * + * word reason subcode + * other arguments as reason subcode determines + * + */ + +/* ADP_ICEman sub-reason codes: */ + + +#define ADP_ICEM_AddConfig ADPSUBREASON(CI_HADP,0) +/* ADP_ICEM_AddConfig + * ------------------ + * Summary: Prepares target to receive configuration data block. + * + * Arguments: + * Send: (word nbytes) + * Return: (word status) + * + * 'nbytes' is the number of bytes in the configuration block. + * 'status' is RDIError_NoError to indicate success, non-zero if a + * configuration block of this size can't be accepted. + * + * NOTE: Equivalent to RDP_AddConfig. + */ + + +#define ADP_ICEM_SelectConfig ADPSUBREASON(CI_HADP,1) +/* ADP_ICEM_SelectConfig + * --------------------- + * Summary: Selects one of the sets of configuration data blocks and + * reinitialises to use the new configuration. + * + * Arguments: + * Send: (byte aspect, byte namelen, byte matchtype, word vsn_req, + bytes name) + * Return: (word status, word vsn_sel) + * + * 'aspect' is one of two values defined below. + * 'namelen' is the number of bytes in 'name'. + * 'matchtype' specifies how the selected version must match that specified, + * and takes one of the values defined below. + * 'vsn_req' is the requested version of the named configuration. + * 'name' is the name of the configuration. + * 'status' is RDIError_NoError to indicate success, non-zero otherwise. + * 'vsn_sel' is the version number of the configuration selected on success. + * + * NOTE: Equivalent to RDP_SelectConfig. + */ + +/* 'aspect':- */ +#define ADP_ICEM_SelectConfig_ConfigCPU (0) +#define ADP_ICEM_SelectConfig_ConfigSystem (1) + +/* 'matchtype':- */ +#define ADP_ICEM_SelectConfig_MatchAny (0) +#define ADP_ICEM_SelectConfig_MatchExactly (1) +#define ADP_ICEM_SelectConfig_MatchNoEarlier (2) + + +#define ADP_ICEM_ConfigCount ADPSUBREASON(CI_HADP,2) +/* ADP_ICEM_ConfigCount + * -------------------- + * Summary: Return number of configurations. + * + * Arguments: + * Send: () + * Return: (word status [, word count]) + * + * 'status' is RDIError_NoError to indicate success, non-zero otherwise. + * 'count' returns the number of configurations if status is zero. + * + * NOTE: Equivalent to RDIConfig_Count. + */ + + +#define ADP_ICEM_ConfigNth ADPSUBREASON(CI_HADP,3) +/* ADP_ICEM_ConfigNth + * ------------------ + * Summary: Gets the nth configuration details. + * + * Arguments: + * Send: (word confign) + * Return: (word status, word version, byte namelen, bytes name) + * + * 'confign' is the number of the configuration. + * 'status' is RDIError_NoError to indicate success, non-zero otherwise. + * 'version' is the configuration version number. + * 'namelen' is the number of bytes in 'name'. + * 'name' is the name of the configuration. + * + * NOTE: Equivalent to RDIConfig_Nth. + */ + + + +#define ADP_Profile ADPREASON(CI_HADP,19) + +/* The first parameter to ADP_Profile is a Reason Subcode, and + * subsequent parameters are defined by that subcode + * + * word reason subcode + * other arguments as reason subcode determines + * + */ + +/* ADP_Profile sub-reason codes: */ + + +#define ADP_Profile_Supported ADPSUBREASON(CI_HADP,0) +/* ADP_Profile_Supported + * --------------------- + * Summary: Checks whether profiling is supported. + * + * Arguments: + * Send: () + * Return: (word status) + * + * 'status' is RDIError_NoError if profiling is supported, non-zero otherwise. + * + * NOTE: Can also be determined using Info_Target. + */ + + +#define ADP_Profile_Stop ADPSUBREASON(CI_HADP,1) +/* ADP_Profile_Stop + * ---------------- + * Summary: Stops profiling. + * + * Arguments: + * Send: () + * Return: (word status) + * + * 'status' is RDIError_NoError to indicate success, non-zero otherwise. + * + * NOTE: Equivalent to RDIProfile_Stop. + */ + + +#define ADP_Profile_Start ADPSUBREASON(CI_HADP,2) +/* ADP_Profile_Start + * ----------------- + * Summary: Starts profiling (PC sampling). + * + * Arguments: + * Send: (word interval) + * Return: (word status) + * + * 'interval' is the period of PC sampling in micro seconds. + * 'status' is RDIError_NoError to indicate success, non-zero otherwise. + * + * NOTE: Equivalent to RDIProfile_Start. + */ + + +#define ADP_Profile_WriteMap ADPSUBREASON(CI_HADP,3) +#define ADP_ProfileWriteHeaderSize (ADP_DEFAULT_HEADER_SIZE + 4*sizeof(word)) + +/* ADP_Profile_WriteMap + * -------------------- + * Summary: Downloads a map array, which describes the PC ranges for profiling. + * + * Arguments: A number of messages each of form:- + * Send: (word len, word size, word offset, words map_data) + * Return: (word status) + * + * 'len' is the number of elements in the entire map array being downloaded. + * 'size' is the number of words being downloaded in this message, i.e. the + * length of 'map_data'. + * 'offset' is the offset into the entire map array which this message starts + * from, in words. + * 'map_data' consists of 'size' words of map data. + * 'status' is RDIError_NoError to indicate success, non-zero otherwise. + * + * NOTE: Equivalent to RDIProfile_WriteMap. + */ + + +#define ADP_Profile_ReadMap ADPSUBREASON(CI_HADP,4) +#define ADP_ProfileReadHeaderSize (ADP_DEFAULT_HEADER_SIZE + 2*sizeof(word)) + +/* ADP_Profile_ReadMap + * ------------------- + * Summary: Uploads a set of profile counts which correspond to the current + * profile map. + * + * Arguments: A number of messages, each of the form: + * Send: (word offset, word size) + * Return: (word status, words counts) + * + * 'offset' is the offset in the entire array of counts that this message + * starts from, in words. + * 'size' is the number of words uploaded in this message (in counts). + * 'status' is RDIError_NoError to indicate success, non-zero otherwise. + * 'counts' is 'size' words of profile counts. + * + * NOTE: Equivalent to RDIProfile_ReadMap. + */ + + +#define ADP_Profile_ClearCounts ADPSUBREASON(CI_HADP,5) +/* ADP_Profile_ClearCounts + * ----------------------- + * Summary: Requests that PC sample counts be set to zero. + * + * Arguments: + * Send: () + * Return: (word status) + * + * 'status' is RDIError_NoError to indicate success, non-zero otherwise. + * + * NOTE: Equivalent to RDIProfile_ClearCounts. + */ + +#define ADP_InitialiseApplication ADPREASON(CI_HADP,20) +/* ADP_InitialiseApplication + * ------------------------- + * Summary: Requests that OS setup up the thread/task so that it can be + * executed. + * + * Arguments: + * Send: () + * Return: (word status) + * + * 'status' is RDIError_NoError to indicate success, non-zero otherwise. + */ + +#define ADP_End ADPREASON(CI_HADP,21) +/* ADP_End + * ------- + * Summary: Sent by the host debugger to tell angel this debugging session + * is is finished + * Arguments: + * Send: () + * Return: (word status) + * status' is RDIError_NoError to indicate success, non-zero otherwise. + */ + +/****************************************************************** + * + * CI_TADP messages + * + */ + +#define ADP_TADPUnrecognised ADPREASON(CI_TADP,0) +/* This message is unusual in that it is normally sent in reply to + * another message which is not understood. This is an exception + * to the normal protocol which says that a reply must have the + * same base reason code as the original. There is a single reply + * parameter which is the reason code which was not understood. + * + * As well as being a reply this message can also be sent and will + * return as if this message were unrecognised! + * + * Parameters: + * none + * + * Reply: + * word reason code which was not recognised + */ + +/*-------------------------------------------------------------------------*/ + +#define ADP_Stopped ADPREASON(CI_TADP,1) +/* ADP_Stopped + * ----------- + * Summary: This message is sent to the host when the application stops, + * either naturally or due to an exception. + * + * Parameters: + * word reason subcode + * other arguments as reason subcode determines. + * Unless stated otherwise (below) there will be none. + * + * Reply: + * word status unless reason subcode says otherwise + * + * This message is sent to the host when execution has stopped. This + * can be when the end of the application has been reached, or as the + * result of an exception. It can also be the return from an ADP_Step + * process, when the requested number of instructions have been + * executed., or a breakpoint or watchpoint has been hit etc. + */ + +/* The first set of Stopped subreason codes are for the ARM hardware + * vectors. These events will be raised if the + * ADP_Control_Vector_Catch allows, or if the target application has + * not provided its own handlers. + */ +#define ADP_Stopped_BranchThroughZero ADPSUBREASON(CI_TADP,0) +#define ADP_Stopped_UndefinedInstr ADPSUBREASON(CI_TADP,1) +#define ADP_Stopped_SoftwareInterrupt ADPSUBREASON(CI_TADP,2) +#define ADP_Stopped_PrefetchAbort ADPSUBREASON(CI_TADP,3) +#define ADP_Stopped_DataAbort ADPSUBREASON(CI_TADP,4) +#define ADP_Stopped_AddressException ADPSUBREASON(CI_TADP,5) +#define ADP_Stopped_IRQ ADPSUBREASON(CI_TADP,6) +#define ADP_Stopped_FIQ ADPSUBREASON(CI_TADP,7) + +/* We leave the rest of what would be the bits in the VectorCatch + * bitmask free for future expansion. + */ + +/* The following are software reasons for execution stopping: */ +#define ADP_Stopped_BreakPoint ADPSUBREASON(CI_TADP,32) +/* Breakpoint was reached + * extra send parameter: word handle - indicates which breakpoint + */ + +#define ADP_Stopped_WatchPoint ADPSUBREASON(CI_TADP,33) +/* Watchpoint was triggered + * extra send parameter: word handle - indicates which watchpoint + */ + +#define ADP_Stopped_StepComplete ADPSUBREASON(CI_TADP,34) +/* End of ADP_Step request */ + +#define ADP_Stopped_RunTimeErrorUnknown ADPSUBREASON(CI_TADP,35) +/* + * non-specific fatal runtime support error + */ + +#define ADP_Stopped_InternalError ADPSUBREASON(CI_TADP,36) +/* extra send parameter: word error - indicates the nature of the error + * + * An Angel internal error has happened. The error number should be + * displayed for the user to report to his software supplier. Once + * this error has been received the internal state of Angel can no longer + * be trusted. + */ + +#define ADP_Stopped_UserInterruption ADPSUBREASON(CI_TADP,37) +/* Host requested interruption */ + +#define ADP_Stopped_ApplicationExit ADPSUBREASON(CI_TADP,38) +/* extra send parameter: word exitcode + * This indicates that the application has exited via exit(), an exitcode + * of zero indiactes successful termination. + */ + +#define ADP_Stopped_StackOverflow ADPSUBREASON(CI_TADP, 39) +/* + * Software stack overflow has occurred + */ + +#define ADP_Stopped_DivisionByZero ADPSUBREASON(CI_TADP, 40) +/* + * Division by zero has occurred + */ + +#define ADP_Stopped_OSSpecific ADPSUBREASON(CI_TADP, 41) +/* + * The OS has requested that execution stops. The OS will know + * why this has happened. + */ + + + +/****************************************************************** + * + * CI_TTDCC messages (Target-initiated debug comms channel) + * + */ + +#define ADP_TDCC_ToHost ADPREASON(CI_TTDCC,0) +/* ADP_TDCC_ToHost + * ------------------ + * Summary: Send Data down Comms Channel in ToHost direction. + * + * Arguments: + * Send: (word nbytes, words data) + * Return: (word status) + * + * 'nbytes' is number of BYTES to be transferred from the target to the + * host via the Debug Comms channel. + * 'data' is (nbytes/sizeof(word)) WORDS of data to be transferred from + * the target to the host via the Debug Comms channel. + * 'status' is RDIError_NoError to indicate success, non-zero otherwise. + * + * NOTE: Equivalent to RDP_CCToHost and RDP_CCToHostReply (just set the + * direction bit). + * NOTE II: Current implementations only support single word transfers + * (nbytes = 4). + */ + + +#define ADP_TDCC_FromHost ADPREASON(CI_TTDCC,1) +/* ADP_TDCC_FromHost + * -------------------- + * Summary: Send Data down Comms Channel in FromHost direction. + * + * Arguments: + * Send: () + * Return: (word status, word nbytes, words data) + * + * 'status' is RDIError_NoError to indicate success, non-zero otherwise. + * 'nbytes' is number of BYTES to be transferred from the host to the + * target via the Debug Comms channel, or zero if the host has no data + * to transfer. + * 'data' is (nbytes/sizeof(word)) WORDS of transferred data. + * + * NOTE: Equivalent to RDP_CCFromHost and RDP_CCFromHostReply (just set the + * direction bit). + * NOTE II: Current implementations only support single word transfers + * (nbytes = 4). + */ + + +/******************************************************************* + * + * Error Codes + * + */ + +#define RDIError_NoError 0 + +#define RDIError_Reset 1 +#define RDIError_UndefinedInstruction 2 +#define RDIError_SoftwareInterrupt 3 +#define RDIError_PrefetchAbort 4 +#define RDIError_DataAbort 5 +#define RDIError_AddressException 6 +#define RDIError_IRQ 7 +#define RDIError_FIQ 8 +#define RDIError_Error 9 +#define RDIError_BranchThrough0 10 + +#define RDIError_NotInitialised 128 +#define RDIError_UnableToInitialise 129 +#define RDIError_WrongByteSex 130 +#define RDIError_UnableToTerminate 131 +#define RDIError_BadInstruction 132 +#define RDIError_IllegalInstruction 133 +#define RDIError_BadCPUStateSetting 134 +#define RDIError_UnknownCoPro 135 +#define RDIError_UnknownCoProState 136 +#define RDIError_BadCoProState 137 +#define RDIError_BadPointType 138 +#define RDIError_UnimplementedType 139 +#define RDIError_BadPointSize 140 +#define RDIError_UnimplementedSize 141 +#define RDIError_NoMorePoints 142 +#define RDIError_BreakpointReached 143 +#define RDIError_WatchpointAccessed 144 +#define RDIError_NoSuchPoint 145 +#define RDIError_ProgramFinishedInStep 146 +#define RDIError_UserInterrupt 147 +#define RDIError_CantSetPoint 148 +#define RDIError_IncompatibleRDILevels 149 + +#define RDIError_CantLoadConfig 150 +#define RDIError_BadConfigData 151 +#define RDIError_NoSuchConfig 152 +#define RDIError_BufferFull 153 +#define RDIError_OutOfStore 154 +#define RDIError_NotInDownload 155 +#define RDIError_PointInUse 156 +#define RDIError_BadImageFormat 157 +#define RDIError_TargetRunning 158 +#define RDIError_DeviceWouldNotOpen 159 +#define RDIError_NoSuchHandle 160 +#define RDIError_ConflictingPoint 161 + +#define RDIError_LittleEndian 240 +#define RDIError_BigEndian 241 +#define RDIError_SoftInitialiseError 242 + +#define RDIError_InsufficientPrivilege 253 +#define RDIError_UnimplementedMessage 254 +#define RDIError_UndefinedMessage 255 + + +#endif + +/* EOF adp_h */ diff --git a/gdb/rdi-share/adperr.h b/gdb/rdi-share/adperr.h new file mode 100644 index 00000000000..f90f1dcc3fd --- /dev/null +++ b/gdb/rdi-share/adperr.h @@ -0,0 +1,74 @@ +/* + * Copyright (C) 1995 Advanced RISC Machines Limited. All rights reserved. + * + * This software may be freely used, copied, modified, and distributed + * provided that the above copyright notice is preserved in all copies of the + * software. + */ + +/* -*-C-*- + * + * $Revision$ + * $Date$ + * + * + * Project: ANGEL + * + * Title: Definitions of ADP error codes + */ + +#ifndef angsd_adperrs_h +#define angsd_adperrs_h +/* + * ADP failure codes start at 256 to distinguish them for debug purposes + */ +enum AdpErrs +{ + adp_ok = 0, + adp_failed = 256, + adp_malloc_failure, + adp_illegal_args, + adp_device_not_found, + adp_device_open_failed, + adp_device_already_open, + adp_device_not_open, + adp_bad_channel_id, + adp_callback_already_registered, + adp_write_busy, + adp_bad_packet, + adp_seq_high, + adp_seq_low, + adp_timeout_on_open, + adp_abandon_boot_wait, + adp_late_startup, + adp_new_agent_starting +}; + +#ifndef __cplusplus +typedef enum AdpErrs AdpErrs; +#endif + +#define AdpMess_Failed "ADP Error - unspecific failure" +#define AdpMess_MallocFailed "ADP Error - malloc failed" +#define AdpMess_IllegalArgs "ADP Error - illegal arguments" +#define AdpMess_DeviceNotFound "ADP Error - invalid device specified" +#define AdpMess_DeviceOpenFailed "ADP Error - specified device failed to open" +#define AdpMess_DeviceAlreadyOpen "ADP Error - device already open" +#define AdpMess_DeviceNotOpen "ADP Error - device not open" +#define AdpMess_BadChannelId "ADP Error - bad channel Id" +#define AdpMess_CBAlreadyRegd "ADP Error - callback already registered" +#define AdpMess_WriteBusy "ADP Error - write busy" +#define AdpMess_BadPacket "ADP Error - bad packet" +#define AdpMess_SeqHigh "ADP Error - sequence number too high" +#define AdpMess_SeqLow "ADP Error - sequence number too low" +#define AdpMess_TimeoutOnOpen "ADP Error - target did not respond" +#define AdpMess_AbandonBootWait "abandoned wait for late startup" +#define AdpMess_LateStartup "Target compiled with LATE_STARTUP set.\n" \ + "Waiting for target...\n" \ + "Press to abort.\n" +#define AdpMessLen_LateStartup (3*80) +#define AdpMess_NewAgentStarting "New Debug Agent about to start.\n" + +#endif /* ndef angsd_adperr_h */ + +/* EOF adperr.h */ diff --git a/gdb/rdi-share/angel.h b/gdb/rdi-share/angel.h new file mode 100644 index 00000000000..60a5f31720f --- /dev/null +++ b/gdb/rdi-share/angel.h @@ -0,0 +1,177 @@ +/* + * Copyright (C) 1995 Advanced RISC Machines Limited. All rights reserved. + * + * This software may be freely used, copied, modified, and distributed + * provided that the above copyright notice is preserved in all copies of the + * software. + */ + +/*> angel.h <*/ +/*---------------------------------------------------------------------------*/ +/* This header file is the main holder for the declarations and + * prototypes for the core Angel system. Some Angel concepts are + * described at the start of this file to ensure that a complete view + * of the Angel world can be derived purely from the source. + * + * $Revision$ + * $Date$ + * + * + * NOTE: Currently the Angel source is designed to be simple, + * understandable and easy to port to new hardware platforms. However, + * this does not always yield the highest performing system. The + * current layered approach introduces an overhead to the performance + * of the system. In a true commercial target, this code should be + * re-designed to build a system where the Angel logical message + * system, device driver and hardware accesses are merged to provide + * the best performance. + */ +/*---------------------------------------------------------------------------*/ +/* Angel overview: + +... some comments describing Angel ... + + * Angel is designed as a kit-of-parts that can be used to provide + * run-time support for the development of ARM applications. The main + * core of Angel is in providing support for the "debug" message + * communication with a host system. These messages do not just cover + * debugging ARM processes, but also the process of downloading ARM + * programs or attaching to executing processes on the target. + * + * A stand-alone ROM based Angel world is the basic starting point for + * a system, since it will allow programs to be downloaded to the + * target. The ROM version of Angel will provide the generic debug + * support, but no system specific routines. The preferred method of + * using Angel is as a link library. This ensures that applications + * carry with them the Angel routines necessary to support debugging + * (and also ensure that the Angel version is up-to-date, independant + * of the version in the target ROM). Eventually, once a program has + * been fully debugged, a ROMmed version of the program can be + * generated with the Angel code being provided in the application. + +.. more comments .. + + * The standard Angel routines do *NOT* perform any dynamic memory + * allocation. To simplify the source, and aid the porting to a non C + * library world, memory is either pre-allocated (as build-time + * globals) or actually given to the particular Angel routine by the + * active run-time. This ensures that the interaction between Angel + * and the target O/S is minimised. + * + * Notes: We sub-include more header files to keep the source + * modular. Since Angel is a kit-of-parts alternative systems may need + * to change the prototypes of particular functions, whilst + * maintaining a fixed external interface. e.g. using the standard + * DEBUG messages, but with a different communications world. + */ +/*---------------------------------------------------------------------------*/ + +#ifndef __angel_h +#define __angel_h + +/*---------------------------------------------------------------------------*/ +/*-- Global Angel definitions and manifests ---------------------------------*/ +/*---------------------------------------------------------------------------*/ +/* When building Angel we may not include the standard library + * headers. However, it is useful coding using standard macro names + * since it makes the code easier to understand. + */ + +typedef unsigned int word ; +typedef unsigned char byte ; + +/* The following typedefs can be used to access I/O registers: */ +typedef volatile unsigned int vuword ; +typedef volatile unsigned char vubyte ; + +/* + * The following typedefs are used when defining objects that may also + * be created on a host system, where the word size is not + * 32bits. This ensures that the same data values are manipulated. + */ +#ifdef TARGET +typedef unsigned int unsigned32; +typedef signed int signed32; +typedef int int32; + +typedef unsigned short int unsigned16; +typedef signed short int signed16; + +/* + * yet another solution for the bool/boolean problem, this one is + * copied from Scott's modifications to clx/host.h + */ +# ifdef IMPLEMENT_BOOL_AS_ENUM + enum _bool { _false, _true }; +# define _bool enum _bool +# elif defined(IMPLEMENT_BOOL_AS_INT) || !defined(__cplusplus) +# define _bool int +# define _false 0 +# define _true 1 +# endif + +# ifdef _bool +# define bool _bool +# endif + +# ifndef true +# define true _true +# define false _false +# endif + +# ifndef YES +# define YES true +# define NO false +# endif + +# undef TRUE /* some OSF headers define as 1 */ +# define TRUE true + +# undef FALSE /* some OSF headers define as 1 */ +# define FALSE false + +# ifndef NULL +# define NULL 0 +# endif + +#else + +# include "host.h" + +#endif + +#ifndef IGNORE +# define IGNORE(x) ((x)=(x)) +#endif + +/* The following typedef allows us to cast between integral and + * function pointers. This isn't allowed by direct casting when + * conforming to the ANSI spec. + */ +typedef union ansibodge +{ + word w ; + word *wp ; + void *vp ; + byte *bp ; + void (*vfn)(void) ; + word (*wfn)(void) ; + int (*ifn)(void) ; + byte (*bfn)(void) ; +} ansibodge ; + +/*---------------------------------------------------------------------------*/ + +/* The amount setup aside by the run-time system for stack overflow + * handlers to execute in. This must be at least 256bytes, since that + * value is assumed by the current ARM Ltd compiler. + * This space is _only_ kept for the USR stack, not any of the privileged + * mode stacks, as stack overflow on these is always fatal - there is + * no point attemptingto recover. In addition is is important that + * Angel should keep privileged stack space requirements to a minimum. + */ +#define APCS_STACKGUARD 256 + +#endif /* __angel_h */ + +/* EOF angel.h */ diff --git a/gdb/rdi-share/ardi.c b/gdb/rdi-share/ardi.c new file mode 100644 index 00000000000..f61f7242f73 --- /dev/null +++ b/gdb/rdi-share/ardi.c @@ -0,0 +1,2672 @@ +/* + * Copyright (C) 1995 Advanced RISC Machines Limited. All rights reserved. + * + * This software may be freely used, copied, modified, and distributed + * provided that the above copyright notice is preserved in all copies of the + * software. + */ + +/* + * ARDI.c + * Angel Remote Debug Interface + * + * + * $Revision$ + * $Date$ + * + * This file is based on /plg/pisd/rdi.c, but instead of using RDP it uses + * ADP messages. + */ + +#include +#include +#include +#include +#define uint HIDE_HPs_uint +#include +#undef uint + + +#include "endian.h" +#include "ardi.h" +#include "buffers.h" +#include "channels.h" +#include "hostchan.h" +#include "host.h" +#include "bytesex.h" +#include "dbg_cp.h" +#include "adp.h" +#include "hsys.h" +#include "logging.h" +#include "msgbuild.h" +#include "rxtx.h" +#include "devsw.h" +#include "params.h" + +#ifdef COMPILING_ON_WINDOWS +# define IGNORE(x) (x = x) /* must go after #includes to work on Windows */ +#endif +#define NOT(x) (!(x)) + +#define ADP_INITIAL_TIMEOUT_PERIOD 5 + +static volatile int executing; +static int rdi_log = 0 ; /* debugging ? */ + +/* we need a starting point for our first buffers, this is a safe one */ +int Armsd_BufferSize = ADP_BUFFER_MIN_SIZE; +int Armsd_LongBufSize = ADP_BUFFER_MIN_SIZE; + +#ifdef WIN32 + extern int interrupted; + extern int swiprocessing; +#endif + +static char dummycline = 0; +char *ardi_commandline = &dummycline ; /* exported in ardi.h */ + +extern unsigned int heartbeat_enabled; + +static unsigned char *cpwords[16]; + +typedef struct stoppedProcListElement { + struct stoppedProcListElement *next; + angel_RDI_TargetStoppedProc *fn; + void *arg; +} stoppedProcListElement; + +static stoppedProcListElement *stopped_proc_list=NULL; + +const struct Dbg_HostosInterface *angel_hostif; +static hsys_state *hstate; + +static void angel_DebugPrint(const char *format, ...) +{ va_list ap; + va_start(ap, format); + angel_hostif->dbgprint(angel_hostif->dbgarg, format, ap); + va_end(ap); +} + +#ifdef RDI_VERBOSE +#define TracePrint(s) \ + if (rdi_log & 2) angel_DebugPrint("\n"); \ + if (rdi_log & 1) angel_DebugPrint s +#else +#define TracePrint(s) +#endif + +typedef struct receive_dbgmsg_state { + volatile int received; + Packet *packet; +} receive_dbgmsg_state; + +static receive_dbgmsg_state dbgmsg_state; + +static void receive_debug_packet(Packet *packet, void *stateptr) +{ + receive_dbgmsg_state *state = stateptr; + + state->packet = packet; + state->received = 1; +} + +static int register_debug_message_handler(void) +{ + int err; + dbgmsg_state.received = 0; + + err = Adp_ChannelRegisterRead(CI_HADP, receive_debug_packet, &dbgmsg_state); +#ifdef DEBUG + if (err!=adp_ok) angel_DebugPrint("register_debug_message_handler failed %i\n", err); +#endif + return err; +} + + +static int wait_for_debug_message(int *rcode, int *debugID, + int *OSinfo1, int *OSinfo2, + int *status, Packet **packet) +{ + unsigned int reason; + +#ifdef DEBUG + angel_DebugPrint("wait_for_debug_message waiting for %X\n", *rcode); +#endif + + for ( ; dbgmsg_state.received == 0 ; ) + Adp_AsynchronousProcessing(async_block_on_read); + +#ifdef DEBUG + angel_DebugPrint("wait_for_debug_message got packet\n"); +#endif + + *packet = dbgmsg_state.packet; + + Adp_ChannelRegisterRead(CI_HADP, NULL, NULL); + + /* + * TODO: + * If ADP_Unrecognised return error. + * If ADP_Acknowledge - handle appropriately. + * If expected message read arguments and return RDIError_NoError. + * Note: if RDIError occurs then the data values returned are junk + */ + + unpack_message(BUFFERDATA((*packet)->pk_buffer), "%w%w%w%w%w", &reason, debugID, + OSinfo1, OSinfo2, status); + if (reason&0xffffff == ADP_HADPUnrecognised) + return RDIError_UnimplementedMessage; + if (reason != (unsigned ) *rcode) { + if((reason&0xffffff) == ADP_HADPUnrecognised) + return RDIError_UnimplementedMessage; + else { + angel_DebugPrint("ARDI ERROR: Expected reasoncode %x got reasoncode %x.\n", + *rcode, reason); + return RDIError_Error; + } + } + else + return RDIError_NoError; + return RDIError_Error; /* stop a pesky ANSI compiler warning */ +} + + +/* + * Handler and registration for logging messages from target + */ +static void TargetLogCallback( Packet *packet, void *state ) +{ + p_Buffer reply = BUFFERDATA(packet->pk_buffer); + unsigned int len = packet->pk_length; + IGNORE(state); + angel_hostif->write(angel_hostif->hostosarg, + (char *)reply, len - CHAN_HEADER_SIZE); + DevSW_FreePacket(packet); + + packet = DevSW_AllocatePacket(4); /* better not ask for 0 */ + /* the reply is the ACK - any contents are ignored */ + if (packet != NULL) + Adp_ChannelWrite( CI_TLOG, packet ); +} + +static void TargetLogInit( void ) +{ + AdpErrs err = Adp_ChannelRegisterRead( CI_TLOG, TargetLogCallback, NULL ); + +#ifdef DEBUG + if (err != adp_ok) + angel_DebugPrint("CI_TLOG RegisterRead failed %d\n", err); +#else + IGNORE(err); +#endif +} + +/*----------------------------------------------------------------------*/ +/*----angel_RDI_open-----------------------------------------------------*/ +/*----------------------------------------------------------------------*/ + +typedef struct NegotiateState { + bool negotiate_resp; + bool negotiate_ack; + bool link_check_resp; + ParameterConfig *accepted_config; +} NegotiateState; + +static void receive_negotiate(Packet *packet, void *stateptr) +{ + unsigned reason, debugID, OSinfo1, OSinfo2, status; + NegotiateState *n_state = (NegotiateState *)stateptr; + p_Buffer reply = BUFFERDATA(packet->pk_buffer); + + unpack_message( reply, "%w%w%w%w", + &reason, &debugID, &OSinfo1, &OSinfo2 ); + reply += ADP_DEFAULT_HEADER_SIZE; + +#ifdef DEBUG + angel_DebugPrint( "receive_negotiate: reason %x\n", reason ); +#endif + + switch ( reason ) + { + case ADP_ParamNegotiate | TtoH: + { + n_state->negotiate_resp = TRUE; + + status = GET32LE( reply ); + reply += sizeof(word); +#ifdef DEBUG + angel_DebugPrint( "ParamNegotiate status %u\n", status ); +#endif + if ( status == RDIError_NoError ) + { + if ( Angel_ReadParamConfigMessage( + reply, n_state->accepted_config ) ) + n_state->negotiate_ack = TRUE; + } + break; + } + + case ADP_LinkCheck | TtoH: + { +#ifdef DEBUG + angel_DebugPrint( "PONG!\n" ); +#endif + n_state->link_check_resp = TRUE; + break; + } + + default: + { +#ifdef DEBUG + angel_DebugPrint( "Unexpected!\n" ); +#endif + break; + } + } + DevSW_FreePacket( packet ); +} + +# include +#ifdef __unix +# include +#else +# include +#endif + +/* + * convert a config into a single-valued options list + */ +static ParameterOptions *config_to_options( const ParameterConfig *config ) +{ + unsigned int num_params; + size_t size; + ParameterOptions *base_p; + + num_params = config->num_parameters; + size = + sizeof(ParameterOptions) + + num_params*(sizeof(ParameterList) + sizeof(unsigned int)); + base_p = malloc( size ); + + if ( base_p != NULL ) + { + unsigned int u; + ParameterList *list_p = + (ParameterList *)((char *)base_p + sizeof(ParameterOptions)); + unsigned int *option_p = + (unsigned int *)(list_p + num_params); + + base_p->num_param_lists = num_params; + base_p->param_list = list_p; + + for ( u = 0; u < num_params; ++u ) + { + option_p[u] = config->param[u].value; + list_p[u].type = config->param[u].type; + list_p[u].num_options = 1; + list_p[u].option = &option_p[u]; + } + } + + return base_p; +} + +static AdpErrs negotiate_params( const ParameterOptions *user_options ) +{ + Packet *packet; + unsigned int count; + static Parameter params[AP_NUM_PARAMS]; + static ParameterConfig accepted_config = { AP_NUM_PARAMS, params }; + + time_t t; + + static volatile NegotiateState n_state = { + FALSE, FALSE, FALSE, &accepted_config }; + +#ifdef DEBUG + angel_DebugPrint( "negotiate_params\n" ); +#endif + + Adp_ChannelRegisterRead( CI_HBOOT, receive_negotiate, (void *)&n_state ); + + packet = (Packet *)DevSW_AllocatePacket(Armsd_BufferSize); + count = msgbuild( BUFFERDATA(packet->pk_buffer), "%w%w%w%w", + ADP_ParamNegotiate | HtoT, 0, + ADP_HandleUnknown, ADP_HandleUnknown ); + count += Angel_BuildParamOptionsMessage( + BUFFERDATA(packet->pk_buffer) + count, user_options ); + packet->pk_length = count; + Adp_ChannelWriteAsync( CI_HBOOT, packet ); + +#ifdef DEBUG + angel_DebugPrint( "sent negotiate packet\n" ); +#endif + + t=time(NULL); + + do { + Adp_AsynchronousProcessing(async_block_on_nothing); + + if ((time(NULL)-t) > ADP_INITIAL_TIMEOUT_PERIOD) { + return adp_timeout_on_open; + } + } while ( ! n_state.negotiate_resp ); + + if ( n_state.negotiate_ack ) + { + /* select accepted config */ + Adp_Ioctl( DC_SET_PARAMS, (void *)n_state.accepted_config ); + + /* + * 960430 KWelton + * + * There is a race in the renegotiation protocol: the + * target has to have had time to load new config before + * we send the link check packet - insert a deliberate + * pause (100ms) to give the target some time + */ + Adp_delay(100000); + + /* do link check */ + msgsend( CI_HBOOT, "%w%w%w%w", ADP_LinkCheck | HtoT, 0, + ADP_HandleUnknown, ADP_HandleUnknown ); +#ifdef DEBUG + angel_DebugPrint("sent link check\n"); +#endif + + do { + Adp_AsynchronousProcessing(async_block_on_read); + } while ( ! n_state.link_check_resp ); + Adp_initSeq(); + } + return adp_ok; +} + +static int late_booted = FALSE; +static bool ardi_handler_installed = FALSE; + +#ifdef __unix +static struct sigaction old_action; +#else +static void (*old_handler)(); +#endif + +static bool boot_interrupted = FALSE; + +static void ardi_sigint_handler(int sig) { +#ifdef DEBUG + if (sig != SIGINT) + angel_DebugPrint("Expecting SIGINT got %d.\n", sig); +#else + IGNORE(sig); +#endif + boot_interrupted = TRUE; +#ifndef __unix + signal(SIGINT, ardi_sigint_handler); +#endif +} + +static void install_ardi_handler( void ) { + if (!ardi_handler_installed) { + /* install a new Ctrl-C handler so we can abandon waiting */ +#ifdef __unix + struct sigaction new_action; + sigemptyset(&new_action.sa_mask); + new_action.sa_handler = ardi_sigint_handler; + new_action.sa_flags = 0; + sigaction(SIGINT, &new_action, &old_action); +#else + old_handler = signal(SIGINT, ardi_sigint_handler); +#endif + ardi_handler_installed = TRUE; + } +} + +static int angel_RDI_errmess(char *buf, int blen, int errnum); + +static void receive_reset_acknowledge(Packet *packet, void *stateptr) { + unsigned reason, debugID, OSinfo1, OSinfo2, status; + IGNORE(stateptr); + + unpack_message(BUFFERDATA(packet->pk_buffer), "%w%w%w%w%w", &reason, &debugID, + &OSinfo1, &OSinfo2, &status); + if (reason==(ADP_Reset | TtoH) && status==AB_NORMAL_ACK) { +#ifdef DEBUG + angel_DebugPrint("DEBUG: Successfully received normal reset acknowledgement\n"); + late_booted = FALSE; +#endif + } else if (reason==(ADP_Reset | TtoH) && status==AB_LATE_ACK) { + char late_msg[AdpMessLen_LateStartup]; + int late_len; +#ifdef DEBUG + angel_DebugPrint("DEBUG: Successfully received LATE reset acknowledgement\n"); +#endif + late_booted = TRUE; + install_ardi_handler(); + late_len = angel_RDI_errmess(late_msg, + AdpMessLen_LateStartup, adp_late_startup); + angel_hostif->write(angel_hostif->hostosarg, late_msg, late_len); + } else { +#ifdef DEBUG + angel_DebugPrint("DEBUG: Bad reset ack: reason=%8X, status=%8X\n", reason, status); +#endif + } + DevSW_FreePacket(packet); +} + +static int booted_not_received; +static unsigned int angel_version; +static unsigned int adp_version; +static unsigned int arch_info; +static unsigned int cpu_info; +static unsigned int hw_status; + +static void receive_booted(Packet *packet, void *stateptr) { + unsigned reason, debugID, OSinfo1, OSinfo2, banner_length, bufsiz, longsiz; + unsigned i, count; + + IGNORE(stateptr); + + count = unpack_message(BUFFERDATA(packet->pk_buffer), + "%w%w%w%w%w%w%w%w%w%w%w%w", + &reason, &debugID, &OSinfo1, &OSinfo2, &bufsiz, &longsiz, + &angel_version, &adp_version, + &arch_info, &cpu_info, &hw_status, &banner_length); + if (reason==(ADP_Booted | TtoH)) { +#ifdef MONITOR_DOWNLOAD_PACKETS + angel_DebugPrint("DEBUG: Successfully received Booted\n"); + angel_DebugPrint(" cpu_info=%8X, hw_status=%8X, bufsiz=%d, longsiz=%d\n", + cpu_info, hw_status, bufsiz, longsiz); +#endif + /* Get the banner from the booted message */ + for (i=0; iwritec(angel_hostif->hostosarg, + (BUFFERDATA(packet->pk_buffer)+count)[i]); + + booted_not_received=0; +#ifndef NO_HEARTBEAT + heartbeat_enabled = TRUE; +#endif + Armsd_BufferSize = bufsiz + CHAN_HEADER_SIZE; + Armsd_LongBufSize = longsiz + CHAN_HEADER_SIZE; + } else { +#ifdef DEBUG + angel_DebugPrint("DEBUG: Bad Booted msg: reason=%8X\n", reason); +#endif + } + DevSW_FreePacket(packet); +} + + +/* forward declaration */ +static int angel_negotiate_defaults( void ); + +/* Open communications. */ +int angel_RDI_open( + unsigned type, Dbg_ConfigBlock const *config, + Dbg_HostosInterface const *hostif, struct Dbg_MCState *dbg_state) +{ + Packet *packet; + int status, reasoncode, debugID, OSinfo1, OSinfo2, err; + ParameterOptions *user_options = NULL; + + time_t t; + + IGNORE( dbg_state ); + + if ((type & 1) == 0) { + /* cold start */ + if (hostif != NULL) { + angel_hostif = hostif; + err = HostSysInit(hostif, &ardi_commandline, &hstate); + if (err != RDIError_NoError) { +#ifdef DEBUG + angel_DebugPrint("DEBUG: HostSysInit error %i\n",err); +#endif + return err; + } + } + TargetLogInit(); + } + +#ifdef DEBUG + angel_DebugPrint("DEBUG: Buffer allocated in angel_RDI_open(type=%i).\n",type); +#endif + + if ((type & 1) == 0) { + /* cold start */ + unsigned endian; + Adp_Ioctl( DC_GET_USER_PARAMS, (void *)&user_options ); + if ( user_options != NULL ) { + err = negotiate_params( user_options ); + if (err != adp_ok) return err; + } + else { + ParameterConfig *default_config = NULL; + Adp_Ioctl( DC_GET_DEFAULT_PARAMS, (void *)&default_config ); + if ( default_config != NULL ) { + ParameterOptions *default_options = config_to_options(default_config); + err = negotiate_params( default_options ); + if (err != adp_ok) return err; + } + } + + /* Register handlers before sending any messages */ + booted_not_received=1; + Adp_ChannelRegisterRead(CI_HBOOT, receive_reset_acknowledge, NULL); + Adp_ChannelRegisterRead(CI_TBOOT, receive_booted, NULL); + endian = 0; + if (config!=NULL) { + if (config->bytesex & RDISex_Little) endian |= ADP_BootHostFeature_LittleEnd; + if (config->bytesex & RDISex_Big) endian |= ADP_BootHostFeature_BigEnd; + } + msgsend(CI_HBOOT,"%w%w%w%w%w", ADP_Reset | HtoT, 0, + ADP_HandleUnknown, ADP_HandleUnknown, endian); +#ifdef DEBUG + angel_DebugPrint("DEBUG: Transmitted Reset message in angel_RDI_open.\n"); +#endif + + /* We will now either get an acknowledgement for the Reset message + * or if the target was started after the host, we will get a + * rebooted message first. + */ + +#ifdef DEBUG + angel_DebugPrint("DEBUG: waiting for a booted message\n"); +#endif + + { + boot_interrupted = FALSE; + + if (late_booted) + install_ardi_handler(); + + t=time(NULL); + + do { + Adp_AsynchronousProcessing(async_block_on_nothing); + if ((time(NULL)-t) > ADP_INITIAL_TIMEOUT_PERIOD && !late_booted) { + return adp_timeout_on_open; + } + } while (booted_not_received && !boot_interrupted); + + if (ardi_handler_installed) + { + /* uninstall our Ctrl-C handler */ +#ifdef __unix + sigaction(SIGINT, &old_action, NULL); +#else + signal(SIGINT, old_handler); +#endif + } + + if (boot_interrupted) { + angel_negotiate_defaults(); + return adp_abandon_boot_wait; + } + } + + booted_not_received=1; + Adp_ChannelRegisterRead(CI_HBOOT, NULL, NULL); + + /* Leave the booted handler installed */ + msgsend(CI_TBOOT, "%w%w%w%w%w", ADP_Booted | HtoT, 0, + ADP_HandleUnknown, ADP_HandleUnknown, 0); + Adp_initSeq(); +#ifdef DEBUG + angel_DebugPrint("DEBUG: Transmitted ADP_Booted acknowledgement.\n"); + angel_DebugPrint("DEBUG: Boot sequence completed, leaving angel_RDI_open.\n"); +#endif + + return (hw_status & ADP_CPU_BigEndian )? RDIError_BigEndian : + RDIError_LittleEndian; + } + else { + /* warm start */ + register_debug_message_handler(); + + msgsend(CI_HADP, "%w%w%w%w", + ADP_InitialiseApplication | HtoT, 0, + ADP_HandleUnknown, ADP_HandleUnknown); +#ifdef DEBUG + angel_DebugPrint("DEBUG: Transmitted Initialise Application\n"); +#endif + reasoncode=ADP_InitialiseApplication | TtoH; + err = wait_for_debug_message(&reasoncode, &debugID, &OSinfo1, &OSinfo2, + &status, &packet); + if (err != RDIError_NoError) return err; + return status; + } + return -1; +} + + +/*----------------------------------------------------------------------*/ +/*----angel_RDI_close----------------------------------------------------*/ +/*----------------------------------------------------------------------*/ + +static int angel_negotiate_defaults( void ) { + int err = adp_ok; + ParameterConfig *default_config = NULL; + Adp_Ioctl( DC_GET_DEFAULT_PARAMS, (void *)&default_config ); + if ( default_config != NULL ) { + ParameterOptions *default_options = config_to_options(default_config); + err = negotiate_params( default_options ); + free( default_options ); + } + return err; +} + +int angel_RDI_close(void) { +/*Angel host exit */ + int err; + int status,debugID, OSinfo1,OSinfo2; + int reason; + Packet *packet = NULL;; +#ifdef DEBUG + angel_DebugPrint("DEBUG: Entered angel_RDI_Close.\n"); +#endif + + register_debug_message_handler(); + + heartbeat_enabled = FALSE; + + err = msgsend(CI_HADP,"%w%w%w%w",ADP_End | HtoT,0, + ADP_HandleUnknown, ADP_HandleUnknown); + if (err != RDIError_NoError) return err; + reason = ADP_End | TtoH; + err = wait_for_debug_message(&reason, &debugID, &OSinfo1, &OSinfo2, + &status, &packet); + DevSW_FreePacket(packet); + if (err != RDIError_NoError) return err; + if (status == RDIError_NoError) { + err = angel_negotiate_defaults(); + if (err != adp_ok) return err; + Adp_Ioctl( DC_RESET, NULL ); /* just to be safe */ + return HostSysExit(hstate); + } + else + return status; +} + + +/*----------------------------------------------------------------------*/ +/*----angel_RDI_read-----------------------------------------------------*/ +/*----------------------------------------------------------------------*/ + +/* Read memory contents from target to host: use ADP_Read */ +int angel_RDI_read(ARMword source, void *dest, unsigned *nbytes) +{ + Packet *packet=NULL; + int len; /* Integer to hold message length. */ + unsigned int nbtogo = *nbytes, nbinpacket, nbdone=0; + int rnbytes = 0, status, reason, debugID, OSinfo1, OSinfo2, err; + unsigned int maxlen = Armsd_BufferSize-CHAN_HEADER_SIZE-ADP_ReadHeaderSize; + + /* Print debug trace information, this is just copied straight from rdi.c + and I can see no reason why it should have to be changed. */ + TracePrint(("angel_RDI_read: source=%.8lx dest=%p nbytes=%.8x\n", + (unsigned long)source, dest, *nbytes)); + if (*nbytes == 0) return RDIError_NoError; /* Read nothing - easy! */ + /* check the buffer size */ + while (nbtogo >0) { + register_debug_message_handler(); + + nbinpacket = (nbtogo <= maxlen) ? nbtogo : maxlen; + len = msgsend(CI_HADP, "%w%w%w%w%w%w", ADP_Read | HtoT, 0, + ADP_HandleUnknown, ADP_HandleUnknown, source+nbdone, + nbinpacket); + reason=ADP_Read | TtoH; + err = wait_for_debug_message(&reason, &debugID, &OSinfo1, &OSinfo2, + &status, &packet); + TracePrint(("angel_RDI_read: nbinpacket =%d status=%08x err = %d\n", + nbinpacket,status,err)); + if (err != RDIError_NoError) return err; /* Was there an error? */ + if (status == RDIError_NoError){ + rnbytes += PREAD(LE,(unsigned int *)(BUFFERDATA(packet->pk_buffer)+20)); + TracePrint(("angel_RDI_read: rnbytes = %d\n",rnbytes)); + memcpy(((unsigned char *)dest)+nbdone, BUFFERDATA(packet->pk_buffer)+24, + nbinpacket); + } + nbdone += nbinpacket; + nbtogo -= nbinpacket; + } + *nbytes -= rnbytes; + return status; +} + + +/*----------------------------------------------------------------------*/ +/*----angel_RDI_write----------------------------------------------------*/ +/*----------------------------------------------------------------------*/ + +/* Transfer memory block from host to target. Use ADP_Write>. */ +int angel_RDI_write(const void *source, ARMword dest, unsigned *nbytes) +{ + Packet *packet;/* Message buffers. */ + unsigned int len, nbtogo = *nbytes, nboffset = 0, nbinpacket; + int status, reason, debugID, OSinfo1, OSinfo2, err; + unsigned int maxlen = Armsd_LongBufSize-CHAN_HEADER_SIZE-ADP_WriteHeaderSize; + + TracePrint(("angel_RDI_write: source=%p dest=%.8lx nbytes=%.8x\n", + source, (unsigned long)dest, *nbytes)); + + if (*nbytes == 0) return RDIError_NoError; + + *nbytes = 0; + while (nbtogo > 0) { + packet = (Packet *) DevSW_AllocatePacket(Armsd_LongBufSize); + nbinpacket = (nbtogo <= maxlen) ? nbtogo : maxlen; + len = msgbuild(BUFFERDATA(packet->pk_buffer), "%w%w%w%w%w%w", + ADP_Write | HtoT, 0, ADP_HandleUnknown, + ADP_HandleUnknown, dest+nboffset, nbinpacket); + /* Copy the data into the packet. */ + + memcpy(BUFFERDATA(packet->pk_buffer)+len, + ((const unsigned char *) source)+nboffset, nbinpacket); + nboffset += nbinpacket; + packet->pk_length = nbinpacket+len; + +#ifdef MONITOR_DOWNLOAD_PACKETS + angel_DebugPrint("angel_RDI_write packet size=%i, bytes done=%i\n", + nbinpacket, nboffset); +#endif + + register_debug_message_handler(); + Adp_ChannelWrite(CI_HADP, packet); + reason=ADP_Write | TtoH; + err = wait_for_debug_message(&reason, &debugID, &OSinfo1, &OSinfo2, + &status, &packet); + nbtogo -= nbinpacket; + if (err != RDIError_NoError) return err; + if (status == RDIError_NoError) + *nbytes += nbinpacket; + + DevSW_FreePacket(packet); + } + return status; +} + + +/*----------------------------------------------------------------------*/ +/*----angel_RDI_CPUread--------------------------------------------------*/ +/*----------------------------------------------------------------------*/ + +/* Reads the values of registers in the CPU, uses ADP_CPUwrite. */ +int angel_RDI_CPUread(unsigned mode, unsigned long mask, ARMword *buffer) +{ + unsigned int i, j; + Packet *packet = NULL; + int err, status, reason, debugID, OSinfo1, OSinfo2; +#ifdef DEBUG + angel_DebugPrint("DEBUG: Entered angel_RDI_CPUread.\n"); +#endif + for (i=0, j=0 ; i < RDINumCPURegs ; i++) + if (mask & (1L << i)) j++; /* Count the number of registers. */ + + register_debug_message_handler(); + msgsend(CI_HADP, "%w%w%w%w%c%w", ADP_CPUread | HtoT, 0, + ADP_HandleUnknown, ADP_HandleUnknown, mode, mask); + reason = ADP_CPUread | TtoH; + err = wait_for_debug_message(&reason, &debugID, &OSinfo1, &OSinfo2, + &status, &packet); + if (err != RDIError_NoError) { + DevSW_FreePacket(packet); + return err; + } + if(status == RDIError_NoError) { + for (i=0; ipk_buffer)+20+(i*4)); + TracePrint(("angel_RDI_CPUread: mode=%.8x mask=%.8lx", mode, mask)); + DevSW_FreePacket(packet); +#ifdef RDI_VERBOSE + if (rdi_log & 1) { + unsigned k; + for (k = 0, j = 0 ; j <= 20 ; j++) + if (mask & (1L << j)) { + angel_DebugPrint("%c%.8lx",k%4==0?'\n':' ', + (unsigned long)buffer[k]); + k++ ; + } + angel_DebugPrint("\n") ; + } +#endif + + } + return status; +} + +/*----------------------------------------------------------------------*/ +/*----angel_RDI_CPUwrite-------------------------------------------------*/ +/*----------------------------------------------------------------------*/ + +/* Write CPU registers: use ADP_CPUwrite. */ +int angel_RDI_CPUwrite(unsigned mode, unsigned long mask, + ARMword const *buffer){ + + unsigned i, j, c; + Packet *packet; + int status, reason, debugID, OSinfo1, OSinfo2, err, len; + + TracePrint(("angel_RDI_CPUwrite: mode=%.8x mask=%.8lx", mode, mask)); +#ifdef RDI_VERBOSE + if (rdi_log & 1) { + for (j = 0, i = 0 ; i <= 20 ; i++) + if (mask & (1L << i)) { + angel_DebugPrint("%c%.8lx",j%4==0?'\n':' ', + (unsigned long)buffer[j]); + j++ ; + } + angel_DebugPrint("\n") ; + } +#endif + packet = (Packet *)DevSW_AllocatePacket(Armsd_BufferSize); + for (i=0, j=0; i < RDINumCPURegs ; i++) + if (mask & (1L << i)) j++; /* count the number of registers */ + + len = msgbuild(BUFFERDATA(packet->pk_buffer), "%w%w%w%w%b%w", + ADP_CPUwrite | HtoT, 0, + ADP_HandleUnknown, ADP_HandleUnknown, mode, mask); + for(c=0; cpk_buffer)+len+(c*4), buffer[c]); + packet->pk_length = len+(j*4); + register_debug_message_handler(); + + Adp_ChannelWrite(CI_HADP, packet); + reason = ADP_CPUwrite | TtoH; + err = wait_for_debug_message(&reason, &debugID, &OSinfo1, &OSinfo2, + &status, &packet); + unpack_message(BUFFERDATA(packet->pk_buffer), "%w%w%w%w%w", &reason, &debugID, + &OSinfo1, &OSinfo2, &status); + DevSW_FreePacket(packet); + if (err != RDIError_NoError) + return err; /* Was there an error? */ + else + return status; + } + + +/*----------------------------------------------------------------------*/ +/*----angel_RDI_CPread---------------------------------------------------*/ +/*----------------------------------------------------------------------*/ + +/* Read coprocessor's internal state. See dbg_cp.h for help. + * Use ADP_CPRead. + * It would appear that the correct behaviour at this point is to leave + * the unpacking to a the caller and to simply copy the stream of data + * words into the buffer + */ + +int angel_RDI_CPread(unsigned CPnum, unsigned long mask, ARMword *buffer){ + Packet *packet = NULL; + int i, j, status, reasoncode, OSinfo1, OSinfo2, err, debugID; + unsigned char *rmap = cpwords[CPnum]; + int n; +#ifdef DEBUG + angel_DebugPrint("DEBUG: Entered angel_RDI_CPread.\n"); +#endif + if (rmap == NULL) return RDIError_UnknownCoPro; + + register_debug_message_handler(); + n = rmap[-1]; + msgsend(CI_HADP, "%w%w%w%w%b%w", ADP_CPread | HtoT, 0, + ADP_HandleUnknown, ADP_HandleUnknown, CPnum, mask); + reasoncode=ADP_CPread | TtoH; + err = wait_for_debug_message(&reasoncode, &debugID, &OSinfo1, &OSinfo2, + &status, &packet); + if (err != RDIError_NoError) { + DevSW_FreePacket(packet); + return err; /* Was there an error? */ + } + for (j=i=0; i < n ; i++) /* count the number of registers */ + if (mask & (1L << i)) { + j++; + } + for (i=0; ipk_buffer) + 20 + (i*4)); + DevSW_FreePacket(packet); + TracePrint(("angel_RDI_CPread: CPnum=%.8x mask=%.8lx\n", CPnum, mask)); +#ifdef RDI_VERBOSE + if (rdi_log & 1) { + for (i = 0, j = 0; j < n ; j++) { + if (mask & (1L << j)) { + int nw = rmap[j]; + angel_DebugPrint("%2d ", j); + while (--nw > 0) + angel_DebugPrint("%.8lx ", (unsigned long)buffer[i++]); + angel_DebugPrint("%.8lx\n", (unsigned long)buffer[i++]); + } + } + } +#endif + return status; +} + + +/*----------------------------------------------------------------------*/ +/*----angel_RDI_CPwrite--------------------------------------------------*/ +/*----------------------------------------------------------------------*/ + +/* Write coprocessor's internal state. See dbg_cp.h for help. Use + * ADP_CPwrite. + */ + +int angel_RDI_CPwrite(unsigned CPnum, unsigned long mask, + ARMword const *buffer) +{ + Packet *packet = NULL; + int i, j, len, status, reason, OSinfo1, OSinfo2, err, debugID; + unsigned char *rmap = cpwords[CPnum]; + int n; + + if (rmap == NULL) return RDIError_UnknownCoPro; + n = rmap[-1]; + + TracePrint(("angel_RDI_CPwrite: CPnum=%d mask=%.8lx\n", CPnum, mask)); + +#ifdef RDI_VERBOSE + if (rdi_log & 1) { + for (i = 0, j = 0; j < n ; j++) + if (mask & (1L << j)) { + int nw = rmap[j]; + angel_DebugPrint("%2d ", j); + while (--nw > 0) + angel_DebugPrint("%.8lx ", (unsigned long)buffer[i++]); + angel_DebugPrint("%.8lx\n", (unsigned long)buffer[i++]); + } + } +#endif + + for (j=i=0; i < n ; i++) /* Count the number of registers. */ + if (mask & (1L << i)) j++; + packet = DevSW_AllocatePacket(Armsd_BufferSize); + len = msgbuild(BUFFERDATA(packet->pk_buffer), "%w%w%w%w%c%w", + ADP_CPwrite | HtoT, 0, + ADP_HandleUnknown, ADP_HandleUnknown, CPnum, mask); + for(i=0; ipk_buffer) + len, "%w", buffer[i]); + packet->pk_length = len; + register_debug_message_handler(); + Adp_ChannelWrite(CI_HADP, packet); /* Transmit message. */ + reason=ADP_CPwrite | TtoH; + err = wait_for_debug_message(&reason, &debugID, &OSinfo1, &OSinfo2, + &status, &packet); + DevSW_FreePacket(packet); + if (err != RDIError_NoError) + return err; + else + return status; +} + + +/*----------------------------------------------------------------------*/ +/*----angel_RDI_pointinq-------------------------------------------------*/ +/*----------------------------------------------------------------------*/ + +/* Do test calls to ADP_SetBreak/ADP_SetWatch to see if resources exist to + carry out request. */ +int angel_RDI_pointinq(ARMword *address, unsigned type, unsigned datatype, + ARMword *bound) +{ + Packet *packet = NULL; + int len, status, reason, OSinfo1, OSinfo2, err=RDIError_NoError; + /* stop a compiler warning */ + int debugID, pointhandle; + TracePrint( + ("angel_RDI_pointinq: address=%.8lx type=%d datatype=%d bound=%.8lx ", + (unsigned long)*address, type, datatype, (unsigned long)*bound)); + /* for a buffer. */ + packet = DevSW_AllocatePacket(Armsd_BufferSize); + len = msgbuild(BUFFERDATA(packet->pk_buffer), "%w%w%w%w%w%b", + ((datatype == 0) ? ADP_SetBreak : ADP_SetWatch) | HtoT, 0, + ADP_HandleUnknown, ADP_HandleUnknown, address, type); + if (datatype == 0) + len += msgbuild(BUFFERDATA(packet->pk_buffer) + 21, "%w", bound); + else + len += msgbuild(BUFFERDATA(packet->pk_buffer) + 21, "%b%w", datatype, bound); + + register_debug_message_handler(); + packet->pk_length = len; + Adp_ChannelWrite(CI_HADP, packet); + reason = ((datatype == 0) ? ADP_SetBreak : ADP_SetWatch | TtoH); + err = wait_for_debug_message(&reason, &debugID, &OSinfo1, &OSinfo2, + &status, &packet); + if (err != RDIError_NoError) { + DevSW_FreePacket(packet); + return err; /* Was there an error? */ + } + unpack_message(BUFFERDATA(packet->pk_buffer), "%w%w%w%w%w%w%w%w", + &reason, &debugID, &OSinfo1, &OSinfo2, &status, + &pointhandle, &address, &bound); + DevSW_FreePacket(packet); + return err; +} + + +/*----------------------------------------------------------------------*/ +/*----angel_RDI_setbreak-------------------------------------------------*/ +/*----------------------------------------------------------------------*/ + +/* Set a breakpoint: Use ADP_SetBreak */ +int angel_RDI_setbreak(ARMword address, unsigned type, ARMword bound, + PointHandle *handle) +{ + int status, reason, OSinfo1, OSinfo2, err, debugID; + int tmpval, tmpaddr, tmpbnd; + Packet *packet; + TracePrint(("angel_RDI_setbreak address=%.8lx type=%d bound=%.8lx \n", + (unsigned long)address, type, (unsigned long)bound)); + + register_debug_message_handler(); + msgsend(CI_HADP, "%w%w%w%w%w%b%w", + ADP_SetBreak| HtoT, 0, ADP_HandleUnknown, + ADP_HandleUnknown, address, type, bound); + reason = ADP_SetBreak |TtoH; + err = wait_for_debug_message(&reason, &debugID, &OSinfo1, &OSinfo2, + &status, &packet); + if (err != RDIError_NoError) { + DevSW_FreePacket(packet); + return err; /* Was there an error? */ + } + /* Work around varargs problem... -sts */ + unpack_message(BUFFERDATA(packet->pk_buffer), "%w%w%w%w%w%w%w%w", + &reason, &debugID, &OSinfo1, &OSinfo2, &status, + &tmpval, &tmpaddr, &tmpbnd); + *handle = tmpval; + address = tmpaddr; + bound = tmpbnd; + DevSW_FreePacket(packet); + if (status != RDIError_NoError) return status; + TracePrint(("returns handle %.8lx\n", (unsigned long)*handle)); + return RDIError_NoError; +} + + +/*----------------------------------------------------------------------*/ +/*----angel_RDI_clearbreak-----------------------------------------------*/ +/*----------------------------------------------------------------------*/ + +/* Clear a breakpoint: Use ADP_ClearBreak. */ +int angel_RDI_clearbreak(PointHandle handle) +{ + Packet *packet = NULL; + int status, reason, OSinfo1, OSinfo2, err, debugID; + + TracePrint(("angel_RDI_clearbreak: handle=%.8lx\n", (unsigned long)handle)); + + register_debug_message_handler(); + msgsend(CI_HADP, "%w%w%w%w%w", + ADP_ClearBreak| HtoT, 0, ADP_HandleUnknown, + ADP_HandleUnknown, handle); + reason = ADP_ClearBreak|TtoH; + err = wait_for_debug_message(&reason, &debugID, &OSinfo1, &OSinfo2, + &status, &packet); + if (err != RDIError_NoError) { + DevSW_FreePacket(packet); + angel_DebugPrint("***RECEIVE DEBUG MESSAGE RETURNED ERR = %d.\n", err); + return err; /* Was there an error? */ + } + unpack_message(BUFFERDATA(packet->pk_buffer), "%w%w%w%w%w", &reason, + &debugID, &OSinfo1, &OSinfo2, &status); + DevSW_FreePacket(packet); +#ifdef DEBUG + angel_DebugPrint("DEBUG: Clear Break completed OK.\n"); +#endif + return RDIError_NoError; +} + + +/*----------------------------------------------------------------------*/ +/*----angel_RDI_setwatch-------------------------------------------------*/ +/*----------------------------------------------------------------------*/ + +/* Set a watchpoint: use ADP_SetWatch. */ +int angel_RDI_setwatch(ARMword address, unsigned type, unsigned datatype, + ARMword bound, PointHandle *handle) +{ + Packet *packet = NULL; + int status, reason, OSinfo1, OSinfo2, err, debugID; + + TracePrint(("angel_RDI_setwatch: address=%.8lx type=%d bound=%.8lx ", + (unsigned long)address, type, (unsigned long)bound)); + + register_debug_message_handler(); + msgsend(CI_HADP, "%w%w%w%w%w%b%b%w", + ADP_SetWatch| HtoT, 0, ADP_HandleUnknown, + ADP_HandleUnknown, address, type, datatype, bound); + + reason = ADP_SetWatch | TtoH; + err = wait_for_debug_message(&reason, &debugID, &OSinfo1, &OSinfo2, + &status, &packet); + if (err != RDIError_NoError) { + DevSW_FreePacket(packet); + return err; /* Was there an error? */ + } + unpack_message(BUFFERDATA(packet->pk_buffer), "%w%w%w%w%w%w%w%w", + &reason, &debugID, &OSinfo1, &OSinfo2, &status, + handle, &address, &bound); + DevSW_FreePacket(packet); + TracePrint(("returns handle %.8lx\n", (unsigned long)*handle)); + return RDIError_NoError; +} + +/*----------------------------------------------------------------------*/ +/*----angel_RDI_clearwatch-----------------------------------------------*/ +/*----------------------------------------------------------------------*/ + +/* Clear a watchpoint: use ADP_ClearWatch. */ +int angel_RDI_clearwatch(PointHandle handle) { + + int status, reason, OSinfo1, OSinfo2, err, debugID; + Packet *packet = NULL; + + TracePrint(("angel_RDI_clearwatch: handle=%.8lx\n", (unsigned long)handle)); + + register_debug_message_handler(); + msgsend(CI_HADP, "%w%w%w%w%w", + ADP_ClearWatch| HtoT, 0, ADP_HandleUnknown, + ADP_HandleUnknown, handle); + reason = ADP_ClearWatch|TtoH; + err = wait_for_debug_message(&reason, &debugID, &OSinfo1, &OSinfo2, + &status, &packet); + if (err != RDIError_NoError) { + DevSW_FreePacket(packet); + return err; /* Was there an error? */ + } + unpack_message(BUFFERDATA(packet->pk_buffer), "%w%w%w%w%w", &reason, &debugID, + &OSinfo1, &OSinfo2, &status); + DevSW_FreePacket(packet); + return RDIError_NoError; +} + +typedef struct { + unsigned stopped_reason; + int stopped_status; + int data; +} adp_stopped_struct; + + +int angel_RDI_OnTargetStopping(angel_RDI_TargetStoppedProc *fn, + void *arg) +{ + stoppedProcListElement **lptr = &stopped_proc_list; + + /* Find the address of the NULL ptr at the end of the list */ + for (; *lptr!=NULL ; lptr = &((*lptr)->next)) + ; /* Do nothing */ + + *lptr = (stoppedProcListElement *) malloc(sizeof(stoppedProcListElement)); + if (*lptr == NULL) return RDIError_OutOfStore; + (*lptr)->fn = fn; + (*lptr)->arg = arg; + + return RDIError_NoError; +} + +static int CallStoppedProcs(unsigned reason) +{ + stoppedProcListElement *p = stopped_proc_list; + int err=RDIError_NoError; + + for (; p!=NULL ; p=p->next) { + int local_err = p->fn(reason, p->arg); + if (local_err != RDIError_NoError) err=local_err; + } + + return err; +} + +/*----------------------------------------------------------------------*/ +/*----angel_RDI_execute--------------------------------------------------*/ +/*----------------------------------------------------------------------*/ + +static int HandleStoppedMessage(Packet *packet, void *stateptr) { + unsigned int err, reason, debugID, OSinfo1, OSinfo2, count; + adp_stopped_struct *stopped_info; + stopped_info = (adp_stopped_struct *) stateptr; + IGNORE(stateptr); + count = unpack_message(BUFFERDATA(packet->pk_buffer), "%w%w%w%w%w%w", + &reason, &debugID, + &OSinfo1, &OSinfo2, + &stopped_info->stopped_reason, &stopped_info->data); + DevSW_FreePacket(packet); + + if (reason != (ADP_Stopped | TtoH)) { +#ifdef DEBUG + angel_DebugPrint("Expecting stopped message, got %x", reason); +#endif + return RDIError_Error; + } + else { + executing = FALSE; +#ifdef DEBUG + angel_DebugPrint("Received stopped message.\n"); +#endif + } + + err = msgsend(CI_TADP, "%w%w%w%w%w", (ADP_Stopped | HtoT), 0, + ADP_HandleUnknown, ADP_HandleUnknown, RDIError_NoError); +#ifdef DEBUG + angel_DebugPrint("Transmiting stopped acknowledge.\n"); +#endif + if (err != RDIError_NoError) angel_DebugPrint("Transmit failed.\n"); +#ifdef DEBUG + angel_DebugPrint("DEBUG: Stopped reason : %x\n", stopped_info->stopped_reason); +#endif + switch (stopped_info->stopped_reason) { + case ADP_Stopped_BranchThroughZero: + stopped_info->stopped_status = RDIError_BranchThrough0; + break; + case ADP_Stopped_UndefinedInstr: + stopped_info->stopped_status = RDIError_UndefinedInstruction; + break; + case ADP_Stopped_SoftwareInterrupt: + stopped_info->stopped_status = RDIError_SoftwareInterrupt; + break; + case ADP_Stopped_PrefetchAbort: + stopped_info->stopped_status = RDIError_PrefetchAbort; + break; + case ADP_Stopped_DataAbort: + stopped_info->stopped_status = RDIError_DataAbort; + break; + case ADP_Stopped_AddressException: + stopped_info->stopped_status = RDIError_AddressException; + break; + case ADP_Stopped_IRQ: + stopped_info->stopped_status = RDIError_IRQ; + break; + case ADP_Stopped_BreakPoint: + stopped_info->stopped_status = RDIError_BreakpointReached; + break; + case ADP_Stopped_WatchPoint: + stopped_info->stopped_status = RDIError_WatchpointAccessed; + break; + case ADP_Stopped_StepComplete: + stopped_info->stopped_status = RDIError_ProgramFinishedInStep; + break; + case ADP_Stopped_RunTimeErrorUnknown: + case ADP_Stopped_StackOverflow: + case ADP_Stopped_DivisionByZero: + stopped_info->stopped_status = RDIError_Error; + break; + case ADP_Stopped_FIQ: + stopped_info->stopped_status = RDIError_FIQ; + break; + case ADP_Stopped_UserInterruption: + case ADP_Stopped_OSSpecific: + stopped_info->stopped_status = RDIError_UserInterrupt; + break; + case ADP_Stopped_ApplicationExit: + stopped_info->stopped_status = RDIError_NoError; + break; + default: + stopped_info->stopped_status = RDIError_NoError; + break; + } + return RDIError_NoError; +} + +static volatile bool interrupt_request = FALSE; + +static void interrupt_target( void ) +{ + Packet *packet = NULL; + int err; + int reason, debugID, OSinfo1, OSinfo2, status; + +#ifdef DEBUG + angel_DebugPrint("DEBUG: interrupt_target.\n"); +#endif + + register_debug_message_handler(); + msgsend(CI_HADP, "%w%w%w%w", ADP_InterruptRequest | HtoT, 0, + ADP_HandleUnknown, ADP_HandleUnknown); + + reason = ADP_InterruptRequest |TtoH; + err = wait_for_debug_message(&reason, &debugID, &OSinfo1, &OSinfo2, + &status, &packet); + DevSW_FreePacket(packet); +#ifdef DEBUG + angel_DebugPrint("DEBUG: got interrupt ack ok err = %d, status=%i\n", + err, status); +#endif + + return; +} + +#ifdef TEST_DC_APPL + extern void test_dc_appl_handler( const DeviceDescr *device, + Packet *packet ); +#endif + +/* Core functionality for execute and step */ +static int angel_RDI_ExecuteOrStep(PointHandle *handle, word type, + unsigned ninstr) +{ + int err; + adp_stopped_struct stopped_info; + void* stateptr = (void *)&stopped_info; + ChannelCallback HandleStoppedMessageFPtr=(ChannelCallback) HandleStoppedMessage; + int status, reasoncode, debugID, OSinfo1, OSinfo2; + Packet *packet = NULL; + + TracePrint(("angel_RDI_ExecuteOrStep\n")); + + err = Adp_ChannelRegisterRead(CI_TADP, + HandleStoppedMessageFPtr, stateptr); + if (err != RDIError_NoError) { +#ifdef DEBUG + angel_DebugPrint("TADP Register failed.\n"); +#endif + return err; + } + /* Set executing TRUE here, as it must be set up before the target has + * had any chance at all to execute, or it may send its stopped message + * before we get round to setting executing = TRUE !!! + */ + executing = TRUE; + + register_debug_message_handler(); + +#ifdef TEST_DC_APPL + Adp_Install_DC_Appl_Handler( test_dc_appl_handler ); +#endif + +#ifdef DEBUG + angel_DebugPrint("Transmiting %s message.\n", + type == ADP_Execute ? "execute": "step"); +#endif + + register_debug_message_handler(); + /* Extra ninstr parameter for execute message will simply be ignored */ + err = msgsend(CI_HADP,"%w%w%w%w%w", type | HtoT, 0, + ADP_HandleUnknown, ADP_HandleUnknown, ninstr); +#if DEBUG + if (err != RDIError_NoError) angel_DebugPrint("Transmit failed.\n"); +#endif + + reasoncode = type | TtoH; + err = wait_for_debug_message( &reasoncode, &debugID, &OSinfo1, &OSinfo2, + &status, &packet ); + if (err != RDIError_NoError) + return err; + else if (status != RDIError_NoError) + return status; + +#ifdef DEBUG + angel_DebugPrint("Waiting for program to finish...\n"); +#endif + + while( executing ) + { + if (interrupt_request) + { + interrupt_target(); + interrupt_request = FALSE; + } + Adp_AsynchronousProcessing( async_block_on_nothing ); + } + +#ifdef TEST_DC_APPL + Adp_Install_DC_Appl_Handler( NULL ); +#endif + + (void)Adp_ChannelRegisterRead(CI_TADP, NULL, NULL); + + *handle = (PointHandle)stopped_info.data; + + CallStoppedProcs(stopped_info.stopped_reason); + + return stopped_info.stopped_status; +} + +/* Request that the target starts executing from the stored CPU state: use + ADP_Execute. */ +int angel_RDI_execute(PointHandle *handle) +{ + return angel_RDI_ExecuteOrStep(handle, ADP_Execute, 0); +} + +#ifdef __WATCOMC__ +typedef void handlertype(int); + +static int interrupted=0; + +static void myhandler(int sig) { + IGNORE(sig); + interrupted=1; + signal(SIGINT, myhandler); +} +#endif + +/*----------------------------------------------------------------------*/ +/*----angel_RDI_step-----------------------------------------------------*/ +/*----------------------------------------------------------------------*/ + +/* Step 'ninstr' through the code: use ADP_Step. */ +int angel_RDI_step(unsigned ninstr, PointHandle *handle) +{ + int err = angel_RDI_ExecuteOrStep(handle, ADP_Step, ninstr); + if (err == RDIError_ProgramFinishedInStep) + return RDIError_NoError; + else + return err; +} + + +static void SetCPWords(int cpnum, struct Dbg_CoProDesc const *cpd) { + int i, rmax = 0; + for (i = 0; i < cpd->entries; i++) + if (cpd->regdesc[i].rmax > rmax) + rmax = cpd->regdesc[i].rmax; + + { unsigned char *rmap = (unsigned char *)malloc(rmax + 2); + *rmap++ = rmax + 1; + for (i = 0; i < cpd->entries; i++) { + int r; + for (r = cpd->regdesc[i].rmin; r <= cpd->regdesc[i].rmax; r++) + rmap[r] = (cpd->regdesc[i].nbytes+3) / 4; + } +/* if (cpwords[cpnum] != NULL) free(cpwords[cpnum]); */ + cpwords[cpnum] = rmap; + } +} + +/*----------------------------------------------------------------------*/ +/*----angel_RDI_info-----------------------------------------------------*/ +/*----------------------------------------------------------------------*/ + +/* Use ADP_Info, ADP_Ctrl and ADP_Profile calls to implement these, + see adp.h for more details. */ + +static int angel_cc_exists( void ) +{ + Packet *packet = NULL; + int err; + int reason, debugID, OSinfo1, OSinfo2, subreason, status; + +#ifdef DEBUG + angel_DebugPrint("DEBUG: ADP_ICEB_CC_Exists.\n"); +#endif + + if ( angel_RDI_info( RDIInfo_Icebreaker, NULL, NULL ) == RDIError_NoError ) { + register_debug_message_handler(); + msgsend(CI_HADP, "%w%w%w%w%w", ADP_ICEbreakerHADP | HtoT, 0, + ADP_HandleUnknown, ADP_HandleUnknown, + ADP_ICEB_CC_Exists ); + reason = ADP_ICEbreakerHADP |TtoH; + err = wait_for_debug_message(&reason, &debugID, &OSinfo1, &OSinfo2, + &status, &packet); + if (err != RDIError_NoError) { + DevSW_FreePacket(packet); + return err; + } + unpack_message(BUFFERDATA(packet->pk_buffer), "%w%w%w%w%w%w", &reason, + &debugID, &OSinfo1, &OSinfo2, &subreason, &status); + if (subreason != ADP_ICEB_CC_Exists) { + DevSW_FreePacket(packet); + return RDIError_Error; + } + else + return status; + } + else + return RDIError_UnimplementedMessage; +} + +typedef struct { + RDICCProc_ToHost *tohost; void *tohostarg; + RDICCProc_FromHost *fromhost; void *fromhostarg; + bool registered; +} CCState; +static CCState ccstate = { NULL, NULL, NULL, NULL, FALSE }; + +static void HandleDCCMessage( Packet *packet, void *stateptr ) +{ + unsigned int reason, debugID, OSinfo1, OSinfo2; + int count; + CCState *ccstate_p = (CCState *)stateptr; + + count = unpack_message( BUFFERDATA(packet->pk_buffer), "%w%w%w%w", + &reason, &debugID, &OSinfo1, &OSinfo2 ); + switch ( reason ) + { + case ADP_TDCC_ToHost | TtoH: + { + /* only handles a single word of data, for now */ + + unsigned int nbytes, data; + + unpack_message( BUFFERDATA(packet->pk_buffer)+count, "%w%w", + &nbytes, &data ); +#ifdef DEBUG + angel_DebugPrint( "DEBUG: received CC_ToHost message: nbytes %d data %08x.\n", + nbytes, data ); +#endif + ccstate_p->tohost( ccstate_p->tohostarg, data ); + msgsend(CI_TTDCC, "%w%w%w%w%w", + ADP_TDCC_ToHost | HtoT, debugID, OSinfo1, OSinfo2, + RDIError_NoError ); + break; + } + + case ADP_TDCC_FromHost | TtoH: + { + /* only handles a single word of data, for now */ + + int valid; + ARMword data; + + ccstate_p->fromhost( ccstate_p->fromhostarg, &data, &valid ); +#ifdef DEBUG + angel_DebugPrint( "DEBUG: received CC_FromHost message, returning: %08x %s.\n", + data, valid ? "VALID" : "INvalid" ); +#endif + msgsend(CI_TTDCC, "%w%w%w%w%w%w%w", + ADP_TDCC_FromHost | HtoT, debugID, OSinfo1, OSinfo2, + RDIError_NoError, valid ? 1 : 0, data ); + break; + } + + default: +#ifdef DEBUG + angel_DebugPrint( "Unexpected TDCC message %08x received\n", reason ); +#endif + break; + } + DevSW_FreePacket(packet); + return; +} + +static void angel_check_DCC_handler( CCState *ccstate_p ) +{ + int err; + + if ( ccstate_p->tohost != NULL || ccstate_p->fromhost != NULL ) + { + /* doing DCC, so need a handler */ + if ( ! ccstate_p->registered ) + { +#ifdef DEBUG + angel_DebugPrint( "Registering handler for TTDCC channel.\n" ); +#endif + err = Adp_ChannelRegisterRead( CI_TTDCC, HandleDCCMessage, + ccstate_p ); + if ( err == adp_ok ) + ccstate_p->registered = TRUE; +#ifdef DEBUG + else + angel_DebugPrint( "angel_check_DCC_handler: register failed!\n" ); +#endif + } + } + else + { + /* not doing DCC, so don't need a handler */ + if ( ccstate_p->registered ) + { +#ifdef DEBUG + angel_DebugPrint( "Unregistering handler for TTDCC channel.\n" ); +#endif + err = Adp_ChannelRegisterRead( CI_TTDCC, NULL, NULL ); + if ( err == adp_ok ) + ccstate_p->registered = FALSE; +#ifdef DEBUG + else + angel_DebugPrint( "angel_check_DCC_handler: unregister failed!\n" ); +#endif + } + } +} + + +static int CheckSubMessageReply(int reason, int subreason) { + Packet *packet = NULL; + int status, debugID, OSinfo1, OSinfo2; + int err = RDIError_NoError; + reason |= TtoH; + err = wait_for_debug_message(&reason, &debugID, &OSinfo1, &OSinfo2, + &status, &packet); + if (err != RDIError_NoError) { + status = err; + } else { + int sr; + unpack_message(BUFFERDATA(packet->pk_buffer), "%w%w%w%w%w%w", &reason, &debugID, + &OSinfo1, &OSinfo2, &sr, &status); + if (subreason != sr) status = RDIError_Error; + } + DevSW_FreePacket(packet); + return status; +} + +static int SendSubMessageAndCheckReply(int reason, int subreason) { + register_debug_message_handler(); + msgsend(CI_HADP, "%w%w%w%w%w", reason | HtoT, 0, + ADP_HandleUnknown, ADP_HandleUnknown, + subreason); + return CheckSubMessageReply(reason, subreason); +} + +static int SendSubMessageWordAndCheckReply(int reason, int subreason, ARMword word) { + register_debug_message_handler(); + msgsend(CI_HADP, "%w%w%w%w%w%w", reason | HtoT, 0, + ADP_HandleUnknown, ADP_HandleUnknown, + subreason, word); + return CheckSubMessageReply(reason, subreason); +} + +static int SendSubMessageGetWordAndCheckReply(int reason, int subreason, ARMword *resp) { + Packet *packet = NULL; + int status, debugID, OSinfo1, OSinfo2; + int err = RDIError_NoError; + + register_debug_message_handler(); + msgsend(CI_HADP, "%w%w%w%w%w", reason | HtoT, 0, + ADP_HandleUnknown, ADP_HandleUnknown, + subreason); + reason |= TtoH; + err = wait_for_debug_message(&reason, &debugID, &OSinfo1, &OSinfo2, + &status, &packet); + if (err != RDIError_NoError) { + status = err; + } else { + int sr; + unpack_message(BUFFERDATA(packet->pk_buffer), "%w%w%w%w%w%w%w", &reason, &debugID, + &OSinfo1, &OSinfo2, &sr, &status, resp); + if (subreason != sr) status = RDIError_Error; + } + DevSW_FreePacket(packet); + return status; +} + +static int const hostsex = 1; + +int angel_RDI_info(unsigned type, ARMword *arg1, ARMword *arg2) { + Packet *packet = NULL; + int len, status, c, reason, subreason, debugID, OSinfo1, OSinfo2; + int err=RDIError_NoError, cpnum=0; + struct Dbg_CoProDesc *cpd; + int count, i; + unsigned char *bp; + +#ifdef DEBUG + angel_DebugPrint("DEBUG: Entered angel_RDI_info.\n"); +#endif + switch (type) { + case RDIInfo_Target: +#ifdef DEBUG + angel_DebugPrint("DEBUG: RDIInfo_Target.\n"); +#endif + + register_debug_message_handler(); + msgsend(CI_HADP, "%w%w%w%w%w", ADP_Info | HtoT, 0, + ADP_HandleUnknown, ADP_HandleUnknown, ADP_Info_Target); + reason = ADP_Info |TtoH; + err = wait_for_debug_message(&reason, &debugID, &OSinfo1, &OSinfo2, + &status, &packet); + if (err != RDIError_NoError) { + DevSW_FreePacket(packet); + return err; + } + unpack_message(BUFFERDATA(packet->pk_buffer), "%w%w%w%w%w%w%w%w", &reason, + &debugID, &OSinfo1, &OSinfo2, &subreason, &status, + arg1, arg2); + DevSW_FreePacket(packet); + + if (subreason != ADP_Info_Target) + return RDIError_Error; + else + return status; + + case RDISignal_Stop: +#ifdef DEBUG + angel_DebugPrint("DEBUG: RDISignal_Stop.\n"); + if (interrupt_request) + angel_DebugPrint(" STILL WAITING to send previous interrupt request\n"); +#endif + interrupt_request = TRUE; + return RDIError_NoError; + + case RDIInfo_Points: +#ifdef DEBUG + angel_DebugPrint("DEBUG: RDIInfo_Points.\n"); +#endif + return SendSubMessageGetWordAndCheckReply(ADP_Info, ADP_Info_Points, arg1); + + case RDIInfo_Step: +#ifdef DEBUG + angel_DebugPrint("DEBUG: RDIInfo_Step.\n"); +#endif + return SendSubMessageGetWordAndCheckReply(ADP_Info, ADP_Info_Step, arg1); + + case RDISet_Cmdline: +#ifdef DEBUG + angel_DebugPrint("DEBUG: RDISet_Cmdline.\n"); +#endif + if (ardi_commandline != &dummycline) + free(ardi_commandline); + ardi_commandline = (char *)malloc(strlen((char*)arg1) + 1) ; + (void)strcpy(ardi_commandline, (char *)arg1) ; + return RDIError_NoError; + + case RDIInfo_SetLog: +#ifdef DEBUG + angel_DebugPrint("DEBUG: RDIInfo_SetLog.\n"); +#endif + rdi_log = (int) *arg1; + return RDIError_NoError; + + case RDIInfo_Log: +#ifdef DEBUG + angel_DebugPrint("DEBUG: RDIInfo_Log.\n"); +#endif + *arg1 = rdi_log; + return RDIError_NoError; + + + case RDIInfo_MMU: +#ifdef DEBUG + angel_DebugPrint("DEBUG: RDIInfo_MMU.\n"); +#endif + return SendSubMessageGetWordAndCheckReply(ADP_Info, ADP_Info_MMU, arg1); + + case RDIInfo_SemiHosting: +#ifdef DEBUG + angel_DebugPrint("DEBUG: RDIInfo_SemiHosting.\n"); +#endif + return SendSubMessageAndCheckReply(ADP_Info, ADP_Info_SemiHosting); + + case RDIInfo_CoPro: +#ifdef DEBUG + angel_DebugPrint("DEBUG: RDIInfo_CoPro.\n"); +#endif + return SendSubMessageAndCheckReply(ADP_Info, ADP_Info_CoPro); + + case RDICycles: +#ifdef DEBUG + angel_DebugPrint("DEBUG: RDICycles.\n"); +#endif + register_debug_message_handler(); + msgsend(CI_HADP, "%w%w%w%w%w", ADP_Info | HtoT, 0, + ADP_HandleUnknown, ADP_HandleUnknown, ADP_Info_Cycles); + reason = ADP_Info |TtoH; + err = wait_for_debug_message(&reason, &debugID, &OSinfo1, &OSinfo2, + &status, &packet); + if (err != RDIError_NoError) { + DevSW_FreePacket(packet); + return err; + } + unpack_message(BUFFERDATA(packet->pk_buffer), "%w%w%w%w%w%w", &reason, &debugID, + &OSinfo1, &OSinfo2, &subreason, &status); + DevSW_FreePacket(packet); + if (subreason != ADP_Info_Cycles) + return RDIError_Error; + if (status != RDIError_NoError) return status; + for (c=0; c<12; c++) + arg1[c]=GET32LE(BUFFERDATA(packet->pk_buffer)+24+(c*4)); + return status; + + case RDIInfo_DescribeCoPro: +#ifdef DEBUG + angel_DebugPrint("DEBUG: RDIInfo_DescribeCoPro.\n"); +#endif + cpnum = *(int *)arg1; + cpd = (struct Dbg_CoProDesc *)arg2; + packet = DevSW_AllocatePacket(Armsd_BufferSize); + if (angel_RDI_info(ADP_Info_CoPro, NULL, NULL) != RDIError_NoError) + return RDIError_Error; + len = msgbuild(BUFFERDATA(packet->pk_buffer), "%w%w%w%w%w", ADP_Info | HtoT, 0, + ADP_HandleUnknown, ADP_HandleUnknown, + ADP_Info_DescribeCoPro); + len +=msgbuild(BUFFERDATA(packet->pk_buffer)+20, "%b%b%b%b%b", cpnum, + cpd->regdesc[cpnum].rmin, cpd->regdesc[cpnum].rmax, + cpd->regdesc[cpnum].nbytes, cpd->regdesc[cpnum].access); + if (cpd->regdesc[cpnum].access&0x3 == 0x3){ + len += msgbuild(BUFFERDATA(packet->pk_buffer)+25, "%b%b%b%b%b", + cpd->regdesc[cpnum].accessinst.cprt.read_b0, + cpd->regdesc[cpnum].accessinst.cprt.read_b1, + cpd->regdesc[cpnum].accessinst.cprt.write_b0, + cpd->regdesc[cpnum].accessinst.cprt.write_b1, 0xff); + } + else { + len += msgbuild(BUFFERDATA(packet->pk_buffer)+25, "%b%b%b%b%b%", + cpd->regdesc[cpnum].accessinst.cpdt.rdbits, + cpd->regdesc[cpnum].accessinst.cpdt.nbit,0,0, 0xff); + } + register_debug_message_handler(); + packet->pk_length = len; + Adp_ChannelWrite(CI_HADP, packet); /* Transmit message. */ + reason = ADP_Info |TtoH; + err = wait_for_debug_message(&reason, &debugID, &OSinfo1, &OSinfo2, + &status, &packet); + if (err != RDIError_NoError) { + DevSW_FreePacket(packet); + return err; + } + unpack_message(BUFFERDATA(packet->pk_buffer), "%w%w%w%w%w%w", &reason, &debugID, + &OSinfo1, &OSinfo2, &subreason, &status); + DevSW_FreePacket(packet); + if (subreason != ADP_Info_DescribeCoPro) + return RDIError_Error; + else + return status; + + case RDIInfo_RequestCoProDesc: +#ifdef DEBUG + angel_DebugPrint("DEBUG: RDIInfo_RequestCoProDesc.\n"); +#endif + cpnum = *(int *)arg1; + cpd = (struct Dbg_CoProDesc *)arg2; + packet = DevSW_AllocatePacket(Armsd_BufferSize); + len = msgbuild(BUFFERDATA(packet->pk_buffer), "%w%w%w%w%w", ADP_Info | HtoT, 0, + ADP_HandleUnknown, ADP_HandleUnknown, + ADP_Info_RequestCoProDesc); + len += msgbuild(BUFFERDATA(packet->pk_buffer)+20, "%b", *(int *)arg1); + packet->pk_length = len; + register_debug_message_handler(); + Adp_ChannelWrite(CI_HADP, packet); /* Transmit message. */ + reason = ADP_Info |TtoH; + err = wait_for_debug_message(&reason, &debugID, &OSinfo1, &OSinfo2, + &status, &packet); + if (err != RDIError_NoError) { + DevSW_FreePacket(packet); + return err; + } + count = unpack_message(BUFFERDATA(packet->pk_buffer), "%w%w%w%w%w%w", &reason, + &debugID, &OSinfo1, &OSinfo2, &subreason, &status); + if (subreason != ADP_Info_RequestCoProDesc) { + DevSW_FreePacket(packet); + return RDIError_Error; + } else if ( status != RDIError_NoError ) { + DevSW_FreePacket(packet); + return status; + } else { + bp = BUFFERDATA(packet->pk_buffer)+count; + for ( i = 0; *bp != 0xFF && i < cpd->entries; ++i ) { + cpd->regdesc[i].rmin = *bp++; + cpd->regdesc[i].rmax = *bp++; + cpd->regdesc[i].nbytes = *bp++; + cpd->regdesc[i].access = *bp++; + } + cpd->entries = i; + if ( *bp != 0xFF ) + status = RDIError_BufferFull; + else + SetCPWords( cpnum, cpd ); + DevSW_FreePacket(packet); + return status; + } + + case RDIInfo_GetLoadSize: +#ifdef DEBUG + angel_DebugPrint("DEBUG: ADP_Info_AngelBufferSize.\n"); +#endif + register_debug_message_handler(); + msgsend(CI_HADP, "%w%w%w%w%w", ADP_Info | HtoT, 0, + ADP_HandleUnknown, ADP_HandleUnknown, + ADP_Info_AngelBufferSize); + reason = ADP_Info |TtoH; + err = wait_for_debug_message(&reason, &debugID, &OSinfo1, &OSinfo2, + &status, &packet); + if (err != RDIError_NoError) { + DevSW_FreePacket(packet); + return err; + } + unpack_message(BUFFERDATA(packet->pk_buffer), "%w%w%w%w%w%w", &reason, + &debugID, &OSinfo1, &OSinfo2, &subreason, &status); + if (subreason != ADP_Info_AngelBufferSize) { + DevSW_FreePacket(packet); + return RDIError_Error; + } + else { + word defaultsize, longsize; + unpack_message(BUFFERDATA(packet->pk_buffer)+24, "%w%w", + &defaultsize, &longsize); + *arg1 = longsize - ADP_WriteHeaderSize; /* space for ADP header */ +#ifdef MONITOR_DOWNLOAD_PACKETS + angel_DebugPrint("DEBUG: ADP_Info_AngelBufferSize: got (%d, %d), returning %d.\n", + defaultsize, longsize, *arg1); +#endif + DevSW_FreePacket(packet); + return status; + } + + case RDIVector_Catch: +#ifdef DEBUG + angel_DebugPrint("DEBUG: ADP_Ctrl_VectorCatch %lx.\n", *arg1); +#endif + return SendSubMessageWordAndCheckReply(ADP_Control, ADP_Ctrl_VectorCatch, *arg1); + + case RDISemiHosting_SetState: +#ifdef DEBUG + angel_DebugPrint("DEBUG: ADP_Ctrl_SemiHosting_SetState %lx.\n", *arg1); +#endif + return SendSubMessageWordAndCheckReply(ADP_Control, ADP_Ctrl_SemiHosting_SetState, *arg1); + + case RDISemiHosting_GetState: +#ifdef DEBUG + angel_DebugPrint("DEBUG: ADP_Ctrl_SemiHosting_GetState.\n"); +#endif + return SendSubMessageGetWordAndCheckReply(ADP_Control, ADP_Ctrl_SemiHosting_GetState, arg1); + + case RDISemiHosting_SetVector: +#ifdef DEBUG + angel_DebugPrint("DEBUG: ADP_Ctrl_SemiHosting_SetVector %lx.\n", *arg1); +#endif + return SendSubMessageWordAndCheckReply(ADP_Control, ADP_Ctrl_SemiHosting_SetVector, *arg1); + + case RDISemiHosting_GetVector: +#ifdef DEBUG + angel_DebugPrint("DEBUG: ADP_Ctrl_SemiHosting_GetVector.\n"); +#endif + return SendSubMessageGetWordAndCheckReply(ADP_Control, ADP_Ctrl_SemiHosting_GetVector, arg1); + + case RDISemiHosting_SetARMSWI: +#ifdef DEBUG + angel_DebugPrint("DEBUG: ADP_Ctrl_SemiHosting_SetARMSWI.\n"); +#endif + return SendSubMessageWordAndCheckReply(ADP_Control, ADP_Ctrl_SemiHosting_SetARMSWI, *arg1); + + case RDISemiHosting_GetARMSWI: +#ifdef DEBUG + angel_DebugPrint("DEBUG: ADP_Ctrl_SemiHosting_GetARMSWI.\n"); +#endif + return SendSubMessageGetWordAndCheckReply(ADP_Control, ADP_Ctrl_SemiHosting_GetARMSWI, arg1); + + case RDISemiHosting_SetThumbSWI: +#ifdef DEBUG + angel_DebugPrint("DEBUG: ADP_Ctrl_SemiHosting_SetThumbSWI.\n"); +#endif + return SendSubMessageWordAndCheckReply(ADP_Control, ADP_Ctrl_SemiHosting_SetThumbSWI, *arg1); + + case RDISemiHosting_GetThumbSWI: +#ifdef DEBUG + angel_DebugPrint("DEBUG: ADP_Ctrl_SemiHosting_GetThumbSWI.\n"); +#endif + return SendSubMessageGetWordAndCheckReply(ADP_Control, ADP_Ctrl_SemiHosting_GetThumbSWI, arg1); + + case RDIInfo_SetTopMem: +#ifdef DEBUG + angel_DebugPrint("DEBUG: ADP_Ctrl_SetTopMem.\n"); +#endif + return SendSubMessageWordAndCheckReply(ADP_Control, ADP_Ctrl_SetTopMem, *arg1); + + case RDIPointStatus_Watch: +#ifdef DEBUG + angel_DebugPrint("DEBUG: ADP_Ctrl_PointStatus_Watch.\n"); +#endif + register_debug_message_handler(); + msgsend(CI_HADP, "%w%w%w%w%w%w", ADP_Control | HtoT, 0, + ADP_HandleUnknown, ADP_HandleUnknown, + ADP_Ctrl_PointStatus_Watch, *arg1 ); + reason = ADP_Control |TtoH; + err = wait_for_debug_message(&reason, &debugID, &OSinfo1, &OSinfo2, + &status, &packet); + if (err != RDIError_NoError) { + DevSW_FreePacket(packet); + return err; + } + unpack_message(BUFFERDATA(packet->pk_buffer), "%w%w%w%w%w%w%w%w", &reason, + &debugID, &OSinfo1, &OSinfo2, &subreason, &status, + arg1, arg2); + if (subreason != ADP_Ctrl_PointStatus_Watch) { + DevSW_FreePacket(packet); + return RDIError_Error; + } + else + return status; + + case RDIPointStatus_Break: +#ifdef DEBUG + angel_DebugPrint("DEBUG: ADP_Ctrl_PointStatus_Break.\n"); +#endif + register_debug_message_handler(); + msgsend(CI_HADP, "%w%w%w%w%w%w", ADP_Control | HtoT, 0, + ADP_HandleUnknown, ADP_HandleUnknown, + ADP_Ctrl_PointStatus_Break, *arg1 ); + reason = ADP_Control |TtoH; + err = wait_for_debug_message(&reason, &debugID, &OSinfo1, &OSinfo2, + &status, &packet); + if (err != RDIError_NoError) { + DevSW_FreePacket(packet); + return err; + } + unpack_message(BUFFERDATA(packet->pk_buffer), "%w%w%w%w%w%w%w%w", &reason, + &debugID, &OSinfo1, &OSinfo2, &subreason, &status, + arg1, arg2); + if (subreason != ADP_Ctrl_PointStatus_Break) { + DevSW_FreePacket(packet); + return RDIError_Error; + } + else + return status; + + case RDIInfo_DownLoad: +#ifdef DEBUG + angel_DebugPrint("DEBUG: ADP_Ctrl_Download_Supported.\n"); +#endif + return SendSubMessageAndCheckReply(ADP_Control, ADP_Ctrl_Download_Supported); + + case RDIConfig_Count: +#ifdef DEBUG + angel_DebugPrint("DEBUG: ADP_ICEM_ConfigCount.\n"); +#endif + return SendSubMessageGetWordAndCheckReply(ADP_ICEman, ADP_ICEM_ConfigCount, arg1); + + case RDIConfig_Nth: +#ifdef DEBUG + angel_DebugPrint("DEBUG: ADP_ICEM_ConfigNth.\n"); +#endif + register_debug_message_handler(); + msgsend(CI_HADP, "%w%w%w%w%w%w", ADP_ICEman | HtoT, 0, + ADP_HandleUnknown, ADP_HandleUnknown, + ADP_ICEM_ConfigNth, *arg1 ); + reason = ADP_ICEman |TtoH; + err = wait_for_debug_message(&reason, &debugID, &OSinfo1, &OSinfo2, + &status, &packet); + if (err != RDIError_NoError) { + DevSW_FreePacket(packet); + return err; + } else { + RDI_ConfigDesc *cd = (RDI_ConfigDesc *)arg2; + unsigned char n; + len = unpack_message(BUFFERDATA(packet->pk_buffer), "%w%w%w%w%w%w%w%b", + &reason, &debugID, + &OSinfo1, &OSinfo2, &subreason, &status, + &cd->version, &n); + if (subreason != ADP_ICEM_ConfigNth) { + DevSW_FreePacket(packet); + return RDIError_Error; + } + else { + memcpy( cd->name, BUFFERDATA(packet->pk_buffer)+len, n+1 ); + cd->name[n] = 0; + return status; + } + } + + case RDIInfo_Icebreaker: +#ifdef DEBUG + angel_DebugPrint("DEBUG: ADP_ICEB_Exists.\n"); +#endif + return SendSubMessageAndCheckReply(ADP_ICEbreakerHADP, ADP_ICEB_Exists); + + case RDIIcebreaker_GetLocks: +#ifdef DEBUG + angel_DebugPrint("DEBUG: ADP_ICEB_GetLocks.\n"); +#endif + return SendSubMessageGetWordAndCheckReply(ADP_ICEbreakerHADP, ADP_ICEB_GetLocks, arg1); + + case RDIIcebreaker_SetLocks: +#ifdef DEBUG + angel_DebugPrint("DEBUG: ADP_ICEB_SetLocks.\n"); +#endif + return SendSubMessageWordAndCheckReply(ADP_ICEbreakerHADP, ADP_ICEB_SetLocks, *arg1); + + case RDICommsChannel_ToHost: +#ifdef DEBUG + angel_DebugPrint("DEBUG: ADP_ICEB_CC_Connect_ToHost.\n"); +#endif + if ( angel_cc_exists() == RDIError_NoError ) { + + /* + * The following three lines of code have to be removed in order to get + * the Windows Angel Channel Viewer working with the Thumb comms channel. + * At the moment it allows the ARMSD command line to register a CCIN/CCOUT + * callback which stops the ACV working! + */ +#ifdef __unix + ccstate.tohost = (RDICCProc_ToHost *)arg1; + ccstate.tohostarg = arg2; + angel_check_DCC_handler( &ccstate ); +#endif +#ifdef _WIN32 + +#endif + + register_debug_message_handler(); + msgsend(CI_HADP, "%w%w%w%w%w%b", ADP_ICEbreakerHADP | HtoT, 0, + ADP_HandleUnknown, ADP_HandleUnknown, + ADP_ICEB_CC_Connect_ToHost, (arg1 != NULL) ); + return CheckSubMessageReply(ADP_ICEbreakerHADP, ADP_ICEB_CC_Connect_ToHost); + } else { + return RDIError_UnimplementedMessage; + } + + case RDICommsChannel_FromHost: +#ifdef DEBUG + angel_DebugPrint("DEBUG: ADP_ICEB_CC_Connect_FromHost.\n"); +#endif + if ( angel_cc_exists() == RDIError_NoError ) { + + ccstate.fromhost = (RDICCProc_FromHost *)arg1; + ccstate.fromhostarg = arg2; + angel_check_DCC_handler( &ccstate ); + + register_debug_message_handler(); + msgsend(CI_HADP, "%w%w%w%w%w%b", ADP_ICEbreakerHADP | HtoT, 0, + ADP_HandleUnknown, ADP_HandleUnknown, + ADP_ICEB_CC_Connect_FromHost, (arg1 != NULL) ); + return CheckSubMessageReply(ADP_ICEbreakerHADP, ADP_ICEB_CC_Connect_FromHost); + } else { + return RDIError_UnimplementedMessage; + } + + case RDIProfile_Stop: + return SendSubMessageAndCheckReply(ADP_Profile, ADP_Profile_Stop); + + case RDIProfile_ClearCounts: + return SendSubMessageAndCheckReply(ADP_Profile, ADP_Profile_ClearCounts); + + case RDIProfile_Start: +#ifdef DEBUG + angel_DebugPrint("DEBUG: ADP_Profile_Start %ld.\n", (long)*arg1); +#endif + return SendSubMessageWordAndCheckReply(ADP_Profile, ADP_Profile_Start, *arg1); + + case RDIProfile_WriteMap: + { RDI_ProfileMap *map = (RDI_ProfileMap *)arg1; + int32 maplen = map->len, + offset, + size; + int32 chunk = (Armsd_LongBufSize-CHAN_HEADER_SIZE-ADP_ProfileWriteHeaderSize) / sizeof(ARMword); + /* Maximum number of words sendable in one message */ + int oldrev = bytesex_reversing(); + int host_little = *(uint8 const *)&hostsex; +#ifdef DEBUG + angel_DebugPrint("DEBUG: ADP_Profile_WriteMap %ld.\n", maplen); +#endif + status = RDIError_NoError; + if (!host_little) { + bytesex_reverse(1); + for (offset = 0; offset < maplen; offset++) + map->map[offset] = bytesex_hostval(map->map[offset]); + } + for (offset = 0; offset < maplen; offset += size) { + unsigned hdrlen; + size = maplen - offset; + packet = (Packet *)DevSW_AllocatePacket(Armsd_LongBufSize); + if (size > chunk) size = chunk; + hdrlen = msgbuild(BUFFERDATA(packet->pk_buffer), "%w%w%w%w%w%w%w%w", + ADP_Profile | HtoT, 0, ADP_HandleUnknown, + ADP_HandleUnknown, ADP_Profile_WriteMap, + maplen, size, offset); + + /* Copy the data into the packet. */ + memcpy(BUFFERDATA(packet->pk_buffer)+hdrlen, + &map->map[offset], (size_t)size * sizeof(ARMword)); + packet->pk_length = size * sizeof(ARMword) + hdrlen; + register_debug_message_handler(); + Adp_ChannelWrite(CI_HADP, packet); + reason = ADP_Profile | TtoH; + err = wait_for_debug_message(&reason, &debugID, &OSinfo1, &OSinfo2, + &status, &packet); + if (err == RDIError_NoError) { + unpack_message(BUFFERDATA(packet->pk_buffer), "%w%w%w%w%w%w", &reason, + &debugID, &OSinfo1, &OSinfo2, &subreason, &status); + if (subreason != ADP_Profile_WriteMap) { + err = RDIError_Error; + } + DevSW_FreePacket(packet); + } + if (err != RDIError_NoError) { status = err; break; } + } + if (!host_little) { + for (offset = 0; offset < maplen; offset++) + map->map[offset] = bytesex_hostval(map->map[offset]); + bytesex_reverse(oldrev); + } + return status; + } + + case RDIProfile_ReadMap: + { int32 maplen = *(int32 *)arg1, + offset = 0, + size; + int32 chunk = (Armsd_BufferSize-CHAN_HEADER_SIZE-ADP_ProfileReadHeaderSize) / sizeof(ARMword); +#ifdef DEBUG + angel_DebugPrint("DEBUG: ADP_Profile_ReadMap %ld.\n", maplen); +#endif + status = RDIError_NoError; + for (offset = 0; offset < maplen; offset += size) { + size = maplen - offset; + if (size > chunk) size = chunk; + register_debug_message_handler(); + msgsend(CI_HADP, "%w%w%w%w%w%w%w", ADP_Profile | HtoT, 0, + ADP_HandleUnknown, ADP_HandleUnknown, + ADP_Profile_ReadMap, offset, size); + reason = ADP_Profile | TtoH; + err = wait_for_debug_message(&reason, &debugID, &OSinfo1, &OSinfo2, + &status, &packet); + if (err != RDIError_NoError) return err; + unpack_message(BUFFERDATA(packet->pk_buffer), "%w%w%w%w%w%w", &reason, + &debugID, &OSinfo1, &OSinfo2, &subreason, &status); + memcpy(&arg2[offset], BUFFERDATA(packet->pk_buffer)+ADP_ProfileReadHeaderSize, + size * sizeof(ARMword)); + DevSW_FreePacket(packet); + if (status != RDIError_NoError) break; + } + { int oldrev = bytesex_reversing(); + int host_little = *(uint8 const *)&hostsex; + if (!host_little) { + bytesex_reverse(1); + for (offset = 0; offset < maplen; offset++) + arg2[offset] = bytesex_hostval(arg2[offset]); + } + bytesex_reverse(oldrev); + } + return status; + } + + case RDIInfo_CanTargetExecute: +#ifdef DEBUG + printf("DEBUG: RDIInfo_CanTargetExecute.\n"); +#endif + return SendSubMessageAndCheckReply(ADP_Info, ADP_Info_CanTargetExecute); + + case RDIInfo_AgentEndianess: + return SendSubMessageAndCheckReply(ADP_Info, ADP_Info_AgentEndianess); + + default: +#ifdef DEBUG + angel_DebugPrint("DEBUG: Fell through ADP_Info, default case taken.\n"); + angel_DebugPrint("DEBUG: type = 0x%x.\n", type); +#endif + if (type & RDIInfo_CapabilityRequest) { + switch (type & ~RDIInfo_CapabilityRequest) { + case RDISemiHosting_SetARMSWI: + return SendSubMessageAndCheckReply(ADP_Info, ADP_Info_ChangeableSHSWI); + default: +#ifdef DEBUG + angel_DebugPrint( + "DEBUG: ADP_Info - Capability Request(%d) - reporting unimplemented \n", + type & ~RDIInfo_CapabilityRequest); +#endif + break; + } + } + return RDIError_UnimplementedMessage; + } +} + + +/*----------------------------------------------------------------------*/ +/*----angel_RDI_AddConfig------------------------------------------------*/ +/*----------------------------------------------------------------------*/ + +/* Add a configuration: use ADP_ICEM_AddConfig. */ +int angel_RDI_AddConfig(unsigned long nbytes) { + Packet *packet = NULL; + int status, reason, subreason, debugID, OSinfo1, OSinfo2, err; + +#ifdef DEBUG + angel_DebugPrint("DEBUG: Entered angel_RDI_AddConfig.\n"); +#endif + register_debug_message_handler(); + msgsend(CI_HADP, "%w%w%w%w%w%w", ADP_ICEman | HtoT, + 0, ADP_HandleUnknown, ADP_HandleUnknown, + ADP_ICEM_AddConfig, nbytes); + reason=ADP_ICEman | TtoH; + err = wait_for_debug_message(&reason, &debugID, &OSinfo1, &OSinfo2, + &status, &packet); + if (err != RDIError_NoError) { + DevSW_FreePacket(packet); + return -1; + } + unpack_message(BUFFERDATA(packet->pk_buffer), "%w%w%w%w%w%w", &reason, &debugID, + &OSinfo1, &OSinfo2, &subreason, &status); + DevSW_FreePacket(packet); + if ( subreason != ADP_ICEM_AddConfig ) + return RDIError_Error; + else + return status; +} + + +/*----------------------------------------------------------------------*/ +/*----angel_RDI_LoadConfigData-------------------------------------------*/ +/*----------------------------------------------------------------------*/ + +/* Load configuration data: use ADP_Ctrl_Download_Data. */ +int angel_RDI_LoadConfigData(unsigned long nbytes, char const *data) { + Packet *packet = NULL; + int len, status, reason, subreason, debugID, OSinfo1, OSinfo2, err; + +#ifdef DEBUG + angel_DebugPrint("DEBUG: Entered angel_RDI_LoadConfigData (%d bytes)\n", nbytes); +#endif +#if 0 + if (err = angel_RDI_AddConfig(nbytes) != RDIError_NoError) + return err; +#endif + packet = DevSW_AllocatePacket(Armsd_LongBufSize); + len = msgbuild(BUFFERDATA(packet->pk_buffer), "%w%w%w%w%w%w", + ADP_Control | HtoT, 0, + ADP_HandleUnknown, ADP_HandleUnknown, + ADP_Ctrl_Download_Data, nbytes); + memcpy(BUFFERDATA(packet->pk_buffer)+len, data, nbytes); + len += nbytes; + packet->pk_length = len; +#ifdef DEBUG + angel_DebugPrint("DEBUG: packet len %d.\n", len); +#endif + register_debug_message_handler(); + Adp_ChannelWrite(CI_HADP, packet); + reason=ADP_Control | TtoH; + err = wait_for_debug_message(&reason, &debugID, &OSinfo1, &OSinfo2, + &status, &packet); + if (err != RDIError_NoError) { + DevSW_FreePacket(packet); + return -1; + } + unpack_message(BUFFERDATA(packet->pk_buffer), "%w%w%w%w%w%w", &reason, &debugID, + &OSinfo1, &OSinfo2, &subreason, &status); + DevSW_FreePacket(packet); + if ( subreason != ADP_Ctrl_Download_Data ) + return RDIError_Error; + else + return status; +} + + +/*----------------------------------------------------------------------*/ +/*----angel_RDI_SelectConfig---------------------------------------------*/ +/*----------------------------------------------------------------------*/ + +/* Select a configuration: use ADP_ICEM_SelecConfig.*/ +int angel_RDI_SelectConfig(RDI_ConfigAspect aspect, char const *name, + RDI_ConfigMatchType matchtype, unsigned versionreq, + unsigned *versionp) +{ + Packet *packet = NULL; + int len, status, reason, subreason, debugID, OSinfo1, OSinfo2, err; + +#ifdef DEBUG + angel_DebugPrint("DEBUG: Entered angel_RDI_SelectConfig.\n"); +#endif + packet = DevSW_AllocatePacket(Armsd_BufferSize); + len = msgbuild(BUFFERDATA(packet->pk_buffer), "%w%w%w%w%w%b%b%b%w", + ADP_ICEman | HtoT, 0, + ADP_HandleUnknown, ADP_HandleUnknown, + ADP_ICEM_SelectConfig, aspect, strlen(name), + matchtype, versionreq); + /* copy the name into the buffer */ + memcpy(BUFFERDATA(packet->pk_buffer)+len, name, strlen(name)); + len += strlen(name); + packet->pk_length = len; + register_debug_message_handler(); + Adp_ChannelWrite(CI_HADP, packet); + reason=ADP_ICEman | TtoH; + err = wait_for_debug_message(&reason, &debugID, &OSinfo1, &OSinfo2, + &status, &packet); + if (err != RDIError_NoError) { + DevSW_FreePacket(packet); + return err; + } + unpack_message(BUFFERDATA(packet->pk_buffer), "%w%w%w%w%w%w%w", + &reason, &debugID, &OSinfo1, &OSinfo2, + &subreason, &status, versionp); + DevSW_FreePacket(packet); + if ( subreason != ADP_ICEM_SelectConfig ) + return RDIError_Error; + else + return status; +} + + +/*----------------------------------------------------------------------*/ +/*----angel_RDI_LoadAgent------------------------------------------------*/ +/*----------------------------------------------------------------------*/ + +/* Load a new debug agent: use ADP_Ctrl_Download_Agent. */ +int angel_RDI_LoadAgent(ARMword dest, unsigned long size, + getbufferproc *getb, void *getbarg) +{ + Packet *packet = NULL; + int status, reason, subreason, debugID, OSinfo1, OSinfo2, err; + time_t t; + +#if defined(DEBUG) || defined(DEBUG_LOADAGENT) + angel_DebugPrint("DEBUG: Entered angel_RDI_LoadAgent.\n"); +#endif + register_debug_message_handler(); + msgsend(CI_HADP, "%w%w%w%w%w%w%w", ADP_Control | HtoT, + 0, ADP_HandleUnknown, ADP_HandleUnknown, + ADP_Ctrl_Download_Agent, dest, size); + reason=ADP_Control | TtoH; + err = wait_for_debug_message(&reason, &debugID, &OSinfo1, &OSinfo2, + &status, &packet); + if (err != RDIError_NoError) { + DevSW_FreePacket(packet); + return -1; + } + unpack_message(BUFFERDATA(packet->pk_buffer), "%w%w%w%w%w%w", &reason, &debugID, + &OSinfo1, &OSinfo2, &subreason, &status); + DevSW_FreePacket(packet); + if ( subreason != ADP_Ctrl_Download_Agent ) + return RDIError_Error; + if ( status != RDIError_NoError ) + return status; + +#if defined(DEBUG) || defined(DEBUG_LOADAGENT) + angel_DebugPrint("DEBUG: starting agent data download.\n"); +#endif + { unsigned long pos = 0, segsize; + for (; pos < size; pos += segsize) { + char *b = getb(getbarg, &segsize); + if (b == NULL) return RDIError_NoError; + err = angel_RDI_LoadConfigData( segsize, b ); + if (err != RDIError_NoError) return err; + } + } +#if defined(DEBUG) || defined(DEBUG_LOADAGENT) + angel_DebugPrint("DEBUG: finished downloading new agent.\n"); +#endif + + /* renegotiate back down */ + err = angel_negotiate_defaults(); + if (err != adp_ok) + return err; + + /* Output a message to tell the user what is going on. This is vital + * when switching from ADP EICE to ADP over JTAG, as then the user + * has to reset the target board ! + */ + { char msg[256]; + int len=angel_RDI_errmess(msg, 256, adp_new_agent_starting); + angel_hostif->write(angel_hostif->hostosarg, msg, len); + } + + /* get new image started */ +#if defined(DEBUG) || defined(DEBUG_LOADAGENT) + angel_DebugPrint("DEBUG: sending start message for new agent.\n"); +#endif + + register_debug_message_handler(); + msgsend(CI_HADP, "%w%w%w%w%w%w", ADP_Control | HtoT, + 0, ADP_HandleUnknown, ADP_HandleUnknown, + ADP_Ctrl_Start_Agent, dest); + reason=ADP_Control | TtoH; + err = wait_for_debug_message(&reason, &debugID, &OSinfo1, &OSinfo2, + &status, &packet); + if (err != RDIError_NoError) { + DevSW_FreePacket(packet); + return -1; + } + unpack_message(BUFFERDATA(packet->pk_buffer), "%w%w%w%w%w%w", &reason, + &debugID, &OSinfo1, &OSinfo2, &subreason, &status); + DevSW_FreePacket(packet); + if ( subreason != ADP_Ctrl_Start_Agent ) + return RDIError_Error; + if ( status != RDIError_NoError ) + return status; + + /* wait for image to start up */ + heartbeat_enabled = FALSE; + t=time(NULL); + do { + Adp_AsynchronousProcessing(async_block_on_nothing); + if ((time(NULL)-t) > 2) { +#ifdef DEBUG + angel_DebugPrint("DEBUG: no booted message from new image yet.\n"); +#endif + break; + } + } while (booted_not_received); + booted_not_received=1; + + /* Give device driver a chance to do any necessary resyncing with new agent. + * Only used by etherdrv.c at the moment. + */ + (void)Adp_Ioctl( DC_RESYNC, NULL ); + +#if defined(DEBUG) || defined(DEBUG_LOADAGENT) + angel_DebugPrint("DEBUG: reopening to new agent.\n"); +#endif + err = angel_RDI_open(0, NULL, NULL, NULL); + switch ( err ) + { + case RDIError_NoError: + { +#if defined(DEBUG) || defined(DEBUG_LOADAGENT) + angel_DebugPrint( "LoadAgent: Open returned RDIError_NoError\n" ); +#endif + break; + } + + case RDIError_LittleEndian: + { +#if defined(DEBUG) || defined(DEBUG_LOADAGENT) + angel_DebugPrint( "LoadAgent: Open returned RDIError_LittleEndian (OK)\n" ); +#endif + err = RDIError_NoError; + break; + } + + case RDIError_BigEndian: + { +#if defined(DEBUG) || defined(DEBUG_LOADAGENT) + angel_DebugPrint( "LoadAgent: Open returned RDIError_BigEndian (OK)\n" ); +#endif + err = RDIError_NoError; + break; + } + + default: + { +#if defined(DEBUG) || defined(DEBUG_LOADAGENT) + angel_DebugPrint( "LoadAgent: Open returned %d - unexpected!\n", err ); +#endif + break; + } + } +#ifndef NO_HEARTBEAT + heartbeat_enabled = TRUE; +#endif + return err; +} + +static int angel_RDI_errmess(char *buf, int blen, int errnum) { + char *s=NULL; + int n; + + switch (errnum) { + case adp_malloc_failure: + s=AdpMess_MallocFailed; break; + case adp_illegal_args: + s=AdpMess_IllegalArgs; break; + case adp_device_not_found: + s=AdpMess_DeviceNotFound; break; + case adp_device_open_failed: + s=AdpMess_DeviceOpenFailed; break; + case adp_device_already_open: + s=AdpMess_DeviceAlreadyOpen; break; + case adp_device_not_open: + s=AdpMess_DeviceNotOpen; break; + case adp_bad_channel_id: + s=AdpMess_BadChannelId; break; + case adp_callback_already_registered: + s=AdpMess_CBAlreadyRegd; break; + case adp_write_busy: + s=AdpMess_WriteBusy; break; + case adp_bad_packet: + s=AdpMess_BadPacket; break; + case adp_seq_high: + s=AdpMess_SeqHigh; break; + case adp_seq_low: + s=AdpMess_SeqLow; break; + case adp_timeout_on_open: + s=AdpMess_TimeoutOnOpen; break; + case adp_failed: + s=AdpMess_Failed; break; + case adp_abandon_boot_wait: + s=AdpMess_AbandonBootWait; break; + case adp_late_startup: + s=AdpMess_LateStartup; break; + case adp_new_agent_starting: + s=AdpMess_NewAgentStarting; break; + default: return 0; + } + n=strlen(s); + if (n>blen-1) n=blen-1; + memcpy(buf, s, n); + buf[n++]=0; + return n; +} + +extern const struct RDIProcVec angel_rdi; +const struct RDIProcVec angel_rdi = { + "ADP", + angel_RDI_open, + angel_RDI_close, + angel_RDI_read, + angel_RDI_write, + angel_RDI_CPUread, + angel_RDI_CPUwrite, + angel_RDI_CPread, + angel_RDI_CPwrite, + angel_RDI_setbreak, + angel_RDI_clearbreak, + angel_RDI_setwatch, + angel_RDI_clearwatch, + angel_RDI_execute, + angel_RDI_step, + angel_RDI_info, + angel_RDI_pointinq, + + angel_RDI_AddConfig, + angel_RDI_LoadConfigData, + angel_RDI_SelectConfig, + + 0, /*angel_RDI_drivernames,*/ + 0, /* cpunames */ + + angel_RDI_errmess, + + angel_RDI_LoadAgent +}; + +/* EOF ardi.c */ + +/* Not strictly necessary, but allows linking this code into armsd. */ + +struct foo { + char *name; + int (*action)(); + char *syntax; + char **helpmessage; + int doafterend; + int dobeforestart; + int doinmidline; +} hostappl_CmdTable[1] = {{"", NULL}}; + +void +hostappl_Init() +{ +} + +int +hostappl_Backstop() +{ + return -30; +} diff --git a/gdb/rdi-share/ardi.h b/gdb/rdi-share/ardi.h new file mode 100644 index 00000000000..66acd1ad04c --- /dev/null +++ b/gdb/rdi-share/ardi.h @@ -0,0 +1,85 @@ +/* + * Copyright (C) 1995 Advanced RISC Machines Limited. All rights reserved. + * + * This software may be freely used, copied, modified, and distributed + * provided that the above copyright notice is preserved in all copies of the + * software. + */ + +/* + * ardi.h + * ADP RDI interfaces + * + * $Revision$ + * $Date$ + */ + +#include "host.h" + +typedef unsigned32 ARMword; + +#include "dbg_rdi.h" +#include "dbg_conf.h" + +extern char *commandline; +extern ARMword last_vector_catch; + +/* This is the size of buffers that are asked for by standard channels + * Non standard channels may wish to copy this! + */ +extern int Armsd_BufferSize; + +typedef int (*host_ChannelBufferFilledFnPtr)(unsigned int ,unsigned char ** ,void *); + +int angel_RDI_open( + unsigned type, Dbg_ConfigBlock const *config, + Dbg_HostosInterface const *hostif, struct Dbg_MCState *dbg_state); +int angel_RDI_close(void); + +int angel_RDI_read(ARMword source, void *dest, unsigned *nbytes); +int angel_RDI_write(const void *source, ARMword dest, unsigned *nbytes); + +int angel_RDI_CPUread(unsigned mode, unsigned long mask, ARMword *buffer); +int angel_RDI_CPUwrite(unsigned mode, unsigned long mask, + ARMword const *buffer); + +int angel_RDI_CPread(unsigned CPnum, unsigned long mask, ARMword *buffer); +int angel_RDI_CPwrite(unsigned CPnum, unsigned long mask, + ARMword const *buffer); + +int angel_RDI_setbreak(ARMword address, unsigned type, ARMword bound, + PointHandle *handle); +int angel_RDI_clearbreak(PointHandle handle); + +int angel_RDI_setwatch(ARMword address, unsigned type, unsigned datatype, + ARMword bound, PointHandle *handle); +int angel_RDI_clearwatch(PointHandle handle); + +int angel_RDI_pointinq(ARMword *address, unsigned type, unsigned datatype, + ARMword *bound); + +int angel_RDI_execute(PointHandle *handle); + +int angel_RDI_step(unsigned ninstr, PointHandle *handle); + +int angel_RDI_info(unsigned type, ARMword *arg1, ARMword *arg2); + +int angel_RDI_AddConfig(unsigned long nbytes); + +int angel_RDI_LoadConfigData(unsigned long nbytes, char const *data); + +int angel_RDI_SelectConfig(RDI_ConfigAspect aspect, char const *name, + RDI_ConfigMatchType matchtype, unsigned versionreq, + unsigned *versionp); + +RDI_NameList const *angel_RDI_drivernames(void); + +int angel_RDI_LoadAgent(ARMword dest, unsigned long size, getbufferproc *getb, + void *getbarg); + +extern const struct Dbg_HostosInterface *angel_hostif; + +typedef int angel_RDI_TargetStoppedProc(unsigned stopped_reason, void *arg); + +extern int angel_RDI_OnTargetStopping(angel_RDI_TargetStoppedProc *fn, + void *arg); diff --git a/gdb/rdi-share/armdbg.h b/gdb/rdi-share/armdbg.h new file mode 100644 index 00000000000..b5fae113281 --- /dev/null +++ b/gdb/rdi-share/armdbg.h @@ -0,0 +1,1452 @@ +/* + * Copyright (C) 1995 Advanced RISC Machines Limited. All rights reserved. + * + * This software may be freely used, copied, modified, and distributed + * provided that the above copyright notice is preserved in all copies of the + * software. + */ + +/* + * ARM symbolic debugger toolbox interface + */ + +/* + * RCS $Revision$ + * Checkin $Date$ + */ + +/* Minor points of uncertainty are indicated by a question mark in the + LH margin. + + Wherever an interface is required to iterate over things of some class, + I prefer something of the form EnumerateXXs(..., XXProc *p, void *arg) + which results in a call of p(xx, arg) for each xx, rather than something + of the form + for (xxh = StartIterationOverXXs(); (xx = Next(xxh)) != 0; ) { ... } + EndIterationOverXXs(xxh); + Others may disagree. + (Each XXProc returns an Error value: if this is not Err_OK, iteration + stops immediately and the EnumerateXXs function returns that value). + + ptrace has been retired as of insufficient utility. If such fuctionality is + required, it can be constructed using breakpoints. + + The file form of all name fields in debug areas is in-line, with a length + byte and no terminator. The debugger toolbox makes an in-store translation, + where the strings are out of line (the namep variant in asdfmt.h) and have a + terminating zero byte: the pointer is to the first character of the string + with the length byte at ...->n.namep[-1]. + */ + +#ifndef armdbg__h +#define armdbg__h + +#include + +#include "host.h" +#include "msg.h" + +typedef unsigned32 ARMaddress; +typedef unsigned32 ARMword; +typedef unsigned16 ARMhword; + +#include "dbg_conf.h" +#include "dbg_rdi.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +typedef unsigned char Dbg_Byte; + +typedef int Dbg_Error; + +typedef struct Dbg_MCState Dbg_MCState; +/* A representation of the state of the target. The structure is not revealed. + A pointer to one of these is returned by Dbg_Initialise(), is passed to all + toolbox calls which refer to the state of the target, and is discarded + by Dbg_Finalise(). + Nothing in the toolbox itself precludes there being multiple targets, each + with its own state. + */ + +/* Most toolbox interfaces return an error status. Only a few of the status + values are expected to be interesting to clients and defined here; the + rest are private (but a textual form can be produced by ErrorToChars()). + */ + +#define Error_OK 0 + +/* Partitioning of the error code space: errors below Dbg_Error_Base are RDI + errors (as defined in dbg_rdi.h). Codes above Dbg_Error_Limit are + available to clients, who may impose some further structure. + */ +#define Dbg_Error_Base 0x1000 +#define Dbg_Error_Limit 0x2000 + +#define DbgError(n) ((Dbg_Error)(Dbg_Error_Base+(n))) + +#define Dbg_Err_OK Error_OK +#define Dbg_Err_Interrupted DbgError(1) +#define Dbg_Err_Overflow DbgError(2) +#define Dbg_Err_FileNotFound DbgError(3) +#define Dbg_Err_ActivationNotPresent DbgError(4) +#define Dbg_Err_OutOfHeap DbgError(5) +#define Dbg_Err_TypeNotSimple DbgError(6) +#define Dbg_Err_BufferFull DbgError(7) +#define Dbg_Err_AtStackBase DbgError(8) +#define Dbg_Err_AtStackTop DbgError(9) +#define Dbg_Err_DbgTableFormat DbgError(10) +#define Dbg_Err_NotVariable DbgError(11) +#define Dbg_Err_NoSuchBreakPoint DbgError(12) +#define Dbg_Err_NoSuchWatchPoint DbgError(13) +#define Dbg_Err_FileLineNotFound DbgError(14) +#define Dbg_Err_DbgTableVersion DbgError(15) +#define Dbg_Err_NoSuchPath DbgError(16) +#define Dbg_Err_StateChanged DbgError(17) +#define Dbg_Err_SoftInitialiseError DbgError(18) +#define Dbg_Err_CoProRegNotWritable DbgError(19) +#define Dbg_Err_NotInHistory DbgError(20) +#define Dbg_Err_ContextSyntax DbgError(21) +#define Dbg_Err_ContextNoLine DbgError(22) +#define Dbg_Err_ContextTwoLines DbgError(23) +#define Dbg_Err_VarReadOnly DbgError(24) +#define Dbg_Err_FileNewerThanImage DbgError(25) +#define Dbg_Err_NotFound DbgError(26) + + /* functions which evaluate expressions may return this value, to indicate + that execution became suspended within a function called in the debugee */ + +/* Functions returning characters take a BufDesc argument, with fields buffer + and bufsize being input arguments describing the buffer to be filled, and + filled being set on return to the number of bytes written to the buffer + (omitting the terminating 0). + */ + +typedef struct Dbg_BufDesc Dbg_BufDesc; + +typedef void Dbg_BufferFullProc(Dbg_BufDesc *bd); + +struct Dbg_BufDesc { + char *buffer; + size_t size, + filled; + Dbg_BufferFullProc *p; + void *arg; +}; + +#define Dbg_InitBufDesc(bd, buf, bytes) \ + ((bd).buffer = (buf), (bd).size = (bytes), (bd).filled = 0,\ + (bd).p = NULL, (bd).arg = NULL) + +#define Dbg_InitBufDesc_P(bd, buf, bytes, fn, a) \ + ((bd).buffer = (buf), (bd).size = (bytes), (bd).filled = 0,\ + (bd).p = (fn), (bd).arg = (a)) + +Dbg_Error Dbg_StringToBuf(Dbg_BufDesc *buf, char const *s); +Dbg_Error Dbg_BufPrintf(Dbg_BufDesc *buf, char const *form, ...); +#ifdef NLS +Dbg_Error Dbg_MsgToBuf(Dbg_BufDesc *buf, msg_t t); +Dbg_Error Dbg_BufMsgPrintf(Dbg_BufDesc *buf, msg_t form, ...); +#else +#define Dbg_MsgToBuf Dbg_StringToBuf +#define Dbg_BufMsgPrintf Dbg_BufPrintf +#endif +Dbg_Error Dbg_CharToBuf(Dbg_BufDesc *buf, int ch); + +int Dbg_CIStrCmp(char const *s1, char const *s2); +/* Case-independent string comparison, interface as for strcmp */ + +int Dbg_CIStrnCmp(char const *s1, char const *s2, size_t n); +/* Case-independent string comparison, interface as for strncmp */ + +void Dbg_ErrorToChars(Dbg_MCState *state, Dbg_Error err, Dbg_BufDesc *buf); + +typedef int Dbg_RDIResetCheckProc(int); +/* Type of a function to be called after each RDI operation performed by the + toolbox, with the status from the operation as argument. The value returned + is treated as the status. (The intent is to allow the toolbox's client to + take special action to handle RDIDbg_Error_Reset). + */ + +typedef struct Dbg_CoProDesc Dbg_CoProDesc; + +typedef Dbg_Error Dbg_CoProFoundProc(Dbg_MCState *state, int cpno, Dbg_CoProDesc const *cpd); +/* Type of a function to be called when the shape of a coprocessor is discovered + by enquiry of the target or agent (via RequestCoProDesc) + */ + +typedef struct RDIProcVec RDIProcVec; + +Dbg_Error Dbg_RequestReset(Dbg_MCState *); + +Dbg_Error Dbg_Initialise( + Dbg_ConfigBlock *config, Dbg_HostosInterface const *i, + Dbg_RDIResetCheckProc *checkreset, Dbg_CoProFoundProc *coprofound, + RDIProcVec const *rdi, Dbg_MCState **statep); +/* values in config are updated if they call for default values */ + +void Dbg_Finalise(Dbg_MCState *state, bool targetdead); + +typedef struct { + char name[16]; + RDI_MemDescr md; + RDI_MemAccessStats a; +} Dbg_MemStats; + +/*--------------------------------------------------------------------------*/ + +/* Symbol table management. + The structure of a Dbg_SymTable is not revealed. It is created by + Dbg_ReadSymbols() or by Dbg_LoadFile(), and associated with the argument + Dbg_MCState. + Many symbol tables may be concurrently active. + A Dbg_SymTable is removed either explicitly (by call to Dbg_DeleteSymbols) + or implicitly when a symbol table for an overlapping address range is read. + + There is a pre-defined symbol table containing entries for ARM registers, + co-processor registers and the like. + */ + +typedef struct Dbg_SymTable Dbg_SymTable; + +typedef struct Dbg_ImageFragmentDesc { + ARMaddress base, limit; +} Dbg_ImageFragmentDesc; + +typedef enum { + Dbg_Lang_None, + Dbg_Lang_C, + Dbg_Lang_Pascal, + Dbg_Lang_Fortran, + Dbg_Lang_Asm, + Dbg_Lang_Cpp +} Dbg_Lang; + +typedef struct Dbg_ImageDesc { + Dbg_Lang lang; + int executable; + ARMaddress robase, rolimit, rwbase, rwlimit; + int nfrags; + Dbg_ImageFragmentDesc *fragments; + char *name; +} Dbg_ImageDesc; + +Dbg_ImageDesc *Dbg_ImageAreas(Dbg_SymTable *st); + +Dbg_SymTable *Dbg_LastImage(Dbg_MCState *state); + +Dbg_SymTable *Dbg_NewSymTable(Dbg_MCState *state, const char *name); + +Dbg_Error Dbg_ReadSymbols(Dbg_MCState *state, const char *filename, Dbg_SymTable **st); +/* Just read the symbols from the named image. is set to the allocated + symbol table. +? Maybe we could usefully allow other formats than AIF images to describe + the symbols (eg) of shared libraries + */ + +typedef struct Dbg_SymInfo { + int isize; + ARMaddress addr; + char *name; +} Dbg_SymInfo; + +Dbg_SymInfo *Dbg_AsmSym(Dbg_SymTable *st, ARMaddress addr); +int32 Dbg_AsmAddr(Dbg_SymTable *st, int32 line); +int32 Dbg_AsmLine(Dbg_SymTable *st, ARMaddress addr); +int32 Dbg_AsmLinesInRange(Dbg_SymTable *st, ARMaddress start, ARMaddress end); + +Dbg_Error Dbg_LoadFile(Dbg_MCState *state, const char *filename, Dbg_SymTable **st); +/* load the image into target memory, and read its symbols. is set to + the allocated symbol table. + A null filename reloads the most recently loaded file (and rereads its + symbols). + Loading an image leaves breakpoints unchanged. If a client wishes + otherwise, it must remove the breakpoints explicitly. +*/ + +Dbg_Error Dbg_CallGLoadFile(Dbg_MCState *state, const char *filename, Dbg_SymTable **st); + +typedef void Dbg_ImageLoadProc(Dbg_MCState *, Dbg_SymTable *); +Dbg_Error Dbg_OnImageLoad(Dbg_MCState *, Dbg_ImageLoadProc *); +/* Register function to be called back whenever an image is loaded, or symbols + * for an image read. (To allow multiple toolbox clients to coexist). + */ + +Dbg_Error Dbg_LoadAgent(Dbg_MCState *state, const char *filename); +/* Load a debug agent, and start it. + Symbols in the image for the agent are ignored. +*/ + +Dbg_Error Dbg_RelocateSymbols(Dbg_SymTable *st, ARMaddress reloc); +/* add to the value of all symbols in describing absolute memory + locations. The intent is to allow the symbols in a load-time relocating + image (for example) to be useful. + */ + +Dbg_Error Dbg_DeleteSymbols(Dbg_MCState *state, Dbg_SymTable **st); + +typedef enum Dbg_LLSymType { + llst_code, + llst_code16, + llst_data, + llst_const, + llst_unknown, + llst_max +} Dbg_LLSymType; +/* Since AIF images contain no type information for low-level symbols, this + classification is only a guess, and some symbols describing constants will + incorrectly be described as code or data. + */ + +typedef Dbg_Error Dbg_SymProc( + Dbg_MCState *state, + const char *symbol, Dbg_LLSymType symtype, ARMaddress value, + void *arg); + +Dbg_Error Dbg_EnumerateLowLevelSymbols( + Dbg_MCState *state, const char *match, Dbg_SymProc *p, + void *arg); +/* Call p(name, value) for each low level symbol in the tables of + whose name matches the regular expression (a NULL matches + any name). Symbols are enumerated in no particular order. + */ + +/*--------------------------------------------------------------------------*/ + +/* Functions are provided here to allow quick mass access to register values + for display. There is no comparable need for quick mass update, so writing + should be via Assign(). + */ + +typedef struct Dbg_RegSet { + ARMword + user[15], + pc, + psr, + fiq[7], + spsr_fiq, + irq[2], + spsr_irq, + svc[2], + spsr_svc, + abort[2], + spsr_abort, + undef[2], + spsr_undef; +} Dbg_RegSet; + +/* bits in the modemask argument for ReadRegisters */ + +#define Dbg_MM_User 1 +#define Dbg_MM_FIQ 2 +#define Dbg_MM_IRQ 4 +#define Dbg_MM_SVC 8 +#define Dbg_MM_Abort 0x10 +#define Dbg_MM_Undef 0x20 +#define Dbg_MM_System 0x40 + +Dbg_Error Dbg_ReadRegisters(Dbg_MCState *state, Dbg_RegSet *regs, int modemask); + +Dbg_Error Dbg_WriteRegister(Dbg_MCState *state, int rno, int modemask, ARMword val); + +int Dbg_StringToMode(const char *name); + +int Dbg_ModeToModeMask(ARMword mode); + +/* Some implementations of the FP instruction set keep FP values loaded into + registers in their unconverted format, converting only when necessary. + Some RDI implementations deliver these values uninterpreted. + (For the rest, register values will always have type F_Extended). + */ + +typedef enum { F_Single, F_Double, F_Extended, F_Packed, /* fpe340 values */ + F_Internal, /* new fpe : mostly as extended */ + F_None } Dbg_FPType; + +typedef struct { ARMword w[3]; } Dbg_TargetExtendedVal; +typedef struct { ARMword w[3]; } Dbg_TargetPackedVal; +typedef struct { ARMword w[2]; } Dbg_TargetDoubleVal; +typedef struct { ARMword w[1]; } Dbg_TargetFloatVal; + +typedef union { Dbg_TargetExtendedVal e; Dbg_TargetPackedVal p; + Dbg_TargetDoubleVal d; Dbg_TargetFloatVal f; } Dbg_TargetFPVal; + +#define TargetSizeof_Extended 12 +#define TargetSizeof_Packed 12 +#define TargetSizeof_Double 8 +#define TargetSizeof_Float 4 + +typedef struct Dbg_FPRegVal { + Dbg_FPType type; + Dbg_TargetFPVal v; +} Dbg_FPRegVal; + +typedef struct Dbg_FPRegSet { + Dbg_FPRegVal f[8]; + ARMword fpsr, fpcr; +} Dbg_FPRegSet; + +Dbg_Error Dbg_ReadFPRegisters(Dbg_MCState *state, Dbg_FPRegSet *regs); + +Dbg_Error Dbg_WriteFPRegisters(Dbg_MCState *state, int32 mask, Dbg_FPRegSet *regs); + +Dbg_Error Dbg_FPRegToDouble(DbleBin *d, Dbg_FPRegVal const *f); +/* Converts from a FP register value (in any format) to a double with + approximately the same value (or returns Dbg_Err_Overflow) + */ + +void Dbg_DoubleToFPReg(Dbg_FPRegVal *f, DbleBin const *d); +/* Converts the double to a Dbg_FPRegVal with type F_Extended */ + +/*--------------------------------------------------------------------------*/ + +#include "dbg_cp.h" + +Dbg_Error Dbg_DescribeCoPro(Dbg_MCState *state, int cpnum, Dbg_CoProDesc *p); + +Dbg_Error Dbg_DescribeCoPro_RDI(Dbg_MCState *state, int cpnum, Dbg_CoProDesc *p); + +Dbg_Error Dbg_ReadCPRegisters(Dbg_MCState *state, int cpnum, ARMword *regs); + +Dbg_Error Dbg_WriteCPRegisters(Dbg_MCState *state, int cpnum, int32 mask, ARMword *regs); + +/*--------------------------------------------------------------------------*/ + +Dbg_Error Dbg_ReadWords( + Dbg_MCState *state, + ARMword *words, ARMaddress addr, unsigned count); +/* Reads a number of (32-bit) words from target store. The values are in host + byte order; if they are also to be interpreted as bytes Dbg_SwapByteOrder() + must be called to convert to target byte order. + */ + +Dbg_Error Dbg_WriteWords( + Dbg_MCState *state, + ARMaddress addr, const ARMword *words, unsigned count); +/* Writes a number of (32-bit) words to target store. The values are in host + byte order (if what is being written is actually a byte string it must be + converted by Dbg_SwapByteOrder()). + */ + +Dbg_Error Dbg_ReadHalf(Dbg_MCState *state, ARMhword *val, ARMaddress addr); +Dbg_Error Dbg_WriteHalf(Dbg_MCState *state, ARMaddress addr, ARMword val); + +Dbg_Error Dbg_ReadBytes(Dbg_MCState *state, Dbg_Byte *val, ARMaddress addr, unsigned count); +Dbg_Error Dbg_WriteBytes(Dbg_MCState *state, ARMaddress addr, const Dbg_Byte *val, unsigned count); + +void Dbg_HostWords(Dbg_MCState *state, ARMword *words, unsigned wordcount); +/* (A noop unless host and target bytesexes differ) */ + +ARMword Dbg_HostWord(Dbg_MCState *state, ARMword v); + +ARMhword Dbg_HostHalf(Dbg_MCState *state, ARMword v); + +/*--------------------------------------------------------------------------*/ + +/* Types describing various aspects of position within code. + There are rather a lot of these, in the interests of describing precisely + what fields must be present (rather than having a single type with many + fields which may or may not be valid according to context). + */ + +typedef struct Dbg_LLPos { + Dbg_SymTable *st; + char *llsym; + ARMaddress offset; +} Dbg_LLPos; + +typedef struct Dbg_File { + Dbg_SymTable *st; + char *file; +} Dbg_File; + +typedef struct Dbg_Line { + unsigned32 line; /* linenumber in the file */ + unsigned16 statement, /* within the line (1-based) */ + charpos; /* ditto */ +} Dbg_Line; +/* As an output value from toolbox functions, both statement and charpos are set + if the version of the debugger tables for the section concerned permits. + On input, is used only if is 0 (in which case, if + is non-0, Dbg_Err_DbgTableVersion is returned if the version of + the debugger tables concerned is too early. + */ + +typedef struct Dbg_FilePos { + Dbg_File f; + Dbg_Line line; +} Dbg_FilePos; + +typedef struct Dbg_ProcDesc { + Dbg_File f; + char *name; +} Dbg_ProcDesc; + +typedef struct Dbg_ProcPos { + Dbg_ProcDesc p; + Dbg_Line line; +} Dbg_ProcPos; + +/* Support for conversions between position representations */ + +Dbg_Error Dbg_ProcDescToLine(Dbg_MCState *state, Dbg_ProcDesc *proc, Dbg_Line *line); +/* If proc->f.file is null (and there is just one function proc->name), it is + updated to point to the name of the file containing (the start of) + proc->name. + */ + +Dbg_Error Dbg_FilePosToProc(Dbg_MCState *state, const Dbg_FilePos *pos, char **procname); + +/* Conversions from position representations to and from code addresses */ + +Dbg_Error Dbg_AddressToProcPos( + Dbg_MCState *state, ARMaddress addr, + Dbg_ProcPos *pos); +Dbg_Error Dbg_AddressToLLPos( + Dbg_MCState *state, ARMaddress addr, + Dbg_LLPos *pos, Dbg_LLSymType *res_type, int system_names); + +Dbg_Error Dbg_ProcPosToAddress( + Dbg_MCState *state, const Dbg_ProcPos *pos, + ARMaddress *res); +Dbg_Error Dbg_LLPosToAddress( + Dbg_MCState *state, const Dbg_LLPos *pos, + ARMaddress *res); + +typedef struct { + ARMaddress start, end; +} Dbg_AddressRange; + +typedef Dbg_Error Dbg_AddressRangeProc(void *arg, int32 first, int32 last, Dbg_AddressRange const *range); + +Dbg_Error Dbg_MapAddressRangesForFileRange( + Dbg_MCState *state, + Dbg_SymTable *st, const char *f, int32 first, int32 last, Dbg_AddressRangeProc *p, void *arg); + +typedef struct Dbg_Environment Dbg_Environment; +/* A Dbg_Environment describes the context required to make sense of a variable + name and access its value. Its format is not revealed. Dbg_Environment + values are allocated by Dbg_NewEnvironment() and discarded by + Dbg_DeleteEnvironment(). + */ + +Dbg_Environment *Dbg_NewEnvironment(Dbg_MCState *state); +void Dbg_DeleteEnvironment(Dbg_MCState *state, Dbg_Environment *env); + +Dbg_Error Dbg_StringToEnv( + Dbg_MCState *state, char *str, Dbg_Environment *resenv, + int forcontext, Dbg_Environment const *curenv); + +Dbg_Error Dbg_ProcPosToEnvironment( + Dbg_MCState *state, const Dbg_ProcPos *pos, int activation, + const Dbg_Environment *current, Dbg_Environment *res); + +/* Conversion from a position representation to an Dbg_Environment (as required + to access variable values). Only a Dbg_ProcPos argument here; other + representations need to be converted first. + + Returns describing the th instance of the function + described by , up from the stack base if is negative, + else down from . + If this function returns Dbg_Err_ActivationNotPresent, the result + Dbg_Environment is still valid for accessing non-auto variables. + */ + +typedef struct Dbg_DeclSpec Dbg_DeclSpec; + +Dbg_Error Dbg_EnvToProcItem( + Dbg_MCState *state, Dbg_Environment const *env, Dbg_DeclSpec *proc); + +Dbg_Error Dbg_ContainingEnvironment( + Dbg_MCState *state, const Dbg_Environment *context, Dbg_Environment *res); +/* Set to describe the containing function, file if is within + a top-level function (or error if already describes a file). + */ + +/*--------------------------------------------------------------------------*/ + +/* ASD debug table pointers are not by themselves sufficient description, + since there's an implied section context. Hence the DeclSpec and TypeSpec + structures. + */ + + +#ifndef Dbg_TypeSpec_Defined + +struct Dbg_DeclSpec { void *a; }; + +#ifdef CALLABLE_COMPILER +typedef void *Dbg_TypeSpec; + +/* The intention here is to give an alternative definition for Dbg_BasicType + which follows. + */ + +#define Dbg_T_Void xDbg_T_Void +#define Dbg_T_Bool xDbg_T_Bool +#define Dbg_T_SByte xDbg_T_SByte +#define Dbg_T_SHalf xDbg_T_Half +#define Dbg_T_SWord xDbg_T_SWord +#define Dbg_T_UByte xDbg_T_UByte +#define Dbg_T_UHalf xDbg_T_UHalf +#define Dbg_T_UWord xDbg_T_UWord +#define Dbg_T_Float xDbg_T_Float +#define Dbg_T_Double xDbg_T_Double +#define Dbg_T_LDouble xDbg_T_LDouble +#define Dbg_T_Complex xDbg_T_Complex +#define Dbg_T_DComplex xDbg_T_DComplex +#define Dbg_T_String xDbg_T_String +#define Dbg_T_Function xDbg_T_Function + +#define Dbg_BasicType xDbg_BaiscType +#define Dbg_PrimitiveTypeToTypeSpec xDbg_PrimitiveTypeToTypeSpec + +#else +/* We want a Dbg_TypeSpec to be a an opaque type, but of known size (so the + toolbox's clients can allocate the store to hold one); unfortunately, we + can do this only by having one definition for the toolbox's clients and + one (elsewhere) for the toolbox itself. + */ + +typedef struct Dbg_TypeSpec Dbg_TypeSpec; +struct Dbg_TypeSpec { void *a; int32 b; }; +#endif /* CALLABLE_COMPILER */ + +typedef enum { + Dbg_T_Void, + + Dbg_T_Bool, + + Dbg_T_SByte, + Dbg_T_SHalf, + Dbg_T_SWord, + + Dbg_T_UByte, + Dbg_T_UHalf, + Dbg_T_UWord, + + Dbg_T_Float, + Dbg_T_Double, + Dbg_T_LDouble, + + Dbg_T_Complex, + Dbg_T_DComplex, + + Dbg_T_String, + + Dbg_T_Function +} Dbg_BasicType; + +#endif + +void Dbg_PrimitiveTypeToTypeSpec(Dbg_TypeSpec *ts, Dbg_BasicType t); + +bool Dbg_TypeIsIntegral(Dbg_TypeSpec const *ts); + +bool Dbg_TypeIsPointer(Dbg_TypeSpec const *ts); + +bool Dbg_TypeIsFunction(Dbg_TypeSpec const *ts); + +bool Dbg_PruneType(Dbg_TypeSpec *tsres, Dbg_TypeSpec const *ts); +/* Return to tsres a version of ts which has been pruned by the removal of all + toplevel typedefs. Result is YES if the result has changed. + */ + +typedef Dbg_Error Dbg_FileProc(Dbg_MCState *state, const char *name, const Dbg_DeclSpec *procdef, void *arg); + +Dbg_Error Dbg_EnumerateFiles(Dbg_MCState *state, Dbg_SymTable *st, Dbg_FileProc *p, void *arg); +/* The top level for a high level enumerate. Lower levels are performed by + EnumerateDeclarations (below). + */ + +typedef enum { + ds_Invalid, + ds_Type, + ds_Var, + ds_Proc, + ds_Enum, + ds_Function, + ds_Label +} Dbg_DeclSort; + +Dbg_DeclSort Dbg_SortOfDeclSpec(Dbg_DeclSpec const *decl); + +char *Dbg_NameOfDeclSpec(Dbg_DeclSpec const *decl); + +Dbg_TypeSpec Dbg_TypeSpecOfDeclSpec(Dbg_DeclSpec const *decl); + +typedef enum { + cs_None, + cs_Extern, + cs_Static, + cs_Auto, + cs_Reg, + cs_Var, + cs_Farg, + cs_Fcarg, + cs_Local, + cs_Filtered, + cs_Globalreg +} Dbg_StgClass; + +Dbg_StgClass Dbg_StgClassOfDeclSpec(Dbg_DeclSpec const *decl); + +bool Dbg_VarsAtSameAddress(Dbg_DeclSpec const *d1, Dbg_DeclSpec const *d2); + +bool Dbg_VarsDecribedForDeclSpec(Dbg_DeclSpec const *decl); + +int Dbg_ArgCountOfDeclSpec(Dbg_DeclSpec const *decl); + +typedef struct Dbg_DComplex { DbleBin r, i; } Dbg_DComplex; + +typedef union Dbg_ConstantVal { + int32 l; + unsigned32 u; + DbleBin d; + Dbg_DComplex fc; + ARMaddress a; + char *s; +} Dbg_ConstantVal; + +typedef struct Dbg_Constant { + Dbg_TypeSpec type; + Dbg_ConstantVal val; +} Dbg_Constant; + +typedef enum Dbg_ValueSort { + vs_register, + vs_store, + vs_constant, + vs_local, + vs_filtered, + vs_none, + vs_error +} Dbg_ValueSort; + +/* vs_local allows the use of symbol table entries to describe entities within + the debugger's own address space, accessed in the same way as target + variables. + vs_filtered describes entities which may be read or written only via an + access function (eg r15) + */ + +#define fpr_base 16 +/* There's only one register ValueSort (reflecting asd table StgClass); + fp register n is encoded as register n+fpr_base. + */ + +typedef struct Dbg_Value Dbg_Value; + +typedef Dbg_Error Dbg_AccessFn(Dbg_MCState *state, int write, Dbg_Value *self, Dbg_Constant *c); +/* == 0: read a vs_filtered value, updating the value self. + == 1: update a vs_filtered value, with the value described by c. + allows use of the same Dbg_AccessFn for several different entities + (using different val.f.id fields). + */ + +typedef Dbg_Error Dbg_FormatFn(int decode, char *b, ARMword *valp, void *formatarg); + +typedef struct { Dbg_AccessFn *f; int id; } Dbg_AccessFnRec; + +struct Dbg_Value { + Dbg_TypeSpec type; + Dbg_ValueSort sort; + Dbg_FormatFn *formatp; + void *formatarg; + int f77csize; + union { + struct { int no; ARMaddress frame; } r; + ARMaddress ptr; + Dbg_ConstantVal c; + void *localp; + Dbg_AccessFnRec f; + Dbg_Error err; + } val; +}; + +Dbg_Error Dbg_AddLLSymbol(Dbg_SymTable *st, char const *name, Dbg_LLSymType type, ARMword val); + +Dbg_Error Dbg_AddSymbol(Dbg_SymTable *st, char const *name, Dbg_Value const *val); + +typedef struct Dbg_DeclSpecF { + Dbg_DeclSpec decl; + Dbg_FormatFn *formatp; + void *formatarg; +} Dbg_DeclSpecF; + +typedef Dbg_Error Dbg_DeclProc(Dbg_MCState *state, Dbg_Environment const *context, + Dbg_DeclSpecF const *var, Dbg_DeclSort sort, int masked, + void *arg); + +Dbg_Error Dbg_EnumerateDeclarations(Dbg_MCState *state, Dbg_Environment const *context, + Dbg_DeclProc *p, void *arg); +/* call p once for every declaration local to the function described by + (or file if describes a place outside a function). + p's argument is true if the variable is not visible, thanks to + a declaration in an inner scope. + */ + +Dbg_Error Dbg_ValueOfVar(Dbg_MCState *state, const Dbg_Environment *context, + const Dbg_DeclSpec *var, Dbg_Value *val); +/* Different from Dbg_EvalExpr() in that the thing being evaluated is described + by a Dbg_DeclSpec (which must be for a variable), rather than a string + needing to be decoded and associated with a symbol-table item. Intended to + be called from a Dbg_DeclProc called from Dbg_EnumerateDeclarations. + */ + +Dbg_Error Dbg_EvalExpr(Dbg_MCState *state, Dbg_Environment const *context, + char const *expr, int flags, Dbg_Value *val); + +Dbg_Error Dbg_EvalExpr_ep(Dbg_MCState *state, Dbg_Environment const *context, + char const *expr, char **exprend, int flags, Dbg_Value *val); + +/* Both Dbg_ValueOfVar and Dbg_EvalExpr mostly deliver a value still containing + an indirection (since it may be wanted as the lhs of an assignment) + */ + +void Dbg_RealLocation(Dbg_MCState *state, Dbg_Value *val); +/* If val describes a register, this may really be a register, or a place on + the stack where the register's value is saved. In the latter case, val + is altered to describe the save place. (In all others, it remains + unchanged). + */ + +Dbg_Error Dbg_DereferenceValue(Dbg_MCState *state, const Dbg_Value *value, Dbg_Constant *c); +/* This fails if describes a structure or array, returning + Dbg_Err_TypeNotSimple + */ + +typedef struct Dbg_Expr Dbg_Expr; +/* The result of parsing an expression in an environment: its structure is not + revealed. (Clients may wish to parse just once an expression which may be + evaluated often). In support of which, the following two functions partition + the work of Dbg_EvalExpr(). + */ + +#define Dbg_exfl_heap 1 /* allocate Expr on the heap (FreeExpr must then be + called to discard it). Otherwise, it goes in a + place overwritten by the next call to ParseExpr + or EvalExpr + */ +#define Dbg_exfl_needassign 2 +#define Dbg_exfl_lowlevel 4 + +int Dbg_SetInputRadix(Dbg_MCState *state, int radix); +char *Dbg_SetDefaultIntFormat(Dbg_MCState *state, char *format); + +Dbg_Error Dbg_ParseExpr( + Dbg_MCState *state, Dbg_Environment const *env, char *string, + char **end, Dbg_Expr **res, int flags); +/* Just parse the argument string, returning a pointer to a parsed expression + and a pointer to the first non-white space character in the input string + which is not part of the parsed expression. (If macro expansion has taken + place, the returned pointer will not be into the argument string at all, + rather into the expanded version of it). + */ + +Dbg_Error Dbg_ParseExprCheckEnd( + Dbg_MCState *state, Dbg_Environment const *env, char *string, + Dbg_Expr **res, int flags); +/* As Dbg_ParseExpr, but the parsed expression is required completely to fill + the argument string (apart possibly for trailing whitespace), and an error + is returned if it does not. + */ + +Dbg_Error Dbg_ParsedExprToValue( + Dbg_MCState *state, const Dbg_Environment *env, Dbg_Expr *expr, Dbg_Value *v); + +Dbg_Error Dbg_ReadDecl( + Dbg_MCState *state, Dbg_Environment const *env, char *string, + Dbg_TypeSpec *p, char **varp, int flags); +/* Read a variable declaration, returing a description of the type of the + variable to p, and a pointer to its name to varp. + */ + +bool Dbg_IsCastToArrayType(Dbg_MCState *state, Dbg_Expr *expr); + +void Dbg_FreeExpr(Dbg_Expr *expr); + +Dbg_Error Dbg_CopyType(Dbg_TypeSpec *tdest, Dbg_TypeSpec const *tsource); +Dbg_Error Dbg_FreeCopiedType(Dbg_TypeSpec *ts); + +Dbg_Error Dbg_TypeOfExpr(Dbg_MCState *state, Dbg_Expr *tree, Dbg_TypeSpec *restype); + +Dbg_Error Dbg_ExprToVar(const Dbg_Expr *expr, Dbg_DeclSpec *var, Dbg_Environment *env); + +Dbg_Error Dbg_Assign(Dbg_MCState *state, const Dbg_Value *lv, const Dbg_Value *rv); + +typedef enum Dbg_TypeSort { + ts_simple, + ts_union, + ts_struct, + ts_array +} Dbg_TypeSort; + +Dbg_TypeSort Dbg_TypeSortOfValue(Dbg_MCState *state, const Dbg_Value *val, int *fieldcount); + +Dbg_Error Dbg_TypeToChars(const Dbg_TypeSpec *var, Dbg_BufDesc *buf); + +Dbg_Error Dbg_TypeSize(Dbg_MCState *state, const Dbg_TypeSpec *type, unsigned32 *res); + +typedef int Dbg_ValToChars_cb(Dbg_MCState *state, Dbg_Value *subval, const char *fieldname, + Dbg_BufDesc *buf, void *arg); + +Dbg_Error Dbg_ValToChars(Dbg_MCState *state, Dbg_Value *val, int base, + Dbg_ValToChars_cb *cb, void *arg, + const char *form, Dbg_BufDesc *buf); +/* + is used for (any size) integer values. + If is of an array or structure type, is called for each element, + with as its last parameter, and describing the space remaining + in . If returns 0, conversion ceases. + */ + +Dbg_Error Dbg_NthElement( + Dbg_MCState *state, + const Dbg_Value *val, unsigned32 n, char **fieldname, Dbg_Value *subval); + +typedef Dbg_Error Dbg_HistoryProc(void *, int, Dbg_Value *); + +Dbg_Error Dbg_RegisterHistoryProc(Dbg_MCState *state, Dbg_HistoryProc *p, void *arg); + +typedef enum { + ls_cpu, + ls_store, + ls_copro, + ls_local, + ls_filtered +} Dbg_LocSort; + +typedef struct { + Dbg_LocSort sort; + union { + struct { ARMaddress addr, size; } store; + struct { int modemask; int r; } cpu; + struct { int no; int r; } cp; + void *localp; + Dbg_AccessFnRec f; + } loc; +} Dbg_Loc; + +typedef Dbg_Error Dbg_ObjectWriteProc(Dbg_MCState *state, Dbg_Loc const *loc); +Dbg_Error Dbg_OnObjectWrite(Dbg_MCState *state, Dbg_ObjectWriteProc *p); +/* Register function to be called back whenever the toolbox has written to any + * object accessible by the debuggee (or to local variables belonging to a + * toolbox client). The write has already been done. + * (To allow multiple toolbox clients to coexist). + */ + +Dbg_Error Dbg_ObjectWritten(Dbg_MCState *state, Dbg_Loc const *loc); + +/*--------------------------------------------------------------------------*/ + +/* Control of target program execution. + Currently, only synchronous operation is provided. + Execution could possibly be asynchronous where the target is a seperate + processor, but is necessarily synchronous if the target is Armulator. + Unfortunately, this may require modification to the RDI implementation + if multitasking is required but the the host system provides it only + cooperatively, or if there is no system-provided way to generate SIGINT. + */ + +Dbg_Error Dbg_SetCommandline(Dbg_MCState *state, const char *args); +/* Set the argument string to the concatenation of the name of the most + recently loaded image and args. + */ + +typedef enum Dbg_ProgramState { + ps_notstarted, + /* Normal ways of stopping */ + ps_atbreak, ps_atwatch, ps_stepdone, + ps_interrupted, + ps_stopped, + /* abnormal (but unsurprising) ways of stopping */ + ps_lostwatch, + ps_branchthrough0, ps_undef, ps_caughtswi, ps_prefetch, + ps_abort, ps_addrexcept, ps_caughtirq, ps_caughtfiq, + ps_error, + /* only as a return value from Call() */ + ps_callfailed, ps_callreturned, + /* internal inconsistencies */ + ps_broken, /* target has "broken" */ + ps_unknownbreak, + ps_unknown +} Dbg_ProgramState; + +int Dbg_IsCallLink(Dbg_MCState *state, ARMaddress pc); + +typedef struct { + Dbg_FPRegVal fpres; + ARMword intres; +} Dbg_CallResults; + +Dbg_CallResults *Dbg_GetCallResults(Dbg_MCState *state); + +#define Dbg_S_STATEMENTS 0 +#define Dbg_S_INSTRUCTIONS 1 +#define Dbg_S_STEPINTOPROCS 2 + +Dbg_Error Dbg_Step(Dbg_MCState *state, int32 stepcount, int stepby, Dbg_ProgramState *status); +/* is a combination of the Dbg_S_... values above */ + +Dbg_Error Dbg_StepOut(Dbg_MCState *state, Dbg_ProgramState *status); + +bool Dbg_CanGo(Dbg_MCState *state); + +bool Dbg_IsExecuting(Dbg_MCState *state); + +Dbg_Error Dbg_Go(Dbg_MCState *state, Dbg_ProgramState *status); + +Dbg_Error Dbg_Stop(Dbg_MCState *state); +/* Asynchronous Stop request, for call from SIGINT handler. On return to the + caller, the call of Dbg_Go, Dbg_Step or Dbg_Call which started execution + should return ps_interrupted. + */ + +typedef void Dbg_ExecuteProc(Dbg_MCState *state, Dbg_ProgramState status); +Dbg_Error Dbg_OnExecute(Dbg_MCState *, Dbg_ExecuteProc *); +/* Register function to be called back whenever execution stops. + * (To allow multiple toolbox clients to coexist). + */ + +Dbg_Error Dbg_SetReturn(Dbg_MCState *state, + const Dbg_Environment *context, const Dbg_Value *value); +/* Prepare continuation by returning from the function activation + described by . (Dbg_Go() or Dbg_Step() actually perform the + continuation). + */ + +Dbg_Error Dbg_SetExecution(Dbg_MCState *state, Dbg_Environment *context); +/* Set the pc in a high-level fashion */ + +Dbg_Error Dbg_ProgramStateToChars(Dbg_MCState *state, Dbg_ProgramState event, Dbg_BufDesc *buf); +/* This is guaranteed to give a completely accurate description of if + this was the value returned by the most recent call of Dbg_Go, Dbg_Step, + or Dbg_Call. + */ + +/*--------------------------------------------------------------------------*/ + +Dbg_Error Dbg_CurrentEnvironment(Dbg_MCState *state, Dbg_Environment *context); + +Dbg_Error Dbg_PrevFrame(Dbg_MCState *state, Dbg_Environment *context); +/* towards the base of the stack */ + +Dbg_Error Dbg_NextFrame(Dbg_MCState *state, Dbg_Environment *context); +/* away from the base of the stack */ + +typedef struct Dbg_AnyPos { + enum { pos_source, pos_ll, pos_none } postype; + ARMaddress pc; + union { + Dbg_ProcPos source; + Dbg_LLPos ll; + ARMaddress none; + } pos; +} Dbg_AnyPos; + +Dbg_Error Dbg_EnvironmentToPos(Dbg_MCState *state, const Dbg_Environment *context, Dbg_AnyPos *pos); +/* is set to a Dbg_ProcPos if these is one corresponding to + else a Dbg_LLPos if there is one. + */ + +/*--------------------------------------------------------------------------*/ + +/* Source file management. + Pretty vestigial. Handles source path (per loaded image), + and translates from line-number (as given in debugger tables) to character + position (as required to access files) + */ + +Dbg_Error Dbg_ClearPaths(Dbg_MCState *state, Dbg_SymTable *st); +Dbg_Error Dbg_AddPath(Dbg_MCState *state, Dbg_SymTable *st, const char *path); +Dbg_Error Dbg_DeletePath(Dbg_MCState *state, Dbg_SymTable *st, const char *path); + +typedef enum { + Dbg_PathsCleared, + Dbg_PathAdded, + Dbg_PathDeleted +} Dbg_PathAlteration; + +typedef void Dbg_PathAlteredProc( + Dbg_MCState *state, Dbg_SymTable *st, char const *path, + Dbg_PathAlteration sort); + +Dbg_Error Dbg_OnPathAlteration(Dbg_MCState *state, Dbg_PathAlteredProc *p); +/* Register function to be called back whenever one of the source path + * modification functions above is called. (To allow multiple toolbox + * clients to coexist). + */ + +typedef struct Dbg_FileRec Dbg_FileRec; +typedef struct { + unsigned32 linecount; + Dbg_FileRec *handle; + char *fullname; +} Dbg_FileDetails; + +Dbg_Error Dbg_GetFileDetails( + Dbg_MCState *state, const Dbg_File *fname, Dbg_FileDetails *res); +Dbg_Error Dbg_FinishedWithFile(Dbg_MCState *state, Dbg_FileRec *handle); + +Dbg_Error Dbg_GetFileDetails_fr( + Dbg_MCState *state, Dbg_FileRec *handle, Dbg_FileDetails *res); +/* Refresh details about the file associated with (in particular, + * its linecount). + */ + +Dbg_Error Dbg_FileLineLength( + Dbg_MCState *state, Dbg_FileRec *handle, int32 lineno, int32 *len); +/* Return to the length of line of the file associated with + * (without necessarily reading from the file). + */ + +Dbg_Error Dbg_GetFileLine_fr( + Dbg_MCState *state, Dbg_FileRec *handle, int32 lineno, Dbg_BufDesc *buf); +/* Return to the contents of line of the file associated with + * (including its terminating newline). + */ + +Dbg_Error Dbg_StartFileAccess(Dbg_MCState *state, Dbg_FileRec *handle); +Dbg_Error Dbg_EndFileAccess(Dbg_MCState *state, Dbg_FileRec *handle); +/* These two calls bracket a sequence of calls to GetFileLine. Between the + * calls, the toolbox is permitted to retain state allowing more rapid + * access to text on the file associated with . + */ + +Dbg_Error Dbg_ControlSourceFileAccess( + Dbg_MCState *state, uint32 cachesize, bool closefiles); +/* Control details of how the toolbox manages source files. + * If is non-zero, the text from the most recently accessed + * source files (of total size not to exceed ) is saved in + * store on first access to the file; subsequent access to the text of + * the file uses this copy. + * If is true, no stream is left attached to uncached source + * files after Dbg_EndFileAccess has been closed. Otherwise, the toolbox + * may retain such streams, in order to improve access. + */ + +/*--------------------------------------------------------------------------*/ + +/* disassembly */ + +/* + ? More exact control is wanted here, but that requires a more complicated + ? disass callback interface. + */ + +typedef const char *Dbg_SWI_Decode(Dbg_MCState *state, ARMword swino); + +Dbg_Error Dbg_InstructionAt(Dbg_MCState *state, ARMaddress addr, + int isize, ARMhword *inst, Dbg_SymTable *st, + Dbg_SWI_Decode *swi_name, Dbg_BufDesc *buf, int *length); +/* describes the form of disassembly wanted: 2 for 16-bit, 4 for 32-bit, + * 0 for 16- or 32-bit depending whether addr addresses 16- or 32-bit code. + * is a pointer to a pair of halfwords *in target byte order* + * Possibly only the first halfword will be consumed: the number of bytes used + * is returned via . + */ + +/*--------------------------------------------------------------------------*/ + +int Dbg_RDIOpen(Dbg_MCState *state, unsigned type); +int Dbg_RDIInfo(Dbg_MCState *state, unsigned type, ARMword *arg1, ARMword *arg2); + +/*--------------------------------------------------------------------------*/ + +typedef enum { + Dbg_Point_Toolbox, + Dbg_Point_RDI_Unknown, + Dbg_Point_RDI_SW, + Dbg_Point_RDI_HW +} Dbg_PointType; + +/* breakpoint management + Associated with a breakpoint there may be any of + a count + an expression + a function + the breakpoint is activated if + the expression evaluates to a non-zero value (or fails to evaluate). + && decrementing the count reaches zero (the count is then reset to its + initial value). + && the function, called with the breakpoint address as argument, returns + a non-zero value. +? (The order here may be open to debate. Note that the first two are in + the opposite order in armsd, but I think this order more rational) + */ + +typedef enum Dbg_BreakPosType { + bt_procpos, + bt_procexit, + bt_address +} Dbg_BreakPosType; + +typedef union { + Dbg_ProcPos procpos; + Dbg_ProcDesc procexit; + ARMaddress address; +} Dbg_BreakPosPos; + +typedef struct Dbg_BreakPos { + Dbg_BreakPosType sort; + Dbg_BreakPosPos loc; +} Dbg_BreakPos; + +typedef int Dbg_BPProc(Dbg_MCState *state, void *BPArg, Dbg_BreakPos *where); + +typedef struct Dbg_BreakStatus { + int index; + int initcount, countnow; + Dbg_BreakPos where; + char *expr; + Dbg_BPProc *p; void *p_arg; + int incomplete; + Dbg_PointType type; + ARMword hwresource; +} Dbg_BreakStatus; + +Dbg_Error Dbg_StringToBreakPos( + Dbg_MCState *state, Dbg_Environment *env, char const *str, size_t len, + Dbg_BreakPos *bpos, char *b); + +Dbg_Error Dbg_SetBreakPoint(Dbg_MCState *state, Dbg_BreakPos *where, + int count, + const char *expr, + Dbg_BPProc *p, void *arg); +Dbg_Error Dbg_SetBreakPoint16(Dbg_MCState *state, Dbg_BreakPos *where, + int count, + const char *expr, + Dbg_BPProc *p, void *arg); +Dbg_Error Dbg_SetBreakPointNaturalSize(Dbg_MCState *state, Dbg_BreakPos *where, + int count, + const char *expr, + Dbg_BPProc *p, void *arg); +/* Setting a breakpoint at the same address as a previous breakpoint + completely removes the previous one. + */ + +Dbg_Error Dbg_DeleteBreakPoint(Dbg_MCState *state, Dbg_BreakPos *where); + +Dbg_Error Dbg_SuspendBreakPoint(Dbg_MCState *state, Dbg_BreakPos *where); +/* Temporarily remove the break point (until Reinstated) but leave intact + its associated expr, the value its count has reached, etc. +? The debugger toolbox itself wants this, but I'm not sure what use a client + could have for it. Ditto Reinstate... + */ + +Dbg_Error Dbg_ReinstateBreakPoint(Dbg_MCState *state, Dbg_BreakPos *where); +/* Undo the effect of Dbg_SuspendBreakPoint + */ + +Dbg_Error Dbg_DeleteAllBreakPoints(Dbg_MCState *state); + +Dbg_Error Dbg_SuspendAllBreakPoints(Dbg_MCState *state); + +Dbg_Error Dbg_ReinstateAllBreakPoints(Dbg_MCState *state); + +typedef Dbg_Error Dbg_BPEnumProc(Dbg_MCState *state, Dbg_BreakStatus *status, void *arg); + +Dbg_Error Dbg_EnumerateBreakPoints(Dbg_MCState *state, Dbg_BPEnumProc *p, void *arg); + +Dbg_Error Dbg_BreakPointStatus(Dbg_MCState *state, + const Dbg_BreakPos *where, Dbg_BreakStatus *status); + +typedef void Dbg_BreakAlteredProc(Dbg_MCState *state, ARMaddress addr, bool set); +Dbg_Error Dbg_OnBreak(Dbg_MCState *state, Dbg_BreakAlteredProc *p); +/* Register function to be called back whenever a breakpoint is set or + * cleared. (To allow multiple toolbox clients to coexist). + */ + +bool Dbg_StoppedAtBreakPoint(Dbg_MCState *state, const Dbg_BreakPos *where); +/* Called after execution which resulted in ps_atbreak, to find out whether + the specified breakpoint was hit (could be >1, eg. exit break and another + high-level breakpoint at the same position). + Returns NO if specified breakpoint not found, or execution didn't stop + with ps_atbreak status. + */ + +/*--------------------------------------------------------------------------*/ + +typedef struct { + Dbg_Value val; + char *name; +} Dbg_WatchPos; + +typedef int Dbg_WPProc(Dbg_MCState *state, void *WPArg, Dbg_WatchPos *where); + +typedef struct Dbg_WPStatus { + int index; + int initcount, countnow; + Dbg_WatchPos what, target; + char *expr; + Dbg_WPProc *p; void *p_arg; + Dbg_PointType type; + ARMword hwresource; + int skip; +} Dbg_WPStatus; + +Dbg_Error Dbg_SetWatchPoint( + Dbg_MCState *state, Dbg_Environment *context, char const *watchee, + char const *target, + int count, + char const *expr, + Dbg_WPProc *p, void *arg); + +/* Cause a watchpoint event if the value of changes to the value of + (or changes at all if is NULL). should + evaluate either to an L-value (when the size of the object being watched is + determined by its type) or to an integer constant (when the word with this + address is watched). + */ + +Dbg_Error Dbg_DeleteWatchPoint(Dbg_MCState *state, Dbg_Environment *context, char const *watchee); + + +Dbg_Error Dbg_SetWatchPoint_V( + Dbg_MCState *state, + char const *name, Dbg_Value const *val, char const *tname, Dbg_Value const *tval, + int count, + char const *expr, + Dbg_WPProc *p, void *arg); + +Dbg_Error Dbg_DeleteWatchPoint_V(Dbg_MCState *state, Dbg_Value const *val); + + +Dbg_Error Dbg_DeleteAllWatchPoints(Dbg_MCState *state); + +typedef Dbg_Error Dbg_WPEnumProc(Dbg_MCState *state, Dbg_WPStatus const *watchee, void *arg); + +Dbg_Error Dbg_EnumerateWatchPoints(Dbg_MCState *state, Dbg_WPEnumProc *p, void *arg); + +Dbg_Error Dbg_WatchPointStatus(Dbg_MCState *state, + Dbg_WatchPos const *where, Dbg_WPStatus *status); + +typedef void Dbg_WPRemovedProc(void *arg, Dbg_WPStatus const *wp); +Dbg_Error Dbg_RegisterWPRemovalProc(Dbg_MCState *state, Dbg_WPRemovedProc *p, void *arg); +/* When a watchpoint goes out of scope it is removed by the toolbox, and the + function registered here gets called back to adjust its view + */ + +typedef void Dbg_WatchAlteredProc(Dbg_MCState *state, Dbg_Value const *where, bool set); +Dbg_Error Dbg_OnWatch(Dbg_MCState *state, Dbg_WatchAlteredProc *p); +/* Register function to be called back whenever a watchpoint is set or + * cleared. (To allow multiple toolbox clients to coexist). + */ + +/*--------------------------------------------------------------------------*/ + +Dbg_Error Dbg_ProfileLoad(Dbg_MCState *state); + +Dbg_Error Dbg_ProfileStart(Dbg_MCState *state, ARMword interval); +Dbg_Error Dbg_ProfileStop(Dbg_MCState *state); + +Dbg_Error Dbg_ProfileClear(Dbg_MCState *state); + +Dbg_Error Dbg_WriteProfile(Dbg_MCState *state, char const *filename, + char const *toolid, char const *arg); + +/*--------------------------------------------------------------------------*/ + +Dbg_Error Dbg_ConnectChannel_ToHost(Dbg_MCState *state, RDICCProc_ToHost *p, void *arg); +Dbg_Error Dbg_ConnectChannel_FromHost(Dbg_MCState *state, RDICCProc_FromHost *p, void *arg); + +/*--------------------------------------------------------------------------*/ + +/* Configuration data management */ + +Dbg_Error Dbg_LoadConfigData(Dbg_MCState *state, char const *filename); + +Dbg_Error Dbg_SelectConfig( + Dbg_MCState *state, + RDI_ConfigAspect aspect, char const *name, RDI_ConfigMatchType matchtype, + unsigned versionreq, unsigned *versionp); + +Dbg_Error Dbg_ParseConfigVersion( + char const *s, RDI_ConfigMatchType *matchp, unsigned *versionp); + +typedef Dbg_Error Dbg_ConfigEnumProc(Dbg_MCState *state, RDI_ConfigDesc const *desc, void *arg); + +Dbg_Error Dbg_EnumerateConfigs(Dbg_MCState *state, Dbg_ConfigEnumProc *p, void *arg); + +/*--------------------------------------------------------------------------*/ + +/* Angel OS support */ + +Dbg_Error Dbg_CreateTask(Dbg_MCState **statep, Dbg_MCState *parent, bool inherit); +/* This is called when a task is to be debugged which has not been debugged + before - ie. there is no existing Dbg_MCState for this task. It + initialises a new Dbg_MCState and returns a pointer to it. + is any valid previously-created MCCState. If is TRUE, + the new MCState inherits certain features from it (eg. symbols). + Otherwise, only features which are the same across all tasks are inherited, + (eg. global breakpoints). + */ + +Dbg_Error Dbg_DeleteTask(Dbg_MCState *state); +/* This is called when a task dies, and frees up everything which relates to that + task which is controlled by armdbg. + */ + +Dbg_Error Dbg_DetachTask(Dbg_MCState *state); + +Dbg_Error Dbg_AttachTask(Dbg_MCState *state); +/* These are called to request a switch of the current task. First + Dbg_DetachTask should be called with the state of the old task. + Dbg_DetachTask will ensure that any cached state held by armdbg for + the old task is immediately written out to the target. + + After Dbg_DetachTask is called and before Dbg_AttachTask is called + the OS channel manager should tell the target that any future + requests from the debugger will be fore the new task. + + If the new task does not have an armdbg state structure + already, then Dbg_CreateTask should be called to create one (see + above). Then Dbg_AttachTask is called to tell armdbg to treat the + new armdbg state as the current task. + */ + +typedef Dbg_Error Dbg_TaskSwitchProc(void *arg, Dbg_MCState *newstate); + +Dbg_Error Dbg_OnTaskSwitch(Dbg_MCState *state, Dbg_TaskSwitchProc *fn, void *arg); +/* The front end may register a callback which gets called by armdbg whenever + Dbg_AttachTask is called. This callback tells the front end the new current + Dbg_MCState it should use to call armdbg. + [Note that this is only useful if there is one front end shared between all + tasks rather than one front end per task] + The value of passed to Dbg_OnTaskSwitch is passed to + when it is called. + */ + +typedef Dbg_Error Dbg_RestartProc( + void *arg, Dbg_MCState *curstate, Dbg_MCState **newstate); + +Dbg_Error Dbg_OnRestart(Dbg_MCState *state, Dbg_RestartProc *fn, void *arg); +/* This is used by the OS channels layer to register a callback which + will be made by the debugger toolbox early in the process of resuming + execution. + + This callback must determine which task will be resumed when the target + restarts execution. If this is not already the current task then it must + call Dbg_DetachTask and Dbg_AttachTask as decribed above to switch to the + task about to be resumed and return the state for the new task in + . + + This will ensure that armdbg updates the correct task on execution as well + as ensuring that stepping over a breakpointed instruction on restarting + happens correctly. + + The value of passed to Dbg_OnRestart is passed to + when it is called. + */ + + +#ifdef __cplusplus +} +#endif + +#endif + +/* End of armdbg.h */ diff --git a/gdb/rdi-share/buffers.h b/gdb/rdi-share/buffers.h new file mode 100644 index 00000000000..78549de0097 --- /dev/null +++ b/gdb/rdi-share/buffers.h @@ -0,0 +1,111 @@ +/* + * Copyright (C) 1995 Advanced RISC Machines Limited. All rights reserved. + * + * This software may be freely used, copied, modified, and distributed + * provided that the above copyright notice is preserved in all copies of the + * software. + */ + +/* -*-C-*- + * + * $Revision$ + * $Date$ + * + * + * Project: ANGEL + * + * Title: Public interface to buffer management + */ + +#ifndef angel_buffers_h +#define angel_buffers_h + +#include "chandefs.h" /* CHAN_HEADER_SIZE */ + + +/* the handle to a buffer */ +typedef unsigned char *p_Buffer; + + +/* + * Angel Packets are structured as a fixed size header, followed + * by the packet data + */ +#ifdef TARGET +# define BUFFERDATA(b) (b) /* channels layer takes care of it */ +#else +# define BUFFERDATA(b) (&((b)[CHAN_HEADER_SIZE])) +#endif + + +/* + * The buffer management function prototypes are only applicable + * when compiling target code + */ +#ifdef TARGET + +/* + * Function: Angel_BufferQuerySizes + * Purpose: Request infomation on the default and maximum buffer sizes + * that can be allocated + * + * Params: + * In/Out: default_size, max_size: pointers to place the + * sizes in on return + */ + +void Angel_BufferQuerySizes(unsigned int *default_size, + unsigned int *max_size ); + +/* + * Function: Angel_RxEnginBuffersLeft + * Purpose: return the number of free buffers + * + * Params: + * Returns: number of free buffers + */ +unsigned int Angel_BuffersLeft( void ); + +/* + * Function: Angel_BufferAlloc + * Purpose: allocate a buffer that is at least req_size bytes long + * + * Params: + * Input: req_size the required size of the buffer + * + * Returns: pointer to the buffer NULL if unable to + * fulfil the request + */ +p_Buffer Angel_BufferAlloc(unsigned int req_size); + +/* + * Function: Angel_BufferRelease + * Purpose: release a buffer back to the free pool + * + * Params: + * Input: pointer to the buffer to free + */ +void Angel_BufferRelease(p_Buffer buffer); + + +/* return values for angel_InitBuffers */ +typedef enum buf_init_error{ + INIT_BUF_OK, + INIT_BUF_FAIL +} buf_init_error; + +/* + * Function: Angel_InitBuffers + * Purpose: Initalised and malloc the buffer pool + * + * Params: + * Returns: see above + */ + +buf_init_error Angel_InitBuffers(void); + +#endif /* def TARGET */ + +#endif /* ndef angel_buffers_h */ + +/* EOF buffers.h */ diff --git a/gdb/rdi-share/bytesex.c b/gdb/rdi-share/bytesex.c new file mode 100644 index 00000000000..0c6aaae2c54 --- /dev/null +++ b/gdb/rdi-share/bytesex.c @@ -0,0 +1,57 @@ +/* + * Copyright (C) 1995 Advanced RISC Machines Limited. All rights reserved. + * + * This software may be freely used, copied, modified, and distributed + * provided that the above copyright notice is preserved in all copies of the + * software. + */ + +/* + * bytesex.c - Code to support byte-sex independence + * Copyright: (C) 1991, Advanced RISC Machines Ltd., Cambridge, England. + */ + +/* + * RCS $Revision$ + * Checkin $Date$ + */ + +#include "bytesex.h" + +static int reversing_bytes = 0; + +void bytesex_reverse(yes_or_no) +int yes_or_no; +{ reversing_bytes = yes_or_no; +} + +int bytesex_reversing() +{ + return reversing_bytes; +} + +int32 bytesex_hostval(v) +int32 v; +{ /* Return v with the same endian-ness as the host */ + /* This mess generates better ARM code than the more obvious mess */ + /* and may eventually peephole to optimal code... */ + if (reversing_bytes) + { unsigned32 t; + /* t = v ^ (v ror 16) */ + t = v ^ ((v << 16) | (((unsigned32)v) >> 16)); + t &= ~0xff0000; + /* v = v ror 8 */ + v = (v << 24) | (((unsigned32)v) >> 8); + v = v ^ (t >> 8); + } + return v; +} + +int32 bytesex_hostval_16(v) +int32 v; +{ + if (reversing_bytes) { + v = ((v >> 8) & 0xff) | ((v << 8) & 0xff00); + } + return v; +} diff --git a/gdb/rdi-share/bytesex.h b/gdb/rdi-share/bytesex.h new file mode 100644 index 00000000000..4b53ef38247 --- /dev/null +++ b/gdb/rdi-share/bytesex.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 1995 Advanced RISC Machines Limited. All rights reserved. + * + * This software may be freely used, copied, modified, and distributed + * provided that the above copyright notice is preserved in all copies of the + * software. + */ + +/* + Title: Code to support byte-sex independence + Copyright: (C) 1991, Advanced RISC Machines Ltd., Cambridge, England. +*/ +/* + * RCS $Revision$ + * Checkin $Date$ + */ + +#ifndef __bytesex_h +#define __bytesex_h + +#include "host.h" + +void bytesex_reverse(int yes_or_no); +/* + * Turn sex-reversal on or off - 0 means off, non-0 means on. + */ + +int bytesex_reversing(void); +/* + * Return non-0 if reversing the byte sex, else 0. + */ + +int32 bytesex_hostval(int32 v); +/* + * Return v or byte-reversed v, according to whether sex-reversval + * is on or off. + */ + +int32 bytesex_hostval_16(int32 v); +/* Return v or byte-reversed v for a 16 bit value */ + +#endif diff --git a/gdb/rdi-share/chandefs.h b/gdb/rdi-share/chandefs.h new file mode 100644 index 00000000000..d97f0b5bcef --- /dev/null +++ b/gdb/rdi-share/chandefs.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 1995 Advanced RISC Machines Limited. All rights reserved. + * + * This software may be freely used, copied, modified, and distributed + * provided that the above copyright notice is preserved in all copies of the + * software. + */ + +/* -*-C-*- + * + * $Revision$ + * $Date$ + * + * + * Project: ANGEL + * + * Title: Enumeration with all supported channels + */ + +#ifndef angel_chandefs_h +#define angel_chandefs_h + +enum channelIDs { + CI_PRIVATE = 0, /* channels protocol control messages */ + CI_HADP, /* ADP, host originated */ + CI_TADP, /* ADP, target originated */ + CI_HBOOT, /* Boot, host originated */ + CI_TBOOT, /* Boot, target originated */ + CI_CLIB, /* Semihosting C library support */ + CI_HUDBG, /* User debug support, host originated */ + CI_TUDBG, /* User debug support, target originated */ + CI_HTDCC, /* Thumb direct comms channel, host orig. */ + CI_TTDCC, /* Thumb direct comms channel, target orig. */ + CI_TLOG, /* Target debug/logging */ + CI_NUM_CHANNELS +}; + +typedef unsigned ChannelID; + + +/* + * Size in bytes of the channel header. + * This is a duplicate of XXX in chanpriv.h, but we don't want everyone + * to have access to all of chanpriv.h, so we'll double-check in chanpriv.h. + */ +#define CHAN_HEADER_SIZE (4) + +#endif /* ndef angel_chandefs_h */ + +/* EOF chandefs.h */ diff --git a/gdb/rdi-share/channels.h b/gdb/rdi-share/channels.h new file mode 100644 index 00000000000..b43ebc10a65 --- /dev/null +++ b/gdb/rdi-share/channels.h @@ -0,0 +1,384 @@ +/* + * Copyright (C) 1995 Advanced RISC Machines Limited. All rights reserved. + * + * This software may be freely used, copied, modified, and distributed + * provided that the above copyright notice is preserved in all copies of the + * software. + */ + +/* -*-C-*- + * + * $Revision$ + * $Date$ + * + * + * Project: ANGEL + * + * Title: User interface to the channels layer + */ + +#ifndef angel_channels_h +#define angel_channels_h + +/* + * This provides the public interface to the channels layer read and write + * routines, and buffer management routines. + */ + +/* Nested header files, if required */ + +#include "devices.h" +#include "chandefs.h" +#include "adperr.h" + +/* General purpose constants, macros, enums, typedefs */ + +/* use the default device */ +#define CH_DEFAULT_DEV ((DeviceID)-1) + +/* return codes */ +typedef enum ChanError { + CE_OKAY, /* no error */ + CE_ABANDONED, /* abandoned due to device switch */ + CE_DEV_ERROR, /* unexpected error from device driver */ + CE_BUSY, /* channel in use */ + CE_BUFF_ERROR, /* unable to get buffer */ + CE_PRIVATE /* start of internal error codes */ +} ChanError; + + +/* Publically-accessible globals */ + +/* + * The following two globals are only valid after angel_InitialiseChannels() + * has been called. + */ + +/* the default size of a channel buffer, for global use */ +extern unsigned Angel_ChanBuffSize; + +/* the size of a long buffer, for global use */ +extern unsigned Angel_ChanLongSize; + +#ifdef TARGET +AdpErrs send_resend_msg(DeviceID devid); +#endif + +/* + * Function: angel_InitialiseChannels + * Purpose: initialise the channels layer + * + * Params: + * Input: - + * Output: - + * In/Out: - + * + * Returns: - + * + * Reads globals: - + * Modifies globals: - + * + * Other side effects: - + */ + +void angel_InitialiseChannels( void ); + +/* + * Function: adp_init_seq + * Purpose: initialise sequence numbers and free anyt leftover buffers + * + * Params: + * Input: - + * Output: - + * In/Out: - + * + * Returns: - adp_ok if things went ok else an error code + * + * Reads globals: - + * Modifies globals: - + * + * Other side effects: - + */ + +AdpErrs adp_init_seq(void); + +/* + * Function: angel_ChannelAllocBuffer + * Purpose: allocate a buffer that is at least req_size bytes long + * + * Params: + * Input: req_size the minimum size required + * Output: - + * In/Out: - + * + * Returns: pointer to allocated buffer, or + * NULL if unable to allocate suitable buffer + * + * Reads globals: - + * Modifies globals: - + * + * Other side effects: - + */ + +p_Buffer angel_ChannelAllocBuffer(unsigned req_size); + + +/* + * Function: angel_ChannelReleaseBuffer + * Purpose: release a buffer back to the free pool + * + * Params: + * Input: buffer the buffer to release + * Output: - + * In/Out: - + * + * Returns: - + * + * Reads globals: - + * Modifies globals: - + * + * Other side effects: - + */ + +void angel_ChannelReleaseBuffer(p_Buffer buffer); + + +/* + * Function: angel_ChannelSend + * Purpose: blocking send of a packet via a channel + * + * Params: + * Input: devid Device to use, or CH_DEFAULT_DEV + * chanid Channel to use for tx + * buffer Pointer to data to send + * len Length of data to send + * Output: - + * In/Out: - + * + * Returns: CE_OKAY Transmission completed + * CE_BAD_CHAN Channel id invalid + * CE_ABANDONED Tx abandoned due to device switch + * + * Reads globals: - + * Modifies globals: - + * + * Other side effects: - + */ + +ChanError angel_ChannelSend(DeviceID devid, ChannelID chanid, + const p_Buffer buffer, unsigned len); + + +/* + * Function: angel_ChannelSendAsync + * Purpose: asynchronous send of a packet via a channel + * + * Params: + * Input: devid Device to use, or CH_DEFAULT_DEV + * chanid Channel to use for tx + * buffer Pointer to data to send + * len Length of data to send + * callback Function to call on completion + * callback_data Pointer to pass to callback + * Output: - + * In/Out: - + * + * Returns: CE_OKAY Transmission underway + * CE_BAD_CHAN Channel id invalid + * CE_ABANDONED Tx abandoned due to device switch + * + * Reads globals: - + * Modifies globals: - + * + * Other side effects: - + * + * register an asynchronous send on the given channel + * (blocks until send can be commenced) + */ + +typedef void (*ChanTx_CB_Fn)(ChannelID chanid, /* which channel */ + void *callback_data); /* as supplied... */ + + +ChanError angel_ChannelSendAsync( DeviceID devid, + ChannelID chanid, + const p_Buffer buffer, + unsigned len, + ChanTx_CB_Fn callback, + void *callback_data); + + +/* + * Function: angel_ChannelRead + * Purpose: blocking read of a packet from a channel + * + * Params: + * Input: devid Device to use, or CH_DEFAULT_DEV + * chanid Channel to use for rx + * Output: buffer The buffer, supplied and filled + * len How many bytes there are in the buffer + * In/Out: - + * + * Returns: CE_OKAY Reception successful + * CE_BAD_CHAN Channel id invalid + * CE_ABANDONED Tx abandoned due to device switch + * + * Reads globals: - + * Modifies globals: - + * + * Other side effects: - + * + * Note that in the present version, if an asynchronous read has been + * registered, a blocking read will be refused with CE_BUSY. + */ +ChanError angel_ChannelRead(DeviceID devid, + ChannelID chanid, + p_Buffer *buffer, + unsigned *len); + + +/* + * Function: angel_ChannelReadAsync + * Purpose: asynchronous read of a packet via a channel + * + * Params: + * Input: devid Device to use, or CH_DEFAULT_DEV + * chanid Channel to wait on + * callback Function to call on completion, or NULL + * callback_data Pointer to pass to callback + * Output: - + * In/Out: - + * + * Returns: CE_OKAY Read request registered + * CE_BAD_CHAN Channel id invalid + * CE_BUSY Someone else is using the channel + * (in a single threaded world) + * + * Reads globals: - + * Modifies globals: - + * + * Other side effects: - + * + * Register an asynchronous read on the given channel. There can only be one + * async. reader per channel, and blocking reads are not permitted whilst + * an async. reader is registered. + * + * Reader can unregister by specifying NULL as the callback function. + */ + +typedef void (*ChanRx_CB_Fn)(DeviceID devID, /* ID of receiving device */ + ChannelID chanID, /* ID of receiving channel */ + p_Buffer buff, /* pointer to buffer */ + unsigned len, /* length of data */ + void *cb_data /* callback data */ + ); + +ChanError angel_ChannelReadAsync(DeviceID devid, + ChannelID chanid, + ChanRx_CB_Fn callback, + void *callback_data); + + +/* + * Function: angel_ChannelReadAll + * Purpose: register an asynchronous read across all devices + * + * Params: + * Input: chanid Channel to look for (usually HBOOT) + * callback Function to call on completion + * callback_data Pointer to pass to callback + * Output: - + * In/Out: - + * + * Returns: CE_OKAY Read request registered + * CE_BAD_CHAN Channel id invalid + * CE_BUSY Someone else is reading all devices + * + * Reads globals: - + * Modifies globals: - + * + * Other side effects: - + * + * Register an asynchronous read across all devices. This is a 'fallback', + * which will be superseded (temporarily) by a registered reader or blocking + * read on a specific device. + */ + +ChanError angel_ChannelReadAll( ChannelID chanid, + ChanRx_CB_Fn callback, + void *callback_data); + + + +/* + * Function: angel_ChannelSendThenRead + * Purpose: blocking write to followed by read from a channel + * + * Params: + * Input: devid Device to use, or CH_DEFAULT_DEV + * chanid Channel to use for rx + * In/Out: buffer On entry: the packet to be sent + * On return: the packet received + * len On entry: length of packet to be sent + * On return: length of packet rx'd + * In/Out: - + * + * Returns: CE_OKAY Tx and Reception successful + * CE_BAD_CHAN Channel id invalid + * CE_ABANDONED Tx abandoned due to device switch + * + * Reads globals: - + * Modifies globals: - + * + * Other side effects: - + * + * Note that in the present version, if an asynchronous read has been + * registered, this will be refused with CE_BUSY. + */ +ChanError angel_ChannelSendThenRead(DeviceID devid, + ChannelID chanid, + p_Buffer *buffer, + unsigned *len); + + +/* + * Function: angel_ChannelSelectDevice + * Purpose: select the device to be used for all channel comms + * + * Params: + * Input: device ID of device to use as the default + * Output: - + * In/Out: - + * + * Returns: CE_OKAY Default device selected + * CE_BAD_DEV Invalid device ID + * + * Reads globals: - + * Modifies globals: - + * + * Other side effects: Any channel operations in progress are + * abandoned. + * + * select the device for all channels comms + */ + +ChanError angel_ChannelSelectDevice(DeviceID device); + + +/* + * Function: angel_ChannelReadActiveDevice + * Purpose: reads the device id of the currently active device + * + * Params: + * Input: device address of a DeviceID variable + * Output: *device ID of device currently being used + * In/Out: - + * + * Returns: CE_OKAY Default device selected + */ + +ChanError angel_ChannelReadActiveDevice(DeviceID *device); + +#endif /* ndef angel_channels_h */ + +/* EOF channels.h */ diff --git a/gdb/rdi-share/chanpriv.h b/gdb/rdi-share/chanpriv.h new file mode 100644 index 00000000000..155e864e297 --- /dev/null +++ b/gdb/rdi-share/chanpriv.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 1995 Advanced RISC Machines Limited. All rights reserved. + * + * This software may be freely used, copied, modified, and distributed + * provided that the above copyright notice is preserved in all copies of the + * software. + */ + +/* -*-C-*- + * + * $Revision$ + * $Date$ + * + * + * Project: ANGEL + * + * Title: Private header for channels implementations + */ + +#ifndef angel_chanpriv_h +#define angel_chanpriv_h + +/* + * This describes the internal structure and flags for a channels packet. + */ + +/* byte positions within channel packet */ +#define CF_CHANNEL_BYTE_POS 0 +#define CF_HOME_SEQ_BYTE_POS 1 +#define CF_OPPO_SEQ_BYTE_POS 2 +#define CF_FLAGS_BYTE_POS 3 +#define CF_DATA_BYTE_POS 4 + +/* flags for FLAGS field */ +#define CF_RELIABLE (1 << 0) /* use reliable channels protocol */ +#define CF_RESEND (1 << 1) /* this is a renegotiation packet */ +#define CF_HEARTBEAT (1 << 2) /* heartbeat packet - prod target into sync */ + +/* byte positions within buffer */ +#define CB_LINK_BYTE_POS 0 /* the link pointer */ +#define CB_CHAN_HEADER_BYTE_POS 4 /* the channel frame starts here */ + +/* macro to get buffer position of packet component */ +#define CB_PACKET(x) (CB_CHAN_HEADER_BYTE_POS + (x)) + +/* byte offset of packet data within buffer */ +#define CB_CHAN_DATA_BYTE_POS (CB_PACKET(CF_DATA_BYTE_POS)) + +/* access the link in a buffer, where b is byte pointer to buffer */ +#define CB_LINK(b) ((p_Buffer)(&(b)[0])) + +#define invalidChannelID(chan) (((int)(chan)) < 0 || \ + (chan) >= CI_NUM_CHANNELS) + +#endif /* ndef angel_chanpriv_h */ + +/* EOF chanpriv.h */ diff --git a/gdb/rdi-share/configure.in b/gdb/rdi-share/configure.in new file mode 100644 index 00000000000..cd4a7151859 --- /dev/null +++ b/gdb/rdi-share/configure.in @@ -0,0 +1,44 @@ +srcname="RDI library" +srctrigger=ardi.c + +# per-host: + +. ${srcdir}/../configure.host + +echo "rdi-share/configure.in: host is $host, target is $target" + +if [ ! -f ${srcdir}/../config/${gdb_host_cpu}/${gdb_host}.mh ]; then + echo '***' "GDB remote does not support host ${host}" 1>&2 + exit 1 +fi + +# We really shouldn't depend on there being a space after XM_FILE= ... +hostfile=`awk '$1 == "XM_FILE=" { print $2 }' <${srcdir}/../config/${gdb_host_cpu}/${gdb_host}.mh` + +# per-target: + +. ${srcdir}/../configure.tgt + +echo "rdi-share/configure.in: host_cpu is $host_cpu, target_cpu is $target_cpu" + +if [ ! -f ${srcdir}/../config/${gdb_target_cpu}/${gdb_target}.mt ]; then + echo '***' "GDB remote does not support target ${target}" 1>&2 + exit 1 +fi + +if [ -z "${removing}" ] ; then + cat ${srcdir}/../config/${gdb_host_cpu}/${gdb_host}.mh ${srcdir}/../config/${gdb_target_cpu}/${gdb_target}.mt | awk '$1 == "#msg" { + print substr($0,6)}' +fi + +# We really shouldn't depend on there being a space after TM_FILE= ... +targetfile=`awk '$1 == "TM_FILE=" { print $2 }' <${srcdir}/../config/${gdb_target_cpu}/${gdb_target}.mt` + +if [ "${target}" = "${host}" ] ; then + nativefile=`awk '$1 == "NAT_FILE=" { print $2 }' <${srcdir}/../config/${gdb_host_cpu}/${gdb_host}.mh` +fi + +host_makefile_frag=../config/${gdb_host_cpu}/${gdb_host}.mh +target_makefile_frag=../config/${gdb_target_cpu}/${gdb_target}.mt + +# post-target: diff --git a/gdb/rdi-share/crc.c b/gdb/rdi-share/crc.c new file mode 100644 index 00000000000..cfa6522e8d2 --- /dev/null +++ b/gdb/rdi-share/crc.c @@ -0,0 +1,257 @@ +/* + * Copyright (C) 1995 Advanced RISC Machines Limited. All rights reserved. + * + * This software may be freely used, copied, modified, and distributed + * provided that the above copyright notice is preserved in all copies of the + * software. + */ + +/* -*-C-*- + * + * $Revision$ + * $Date$ + * + * + * crc.c - provides some "standard" CRC calculation routines. + * + */ +#include "crc.h" /* describes this code */ + +/**********************************************************************/ + +/* + * crc32 IEEE-802.3 32bit CRC + * ----- -------------------- + */ + +/* This table was generated by the "crctable" program */ +static const unsigned int crc32table[256] = { + /* 0x00 */ 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, + /* 0x04 */ 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, + /* 0x08 */ 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, + /* 0x0C */ 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, + /* 0x10 */ 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, + /* 0x14 */ 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + /* 0x18 */ 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, + /* 0x1C */ 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, + /* 0x20 */ 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, + /* 0x24 */ 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, + /* 0x28 */ 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, + /* 0x2C */ 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + /* 0x30 */ 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, + /* 0x34 */ 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, + /* 0x38 */ 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, + /* 0x3C */ 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, + /* 0x40 */ 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, + /* 0x44 */ 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + /* 0x48 */ 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, + /* 0x4C */ 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, + /* 0x50 */ 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, + /* 0x54 */ 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, + /* 0x58 */ 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, + /* 0x5C */ 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + /* 0x60 */ 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, + /* 0x64 */ 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, + /* 0x68 */ 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, + /* 0x6C */ 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, + /* 0x70 */ 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, + /* 0x74 */ 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + /* 0x78 */ 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, + /* 0x7C */ 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, + /* 0x80 */ 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, + /* 0x84 */ 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, + /* 0x88 */ 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, + /* 0x8C */ 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + /* 0x90 */ 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, + /* 0x94 */ 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, + /* 0x98 */ 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, + /* 0x9C */ 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, + /* 0xA0 */ 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, + /* 0xA4 */ 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + /* 0xA8 */ 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, + /* 0xAC */ 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, + /* 0xB0 */ 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, + /* 0xB4 */ 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, + /* 0xB8 */ 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, + /* 0xBC */ 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + /* 0xC0 */ 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, + /* 0xC4 */ 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, + /* 0xC8 */ 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, + /* 0xCC */ 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, + /* 0xD0 */ 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, + /* 0xD4 */ 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + /* 0xD8 */ 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, + /* 0xDC */ 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, + /* 0xE0 */ 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, + /* 0xE4 */ 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, + /* 0xE8 */ 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, + /* 0xEC */ 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + /* 0xF0 */ 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, + /* 0xF4 */ 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, + /* 0xF8 */ 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, + /* 0xFC */ 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D, + }; +unsigned int crc32(unsigned char *address, unsigned int size, unsigned int crc) +{ +#if 0 + /* FAST, but bigger and only good for word-aligned data */ + unsigned int *daddr = (unsigned int *)address; + unsigned int data = FALSE; /* little-endian by default */ + + /* + * TODO: We should really get the current processor big- or + * little-endian state and set "data" accordingly. + */ + + /* Perform word loop to save on memory accesses */ + if (data) + /* big-endian */ + for (; (size > 0); size -= sizeof(unsigned int)) + { + data = *daddr++; + crc = (((crc >> 8) & 0x00FFFFFF) ^ + crc32table[(crc ^ ((data >> 24) & 0xFF)) & 0xFF]); + crc = (((crc >> 8) & 0x00FFFFFF) ^ + crc32table[(crc ^ ((data >> 16) & 0xFF)) & 0xFF]); + crc = (((crc >> 8) & 0x00FFFFFF) ^ + crc32table[(crc ^ ((data >> 8) & 0xFF)) & 0xFF]); + crc = (((crc >> 8) & 0x00FFFFFF) ^ + crc32table[(crc ^ ((data >> 0) & 0xFF)) & 0xFF]); + } + else + for (; (size > 0); size -= sizeof(unsigned int)) + { + data = *daddr++; + crc = (((crc >> 8) & 0x00FFFFFF) ^ + crc32table[(crc ^ ((data >> 0) & 0xFF)) & 0xFF]); + crc = (((crc >> 8) & 0x00FFFFFF) ^ + crc32table[(crc ^ ((data >> 8) & 0xFF)) & 0xFF]); + crc = (((crc >> 8) & 0x00FFFFFF) ^ + crc32table[(crc ^ ((data >> 16) & 0xFF)) & 0xFF]); + crc = (((crc >> 8) & 0x00FFFFFF) ^ + crc32table[(crc ^ ((data >> 24) & 0xFF)) & 0xFF]); + } +#else + for (; (size > 0); size--) + /* byte loop */ + crc = (((crc >> 8) & 0x00FFFFFF) ^ + crc32table[(crc ^ *address++) & 0x000000FF]); +#endif + + return(crc); +} + +/**********************************************************************/ + +/* + * crc16 16bit CRC-CCITT + * ----- --------------- + * This function provides a table driven 16bit CRC generation for byte data. + * This CRC is also known as the HDLC CRC. + */ +/* + * 960201 KWelton + * + *TODO: Is this correct? The compiler predefines __arm, *not* __ARM + */ +#ifdef __ARM +/* + * To make the code quicker on the ARM, we double the table size and + * use integer slots rather than short slots for the table. + */ +static const unsigned int crctableA[16] = { +#else +static const unsigned short crctableA[16] = { +#endif + 0x0000, + 0x1081, + 0x2102, + 0x3183, + 0x4204, + 0x5285, + 0x6306, + 0x7387, + 0x8408, + 0x9489, + 0xA50A, + 0xB58B, + 0xC60C, + 0xD68D, + 0xE70E, + 0xF78F + }; + +#ifdef __ARM +/* See comments above */ +static const unsigned int crctableB[16] = { +#else +static const unsigned short crctableB[16] = { +#endif + 0x0000, + 0x1189, + 0x2312, + 0x329B, + 0x4624, + 0x57AD, + 0x6536, + 0x74BF, + 0x8C48, + 0x9DC1, + 0xAF5A, + 0xBED3, + 0xCA6C, + 0xDBE5, + 0xE97E, + 0xF8F7 + }; + +unsigned short crc16(unsigned char *address, unsigned int size, + unsigned short crc) +{ + for (; (size > 0); size--) + { + /* byte loop */ + unsigned char data = *address++; /* fetch the next data byte */ + + data ^= crc; /* EOR data with current CRC value */ + crc = ((crctableA[(data & 0xF0) >> 4] ^ crctableB[data & 0x0F]) ^ + (crc >> 8)); + } + + return(crc); +} + +/**********************************************************************/ + +#if 0 /* not required at the moment */ + +/* + * elf_hash + * -------- + * This function is derived from the one on page 68 of chapter of the "Unix + * SVR4 Programmer's Guide". It is used to generate a hash-code from a + * symbol name. + */ +unsigned int elf_hash(const unsigned char *name) +{ + unsigned int h = 0; + unsigned int g; + + /* NULL pointer returns a hash of zero */ + while (name && (*name)) + { + h = ((h << 4) + *name++); + + if (g = (h & 0xF0000000)) + h ^= (g >> 24); + + h &= ~g; + } + + return(h); +} +#endif + +/**********************************************************************/ + +/* EOF crc.c */ diff --git a/gdb/rdi-share/crc.h b/gdb/rdi-share/crc.h new file mode 100644 index 00000000000..77ba23e97df --- /dev/null +++ b/gdb/rdi-share/crc.h @@ -0,0 +1,90 @@ +/* + * Copyright (C) 1995 Advanced RISC Machines Limited. All rights reserved. + * + * This software may be freely used, copied, modified, and distributed + * provided that the above copyright notice is preserved in all copies of the + * software. + */ + +/* -*-C-*- + * + * $Revision$ + * $Date$ + * + * + * crc.h - describes some "standard" CRC calculation routines. + */ +#ifndef angel_crc_h +#define angel_crc_h + +/* + * manifests + */ + +/* + * When using "crc32" or "crc16" these initial CRC values must be given to + * the respective function the first time it is called. The function can + * then be called with the return value from the last call of the function + * to generate a running CRC over multiple data blocks. + * When the last data block has been processed using the "crc32" algorithm + * the CRC value should be inverted to produce the final CRC value: + * e.g. CRC = ~CRC + */ + +#define startCRC32 (0xFFFFFFFF) /* CRC initialised to all 1s */ +#define startCRC16 (0x0000) /* CRC initialised to all 0s */ + +/* + * For the CRC-32 residual to be calculated correctly requires that the CRC + * value is in memory little-endian due to the byte read, bit-ordering + * nature of the algorithm. + */ +#define CRC32residual (0xDEBB20E3) /* good CRC-32 residual */ + + +/**********************************************************************/ + +/* + * exported functions + */ + +/* + * Function: crc32 + * Purpose: Provides a table driven implementation of the IEEE-802.3 + * 32-bit CRC algorithm for byte data. + * + * Params: + * Input: address pointer to the byte data + * size number of bytes of data to be processed + * crc initial CRC value to be used (can be the output + * from a previous call to this function). + * Returns: + * OK: 32-bit CRC value for the specified data + */ +extern unsigned int crc32(unsigned char *address, unsigned int size, + unsigned int crc); + +/**********************************************************************/ + +/* + * + * Function: crc16 + * Purpose: Generates a table driven 16-bit CRC-CCITT for byte data + * + * Params: + * Input: address pointer to the byte data + * size number of bytes of data to be processed + * crc initial CRC value to be used (can be the output + * from a previous call to this function). + * + * Returns: + * OK: 16-bit CRC value for the specified data + */ +extern unsigned short crc16(unsigned char *address, unsigned int size, + unsigned short crc); + +/**********************************************************************/ + +#endif /* !defined(angel_crc_h) */ + +/* EOF crc.h */ diff --git a/gdb/rdi-share/dbg_conf.h b/gdb/rdi-share/dbg_conf.h new file mode 100644 index 00000000000..bf79958e6c5 --- /dev/null +++ b/gdb/rdi-share/dbg_conf.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 1995 Advanced RISC Machines Limited. All rights reserved. + * + * This software may be freely used, copied, modified, and distributed + * provided that the above copyright notice is preserved in all copies of the + * software. + */ + +/* + * ARM symbolic debugger toolbox: dbg_conf.h + */ + +/* + * RCS $Revision$ + * Checkin $Date$ + */ + +#ifndef Dbg_Conf__h + +#define Dbg_Conf__h + +typedef struct Dbg_ConfigBlock { + int bytesex; + int fpe; /* Target should initialise FPE */ + long memorysize; + unsigned long cpu_speed;/* Cpu speed (HZ) */ + int serialport; /*) remote connection parameters */ + int seriallinespeed; /*) (serial connection) */ + int parallelport; /*) ditto */ + int parallellinespeed; /*) (parallel connection) */ + char *ethernettarget; /* name of remote ethernet target */ + int processor; /* processor the armulator is to emulate (eg ARM60) */ + int rditype; /* armulator / remote processor */ + int heartbeat_on; /* angel heartbeat */ + int drivertype; /* parallel / serial / etc */ + char const *configtoload; + char const *memconfigtoload; + int flags; +} Dbg_ConfigBlock; + +#define Dbg_ConfigFlag_Reset 1 +#define Dbg_ConfigFlag_LLSymsNeedPrefix 2 + +typedef struct Dbg_HostosInterface Dbg_HostosInterface; +/* This structure allows access by the (host-independent) C-library support + module of armulator or pisd (armos.c) to host-dependent functions for + which there is no host-independent interface. Its contents are unknown + to the debugger toolbox. + The assumption is that, in a windowed system, fputc(stderr) for example + may not achieve the desired effect of the character appearing in some + window. + */ + +#endif diff --git a/gdb/rdi-share/dbg_cp.h b/gdb/rdi-share/dbg_cp.h new file mode 100644 index 00000000000..8974f836442 --- /dev/null +++ b/gdb/rdi-share/dbg_cp.h @@ -0,0 +1,62 @@ +/* + * Copyright (C) 1995 Advanced RISC Machines Limited. All rights reserved. + * + * This software may be freely used, copied, modified, and distributed + * provided that the above copyright notice is preserved in all copies of the + * software. + */ + +/* + * ARM symbolic debugger toolbox: dbg_cp.h + */ + +/* + * RCS $Revision$ + * Checkin $Date$ + */ + +#ifndef Dbg_CP__h + +#define Dbg_CP__h + +#define Dbg_Access_Readable 1 +#define Dbg_Access_Writable 2 +#define Dbg_Access_CPDT 4 /* else CPRT */ + +typedef struct { + unsigned short rmin, rmax; + /* a single description can be used for a range of registers with + the same properties *accessed via CPDT instructions* + */ + unsigned char nbytes; /* size of register */ + unsigned char access; /* see above (Access_xxx) */ + union { + struct { /* CPDT instructions do not allow the coprocessor much freedom: + only bit 22 ('N') and 12-15 ('CRd') are free for the + coprocessor to use as it sees fit. + */ + unsigned char nbit; + unsigned char rdbits; + } cpdt; + struct { /* CPRT instructions have much more latitude. The bits fixed + by the ARM are 24..31 (condition mask & opcode) + 20 (direction) + 8..15 (cpnum, arm register) + 4 (CPRT not CPDO) + leaving 14 bits free to the coprocessor (fortunately + falling within two bytes). + */ + unsigned char read_b0, read_b1, + write_b0, write_b1; + } cprt; + } accessinst; +} Dbg_CoProRegDesc; + +struct Dbg_CoProDesc { + int entries; + Dbg_CoProRegDesc regdesc[1/* really nentries */]; +}; + +#define Dbg_CoProDesc_Size(n) (sizeof(struct Dbg_CoProDesc) + ((n)-1)*sizeof(Dbg_CoProRegDesc)) + +#endif diff --git a/gdb/rdi-share/dbg_hif.h b/gdb/rdi-share/dbg_hif.h new file mode 100644 index 00000000000..3982d1147bd --- /dev/null +++ b/gdb/rdi-share/dbg_hif.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 1995 Advanced RISC Machines Limited. All rights reserved. + * + * This software may be freely used, copied, modified, and distributed + * provided that the above copyright notice is preserved in all copies of the + * software. + */ + +/* + * ARM debugger toolbox : dbg_hif.c + * Description of the Dbg_HostosInterface structure. This is *NOT* + * part of the debugger toolbox, but it is required by 2 back ends + * (armul & pisd) and two front ends (armsd & wdbg), so putting it + * in the toolbox is the only way of avoiding multiple copies. + */ + +/* + * RCS $Revision$ + * Checkin $Date$ + */ + +#ifndef dbg_hif__h +#define dbg_hif__h + +#if defined __STDC__ || defined ALMOST_STDC +# include +#else +# include +#endif + +typedef void Hif_DbgPrint(void *arg, const char *format, va_list ap); +typedef void Hif_DbgPause(void *arg); + +typedef void Hif_WriteC(void *arg, int c); +typedef int Hif_ReadC(void *arg); +typedef int Hif_Write(void *arg, char const *buffer, int len); +typedef char *Hif_GetS(void *arg, char *buffer, int len); + +typedef void Hif_RDIResetProc(void *arg); + +struct Dbg_HostosInterface { + Hif_DbgPrint *dbgprint; + Hif_DbgPause *dbgpause; + void *dbgarg; + + Hif_WriteC *writec; + Hif_ReadC *readc; + Hif_Write *write; + Hif_GetS *gets; + void *hostosarg; + + Hif_RDIResetProc *reset; + void *resetarg; +}; + +#endif diff --git a/gdb/rdi-share/dbg_rdi.h b/gdb/rdi-share/dbg_rdi.h new file mode 100644 index 00000000000..efda7bd8800 --- /dev/null +++ b/gdb/rdi-share/dbg_rdi.h @@ -0,0 +1,511 @@ +/* + * Copyright (C) 1995 Advanced RISC Machines Limited. All rights reserved. + * + * This software may be freely used, copied, modified, and distributed + * provided that the above copyright notice is preserved in all copies of the + * software. + */ + +/* + * ARM debugger toolbox : dbg_rdi.h + */ + +/* + * RCS $Revision$ + * Checkin $Date$ + */ + +#ifndef dbg_rdi__h +#define dbg_rdi__h + +/***************************************************************************\ +* Other RDI values * +\***************************************************************************/ + +#define RDISex_Little 0 /* the byte sex of the debuggee */ +#define RDISex_Big 1 +#define RDISex_DontCare 2 + +#define RDIPoint_EQ 0 /* the different types of break/watchpoints */ +#define RDIPoint_GT 1 +#define RDIPoint_GE 2 +#define RDIPoint_LT 3 +#define RDIPoint_LE 4 +#define RDIPoint_IN 5 +#define RDIPoint_OUT 6 +#define RDIPoint_MASK 7 + +#define RDIPoint_16Bit 16 /* 16-bit breakpoint */ +#define RDIPoint_Conditional 32 + +/* ORRed with point type in extended RDP break and watch messages */ +#define RDIPoint_Inquiry 64 +#define RDIPoint_Handle 128 /* messages */ + +#define RDIWatch_ByteRead 1 /* types of data accesses to watch for*/ +#define RDIWatch_HalfRead 2 +#define RDIWatch_WordRead 4 +#define RDIWatch_ByteWrite 8 +#define RDIWatch_HalfWrite 16 +#define RDIWatch_WordWrite 32 + +#define RDIReg_R15 (1L << 15) /* mask values for CPU */ +#define RDIReg_PC (1L << 16) +#define RDIReg_CPSR (1L << 17) +#define RDIReg_SPSR (1L << 18) +#define RDINumCPURegs 19 + +#define RDINumCPRegs 10 /* current maximum */ + +#define RDIMode_Curr 255 + +/* RDI_Info subcodes */ +/* rdp in parameters are all preceded by */ +/* in byte = RDP_Info, word = info subcode */ +/* out parameters are all preceded by */ +/* out byte = RDP_Return */ + +#define RDIInfo_Target 0 +/* rdi: out ARMword *targetflags, out ARMword *processor id */ +/* rdp: in none, out word targetflags, word processorid, byte status */ +/* the following bits are defined in targetflags */ +# define RDITarget_LogSpeed 0x0f +# define RDITarget_HW 0x10 /* else emulator */ +# define RDITarget_AgentMaxLevel 0xe0 +# define RDITarget_AgentLevelShift 5 +# define RDITarget_DebuggerMinLevel 0x700 +# define RDITarget_DebuggerLevelShift 8 +# define RDITarget_CanReloadAgent 0x800 +# define RDITarget_CanInquireLoadSize 0x1000 +# define RDITarget_UnderstandsRDPInterrupt 0x2000 +# define RDITarget_CanProfile 0x4000 +# define RDITarget_Code16 0x8000 +# define RDITarget_HasCommsChannel 0x10000 + +#define RDIInfo_Points 1 +/* rdi: out ARMword *pointcapabilities */ +/* rdp: in none, out word pointcapabilities, byte status */ +/* the following bits are defined in pointcapabilities */ +# define RDIPointCapability_Comparison 1 +# define RDIPointCapability_Range 2 +/* 4 to 128 are RDIWatch_xx{Read,Write} left-shifted by two */ +# define RDIPointCapability_Mask 0x100 +# define RDIPointCapability_ThreadBreak 0x200 +# define RDIPointCapability_ThreadWatch 0x400 +# define RDIPointCapability_CondBreak 0x800 +# define RDIPointCapability_Status 0x1000 /* status enquiries available */ + +#define RDIInfo_Step 2 +/* rdi: out ARMword *stepcapabilities */ +/* rdp: in none, out word stepcapabilities, byte status */ +/* the following bits are defined in stepcapabilities */ +# define RDIStep_Multiple 1 +# define RDIStep_PCChange 2 +# define RDIStep_Single 4 + +#define RDIInfo_MMU 3 +/* rdi: out ARMword *mmuidentity */ +/* rdp: in none, out word mmuidentity, byte status */ + +#define RDIInfo_DownLoad 4 +/* Inquires whether configuration download and selection is available. */ +/* rdp: in none, out byte status */ +/* No argument, no return value. status == ok if available */ + +#define RDIInfo_SemiHosting 5 +/* Inquires whether RDISemiHosting_* RDI_Info calls are available. */ +/* rdp: in none, out byte status */ +/* No argument, no return value. status == ok if available */ + +#define RDIInfo_CoPro 6 +/* Inquires whether CoPro RDI_Info calls are available. */ +/* rdp: in none, out byte status */ +/* No argument, no return value. status == ok if available */ + +#define RDIInfo_Icebreaker 7 +/* Inquires whether debuggee controlled by IceBreaker. */ +/* rdp: in none, out byte status */ +/* No argument, no return value. status == ok if available */ + +#define RDIMemory_Access 8 +/* rdi: out RDI_MemAccessStats *p, in ARMword *handle */ +/* rdp: in word handle */ +/* out word nreads, word nwrites, word sreads, word swrites, */ +/* word ns, word s, byte status */ + +/* Get memory access information for memory block with specified handle */ + +#define RDIMemory_Map 9 +/* rdi: in RDI_MemDescr md[n], in ARMword *n */ +/* rdp: in word n, n * { */ +/* word handle, word start, word limit, */ +/* byte width, byte access */ +/* word Nread_ns, word Nwrite_ns, */ +/* word Sread_ns, word Swrite_ns} */ +/* out byte status */ +/* Sets memory characteristics. */ + +#define RDISet_CPUSpeed 10 +/* rdi: in ARMword *speed */ +/* rdp: in word speed, out byte status */ +/* Sets CPU speed (in ns) */ + +#define RDIRead_Clock 12 +/* rdi: out ARMword *ns, out ARMword *s */ +/* rdp: in none, out word ns, word s, byte status */ +/* Reads simulated time */ + +#define RDIInfo_Memory_Stats 13 +/* Inquires whether RDI_Info codes 8-10 are available */ +/* rdp: in none, out byte status */ +/* No argument, no return value. status == ok if available */ + +/* The next two are only to be used if RDIInfo_DownLoad returned no */ +/* error */ +#define RDIConfig_Count 14 +/* rdi: out ARMword *count */ +/* rdp: out byte status, word count (if status == OK) */ + +/* In addition, the next one is only to be used if RDIConfig_Count */ +/* returned no error */ +typedef struct { unsigned32 version; char name[32]; } RDI_ConfigDesc; +#define RDIConfig_Nth 15 +/* rdi: in ARMword *n, out RDI_ConfigDesc * */ +/* rdp: in word n */ +/* out word version, byte namelen, bytes * bytelen name, */ +/* byte status */ + +/* Set a front-end polling function to be used from within driver poll */ +/* loops */ +typedef void RDI_PollProc(void *); +typedef struct { RDI_PollProc *p; void *arg; } RDI_PollDesc; +#define RDISet_PollProc 16 +/* rdi: in RDI_PollDesc const *from, RDI_PollDesc *to */ +/* if from non-NULL, sets the polling function from it */ +/* if to non-NULL, returns the previous polling function to it */ +/* No corresponding RDP operation */ + +/* Called on debugger startup to see if the target is ready to execute */ +#define RDIInfo_CanTargetExecute 20 +/* rdi: in void + * out byte status (RDIError_NoError => Yes, Otherwise No) + */ + +/* Called to set the top of target memory in an ICEman2 system + * This is then used by ICEman to tell the C Library via the INFOHEAP + * SWI where the stack should start. + * Note that only ICEman2 supports this call. Other systems eg. + * Demon, Angel, will simply return an error, which means that setting + * the top of memory in this fashion is not supported. + */ +#define RDIInfo_SetTopMem 21 +/* rdi: in word mem_top + * out byte status (RDIError_NoError => Done, Other => Not supported + */ + +/* Called before performing a loadagent to determine the endianess of + * the debug agent, so that images of the wrong bytesex can be + * complained about + */ +#define RDIInfo_AgentEndianess 22 +/* rdi: in void + * out byte status + * status should be RDIError_LittleEndian or RDIError_BigEndian + * any other value indicates the target does not support this + * request, so the debugger will have to make a best guess, which + * probably means only allow little endian loadagenting. + */ + +/* The next two are only to be used if the value returned by */ +/* RDIInfo_Points has RDIPointCapability_Status set. */ +#define RDIPointStatus_Watch 0x80 +#define RDIPointStatus_Break 0x81 +/* rdi: inout ARMword * (in handle, out hwresource), out ARMword *type */ +/* rdp: in word handle, out word hwresource, word type, byte status */ + +#define RDISignal_Stop 0x100 +/* Requests that the debuggee stop */ +/* No arguments, no return value */ +/* rdp: no reply (when the debuggee stops, there will be a reply to the */ +/* step or execute request which started it) */ + +#define RDIVector_Catch 0x180 +/* rdi: in ARMword *bitmap */ +/* rdp: int word bitmap, out byte status */ +/* bit i in bitmap set to cause vector i to cause entry to debugger */ + +/* The next four are only to be used if RDIInfo_Semihosting returned */ +/* no error */ +#define RDISemiHosting_SetState 0x181 +/* rdi: in ARMword *semihostingstate */ +/* rdp: in word semihostingstate, out byte status */ +#define RDISemiHosting_GetState 0x182 +/* rdi: out ARMword *semihostingstate */ +/* rdp: in none, out word semihostingstate, byte status */ +#define RDISemiHosting_SetVector 0x183 +/* rdi: in ARMword *semihostingvector */ +/* rdp: in word semihostingvector, out byte status */ +#define RDISemiHosting_GetVector 0x184 +/* rdi: out ARMword *semihostingvector */ +/* rdp: in none, out word semihostingvector, byte status */ + +/* The next two are only to be used if RDIInfo_Icebreaker returned */ +/* no error */ +#define RDIIcebreaker_GetLocks 0x185 +/* rdi: out ARMword *lockedstate */ +/* rdp: in none, out word lockedstate, byte status */ + +#define RDIIcebreaker_SetLocks 0x186 +/* rdi: in ARMword *lockedstate */ +/* rdp: in word lockedstate, out byte status */ + +/* lockedstate is a bitmap of the icebreaker registers locked against */ +/* use by IceMan (because explicitly written by the user) */ + +#define RDIInfo_GetLoadSize 0x187 +/* rdi: out ARMword *maxloadsize */ +/* rdp: in none, out word maxloadsize, byte status */ +/* Inquires the maximum length of data transfer the agent is prepared */ +/* to receive */ +/* Only usable if RDIInfo_Target returned RDITarget_CanInquireLoadSize */ +/* rdi: out ARMword *size */ + +/* Only to be used if the value returned by RDIInfo_Target had */ +/* RDITarget_HasCommsChannel set */ +typedef void RDICCProc_ToHost(void *arg, ARMword data); +typedef void RDICCProc_FromHost(void *arg, ARMword *data, int *valid); + +#define RDICommsChannel_ToHost 0x188 +/* rdi: in RDICCProc_ToHost *, in void *arg */ +/* rdp: in byte connect, out byte status */ +#define RDICommsChannel_FromHost 0x189 +/* rdi: in RDICCProc_FromHost *, in void *arg */ +/* rdp: in byte connect, out byte status */ + +/* These 4 are only to be used if RDIInfo_Semihosting returns no error */ +#define RDISemiHosting_SetARMSWI 0x190 +/* rdi: in ARMword ARM_SWI_number */ +/* rdp: in ARMword ARM_SWI_number, out byte status */ + +#define RDISemiHosting_GetARMSWI 0x191 +/* rdi: out ARMword ARM_SWI_number */ +/* rdp: out ARMword ARM_SWI_number, byte status */ + +#define RDISemiHosting_SetThumbSWI 0x192 +/* rdi: in ARMword Thumb_SWI_number */ +/* rdp: in ARMword Thumb_SWI_number, out byte status */ + +#define RDISemiHosting_GetThumbSWI 0x193 +/* rdi: out ARMword ARM_Thumb_number */ +/* rdp: out ARMword ARM_Thumb_number, byte status */ + + +#define RDICycles 0x200 +/* rdi: out ARMword cycles[12] */ +/* rdp: in none, out 6 words cycles, byte status */ +/* the rdi result represents 6 big-endian doublewords; the rdp results */ +/* return values for the ls halves of these */ +# define RDICycles_Size 48 + +#define RDIErrorP 0x201 +/* rdi: out ARMaddress *errorp */ +/* rdp: in none, out word errorp, byte status */ +/* Returns the error pointer associated with the last return from step */ +/* or execute with status RDIError_Error. */ + +#define RDISet_Cmdline 0x300 +/* rdi: in char *commandline (a null-terminated string) */ +/* No corresponding RDP operation (cmdline is sent to the agent in */ +/* response to SWI_GetEnv) */ + +#define RDISet_RDILevel 0x301 +/* rdi: in ARMword *level */ +/* rdp: in word level, out byte status */ +/* Sets the RDI/RDP protocol level to be used (must lie between the */ +/* limits returned by RDIInfo_Target). */ + +#define RDISet_Thread 0x302 +/* rdi: in ARMword *threadhandle */ +/* rdp: in word threadhandle, out byte status */ +/* Sets the thread context for subsequent thread-sensitive operations */ +/* (null value sets no thread) */ + +/* The next two are only to be used if RDI_read or RDI_write returned */ +/* RDIError_LittleEndian or RDIError_BigEndian, to signify that the */ +/* debugger has noticed. */ +#define RDIInfo_AckByteSex 0x303 +/* rdi: in ARMword *sex (RDISex_Little or RDISex_Big) */ + +/* The next two are only to be used if RDIInfo_CoPro returned no error */ +#define RDIInfo_DescribeCoPro 0x400 +/* rdi: in int *cpno, Dbg_CoProDesc *cpd */ +/* rdp: in byte cpno, */ +/* cpd->entries * { */ +/* byte rmin, byte rmax, byte nbytes, byte access, */ +/* byte cprt_r_b0, cprt_r_b1, cprt_w_b0, cprt_w_b1} */ +/* byte = 255 */ +/* out byte status */ + +#define RDIInfo_RequestCoProDesc 0x401 +/* rdi: in int *cpno, out Dbg_CoProDesc *cpd */ +/* rpd: in byte cpno */ +/* out nentries * { */ +/* byte rmin, byte rmax, byte nbytes, byte access, */ +/* } */ +/* byte = 255, byte status */ + +#define RDIInfo_Log 0x800 +/* rdi: out ARMword *logsetting */ +/* No corresponding RDP operation */ +#define RDIInfo_SetLog 0x801 +/* rdi: in ARMword *logsetting */ +/* No corresponding RDP operation */ + +#define RDIProfile_Stop 0x500 +/* No arguments, no return value */ +/* rdp: in none, out byte status */ +/* Requests that pc sampling stop */ + +#define RDIProfile_Start 0x501 +/* rdi: in ARMword *interval */ +/* rdp: in word interval, out byte status */ +/* Requests that pc sampling start, with period usec */ + +#define RDIProfile_WriteMap 0x502 +/* rdi: in ARMword map[] */ +/* map[0] is the length of the array, subsequent elements are sorted */ +/* and are the base of ranges for pc sampling (so if the sampled pc */ +/* lies between map[i] and map[i+1], count[i] is incremented). */ +/* rdp: a number of messages, each of form: */ +/* in word len, word size, word offset, words map data */ +/* out status */ +/* len, size and offset are all word counts. */ + +#define RDIProfile_ReadMap 0x503 +/* rdi: in ARMword *len, out ARMword counts[len] */ +/* Requests that the counts array be set to the accumulated pc sample */ +/* counts */ +/* rdp: a number of messages, each of form: */ +/* in word offset, word size */ +/* out words, status */ +/* len, size and offset are all word counts. */ + +#define RDIProfile_ClearCounts 0x504 +/* No arguments, no return value */ +/* rdp: in none, out byte status */ +/* Requests that pc sample counts be set to zero */ + +#define RDIInfo_RequestReset 0x900 +/* Request reset of the target environment */ +/* No arguments, no return value */ +/* No RDP equivalent, sends an RDP reset */ + +#define RDIInfo_CapabilityRequest 0x8000 +/* Request whether the interface supports the named capability. The */ +/* capability is specified by or'ing the RDIInfo number with this, and */ +/* sending that request */ +/* rdi: in none */ +/* rdp: in none, out byte status */ + +typedef struct { + ARMword len; + ARMword map[1]; +} RDI_ProfileMap; + +typedef unsigned32 PointHandle; +typedef unsigned32 ThreadHandle; +#define RDINoPointHandle ((PointHandle)-1L) +#define RDINoHandle ((ThreadHandle)-1L) + +struct Dbg_ConfigBlock; +struct Dbg_HostosInterface; +struct Dbg_MCState; +typedef int rdi_open_proc(unsigned type, struct Dbg_ConfigBlock const *config, + struct Dbg_HostosInterface const *i, + struct Dbg_MCState *dbg_state); +typedef int rdi_close_proc(void); +typedef int rdi_read_proc(ARMword source, void *dest, unsigned *nbytes); +typedef int rdi_write_proc(const void *source, ARMword dest, unsigned *nbytes); +typedef int rdi_CPUread_proc(unsigned mode, unsigned32 mask, ARMword *state); +typedef int rdi_CPUwrite_proc(unsigned mode, unsigned32 mask, ARMword const *state); +typedef int rdi_CPread_proc(unsigned CPnum, unsigned32 mask, ARMword *state); +typedef int rdi_CPwrite_proc(unsigned CPnum, unsigned32 mask, ARMword const *state); +typedef int rdi_setbreak_proc(ARMword address, unsigned type, ARMword bound, + PointHandle *handle); +typedef int rdi_clearbreak_proc(PointHandle handle); +typedef int rdi_setwatch_proc(ARMword address, unsigned type, unsigned datatype, + ARMword bound, PointHandle *handle); +typedef int rdi_clearwatch_proc(PointHandle handle); +typedef int rdi_execute_proc(PointHandle *handle); +typedef int rdi_step_proc(unsigned ninstr, PointHandle *handle); +typedef int rdi_info_proc(unsigned type, ARMword *arg1, ARMword *arg2); +typedef int rdi_pointinq_proc(ARMword *address, unsigned type, + unsigned datatype, ARMword *bound); + +typedef enum { + RDI_ConfigCPU, + RDI_ConfigSystem +} RDI_ConfigAspect; + +typedef enum { + RDI_MatchAny, + RDI_MatchExactly, + RDI_MatchNoEarlier +} RDI_ConfigMatchType; + +typedef int rdi_addconfig_proc(unsigned32 nbytes); +typedef int rdi_loadconfigdata_proc(unsigned32 nbytes, char const *data); +typedef int rdi_selectconfig_proc(RDI_ConfigAspect aspect, char const *name, + RDI_ConfigMatchType matchtype, unsigned versionreq, + unsigned *versionp); + +typedef char *getbufferproc(void *getbarg, unsigned32 *sizep); +typedef int rdi_loadagentproc(ARMword dest, unsigned32 size, getbufferproc *getb, void *getbarg); +typedef int rdi_targetisdead(void); + +typedef struct { + int itemmax; + char const * const *names; +} RDI_NameList; + +typedef RDI_NameList const *rdi_namelistproc(void); + +typedef int rdi_errmessproc(char *buf, int buflen, int errnum); + +struct RDIProcVec { + char rditypename[12]; + + rdi_open_proc *open; + rdi_close_proc *close; + rdi_read_proc *read; + rdi_write_proc *write; + rdi_CPUread_proc *CPUread; + rdi_CPUwrite_proc *CPUwrite; + rdi_CPread_proc *CPread; + rdi_CPwrite_proc *CPwrite; + rdi_setbreak_proc *setbreak; + rdi_clearbreak_proc *clearbreak; + rdi_setwatch_proc *setwatch; + rdi_clearwatch_proc *clearwatch; + rdi_execute_proc *execute; + rdi_step_proc *step; + rdi_info_proc *info; + /* V2 RDI */ + rdi_pointinq_proc *pointinquiry; + + /* These three useable only if RDIInfo_DownLoad returns no error */ + rdi_addconfig_proc *addconfig; + rdi_loadconfigdata_proc *loadconfigdata; + rdi_selectconfig_proc *selectconfig; + + rdi_namelistproc *drivernames; + rdi_namelistproc *cpunames; + + rdi_errmessproc *errmess; + + /* Only if RDIInfo_Target returns a value with RDITarget_LoadAgent set */ + rdi_loadagentproc *loadagent; + rdi_targetisdead *targetisdead; +}; + +#endif diff --git a/gdb/rdi-share/devclnt.h b/gdb/rdi-share/devclnt.h new file mode 100644 index 00000000000..cb920f66baf --- /dev/null +++ b/gdb/rdi-share/devclnt.h @@ -0,0 +1,260 @@ +/* + * Copyright (C) 1995 Advanced RISC Machines Limited. All rights reserved. + * + * This software may be freely used, copied, modified, and distributed + * provided that the above copyright notice is preserved in all copies of the + * software. + */ + +/* -*-C-*- + * + * $Revision$ + * $Date$ + * + * + * Project: ANGEL + * + * Title: Public client interface to devices + */ + +#ifndef angel_devclnt_h +#define angel_devclnt_h + +/* + * This header exports the public interface to Angel-compliant device + * drivers. + * + * They are intended to be used solely by Angel, not by the User + * Application. See devappl.h for the User Application interface to + * the device drivers. + */ + +#include "devices.h" + +/* General purpose constants, macros, enums, typedefs */ + +/* + * possible channels at device level + * + * XXX + * + * these are used as array indices, so be specific about their values + */ +typedef enum DevChanID { + DC_DBUG = 0, /* reliable debug packets + * containing SDBG, CLIB,UDBG, etc.) */ + DC_APPL = 1, /* application packets */ + DC_NUM_CHANNELS +} DevChanID; + +/* Publically-accessible globals */ +/* none */ + +/* Public functions */ + +/* + * Function: angel_DeviceWrite + * Purpose: The main entry point for asynchronous writes to a device. + * + * Params: + * Input: devID index of the device to write to + * buff data to write + * length how much data to write + * callback callback here when write finished + * or error + * cb_data data to be passed to callback + * chanID device channel to use + * Output: - + * In/Out: - + * + * Returns: DE_OKAY write request is underway + * DE_NO_DEV no such device + * DE_BAD_DEV device does not support angel writes + * DE_BAD_CHAN no such device channel + * DE_BUSY device busy with another write + * DE_INVAL silly length + * + * Reads globals: - + * Modifies globals: - + * + * Other side effects: - + * + * Commence asynchronous transmission of a buffer on a device. The + * callback will occur when the write completes or if there is an + * error. + * + * This must be called for each packet to be sent. + */ + +DevError angel_DeviceWrite(DeviceID devID, p_Buffer buff, + unsigned length, DevWrite_CB_Fn callback, + void *cb_data, DevChanID chanID); + + +/* + * Function: angel_DeviceRegisterRead + * Purpose: The main entry point for asynchronous reads from a device. + * + * Params: + * Input: devID index of the device to read from + * callback callback here when read finished + * or error + * cb_data data to be passed to callback + * get_buff callback to be used to acquire buffer + * for incoming packets + * getb_data data to be passed to get_buff + * chanID device channel to use + * Output: - + * In/Out: - + * + * Returns: DE_OKAY read request is underway + * DE_NO_DEV no such device + * DE_BAD_DEV device does not support angel reads + * DE_BAD_CHAN no such device channel + * DE_BUSY device busy with another read + * DE_INVAL silly length + * + * Reads globals: - + * Modifies globals: - + * + * Other side effects: - + * + * Register asynchronous packet read from a device. The callback will + * occur when the read completes or if there is an error. + * + * This is persistent: the read remains registered for all incoming + * packets on the device channel. + */ + +DevError angel_DeviceRegisterRead(DeviceID devID, + DevRead_CB_Fn callback, void *cb_data, + DevGetBuff_Fn get_buff, void *getb_data, + DevChanID chanID); + + +/* + * Function: angel_DeviceControl + * Purpose: Call a control function for a device + * + * Params: + * Input: devID index of the device to control to + * op operation to perform + * arg parameter depending on op + * + * Returns: DE_OKAY control request is underway + * DE_NO_DEV no such device + * DE_BAD_OP device does not support operation + * + * Reads globals: - + * Modifies globals: - + * + * Other side effects: - + * + * Have a device perform a control operation. Extra parameters vary + * according to the operation requested. + */ + +DevError angel_DeviceControl(DeviceID devID, DeviceControl op, void *arg); + + +/* + * Function: angel_ReceiveMode + * Purpose: enable or disable reception across all devices + * + * Params: + * Input: mode choose enable or disable + * + * Pass the mode parameter to the receive_mode control method of each device + */ + +void angel_ReceiveMode(DevRecvMode mode); + + +/* + * Function: angel_ResetDevices + * Purpose: reset all devices + * + * Params: none + * + * Call the reset control method for each device + */ + +void angel_ResetDevices(void); + + +/* + * Function: angel_InitialiseDevices + * Purpose: initialise the device driver layer + * + * Params: none + * + * Set up the device driver layer and call the init method for each device + */ + +void angel_InitialiseDevices(void); + + +/* + * Function: angel_IsAngelDevice + * Purpose: Find out if a device supports Angel packets + * + * Params: + * Input: devID index of the device to control to + * + * Returns: TRUE supports Angel packets + * FALSE raw device + * + * Reads globals: - + * Modifies globals: - + * + * Other side effects: - + */ + +bool angel_IsAngelDevice(DeviceID devID); + + +#if !defined(MINIMAL_ANGEL) || MINIMAL_ANGEL == 0 + +/* + * Function: angel_ApplDeviceHandler + * Purpose: The entry point for User Application Device Driver requests + * in a full functiionality version of Angel. + * It will never be called directly by the User Application, + * but gets called indirectly, via the SWI handler. + * + * Params: + * Input: swi_r0 Argument to SWI indicating that + * angel_ApplDeviceHandler was to be called. This + * will not be used in this function, but is needed + * by the SWI handler. + * arg_blk pointer to block of arguments + * arg_blk[0] is one of + * angel_SWIreason_ApplDevice_{Read,Write,Yield} + * which indicates which angel_Device* fn is to + * be called. arg_blk[1] - arg_blk[n] are the + * arguments to the corresponding + * angel_ApplDevice* function. + * Output: - + * In/Out: - + * + * Returns: whatever the specified angel_Device* function + * returns. + * + * Reads globals: - + * Modifies globals: - + * + * Other side effects: - + * + * This has the side effects of angel_Device{Read,Write,Yield} + * depending upon which is operation is specified as described above. + */ + +DevError angel_ApplDeviceHandler( + unsigned swi_r0, unsigned *arg_blk +); + +#endif /* ndef MINIMAL_ANGEL */ + +#endif /* ndef angel_devclnt_h */ + +/* EOF devclnt.h */ diff --git a/gdb/rdi-share/devices.h b/gdb/rdi-share/devices.h new file mode 100644 index 00000000000..eac6ee20fd7 --- /dev/null +++ b/gdb/rdi-share/devices.h @@ -0,0 +1,104 @@ +/* + * Copyright (C) 1995 Advanced RISC Machines Limited. All rights reserved. + * + * This software may be freely used, copied, modified, and distributed + * provided that the above copyright notice is preserved in all copies of the + * software. + */ + +/* -*-C-*- + * + * $Revision$ + * $Date$ + * + * + * Project: ANGEL + * + * Title: Devices header file + */ + +#ifndef angel_devices_h +#define angel_devices_h + +/* + * Provides common types for using devices, and provides access to the + * device table. + */ + +#include "angel.h" +#include "buffers.h" + +/* General purpose constants, macros, enums, typedefs */ + +/* a non-enum holder for device IDs */ +typedef unsigned int DeviceID; + +/* device error codes */ +typedef enum DevError { + DE_OKAY, /* no error */ + DE_NO_DEV, /* no such device */ + DE_BAD_DEV, /* device does not support angel */ + DE_BAD_CHAN, /* no such device channel */ + DE_BAD_OP, /* operation not supported by this device */ + DE_BUSY, /* device already busy */ + DE_INVAL, /* length invalid */ + DE_FAILED /* something else went wrong */ +} DevError; + +/* return codes from asynchronous calls - primarily for channels' benefit */ +typedef enum DevStatus { + DS_DONE, /* operation succeeded */ + DS_OVERFLOW, /* not enough buffer space */ + DS_BAD_PACKET, /* packet failed */ + DS_DEV_ERROR, /* device error */ + DS_INT_ERROR /* internal error */ +} DevStatus; + +/* Callback for async. writes */ +typedef void (*DevWrite_CB_Fn)( + void *buff, /* pointer to data -- cast to p_Buffer */ + void *length, /* how much done -- cast to unsigned */ + void *status, /* success code -- cast to DevStatus */ + void *cb_data /* as supplied */ + ); + +/* Callback for async. reads */ +typedef void (*DevRead_CB_Fn)( + void *buff, /* pointer to data -- cast to p_Buffer */ + void *length, /* how much read -- cast to unsigned */ + void *status, /* success code -- cast to DevStatus */ + void *cb_data /* as supplied */ + ); + +/* control operations */ +typedef enum DeviceControl { + DC_INIT, /* initialise device */ + DC_RESET, /* reset device */ + DC_RECEIVE_MODE, /* control reception */ + DC_SET_PARAMS, /* set parameters of device */ +#ifndef TARGET + DC_GET_USER_PARAMS, /* params set by user at open */ + DC_GET_DEFAULT_PARAMS, /* device default parameters */ + DC_RESYNC, /* resynchronise with new agent */ +#endif + DC_PRIVATE /* start of private device codes */ +} DeviceControl; + +typedef enum DevRecvMode { + DR_DISABLE, + DR_ENABLE +} DevRecvMode; + +/* + * callback to allow a device driver to request a buffer, to be filled + * with an incoming packet + */ +typedef p_Buffer (*DevGetBuff_Fn)(unsigned req_size, void *cb_data); + + +/* Publically-accessible globals */ +/* none */ + +#endif /* ndef angel_devices_h */ + +/* EOF devices.h */ diff --git a/gdb/rdi-share/devsw.c b/gdb/rdi-share/devsw.c new file mode 100644 index 00000000000..590b81241e8 --- /dev/null +++ b/gdb/rdi-share/devsw.c @@ -0,0 +1,400 @@ +/* + * Copyright (C) 1995 Advanced RISC Machines Limited. All rights reserved. + * + * This software may be freely used, copied, modified, and distributed + * provided that the above copyright notice is preserved in all copies of the + * software. + */ + +/* -*-C-*- + * + * $Revision$ + * $Date$ + * + */ +#include +#include + +#include "adp.h" +#include "hsys.h" +#include "rxtx.h" +#include "drivers.h" +#include "buffers.h" +#include "devclnt.h" +#include "adperr.h" +#include "devsw.h" +#include "hostchan.h" +#include "logging.h" + +/* + * TODO: this should be adjustable - it could be done by defining + * a reason code for DevSW_Ioctl. It could even be a + * per-devicechannel parameter. + */ +static const unsigned int allocsize = ADP_BUFFER_MIN_SIZE; + +#define illegalDevChanID(type) ((type) >= DC_NUM_CHANNELS) + +/**********************************************************************/ + +/* + * Function: initialise_read + * Purpose: Set up a read request for another packet + * + * Params: + * In/Out: ds State structure to be initialised + * + * Returns: + * OK: 0 + * Error: -1 + */ +static int initialise_read(DevSWState *ds) +{ + struct data_packet *dp; + + /* + * try to claim the structure that will + * eventually hold the new packet. + */ + if ((ds->ds_nextreadpacket = DevSW_AllocatePacket(allocsize)) == NULL) + return -1; + + /* + * Calls into the device driver use the DriverCall structure: use + * the buffer we have just allocated, and declare its size. We + * are also obliged to clear the driver's context pointer. + */ + dp = &ds->ds_activeread.dc_packet; + dp->buf_len = allocsize; + dp->data = ds->ds_nextreadpacket->pk_buffer; + + ds->ds_activeread.dc_context = NULL; + + return 0; +} + +/* + * Function: initialise_write + * Purpose: Set up a write request for another packet + * + * Params: + * Input: packet The packet to be written + * + * type The type of the packet + * + * In/Out: dc The structure to be intialised + * + * Returns: Nothing + */ +static void initialise_write(DriverCall *dc, Packet *packet, DevChanID type) +{ + struct data_packet *dp = &dc->dc_packet; + + dp->len = packet->pk_length; + dp->data = packet->pk_buffer; + dp->type = type; + + /* + * we are required to clear the state structure for the driver + */ + dc->dc_context = NULL; +} + +/* + * Function: enqueue_packet + * Purpose: move a newly read packet onto the appropriate queue + * of read packets + * + * Params: + * In/Out: ds State structure with new packet + * + * Returns: Nothing + */ +static void enqueue_packet(DevSWState *ds) +{ + struct data_packet *dp = &ds->ds_activeread.dc_packet; + Packet *packet = ds->ds_nextreadpacket; + + /* + * transfer the length + */ + packet->pk_length = dp->len; + + /* + * take this packet out of the incoming slot + */ + ds->ds_nextreadpacket = NULL; + + /* + * try to put it on the correct input queue + */ + if (illegalDevChanID(dp->type)) + { + /* this shouldn't happen */ + WARN("Illegal type for Rx packet"); + DevSW_FreePacket(packet); + } + else + Adp_addToQueue(&ds->ds_readqueue[dp->type], packet); +} + +/* + * Function: flush_packet + * Purpose: Send a packet to the device driver + * + * Params: + * Input: device The device to be written to + * + * In/Out: dc Describes the packet to be sent + * + * Returns: Nothing + * + * Post-conditions: If the whole packet was accepted by the device + * driver, then dc->dc_packet.data will be + * set to NULL. + */ +static void flush_packet(const DeviceDescr *device, DriverCall *dc) +{ + if (device->DeviceWrite(dc) > 0) + /* + * the whole packet was swallowed + */ + dc->dc_packet.data = NULL; +} + +/**********************************************************************/ + +/* + * These are the externally visible functions. They are documented in + * devsw.h + */ +Packet *DevSW_AllocatePacket(const unsigned int length) +{ + Packet *pk; + + if ((pk = malloc(sizeof(*pk))) == NULL) + { + WARN("malloc failure"); + return NULL; + } + + if ((pk->pk_buffer = malloc(length+CHAN_HEADER_SIZE)) == NULL) + { + WARN("malloc failure"); + free(pk); + return NULL; + } + + return pk; +} + +void DevSW_FreePacket(Packet *pk) +{ + free(pk->pk_buffer); + free(pk); +} + +AdpErrs DevSW_Open(DeviceDescr *device, const char *name, const char *arg, + const DevChanID type) +{ + DevSWState *ds; + + /* + * is this the very first open call for this driver? + */ + if ((ds = (DevSWState *)(device->SwitcherState)) == NULL) + { + /* + * yes, it is: initialise state + */ + if ((ds = malloc(sizeof(*ds))) == NULL) + /* give up */ + return adp_malloc_failure; + + (void)memset(ds, 0, sizeof(*ds)); + device->SwitcherState = (void *)ds; + } + + /* + * check that we haven't already been opened for this type + */ + if ((ds->ds_opendevchans & (1 << type)) != 0) + return adp_device_already_open; + + /* + * if no opens have been done for this device, then do it now + */ + if (ds->ds_opendevchans == 0) + if (device->DeviceOpen(name, arg) < 0) + return adp_device_open_failed; + + /* + * open has finished + */ + ds->ds_opendevchans |= (1 << type); + return adp_ok; +} + +AdpErrs DevSW_Match(const DeviceDescr *device, const char *name, + const char *arg) +{ + return (device->DeviceMatch(name, arg) == -1) ? adp_failed : adp_ok; +} + +AdpErrs DevSW_Close(const DeviceDescr *device, const DevChanID type) +{ + DevSWState *ds = (DevSWState *)(device->SwitcherState); + Packet *pk; + + if ((ds->ds_opendevchans & (1 << type)) == 0) + return adp_device_not_open; + + ds->ds_opendevchans &= ~(1 << type); + + /* + * if this is the last close for this channel, then inform the driver + */ + if (ds->ds_opendevchans == 0) + device->DeviceClose(); + + /* + * release all packets of the appropriate type + */ + for (pk = Adp_removeFromQueue(&(ds->ds_readqueue[type])); + pk != NULL; + pk = Adp_removeFromQueue(&(ds->ds_readqueue[type]))) + DevSW_FreePacket(pk); + + /* that's all */ + return adp_ok; +} + +AdpErrs DevSW_Read(const DeviceDescr *device, const DevChanID type, + Packet **packet, bool block) +{ + int read_err; + DevSWState *ds = device->SwitcherState; + + /* + * To try to get information out of the device driver as + * quickly as possible, we try and read more packets, even + * if a completed packet is already available. + */ + + /* + * have we got a packet currently pending? + */ + if (ds->ds_nextreadpacket == NULL) + /* + * no - set things up + */ + if (initialise_read(ds) < 0) { + /* + * we failed to initialise the next packet, but can + * still return a packet that has already arrived. + */ + *packet = Adp_removeFromQueue(&ds->ds_readqueue[type]); + return adp_ok; + } + read_err = device->DeviceRead(&ds->ds_activeread, block); + switch (read_err) { + case 1: + /* + * driver has pulled in a complete packet, queue it up + */ +#ifdef RET_DEBUG + printf("got a complete packet\n"); +#endif + enqueue_packet(ds); + *packet = Adp_removeFromQueue(&ds->ds_readqueue[type]); + return adp_ok; + case 0: + /* + * OK, return the head of the read queue for the given type + */ + /* enqueue_packet(ds); */ + *packet = Adp_removeFromQueue(&ds->ds_readqueue[type]); + return adp_ok; + case -1: +#ifdef RET_DEBUG + printf("got a bad packet\n"); +#endif + /* bad packet */ + *packet = NULL; + return adp_bad_packet; + default: + panic("DevSW_Read: bad read status %d", read_err); + } + return 0; /* get rid of a potential compiler warning */ +} + + +AdpErrs DevSW_FlushPendingWrite(const DeviceDescr *device) +{ + struct DriverCall *dc; + struct data_packet *dp; + + dc = &((DevSWState *)(device->SwitcherState))->ds_activewrite; + dp = &dc->dc_packet; + + /* + * try to flush any packet that is still being written + */ + if (dp->data != NULL) + { + flush_packet(device, dc); + + /* see if it has gone */ + if (dp->data != NULL) + return adp_write_busy; + else + return adp_ok; + } + else + return adp_ok; +} + + +AdpErrs DevSW_Write(const DeviceDescr *device, Packet *packet, DevChanID type) +{ + struct DriverCall *dc; + struct data_packet *dp; + + dc = &((DevSWState *)(device->SwitcherState))->ds_activewrite; + dp = &dc->dc_packet; + + if (illegalDevChanID(type)) + return adp_illegal_args; + + /* + * try to flush any packet that is still being written + */ + if (DevSW_FlushPendingWrite(device) != adp_ok) + return adp_write_busy; + + /* + * we can take this packet - set things up, then try to get rid of it + */ + initialise_write(dc, packet, type); + flush_packet(device, dc); + + return adp_ok; +} + +AdpErrs DevSW_Ioctl(const DeviceDescr *device, const int opcode, void *args) +{ + return (device->DeviceIoctl(opcode, args) < 0) ? adp_failed : adp_ok; +} + +bool DevSW_WriteFinished(const DeviceDescr *device) +{ + struct DriverCall *dc; + struct data_packet *dp; + + dc = &((DevSWState *)(device->SwitcherState))->ds_activewrite; + dp = &dc->dc_packet; + + return (dp == NULL || dp->data == NULL); +} + +/* EOF devsw.c */ diff --git a/gdb/rdi-share/devsw.h b/gdb/rdi-share/devsw.h new file mode 100644 index 00000000000..f561768fd9d --- /dev/null +++ b/gdb/rdi-share/devsw.h @@ -0,0 +1,268 @@ +/* + * Copyright (C) 1995 Advanced RISC Machines Limited. All rights reserved. + * + * This software may be freely used, copied, modified, and distributed + * provided that the above copyright notice is preserved in all copies of the + * software. + */ + +/* -*-C-*- + * + * $Revision$ + * $Date$ + * + */ +#ifndef angsd_devsw_h +#define angsd_devsw_h + +#include "devclnt.h" +#include "adperr.h" +#include "drivers.h" + +#ifndef __cplusplus +typedef struct Packet Packet; +typedef struct DevSWState DevSWState; +#endif + +/* + * the basic structure used for passing packets around + */ +struct Packet +{ + struct Packet *pk_next; /* XXX first field in struct */ + unsigned int pk_length; + unsigned char *pk_buffer; +}; + +/* + * control structure, used for maintaining device switcher state + */ +struct DevSWState +{ + unsigned int ds_opendevchans; /* bitmap of open device channels */ + + /* + * queue of packets read for the various device channels + */ + Packet *ds_readqueue[DC_NUM_CHANNELS]; + + /* + * structures for managing active read and write operations + */ + Packet *ds_nextreadpacket; + DriverCall ds_activeread; + DriverCall ds_activewrite; +}; + +#ifdef __cplusplus + extern "C" { +#endif + +/* + * Function: DevSW_AllocatePacket + * Purpose: Claim some memory to hold a struct Packet, and the buffer for + * that packet. + * + * Params: + * Input: length Size of the buffer in struct Packet. + * + * Returns: + * OK: Pointer to the newly malloc()ed Packet. + * Error: NULL + */ +Packet *DevSW_AllocatePacket(const unsigned int length); + +/* + * Function: DevSW_FreePacket + * Purpose: Free the memory associated with a struct Packet. + * + * Pre-conditions The structure must have been originally claimed + * via DevSW_AllocatePacket. + * + * Params: + * Input: pk The packet to be freed. + * + * Returns: Nothing + */ +void DevSW_FreePacket(Packet *pk); + +/* + * Function: DevSW_Open + * Purpose: Open the specified device driver + * + * Params: + * Input: name Identifies which device to open. This can either be + * a host specific identifier (e.g. "/dev/ttya", + * "COM1:"), or a number which is used to refer to + * `standard' interfaces, so "1" would be the first host + * interface, "2" the second, and so on. + * + * arg Driver specific arguments. For example, some serial + * drivers accept speed and control arguments such as + * "9600" or "19200/NO_BREAK". These arguments are + * completely free-form: it is the individual drivers + * which do the necessary interpretation. + * + * type The type of packet the caller is interested in. Only + * one open is allowed for each type of packet. + * + * In/Out: device The device driver to open + * + * Returns: + * OK: adp_ok + * Error: adp_device_open_failed + * adp_device_already_open + * adp_malloc_failure + */ +AdpErrs DevSW_Open(DeviceDescr *device, const char *name, const char *arg, + const DevChanID type); + +/* + * Function: DevSW_Match + * Purpose: Minimal veneer for DeviceMatch + * + * Params: + * Input: device The device driver to match. + * + * name Identifies which device to open. This can either be + * a host specific identifier (e.g. "/dev/ttya", + * "COM1:"), or a number which is used to refer to + * `standard' interfaces, so "1" would be the first host + * interface, "2" the second, and so on. + * + * arg Driver specific arguments. For example, some serial + * drivers accept speed and control arguments such as + * "9600" or "19200/NO_BREAK". These arguments are + * completely free-form: it is the individual drivers + * which do the necessary interpretation. + * + * Returns: + * OK: adp_ok + * Error: adp_failed + */ +AdpErrs DevSW_Match(const DeviceDescr *device, const char *name, + const char *arg); + +/* + * Function: DevSW_Close + * Purpose: Close the specified device driver. All packets of the type + * used by the caller held within the switching layer will + * be discarded. + * + * Pre-conditions: Device must have been previously opened. + * + * Params: + * Input: device The device driver to close + * + * type The type of packet the caller was interested in. + * + * Returns: + * OK: adp_ok + * Error: adp_device_not_open + */ +AdpErrs DevSW_Close(const DeviceDescr *device, const DevChanID type); + +/* + * Function: DevSW_Read + * Purpose: Read a packet of appropriate type from the device driver + * + * Params: + * Input: device The device driver to read packet from. + * + * type The type of packet the caller is interested in. + * + * Output: packet Pointer to new packet (if one is available) + * NULL (if no complete packet is available) + * + * Input: block If TRUE, read may safely block for a short period + * of time (say up to 20ms), to avoid high CPU load + * whilst waiting for a reply. + * If FALSE, read MUST NOT block. + * + * Returns: + * OK: adp_ok + * Error: adp_bad_packet + * + * Post-conditions: The calling function is responsible for freeing the + * resources used by the packet when it is no longer + * needed. + */ +AdpErrs DevSW_Read(const DeviceDescr *device, const DevChanID type, + Packet **packet, bool block); + +/* + * Function: DevSW_Write + * Purpose: Try to write a packet to the device driver. The write will + * be bounced if another write is still in progress. + * + * Params: + * Input: device The device driver to write a packet to. + * + * packet The packet to be written. + * + * type The type to be assigned to the packet. + * + * Returns: + * OK: adp_ok + * Error: adp_illegal_args + * adp_write_busy + * + * Post-conditions: The calling function retains "ownership" of the packet, + * i.e. it is responsible for freeing the resources used + * by the packet when it is no longer needed. + */ +AdpErrs DevSW_Write(const DeviceDescr *device, Packet *packet, DevChanID type); + +/* + * Function: DevSW_FlushPendingWrite + * Purpose: If a write is in progress, give it a chance to finish. + * + * Params: + * Input: device The device driver to flush. + * + * Returns: + * adp_ok no pending write, or write flushed completely + * adp_write_busy pending write not flushed completely + */ +AdpErrs DevSW_FlushPendingWrite(const DeviceDescr *device); + +/* + * Function: DevSW_Ioctl + * Purpose: Perform miscellaneous control operations. This is a minimal + * veneer to DeviceIoctl. + * + * Params: + * Input: device The device driver to control. + * + * opcode Reason code indicating the operation to perform. + * + * In/Out: args Pointer to opcode-sensitive arguments/result space. + * + * Returns: + * OK: adp_ok + * Error: adp_failed + */ +AdpErrs DevSW_Ioctl(const DeviceDescr *device, const int opcode, void *args); + +/* + * Function: DevSW_WriteFinished + * Purpose: Return TRUE if the active device has finished writing + * the last packet to be sent, or FALSE if a packet is still + * being transmitted. + * + * Params: + * Input: device The device driver to check. + * + * Returns: + * TRUE: write finished or inactive + * FALSE: write in progress + */ +bool DevSW_WriteFinished(const DeviceDescr *device); + +#ifdef __cplusplus + } +#endif + +#endif /* ndef angsd_devsw_h */ + +/* EOF devsw.h */ diff --git a/gdb/rdi-share/drivers.c b/gdb/rdi-share/drivers.c new file mode 100644 index 00000000000..ba0eee50890 --- /dev/null +++ b/gdb/rdi-share/drivers.c @@ -0,0 +1,34 @@ +/* + * Copyright (C) 1995 Advanced RISC Machines Limited. All rights reserved. + * + * This software may be freely used, copied, modified, and distributed + * provided that the above copyright notice is preserved in all copies of the + * software. + */ + +/* -*-C-*- + * + * $Revision$ + * $Date$ + * + * + * drivers.c - declares a NULL terminated list of device driver + * descriptors supported by the host. + */ +#include + +#include "drivers.h" + +extern DeviceDescr angel_SerialDevice; +extern DeviceDescr angel_SerparDevice; +extern DeviceDescr angel_EthernetDevice; + +DeviceDescr *devices[] = +{ + &angel_SerialDevice, + &angel_SerparDevice, + &angel_EthernetDevice, + NULL +}; + +/* EOF drivers.c */ diff --git a/gdb/rdi-share/drivers.h b/gdb/rdi-share/drivers.h new file mode 100644 index 00000000000..3655c18b0a2 --- /dev/null +++ b/gdb/rdi-share/drivers.h @@ -0,0 +1,193 @@ +/* + * Copyright (C) 1995 Advanced RISC Machines Limited. All rights reserved. + * + * This software may be freely used, copied, modified, and distributed + * provided that the above copyright notice is preserved in all copies of the + * software. + */ + +/* -*-C-*- + * + * $Revision$ + * $Date$ + * + * + * Project: ANGEL + * + * Title: Definitions for device driver interface. + */ +#ifndef angsd_drivers_h +#define angsd_drivers_h + +#include "rxtx.h" + +#ifndef __cplusplus +typedef struct DeviceDescr DeviceDescr; +typedef struct DriverCall DriverCall; +#endif + +/* + * used to pass packets across the driver interface + */ +struct DriverCall +{ + struct data_packet dc_packet; + void *dc_context; +}; + +/* + * used to describe a device driver + */ +struct DeviceDescr +{ + char *DeviceName; + int (*DeviceOpen)(const char *name, const char *arg); + int (*DeviceMatch)(const char *name, const char *arg); + void (*DeviceClose)(void); + int (*DeviceRead)(DriverCall *dc, bool block); + int (*DeviceWrite)(DriverCall *dc); + int (*DeviceIoctl)(const int opcode, void *args); + void *SwitcherState; /* used by switcher interface */ +}; + +/* + * Function: DeviceOpen + * + * Purpose: Open a communications device + * + * Pre-conditions: No previous open is still active + * + * Params: + * Input: name Identifies which device to open. This can either be + * a host specific identifier (e.g. "/dev/ttya", + * "COM1:"), or a number which is used to refer to + * `standard' interfaces, so "1" would be the first host + * interface, "2" the second, and so on. + * + * arg Driver specific arguments. For example, some serial + * drivers accept speed and control arguments such as + * "9600" or "19200/NO_BREAK". These arguments are + * completely free-form: it is the individual drivers + * which do the necessary interpretation. + * + * Returns: + * OK: 0 + * Error: -1 + */ +extern int DeviceOpen(const char *name, const char *arg); + +/* + * Function: DeviceMatch + * + * Purpose: Check whether parameters are OK to be passed to DeviceOpen + * + * Params: + * Input: name Identifies which device to open. This can either be + * a host specific identifier (e.g. "/dev/ttya", + * "COM1:"), or a number which is used to refer to + * `standard' interfaces, so "1" would be the first host + * interface, "2" the second, and so on. + * + * arg Driver specific arguments. For example, some serial + * drivers accept speed and control arguments such as + * "9600" or "19200/NO_BREAK". These arguments are + * completely free-form: it is the individual drivers + * which do the necessary interpretation. + * + * Returns: + * OK: 0 + * Error: -1 + */ +extern int DeviceMatch(const char *name, const char *arg); + +/* + * Function: DeviceClose + * + * Purpose: Close a communications device + * + * Pre-conditions: Device must have been previously opened + * + * Params: None + * + * Returns: Nothing + */ +extern void DeviceClose(void); + +/* + * Function: DeviceRead + * + * Purpose: Try to read a complete packet from a communications device. + * This read must usually be non-blocking, i.e. it should read as + * many data from the device as needed to complete the packet, + * but it should not wait if the packet is not complete, and no + * more data are currently available from the device. + * As an optimisation the read can optionally block when 'block' + * is TRUE, but only for a short time. It is acceptable for the + * 'block' parameter to be ignored in which case all reads + * should be non-blocking. + * + * Pre-conditions: Device has been opened via DeviceOpen() + * + * Params: + * In/Out: dc Describes the packet being read (dc->dc_packet); + * dc->dc_context is for the driver to store private + * context, and is guaranteed to be NULL the first + * time DeviceRead is called for a given packet. + * + * In: block If TRUE, read may safely block for a short period + * of time (say up to 20ms), to avoid high CPU load + * whilst waiting for a reply. + * If FALSE, read MUST NOT block. + * + * Returns: + * OK: 1 (packet is complete) + * 0 (packet is not yet complete) + * Error: -1 bad packet + * + * Post-conditions: should a calamatous error occur panic() will be called + */ +extern int DeviceRead(DriverCall *dc, bool block); + +/* + * Function: DeviceWrite + * + * Purpose: Try to write a packet to a communications device. This write + * must be non-blocking, i.e. it should write as many data to + * the device as is immediately possible, but should not wait + * for space to send any more after that. + * + * Pre-conditions: Device has been opened via DeviceOpen() + * + * Params: + * In/Out: dc Describes the packet being written (dc->dc_packet); + * dc->dc_context is for the driver to store private + * context, and is guaranteed to be NULL the first + * time DeviceWrite is called for a given packet. + * + * Returns: + * OK: 1 (all of the packet has been written) + * 0 (some of the packet remains to be written) + * Error: -1 + */ +extern int DeviceWrite(DriverCall *dc); + +/* + * Function: DeviceIoctl + * + * Purpose: Perform miscellaneous driver operations + * + * Pre-conditions: Device has been open via DeviceOpen() + * + * Params: + * Input: opcode Reason code indicating the operation to perform + * In/Out: args Pointer to opcode-sensitive arguments/result space + * + * Returns: + * OK: 0 + * Error: -1 + */ +extern int DeviceIoctl(const int opcode, void *args); + +#endif /* !defined(angsd_drivers_h) */ + +/* EOF drivers.h */ diff --git a/gdb/rdi-share/endian.h b/gdb/rdi-share/endian.h new file mode 100644 index 00000000000..3d32d9a6e60 --- /dev/null +++ b/gdb/rdi-share/endian.h @@ -0,0 +1,125 @@ +/* + * Copyright (C) 1995 Advanced RISC Machines Limited. All rights reserved. + * + * This software may be freely used, copied, modified, and distributed + * provided that the above copyright notice is preserved in all copies of the + * software. + */ + +/* -*-C-*- + * + * $Revision$ + * $Date$ + * + * + * endian.h - target endianness independent read/write primitives. + */ + +#ifndef angel_endian_h +#define angel_endian_h + +/* + * The endianness of the data being processed needs to be known, but + * the host endianness is not required (since the data is constructed + * using bytes). At the moment these are provided as macros. This + * gives the compiler freedom in optimising individual calls. However, + * if space is at a premium then functions should be provided. + * + * NOTE: These macros assume that the data has been packed in the same format + * as the packing on the build host. If this is not the case then + * the wrong addresses could be used when dealing with structures. + * + */ + +/* + * For all the following routines the target endianness is defined by the + * following boolean definitions. + */ +#define BE (1 == 1) /* TRUE : big-endian */ +#define LE (1 == 0) /* FALSE : little-endian */ + +/* + * The following type definitions are used by the endianness converting + * macros. + */ +typedef unsigned char U8; +typedef U8 *P_U8; +typedef const U8 *CP_U8; + +typedef unsigned short U16; +typedef U16 *P_U16; + +typedef unsigned int U32; +typedef U32 *P_U32; + +/* + * If the endianness of the host and target are known (fixed) and the same + * then the following macro definitions can be used. These just directly copy + * the data. + * + * #define READ(e,a) (a) + * #define WRITE(e,a,v) ((a) = (v)) + * #define PREAD(e,a) (a) + * #define PWRITE(e,a,v) (*(a) = (v)) + */ + +/* + * These macros assume that a byte (char) is 8bits in size, and that the + * endianness is not important when reading or writing bytes. + */ +#define PUT8(a,v) (*((P_U8)(a)) = (U8)(v)) +#define PUT16LE(a,v) (PUT8(a,((v) & 0xFF)), \ + PUT8((((P_U8)(a)) + sizeof(char)),((v) >> 8))) +#define PUT16BE(a,v) (PUT8(a,((v) >> 8)), \ + PUT8((((P_U8)(a)) + sizeof(char)),((v) & 0xFF))) +#define PUT32LE(a,v) (PUT16LE(a,v), \ + PUT16LE((((P_U8)(a)) + sizeof(short)),((v) >> 16))) +#define PUT32BE(a,v) (PUT16BE(a,((v) >> 16)), \ + PUT16BE((((P_U8)(a)) + sizeof(short)),v)) + +#define GET8(a) (*((CP_U8)(a))) +#define GET16LE(a) (GET8(a) | (((U16)GET8(((CP_U8)(a)) + sizeof(char))) << 8)) +#define GET16BE(a) ((((U16)GET8(a)) << 8) | GET8(((CP_U8)(a)) + sizeof(char))) +#define GET32LE(a) (GET16LE(a) | \ + (((U32)GET16LE(((CP_U8)(a)) + sizeof(short))) << 16)) +#define GET32BE(a) ((((U32)GET16BE(a)) << 16) | \ + GET16BE(((CP_U8)(a)) + sizeof(short))) + +/* + * These macros simplify the code in respect to reading and writing the + * correct size data when dealing with endianness. "e" is TRUE if we are + * dealing with big-endian data, FALSE if we are dealing with little-endian. + */ + +/* void WRITE(int endianness, void *address, unsigned value); */ + +#define WRITE16(e,a,v) ((e) ? PUT16BE(&(a),v) : PUT16LE(&(a),v)) +#define WRITE32(e,a,v) ((e) ? PUT32BE(&(a),v) : PUT32LE(&(a),v)) +#define WRITE(e,a,v) ((sizeof(v) == sizeof(char)) ? \ + PUT8(&(a),v) : ((sizeof(v) == sizeof(short)) ? \ + WRITE16(e,a,v) : WRITE32(e,a,v))) + +/* unsigned READ(int endianness, void *address) */ +#define READ16(e,a) ((e) ? GET16BE(&(a)) : GET16LE(&(a))) +#define READ32(e,a) ((e) ? GET32BE(&(a)) : GET32LE(&(a))) +#define READ(e,a) ((sizeof(a) == sizeof(char)) ? \ + GET8((CP_U8)&(a)) : ((sizeof(a) == sizeof(short)) ? \ + READ16(e,a) : READ32(e,a))) + +/* void PWRITE(int endianness, void *address, unsigned value); */ +#define PWRITE16(e,a,v) ((e) ? PUT16BE(a,v) : PUT16LE(a,v)) +#define PWRITE32(e,a,v) ((e) ? PUT32BE(a,v) : PUT32LE(a,v)) +#define PWRITE(e,a,v) ((sizeof(v) == sizeof(char)) ? \ + PUT8(a,v) : ((sizeof(v) == sizeof(short)) ? \ + PWRITE16(e,a,v) : PWRITE32(e,a,v))) + +/* unsigned PREAD(int endianness, void *address) */ +#define PREAD16(e,a) ((e) ? GET16BE(a) : GET16LE(a)) +#define PREAD32(e,a) ((e) ? GET32BE(a) : GET32LE(a)) +#define PREAD(e,a) ((sizeof(*(a)) == sizeof(char)) ? \ + GET8((CP_U8)a) : ((sizeof(*(a)) == sizeof(short)) ? \ + PREAD16(e,a) : PREAD32(e,a))) + +#endif /* !defined(angel_endian_h) */ + +/* EOF endian.h */ diff --git a/gdb/rdi-share/etherdrv.c b/gdb/rdi-share/etherdrv.c new file mode 100644 index 00000000000..976b2f5891e --- /dev/null +++ b/gdb/rdi-share/etherdrv.c @@ -0,0 +1,725 @@ +/* + * Copyright (C) 1995 Advanced RISC Machines Limited. All rights reserved. + * + * This software may be freely used, copied, modified, and distributed + * provided that the above copyright notice is preserved in all copies of the + * software. + */ + +/* -*-C-*- + * + * $Revision$ + * $Date$ + * + * + * etherdrv.c - Ethernet Driver for Angel. + */ + +#ifdef __hpux +# define _POSIX_SOURCE 1 +# define _HPUX_SOURCE 1 +# define _XOPEN_SOURCE 1 +#endif + +#include +#ifdef __hpux +# define uint hide_HPs_uint +#endif +#ifdef __unix +# include +# ifdef __hpux +# undef uint +# endif +#endif +#include +#include +#ifdef __hpux +# define uint hide_HPs_uint +#endif +#include +#ifdef __hpux +# undef uint +#endif +#include +#include +#include +#include "host.h" + +#ifdef COMPILING_ON_WINDOWS + typedef char * caddr_t; +# undef IGNORE +# include +# include "angeldll.h" +#else +# ifdef __hpux +# define uint hide_HPs_uint +# endif +# include +# include +# ifdef __hpux +# undef uint +# endif +# include +# include +# include +# if !defined(__hpux) && !defined(__linux__) && !defined(_WIN32) +# include +# endif +# include +# include +#endif + +#include "hsys.h" +#include "devices.h" +#include "endian.h" +#include "buffers.h" +#include "hostchan.h" +#include "params.h" +#include "logging.h" +#include "ethernet.h" + + +#ifndef COMPILING_ON_WINDOWS +/* these two might not work for windows */ + extern int sys_nerr; + extern char *sys_errlist[]; +#endif + +#ifndef UNUSED +# define UNUSED(x) (x = x) /* Silence compiler warnings */ +#endif + +/* + * forward declarations of static functions + */ +static int EthernetOpen(const char *name, const char *arg); +static int EthernetMatch(const char *name, const char *arg); +static void EthernetClose(void); +static int EthernetRead(DriverCall *dc, bool block); +static int EthernetWrite(DriverCall *dc); +static int EthernetIoctl(const int opcode, void *args); + +/* + * the device descriptor for Ethernet + */ +DeviceDescr angel_EthernetDevice = +{ + "Ethernet", + EthernetOpen, + EthernetMatch, + EthernetClose, + EthernetRead, + EthernetWrite, + EthernetIoctl +}; + +/* + * descriptor for the socket that we talk down + */ +static int sock = -1; + +/* + * address of the remote target + */ +static struct sockaddr_in remote, *ia = &remote; + +/* + * array of dynamic port numbers on target + */ +static unsigned short int ports[2]; + +/* + * Function: set_address + * Purpose: Try to get an address into an understandable form + * + * Params: + * Input: addr The address to parse + * + * Output: ia Structure to hold the parsed address + * + * Returns: + * OK: 0 + * Error: -1 + */ +static int set_address(const char *const addr, struct sockaddr_in *const ia) +{ + ia->sin_family = AF_INET; + + /* + * Try address as a dotted decimal + */ + ia->sin_addr.s_addr = inet_addr(addr); + + /* + * If that failed, try it as a hostname + */ + if (ia->sin_addr.s_addr == (u_int)-1) + { + struct hostent *hp = gethostbyname(addr); + + if (hp == NULL) + return -1; + + (void)memcpy((caddr_t)&ia->sin_addr, hp->h_addr, hp->h_length); + } + + return 0; +} + +/* + * Function: open_socket + * Purpose: Open a non-blocking UDP socket, and bind it to a port + * assigned by the system. + * + * Params: None + * + * Returns: + * OK: socket descriptor + * Error: -1 + */ +static int open_socket(void) +{ + int sfd; +#if 0 /* see #if 0 just below -VVV- */ + int yesplease = 1; +#endif + struct sockaddr_in local; + + /* + * open the socket + */ +#ifdef COMPILING_ON_WINDOWS + if ((sfd = socket(AF_INET, SOCK_DGRAM, 0)) == INVALID_SOCKET) + return -1; +#else + if ((sfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) + { +# ifdef DEBUG + perror("socket"); +# endif + return -1; + } +#endif + + /* + * 960731 KWelton + * + * I don't believe that this should be necessary - if we + * use select(), then non-blocking I/O is redundant. + * Unfortunately, select() appears to be broken (under + * Solaris, with a limited amount of time available for + * debug), so this code stays in for the time being + */ +#if 0 + /* + * enable non-blocking I/O + */ + if (ioctlsocket(sfd, FIONBIO, &yesplease) < 0) + { +# ifdef DEBUG + perror("ioctl(FIONBIO)"); +# endif + closesocket(sfd); + + return -1; + } +#endif /* 0/1 */ + + /* + * bind local address to a system-assigned port + */ + memset((char *)&local, 0, sizeof(local)); + local.sin_family = AF_INET; + local.sin_port = htons(0); + local.sin_addr.s_addr = INADDR_ANY; + if (bind(sfd, (struct sockaddr *)&local, sizeof(local)) < 0) + { +#ifdef DEBUG + perror("bind"); +#endif + closesocket(sfd); + + return -1; + } + + /* + * all done + */ + return sfd; +} + +/* + * Function: fetch_ports + * Purpose: Request assigned port numbers from remote target + * + * Params: None + * + * Returns: Nothing + * + * Post-conditions: This routine will *always* return something for the + * port numbers. If the remote target does not + * respond, then it makes something up - this allows + * the standard error message (from ardi.c) to be + * generated when the target is dead for whatever + * reason. + */ +static void fetch_ports(void) +{ + int i; + const char ctrlpacket[] = CTRL_MAGIC; + CtrlResponse response; + + /* + * we will try 3 times to elicit a response from the target + */ + for (i = 0; i < 3; ++i) + { + struct timeval tv; + fd_set fdset; + + /* + * send the magic string to the control + * port on the remote target + */ + ia->sin_port = htons(CTRL_PORT); + if (sendto(sock, ctrlpacket, sizeof(ctrlpacket), 0, + (struct sockaddr *)ia, sizeof(*ia)) < 0) + { +#ifdef DEBUG + perror("fetch_ports: sendto"); +#endif + return; + } + + FD_ZERO(&fdset); + FD_SET(sock, &fdset); + tv.tv_sec = 0; + tv.tv_usec = 250000; + + if (select(sock + 1, &fdset, NULL, NULL, &tv) < 0) + { +#ifdef DEBUG + perror("fetch_ports: select"); +#endif + return; + } + + if (FD_ISSET(sock, &fdset)) + { + /* + * there is something there - read it + */ + if (recv(sock, (char *)&response, sizeof(response), 0) < 0) + { +#ifdef COMPILING_ON_WINDOWS + unsigned int werrno = WSAGetLastError(); + + if (werrno == WSAEWOULDBLOCK || werrno == 0) +#else + if (errno == EWOULDBLOCK) +#endif + { + --i; + continue; + } + else + { +#ifdef DEBUG + perror("fetch_ports: recv"); +#endif + return; + } + } + { + /* + * XXX + * + * this is *very* unpleasant - try to match the structure + * layout + */ + unsigned short *sptr = (unsigned short *)(response + RESP_DBUG); + + if (strcmp(response, ctrlpacket) == 0) + { + ports[DBUG_INDEX] = htons(*sptr); + sptr++; + ports[APPL_INDEX] = htons(*sptr); + } + +#ifdef DEBUG + printf("fetch_ports: got response, DBUG=%d, APPL=%d\n", + ports[DBUG_INDEX], ports[APPL_INDEX]); +#endif + return; + } + } + } + + /* + * we failed to get a response + */ +#ifdef DEBUG + printf("fetch_ports: failed to get a real answer\n"); +#endif +} + +/* + * Function: read_packet + * Purpose: read a packet, and pass it back to higher levels + * + * Params: + * In/Out: packet Holder for the read packet + * + * Returns: 1 - Packet is complete + * 0 - No complete packet read + * + * Post-conditions: Will call panic() if something goes wrong with the OS + */ +static int read_packet(struct data_packet *const packet) +{ + struct sockaddr_in from; + int nbytes, fromlen = sizeof(from); + DevChanID devchan; + + /* + * try to get the packet + */ + if ((nbytes = recvfrom(sock, (char *)(packet->data), packet->buf_len, 0, + (struct sockaddr *)&from, &fromlen)) < 0) + { +#ifdef COMPILING_ON_WINDOWS + if (nbytes == SOCKET_ERROR && WSAGetLastError() != WSAEWOULDBLOCK) + MessageBox(GetFocus(), "Error receiving packet\n", "Angel", MB_OK | MB_ICONSTOP); +#else + if (errno != EWOULDBLOCK) + { +# ifdef DEBUG + perror("recv"); +# endif + panic("ethernet recv failure"); + } +#endif + return 0; + } + +#ifdef COMPILING_ON_WINDOWS + if (pfnProgressCallback != NULL && nbytes != SOCKET_ERROR) + { + progressInfo.nRead += nbytes; + (*pfnProgressCallback)(&progressInfo); + } +#endif + + /* + * work out where the packet was from + */ + if (from.sin_addr.s_addr != remote.sin_addr.s_addr) + { + /* + * not from our target - ignore it + */ +#ifdef DEBUG + printf("read_packet: ignoring packet from %s\n", + inet_ntoa(from.sin_addr)); +#endif + + return 0; + } + else if (ntohs(from.sin_port) == ports[DBUG_INDEX]) + devchan = DC_DBUG; + else if (ntohs(from.sin_port) == ports[APPL_INDEX]) + devchan = DC_APPL; + else + { + /* + * unknown port number - ignore it + */ +#ifdef DEBUG + printf("read_packet: ignore packet from port %hd\n", + htons(from.sin_port)); +#endif + + return 0; + } + +#if defined(DEBUG) && !defined(DO_TRACE) + printf("EthernetRead: %d bytes from %s channel\n", + nbytes, (devchan == DC_DBUG) ? "DBUG" : "APPL"); +#endif + +#ifdef DO_TRACE + printf("[%d on %d]\n", nbytes, devchan); + { + int i = 0; + unsigned char *cptr = packet->data; + + while (i < nbytes) + { + printf("<%02X ", *(cptr++)); + + if (!(++i % 16)) + printf("\n"); + } + + if (i % 16) + printf("\n"); + } +#endif + + /* + * OK - fill in the details + */ + packet->type = devchan; + packet->len = nbytes; + return 1; +} + +/**********************************************************************/ + +/* + * Function: Ethernet_Open + * Purpose: Open the Ethernet device. See the documentation for + * DeviceOpen in drivers.h + * + * Post-conditions: Will have updated struct sockaddr_in remote (*ia) + * with the address of the remote target. + */ +static int EthernetOpen(const char *name, const char *arg) +{ +#ifdef COMPILING_ON_WINDOWS + WORD wVersionRequested; + WSADATA wsaData; +#endif + /* + * name is passed as e=, so skip 1st two characters + */ + const char *etheraddr = name + 2; + +#ifdef DEBUG + printf("EthernetOpen: name `%s'\n", name); +#endif + + /* Check that the name is a valid one */ + if (EthernetMatch(name, arg) != 0) + return -1; + +#ifdef COMPILING_ON_WINDOWS + wVersionRequested = MAKEWORD(1, 1); + if (WSAStartup(wVersionRequested, &wsaData) != 0) + /* + * Couldn't find a useable winsock.dll. + */ + return -1; + + if ( LOBYTE( wsaData.wVersion ) != 1 || HIBYTE( wsaData.wVersion ) != 1 ) + { + WSACleanup(); + + /* + * Couldn't find a winsock.dll with supported version. + */ + return -1; + } +#endif + + memset((char *)ia, 0, sizeof(*ia)); + if (set_address(etheraddr, ia) < 0) + { +#ifdef COMPILING_ON_WINDOWS + /* + * SJ - I'm not sure that this is the correct way to handle this + * as Fail calls remote_disable and exits, while panic just exits. + * However at the time of writing remote_disable does nothing! + */ + /* Panic("EthernetOpen: bad name `%s'\n", etheraddr); */ +#else + Fail("EthernetOpen: bad name `%s'\n", etheraddr); +#endif + return -1; + } + + if ((sock = open_socket()) < 0) + return -1; + + /* + * fetch the port numbers assigned by the remote target + * to its Debug and Application sockets + */ + fetch_ports(); + + return 0; +} + +static int EthernetMatch(const char *name, const char *arg) +{ + /* IGNORE arg */ + if (0) + arg = arg; + + if (name == NULL) + return -1; + + if (tolower(name[0]) != 'e' || name[1] != '=') + return -1; + + return 0; +} + +static void EthernetClose(void) +{ + if (sock >= 0) + { + closesocket(sock); + sock = -1; + } + +#ifdef COMPILING_ON_WINDOWS + WSACleanup(); +#endif +} + +static int EthernetRead(DriverCall *dc, bool block) +{ + fd_set fdset; + struct timeval tv; + int err; + + FD_ZERO(&fdset); + FD_SET(sock, &fdset); + +#ifdef COMPILING_ON_WINDOWS + UNUSED(block); + tv.tv_sec = tv.tv_usec = 0; +#else + tv.tv_sec = 0; + tv.tv_usec = (block ? 10000 : 0); +#endif + + err = select(sock + 1, &fdset, NULL, NULL, &tv); + + if (err < 0) { + if (errno == EINTR) { + return 0; + } + panic("ethernet select failure (errno=%i)",errno); + return 0; + } + + if (FD_ISSET(sock, &fdset)) + return read_packet(&dc->dc_packet); + else + return 0; +} + +static int EthernetWrite(DriverCall *dc) +{ + int nbytes; + struct data_packet *packet = &dc->dc_packet; + + if (packet->type == DC_DBUG) + ia->sin_port = htons(ports[DBUG_INDEX]); + else if (packet->type == DC_APPL) + ia->sin_port = htons(ports[APPL_INDEX]); + else + { + panic("EthernetWrite: unknown devchan"); + return 0; + } + +#if defined(DEBUG) && !defined(DO_TRACE) + printf("EthernetWrite: %d bytes to %s channel\n", + packet->len, (packet->type == DC_DBUG) ? "DBUG" : "APPL"); +#endif + +#ifdef DO_TRACE + printf("[%d on %d]\n", packet->len, packet->type); + { + int i = 0; + unsigned char *cptr = packet->data; + + while (i < packet->len) + { + printf(">%02X ", *(cptr++)); + + if (!(++i % 16)) + printf("\n"); + } + + if (i % 16) + printf("\n"); + } +#endif + + if ((nbytes = sendto(sock, (char *)(packet->data), packet->len, 0, + (struct sockaddr *)ia, sizeof(*ia))) != packet->len) + { +#ifdef COMPILING_ON_WINDOWS + if (nbytes == SOCKET_ERROR && WSAGetLastError() != WSAEWOULDBLOCK) +#else + if (nbytes < 0 && errno != EWOULDBLOCK) +#endif + { +#ifdef DEBUG + perror("sendto"); +#endif +#ifdef COMPILING_ON_WINDOWS + panic("ethernet send failure\n"); +#else + /* might not work for Windows */ + panic("ethernet send failure [%s]\n", + errno < sys_nerr ? sys_errlist[errno] : "unknown errno"); +#endif + } +#ifdef DEBUG + else if (nbytes >= 0) + fprintf(stderr, "ethernet send: asked for %d, sent %d\n", packet->len, nbytes); +#endif + return 0; + } + +#ifdef COMPILING_ON_WINDOWS + if (pfnProgressCallback != NULL && nbytes != SOCKET_ERROR) + { + progressInfo.nWritten += nbytes; + (*pfnProgressCallback)(&progressInfo); + } +#endif + + return 1; +} + +static int EthernetIoctl(const int opcode, void *args) +{ +#ifdef DEBUG + printf( "EthernetIoctl: op %d arg %x\n", opcode, args ); +#endif + + /* + * IGNORE(opcode) + */ + if (0) + { + int dummy = opcode; + UNUSED(dummy); + } + UNUSED(args); + + switch ( opcode ) + { + case DC_RESYNC: + { +#ifdef DEBUG + printf( "EthernetIoctl: resync\n" ); +#endif + fetch_ports(); + return 0; + } + + default: + { + return -1; + } + } +} + +/* EOF etherdrv.c */ diff --git a/gdb/rdi-share/ethernet.h b/gdb/rdi-share/ethernet.h new file mode 100644 index 00000000000..930acedcf57 --- /dev/null +++ b/gdb/rdi-share/ethernet.h @@ -0,0 +1,99 @@ +/* + * Copyright (C) 1995 Advanced RISC Machines Limited. All rights reserved. + * + * This software may be freely used, copied, modified, and distributed + * provided that the above copyright notice is preserved in all copies of the + * software. + */ + +/* -*-C-*- + * + * $Revision$ + * $Date$ + * + * + * ethernet.h: Angel drivers for Ethernet using Fusion UDP/IP stack + */ +#ifndef angel_ethernet_h +#define angel_ethernet_h + +/* + * the UDP ports that Angel Ethernet uses + */ +#define CTRL_PORT 1913 + +/* + * the size of the largest packet accepted on the control socket + */ +#define CTRL_MAXPACKET 6 + +/* + * This is the "magic number" sent to the control port to + * request that the channel port numbers are returned + */ +#define CTRL_MAGIC "Angel" + +/* + * Array used for responding to a request on the control port + */ +typedef unsigned char CtrlResponse[10]; +#define RESP_MAGIC 0 +#define RESP_DBUG 6 +#define RESP_APPL 8 + +/* + * indices for accessing the array of port numbers sent + * over the control socket + */ +#define DBUG_INDEX 0 +#define APPL_INDEX 1 + +#ifdef TARGET + +# include "devdriv.h" + +extern const struct angel_DeviceEntry angel_EthernetDevice; + +/* + * Function: angel_EthernetPoll + * Purpose: Poll Fusion for newly arrived packets + * + * Pre-conditions: Called in SVC mode with the lock + * + * Params: + * Input: data IGNORE'd + * + * Returns: Nothing + * + * Post-conditions: Will have passed any packets received along to + * higher levels + */ +void angel_EthernetPoll(unsigned int data); + +void angel_EthernetNOP(unsigned int data); + + +/* + * Function: angel_FindEthernetConfigBlock + * Purpose: Search the Flash for an ethernet config block and return + * it if found. + * + * Params: None + * + * Returns: NULL if no config block found, the address if one is found. + * + */ +extern angel_EthernetConfigBlock *angel_FindEthernetConfigBlock(void); + +#else /* def TARGET */ + +# ifndef COMPILING_ON_WINDOWS +# define ioctlsocket(x, y, z) ioctl((x), (y), (z)) +# define closesocket(x) close(x) +# endif + +#endif /* def TARGET */ + +#endif /* ndef angel_ethernet_h */ + +/* EOF ethernet.h */ diff --git a/gdb/rdi-share/host.h b/gdb/rdi-share/host.h new file mode 100644 index 00000000000..3ae8fc44e47 --- /dev/null +++ b/gdb/rdi-share/host.h @@ -0,0 +1,222 @@ +/* + * Copyright (C) 1995 Advanced RISC Machines Limited. All rights reserved. + * + * This software may be freely used, copied, modified, and distributed + * provided that the above copyright notice is preserved in all copies of the + * software. + */ + + +#ifndef _host_LOADED +#define _host_LOADED 1 + +#include +#include +#include + +#ifndef SEEK_SET +# define SEEK_SET 0 +#endif +#ifndef SEEK_CUR +# define SEEK_CUR 1 +#endif +#ifndef SEEK_END +# define SEEK_END 2 +#endif + +/* The following for the benefit of compiling on SunOS */ +#ifndef offsetof +# define offsetof(T, member) ((char *)&(((T *)0)->member) - (char *)0) +#endif + +#ifdef unix /* A temporary sop to older compilers */ +# ifndef __unix /* (good for long-term portability?) */ +# define __unix 1 +# endif +#endif + +#ifdef __unix +/* Generic unix -- hopefully a split into other variants will not be */ +/* needed. However, beware the 'bsd' test above and safe_toupper etc. */ +/* which cope with backwards (pre-posix/X/open) unix compatility. */ +# define COMPILING_ON_UNIX 1 +#endif +#if defined(_WIN32) +# define COMPILING_ON_WIN32 1 +# if !defined(__CYGWIN32__) +# define COMPILING_ON_WINDOWS 1 +# endif +#endif +#if defined(_CONSOLE) +# define COMPILING_ON_WINDOWS_CONSOLE 1 +# define COMPILING_ON_WINDOWS 1 +#endif +#ifdef _MSC_VER +# define COMPILING_ON_MSDOS 1 +# define COMPILING_ON_WINDOWS 1 +# if defined(__cplusplus) +# define IMPLEMENT_BOOL_AS_INT 1 /* VC++ doesn't have 'bool' (yet) */ +# endif +#endif +/* The '(defined(__sparc) && defined(P_tmpdir) */ +/* && !defined(__svr4__))' is to detect gcc on SunOS. */ +/* C++ compilers don't have to define __STDC__ */ +#if (defined(__sparc) && defined(P_tmpdir)) +# if defined(__svr4__) +# define COMPILING_ON_SOLARIS +# else +# define COMPILING_ON_SUNOS +# endif +#endif +#ifdef __hppa +# define COMPILING_ON_HPUX +#endif + +/* + * The following typedefs may need alteration for obscure host machines. + */ +#if defined(__alpha) && defined(__osf__) /* =========================== */ +/* Under OSF the alpha has 64-bit pointers and 64-bit longs. */ +typedef int int32; +typedef unsigned int unsigned32; +/* IPtr and UPtr are 'ints of same size as pointer'. Do not use in */ +/* new code. Currently only used within 'ncc'. */ +typedef long int IPtr; +typedef unsigned long int UPtr; + +#else /* all hosts except alpha under OSF ============================= */ + +typedef long int int32; +typedef unsigned long int unsigned32; +/* IPtr and UPtr are 'ints of same size as pointer'. Do not use in */ +/* new code. Currently only used within 'ncc'. */ +#define IPtr int32 +#define UPtr unsigned32 +#endif /* ============================================================= */ + +typedef short int int16; +typedef unsigned short int unsigned16; +typedef signed char int8; +typedef unsigned char unsigned8; + +/* The following code defines the 'bool' type to be 'int' under C */ +/* and real 'bool' under C++. It also avoids warnings such as */ +/* C++ keyword 'bool' used as identifier. It can be overridden by */ +/* defining IMPLEMENT_BOOL_AS_ENUM or IMPLEMENT_BOOL_AS_INT. */ +#undef _bool + +#ifdef IMPLEMENT_BOOL_AS_ENUM + enum _bool { _false, _true }; +# define _bool enum _bool +#elif defined(IMPLEMENT_BOOL_AS_INT) || !defined(__cplusplus) +# define _bool int +# define _false 0 +# define _true 1 +#endif + +#ifdef _bool +# if defined(_MFC_VER) || defined(__CC_NORCROFT) /* When using MS Visual C/C++ v4.2 */ +# define bool _bool /* avoids "'bool' is reserved word" warning */ +# else + typedef _bool bool; +# endif +# define true _true +# define false _false +#endif + +#define YES true +#define NO false +#undef TRUE /* some OSF headers define as 1 */ +#define TRUE true +#undef FALSE /* some OSF headers define as 1 */ +#define FALSE false + +/* 'uint' conflicts with some Unixen sys/types.h, so we now don't define it */ +typedef unsigned8 uint8; +typedef unsigned16 uint16; +typedef unsigned32 uint32; + +typedef unsigned Uint; +typedef unsigned8 Uint8; +typedef unsigned16 Uint16; +typedef unsigned32 Uint32; + +#ifdef ALPHA_TASO_SHORT_ON_OSF /* was __alpha && __osf. */ +/* The following sets ArgvType for 64-bit pointers so that */ +/* DEC Unix (OSF) cc can be used with the -xtaso_short compiler option */ +/* to force pointers to be 32-bit. Not currently used since most/all */ +/* ARM tools accept 32 or 64 bit pointers transparently. See IPtr. */ +#pragma pointer_size (save) +#pragma pointer_size (long) +typedef char *ArgvType; +#pragma pointer_size (restore) +#else +typedef char *ArgvType; +#endif + +/* + * Rotate macros + */ +#define ROL_32(val, n) \ +((((unsigned32)(val) << (n)) | ((unsigned32)(val) >> (32-(n)))) & 0xFFFFFFFFL) +#define ROR_32(val, n) \ +((((unsigned32)(val) >> (n)) | ((unsigned32)(val) << (32-(n)))) & 0xFFFFFFFFL) + +#ifdef COMPILING_ON_UNIX +# define FOPEN_WB "w" +# define FOPEN_RB "r" +# define FOPEN_RWB "r+" +# ifndef __STDC__ /* caveat RISCiX... */ +# define remove(file) unlink(file) /* a horrid hack, but probably best? */ +# endif +#else +# define FOPEN_WB "wb" +# define FOPEN_RB "rb" +# define FOPEN_RWB "rb+" +#endif + +#ifndef FILENAME_MAX +# define FILENAME_MAX 256 +#endif + +#if (!defined(__STDC__) && !defined(__cplusplus) && !defined(_MSC_VER)) || \ + defined(COMPILING_ON_SUNOS) +/* Use bcopy rather than memmove, as memmove is not available. */ +/* There does not seem to be a header for bcopy. */ +void bcopy(const char *src, char *dst, int length); +# define memmove(d,s,l) bcopy(s,d,l) + +/* BSD/SUN don't have strtoul(), but then strtol() doesn't barf on */ +/* overflow as required by ANSI... This bodge is horrid. */ +# define strtoul(s, ptr, base) strtol(s, ptr, base) + +/* strtod is present in the C-library but is not in stdlib.h */ +extern double strtod(const char *str, char **ptr); +#endif + +/* For systems that do not define EXIT_SUCCESS and EXIT_FAILURE */ +#ifndef EXIT_SUCCESS +# define EXIT_SUCCESS 0 +#endif +#ifndef EXIT_FAILURE +# define EXIT_FAILURE 1 +#endif + +#ifndef IGNORE +#define IGNORE(x) (x = x) /* Silence compiler warnings for unused arguments */ +#endif + +/* Define endian-ness of host */ + +#if defined(__acorn) || defined(__mvs) || defined(_WIN32) || \ + (defined(__alpha) && defined(__osf__)) +# define HOST_ENDIAN_LITTLE +#elif defined(__sparc) || defined(macintosh) +# define HOST_ENDIAN_BIG +#else +# define HOST_ENDIAN_UNKNOWN +#endif + +#endif + +/* end of host.h */ diff --git a/gdb/rdi-share/hostchan.c b/gdb/rdi-share/hostchan.c new file mode 100644 index 00000000000..b62fbe3bb36 --- /dev/null +++ b/gdb/rdi-share/hostchan.c @@ -0,0 +1,1060 @@ +/* + * Copyright (C) 1995 Advanced RISC Machines Limited. All rights reserved. + * + * This software may be freely used, copied, modified, and distributed + * provided that the above copyright notice is preserved in all copies of the + * software. + */ + +/* -*-C-*- + * + * $Revision$ + * $Date$ + * + * + * hostchan.c - Semi Synchronous Host side channel interface for Angel. + */ + +#include + +#if defined(__unix) || defined(__CYGWIN32__) +# include +# ifdef sun + int gettimeofday(struct timeval *tp, struct timezone *tzp); +# endif +#else +# include "winsock.h" +# include "time.h" +#endif +#include "hsys.h" +#include "host.h" +#include "logging.h" +#include "chandefs.h" +#include "chanpriv.h" +#include "devclnt.h" +#include "buffers.h" +#include "drivers.h" +#include "adperr.h" +#include "devsw.h" +#include "hostchan.h" + +#ifndef UNUSED +#define UNUSED(x) (x = x) /* Silence compiler warnings for unused arguments */ +#endif + +#define HEARTRATE 5000000 + +/* + * list of available drivers, declared in drivers.c + */ +extern DeviceDescr *devices[]; + +static DeviceDescr *deviceToUse = NULL; + +static struct Channel { + ChannelCallback callback; + void *callback_state; +} channels[CI_NUM_CHANNELS]; + +static unsigned char HomeSeq; +static unsigned char OppoSeq; + +/* + * Handler for DC_APPL packets + */ +static DC_Appl_Handler dc_appl_handler = NULL; + +/* + * slots for registered asynchronous processing callback procedures + */ +#define MAX_ASYNC_CALLBACKS 8 +static unsigned int num_async_callbacks = 0; +static Adp_Async_Callback async_callbacks[MAX_ASYNC_CALLBACKS]; + +/* + * writeQueueRoot is the queue of write requests pending acknowledgement + * writeQueueSend is the queue of pending write requests which will + * be a subset of the list writeQueueRoot + */ +static Packet *writeQueueRoot = NULL; +static Packet *writeQueueSend = NULL; +static Packet *resend_pkt = NULL; +static int resending = FALSE; + +/* heartbeat_enabled is a flag used to indicate whether the heartbeat is + * currently turned on, heartbeat_enabled will be false in situations + * where even though a heartbeat is being used it is problematical or + * dis-advantageous to have it turned on, for instance during the + * initial stages of boot up + */ +unsigned int heartbeat_enabled = FALSE; +/* heartbeat_configured is set up by the device driver to indicate whether + * the heartbeat is being used during this debug session. In contrast to + * heartbeat_enabled it must not be changed during a session. The logic for + * deciding whether to send a heartbeat is: Is heartbeat_configured for this + * session? if and only if it is then if heartbeat[is currently]_enabled and + * we are due to send a pulse then send it + */ +unsigned int heartbeat_configured = TRUE; + +void Adp_initSeq( void ) { + Packet *tmp_pkt = writeQueueSend; + + HomeSeq = 0; + OppoSeq = 0; + if ( writeQueueSend != NULL) { + while (writeQueueSend->pk_next !=NULL) { + tmp_pkt = writeQueueSend; + writeQueueSend = tmp_pkt->pk_next; + DevSW_FreePacket(tmp_pkt); + } + } + tmp_pkt = writeQueueRoot; + if ( writeQueueRoot == NULL) + return; + + while (writeQueueRoot->pk_next !=NULL) { + tmp_pkt = writeQueueRoot; + writeQueueRoot = tmp_pkt->pk_next; + DevSW_FreePacket(tmp_pkt); + } + return; +} + +/**********************************************************************/ + +/* + * Function: DummyCallback + * Purpose: Default callback routine to handle unexpected input + * on a channel + * + * Params: + * Input: packet The received packet + * + * state Contains nothing of significance + * + * Returns: Nothing + */ +static void DummyCallback(Packet *packet, void *state) +{ + ChannelID chan; + const char fmt[] = "Unexpected read on channel %u, length %d\n"; + char fmtbuf[sizeof(fmt) + 24]; + + UNUSED(state); + + chan = *(packet->pk_buffer); + sprintf(fmtbuf, fmt, chan, packet->pk_length); + printf(fmtbuf); + + /* + * junk this packet + */ + DevSW_FreePacket(packet); +} + +/* + * Function: BlockingCallback + * Purpose: Callback routine used to implement a blocking read call + * + * Params: + * Input: packet The received packet. + * + * Output: state Address of higher level's pointer to the received + * packet. + * + * Returns: Nothing + */ +static void BlockingCallback(Packet *packet, void *state) +{ + /* + * Pass the packet back to the caller which requested a packet + * from this channel. This also flags the completion of the I/O + * request to the blocking read call. + */ + *((Packet **)state) = packet; +} + +/* + * Function: FireCallback + * Purpose: Pass received packet along to the callback routine for + * the appropriate channel + * + * Params: + * Input: packet The received packet. + * + * Returns: Nothing + * + * Post-conditions: The Target-to-Host sequence number for the channel + * will have been incremented. + */ +static void FireCallback(Packet *packet) +{ + ChannelID chan; + struct Channel *ch; + + /* + * is this a sensible channel number? + */ + chan = *(packet->pk_buffer); + if (invalidChannelID(chan)) + { + printf("ERROR: invalid ChannelID received from target\n"); + + /* + * free the packet's resources, 'cause no-one else will + */ + DevSW_FreePacket(packet); + return; + } + + /* + * looks OK - increment sequence number, and pass packet to callback + */ + ch = channels + chan; + (ch->callback)(packet, ch->callback_state); +} + +/**********************************************************************/ + +/* + * These are the externally visible functions. They are documented + * in hostchan.h + */ +void Adp_addToQueue(Packet **head, Packet *newpkt) +{ + /* + * this is a bit of a hack + */ + Packet *pk; + + /* + * make sure that the hack we are about to use will work as expected + */ + ASSERT(&(((Packet *)0)->pk_next) == 0, "bad struct Packet layout"); + +#if DEBUG && 0 + printf("Adp_addToQueue(%p, %p)\n", head, newpkt); +#endif + + /* + * here's the hack - it relies upon the next + * pointer being at the start of Packet. + */ + pk = (Packet *)(head); + + /* + * skip to the end of the queue + */ + while (pk->pk_next != NULL) + pk = pk->pk_next; + + /* + * now add the new element + */ + newpkt->pk_next = NULL; + pk->pk_next = newpkt; +} + +Packet *Adp_removeFromQueue(Packet **head) +{ + struct Packet *pk; + + pk = *head; + + if (pk != NULL) + *head = pk->pk_next; + + return pk; +} + +AdpErrs Adp_OpenDevice(const char *name, const char *arg, + unsigned int heartbeat_on) +{ + int i; + AdpErrs retc; + ChannelID chan; + +#ifdef DEBUG + printf("Adp_OpenDevice(%s, %s)\n", name, arg ? arg : ""); +#endif + + heartbeat_configured = heartbeat_on; + if (deviceToUse != NULL) + return adp_device_already_open; + + for (i = 0; (deviceToUse = devices[i]) != NULL; ++i) + if (DevSW_Match(deviceToUse, name, arg) == adp_ok) + break; + + if (deviceToUse == NULL) + return adp_device_not_found; + + /* + * we seem to have found a suitable device driver, so try to open it + */ + if ((retc = DevSW_Open(deviceToUse, name, arg, DC_DBUG)) != adp_ok) + { + /* we don't have a device to use */ + deviceToUse = NULL; + return retc; + } + + /* + * there is no explicit open on channels any more, so + * initialise state for all channels. + */ + for (chan = 0; chan < CI_NUM_CHANNELS; ++chan) + { + struct Channel *ch = channels + chan; + + ch->callback = DummyCallback; + ch->callback_state = NULL; + OppoSeq = 0; + HomeSeq = 0; + } + + return adp_ok; +} + +AdpErrs Adp_CloseDevice(void) +{ + AdpErrs retc; + +#ifdef DEBUG + printf("Adp_CloseDevice\n"); +#endif + + if (deviceToUse == NULL) + return adp_device_not_open; + + heartbeat_enabled = FALSE; + + retc = DevSW_Close(deviceToUse, DC_DBUG); + + /* + * we have to clear deviceToUse, even when the lower layers + * faulted the close, otherwise the condition will never clear + */ + if (retc != adp_ok) + WARN("DevSW_Close faulted the call"); + + deviceToUse = NULL; + return retc; +} + +AdpErrs Adp_Ioctl(int opcode, void *args) +{ +#ifdef DEBUG + printf("Adp_Ioctl\n"); +#endif + + if (deviceToUse == NULL) + return adp_device_not_open; + + return DevSW_Ioctl(deviceToUse, opcode, args); +} + +AdpErrs Adp_ChannelRegisterRead(const ChannelID chan, + const ChannelCallback cbfunc, + void *cbstate) +{ +#ifdef DEBUG + printf("Adp_ChannelRegisterRead(%d, %p, %x)\n", chan, cbfunc, cbstate); +#endif + + if (deviceToUse == NULL) + return adp_device_not_open; + + if (invalidChannelID(chan)) + return adp_bad_channel_id; + + if (cbfunc == NULL) + { + channels[chan].callback = DummyCallback; + channels[chan].callback_state = NULL; + } + else + { + channels[chan].callback = cbfunc; + channels[chan].callback_state = cbstate; + } + + return adp_ok; +} + +AdpErrs Adp_ChannelRead(const ChannelID chan, Packet **packet) +{ + struct Channel *ch; + +#ifdef DEBUG + printf("Adp_ChannelRead(%d, %x)\n", chan, *packet); +#endif + + if (deviceToUse == NULL) + return adp_device_not_open; + + if (invalidChannelID(chan)) + return adp_bad_channel_id; + + /* + * if a callback has already been registered for this + * channel, then we do not allow this blocking read. + */ + ch = channels + chan; + if (ch->callback != DummyCallback) + return adp_callback_already_registered; + + /* + * OK, use our own callback to wait for a packet to arrive + * on this channel + */ + ch->callback = BlockingCallback; + ch->callback_state = packet; + *packet = NULL; + + /* + * keep polling until a packet appears for this channel + */ + while (((volatile Packet *)(*packet)) == NULL) + /* + * this call will block until a packet is read on any channel + */ + Adp_AsynchronousProcessing(async_block_on_read); + + /* + * OK, the packet has arrived: clear the callback + */ + ch->callback = DummyCallback; + ch->callback_state = NULL; + + return adp_ok; +} + +static AdpErrs ChannelWrite( + const ChannelID chan, Packet *packet, AsyncMode mode) +{ + struct Channel *ch; + unsigned char *cptr; + +#ifdef DEBUG + printf( "Adp_ChannelWrite(%d, %x)\n", chan, packet ); +#endif + + if (deviceToUse == NULL) + return adp_device_not_open; + + if (invalidChannelID(chan)) + return adp_bad_channel_id; + + /* + * fill in the channels header at the start of this buffer + */ + ch = channels + chan; + cptr = packet->pk_buffer; + *cptr++ = chan; + *cptr = 0; + packet->pk_length += CHAN_HEADER_SIZE; + + /* + * OK, add this packet to the write queue, and try to flush it out + */ + + Adp_addToQueue(&writeQueueSend, packet); + Adp_AsynchronousProcessing(mode); + + return adp_ok; +} + +AdpErrs Adp_ChannelWrite(const ChannelID chan, Packet *packet) { + return ChannelWrite(chan, packet, async_block_on_write); +} + +AdpErrs Adp_ChannelWriteAsync(const ChannelID chan, Packet *packet) { + return ChannelWrite(chan, packet, async_block_on_nothing); +} + +static AdpErrs send_resend_msg(DeviceID devid) { + + /* + * Send a resend message, usually in response to a bad packet or + * a resend request */ + Packet * packet; + packet = DevSW_AllocatePacket(CF_DATA_BYTE_POS); + packet->pk_buffer[CF_CHANNEL_BYTE_POS] = CI_PRIVATE; + packet->pk_buffer[CF_HOME_SEQ_BYTE_POS] = HomeSeq; + packet->pk_buffer[CF_OPPO_SEQ_BYTE_POS] = OppoSeq; + packet->pk_buffer[CF_FLAGS_BYTE_POS] = CF_RELIABLE | CF_RESEND; + packet->pk_length = CF_DATA_BYTE_POS; + return DevSW_Write(deviceToUse, packet, devid); +} + +static AdpErrs check_seq(unsigned char msg_home, unsigned char msg_oppo) { + Packet *tmp_pkt; + + UNUSED(msg_oppo); + /* + * check if we have got an ack for anything and if so remove it from the + * queue + */ + if (msg_home == (unsigned char)(OppoSeq+1)) { + /* + * arrived in sequence can increment our opposing seq number and remove + * the relevant packet from our queue + * check that the packet we're going to remove really is the right one + */ + tmp_pkt = writeQueueRoot; + while ((tmp_pkt->pk_next != NULL) && + (tmp_pkt->pk_next->pk_buffer[CF_HOME_SEQ_BYTE_POS] + != OppoSeq)){ + tmp_pkt = tmp_pkt->pk_next; + } + OppoSeq++; + if (tmp_pkt->pk_next == NULL) { +#ifdef DEBUG + printf("trying to remove a non existant packet\n"); +#endif + return adp_bad_packet; + } + else { + Packet *tmp = tmp_pkt->pk_next; +#ifdef RET_DEBUG + printf("removing a packet from the root queue\n"); +#endif + tmp_pkt->pk_next = tmp_pkt->pk_next->pk_next; + /* remove the appropriate packet */ + DevSW_FreePacket(tmp); + return adp_ok; + } + } + else if (msg_home < (unsigned char) (OppoSeq+1)){ + /* already received this message */ +#ifdef RET_DEBUG + printf("sequence numbers low\n"); +#endif + return adp_seq_low; + } + else { /* we've missed something */ +#ifdef RET_DEBUG + printf("sequence numbers high\n"); +#endif + return adp_seq_high; + } +} + +static unsigned long tv_diff(const struct timeval *time_now, + const struct timeval *time_was) +{ + return ( ((time_now->tv_sec * 1000000) + time_now->tv_usec) + - ((time_was->tv_sec * 1000000) + time_was->tv_usec) ); +} + +#if !defined(__unix) && !defined(__CYGWIN32__) +static void gettimeofday( struct timeval *time_now, void *dummy ) +{ + time_t t = clock(); + UNUSED(dummy); + time_now->tv_sec = t/CLOCKS_PER_SEC; + time_now->tv_usec = (t%CLOCKS_PER_SEC)*(1000000/CLOCKS_PER_SEC); +} +#endif + +static AdpErrs pacemaker(void) +{ + Packet *packet; + + packet = DevSW_AllocatePacket(CF_DATA_BYTE_POS); + if (packet == NULL) { + printf("ERROR: could not allocate a packet in pacemaker()\n"); + return adp_malloc_failure; + } + packet->pk_buffer[CF_CHANNEL_BYTE_POS] = CI_PRIVATE; + packet->pk_buffer[CF_HOME_SEQ_BYTE_POS] = HomeSeq; + packet->pk_buffer[CF_OPPO_SEQ_BYTE_POS] = OppoSeq; + packet->pk_buffer[CF_FLAGS_BYTE_POS] = CF_RELIABLE | CF_HEARTBEAT; + packet->pk_length = CF_DATA_BYTE_POS; + return DevSW_Write(deviceToUse, packet, DC_DBUG); +} + +#ifdef FAKE_BAD_LINE_RX +static AdpErrs fake_bad_line_rx( const Packet *const packet, AdpErrs adp_err ) +{ + static unsigned int bl_num = 0; + + if ( (packet != NULL) + && (bl_num++ >= 20 ) + && ((bl_num % FAKE_BAD_LINE_RX) == 0)) + { + printf("DEBUG: faking a bad packet\n"); + return adp_bad_packet; + } + return adp_err; +} +#endif /* def FAKE_BAD_LINE_RX */ + +#ifdef FAKE_BAD_LINE_TX +static unsigned char tmp_ch; + +static void fake_bad_line_tx( void ) +{ + static unsigned int bl_num = 0; + + /* give the thing a chance to boot then try corrupting stuff */ + if ( (bl_num++ >= 20) && ((bl_num % FAKE_BAD_LINE_TX) == 0)) + { + printf("DEBUG: faking a bad packet for tx\n"); + tmp_ch = writeQueueSend->pk_buffer[CF_FLAGS_BYTE_POS]; + writeQueueSend->pk_buffer[CF_FLAGS_BYTE_POS] = 77; + } +} + +static void unfake_bad_line_tx( void ) +{ + static unsigned int bl_num = 0; + + /* + * must reset the packet so that its not corrupted when we + * resend it + */ + if ( (bl_num >= 20) && ((bl_num % FAKE_BAD_LINE_TX) != 0)) + { + writeQueueSend->pk_buffer[CF_FLAGS_BYTE_POS] = tmp_ch; + } +} +#endif /* def FAKE_BAD_LINE_TX */ + +/* + * NOTE: we are assuming that a resolution of microseconds will + * be good enough for the purporses of the heartbeat. If this proves + * not to be the case then we may need a rethink, possibly using + * [get,set]itimer + */ +static struct timeval time_now; +static struct timeval time_lastalive; + +static void async_process_dbug_read( const AsyncMode mode, + bool *const finished ) +{ + Packet *packet; + unsigned int msg_home, msg_oppo; + AdpErrs adp_err; + + adp_err = DevSW_Read(deviceToUse, DC_DBUG, &packet, + mode == async_block_on_read ); + +#ifdef FAKE_BAD_LINE_RX + adp_err = fake_bad_line_rx( packet, adp_err ); +#endif + + if (adp_err == adp_bad_packet) { + /* We got a bad packet, ask for a resend, send a resend message */ +#ifdef DEBUG + printf("received a bad packet\n"); +#endif + send_resend_msg(DC_DBUG); + } + else if (packet != NULL) + { + /* update the heartbeat clock */ + gettimeofday(&time_lastalive, NULL); + + /* + * we got a live one here - were we waiting for it? + */ + if (mode == async_block_on_read) + /* not any more */ + *finished = TRUE; +#ifdef RETRANS + + if (packet->pk_length < CF_DATA_BYTE_POS) { + /* we've got a packet with no header information! */ + printf("ERROR: packet with no transport header\n"); + send_resend_msg(DC_DBUG); + } + else { +#ifdef RET_DEBUG + unsigned int c; +#endif + /* + * TODO: Check to see if its acknowledgeing anything, remove + * those packets it is from the queue. If its a retrans add the + * packets to the queue + */ + msg_home = packet->pk_buffer[CF_HOME_SEQ_BYTE_POS]; + msg_oppo = packet->pk_buffer[CF_OPPO_SEQ_BYTE_POS]; +#ifdef RET_DEBUG + printf("msg seq numbers are hseq 0x%x oseq 0x%x\n", + msg_home, msg_oppo); + for (c=0;cpk_length;c++) + printf("%02.2x", packet->pk_buffer[c]); + printf("\n"); +#endif + /* now was it a resend request? */ + if ((packet->pk_buffer[CF_FLAGS_BYTE_POS]) + & CF_RESEND) { + /* we've been asked for a resend so we had better resend */ + /* + * I don't think we can use a resend as acknowledgement for + * anything so lets not do this for the moment + * check_seq(msg_home, msg_oppo); + */ +#ifdef RET_DEBUG + printf("received a resend request\n"); +#endif + if (HomeSeq != msg_oppo) { + int found = FALSE; + /* need to resend from msg_oppo +1 upwards */ + DevSW_FreePacket(packet); + resending = TRUE; + /* find the correct packet to resend from */ + packet = writeQueueRoot; + while (((packet->pk_next) != NULL) && !found) { + if ((packet->pk_buffer[CF_OPPO_SEQ_BYTE_POS]) + != msg_oppo+1) { + resend_pkt = packet; + found = TRUE; + } + packet = packet->pk_next; + } + if (!found) { + panic("trying to resend non-existent packets\n"); + } + } + else if (OppoSeq != msg_home) { + /* + * send a resend request telling the target where we think + * the world is at + */ + DevSW_FreePacket(packet); + send_resend_msg(DC_DBUG); + } + } + else { + /* not a resend request, lets check the sequence numbers */ + + if ((packet->pk_buffer[CF_CHANNEL_BYTE_POS] != CI_HBOOT) && + (packet->pk_buffer[CF_CHANNEL_BYTE_POS] != CI_TBOOT)) { + adp_err = check_seq(msg_home, msg_oppo); + if (adp_err == adp_seq_low) { + /* we have already received this packet so discard */ + DevSW_FreePacket(packet); + } + else if (adp_err == adp_seq_high) { + /* + * we must have missed a packet somewhere, discard this + * packet and tell the target where we are + */ + DevSW_FreePacket(packet); + send_resend_msg(DC_DBUG); + } + else + /* + * now pass the packet to whoever is waiting for it + */ + FireCallback(packet); + } + else + FireCallback(packet); + } + } +#else + /* + * now pass the packet to whoever is waiting for it + */ + FireCallback(packet); +#endif + } +} + +static void async_process_appl_read(void) +{ + Packet *packet; + AdpErrs adp_err; + + /* see if there is anything for the DC_APPL channel */ + adp_err = DevSW_Read(deviceToUse, DC_APPL, &packet, FALSE); + + if (adp_err == adp_ok && packet != NULL) + { + /* got an application packet on a shared device */ + +#ifdef DEBUG + printf("GOT DC_APPL PACKET: len %d\nData: ", packet->pk_length); + { + unsigned int c; + for ( c = 0; c < packet->pk_length; ++c ) + printf( "%02X ", packet->pk_buffer[c] ); + } + printf("\n"); +#endif + + if (dc_appl_handler != NULL) + { + dc_appl_handler( deviceToUse, packet ); + } + else + { + /* for now, just free it!! */ +#ifdef DEBUG + printf("no handler - dropping DC_APPL packet\n"); +#endif + DevSW_FreePacket( packet ); + } + } +} + +static void async_process_write( const AsyncMode mode, + bool *const finished ) +{ + Packet *packet; + +#ifdef DEBUG + static unsigned int num_written = 0; +#endif + + /* + * NOTE: here we rely in the fact that any packet in the writeQueueSend + * section of the queue will need its sequence number setting up while + * and packet in the writeQueueRoot section will have its sequence + * numbers set up from when it was first sent so we can easily look + * up the packet numbers when(if) we want to resend the packet. + */ + +#ifdef DEBUG + if (writeQueueSend!=NULL) + printf("written 0x%x\n",num_written += writeQueueSend->pk_length); +#endif + /* + * give the switcher a chance to complete any partial writes + */ + if (DevSW_FlushPendingWrite(deviceToUse) == adp_write_busy) + { + /* no point trying a new write */ + return; + } + + /* + * now see whether there is anything to write + */ + packet = NULL; + if (resending) { + packet = resend_pkt; +#ifdef RET_DEBUG + printf("resending hseq 0x%x oseq 0x%x\n", + packet->pk_buffer[CF_HOME_SEQ_BYTE_POS], + packet->pk_buffer[CF_OPPO_SEQ_BYTE_POS]); +#endif + } + else if (writeQueueSend != NULL) { +#ifdef RETRANS + /* set up the sequence number on the packet */ + packet = writeQueueSend; + HomeSeq++; + (writeQueueSend->pk_buffer[CF_OPPO_SEQ_BYTE_POS]) + = OppoSeq; + (writeQueueSend->pk_buffer[CF_HOME_SEQ_BYTE_POS]) + = HomeSeq; + (writeQueueSend->pk_buffer[CF_FLAGS_BYTE_POS]) + = CF_RELIABLE; +# ifdef RET_DEBUG + printf("sending packet with hseq 0x%x oseq 0x%x\n", + writeQueueSend->pk_buffer[CF_HOME_SEQ_BYTE_POS], + writeQueueSend->pk_buffer[CF_OPPO_SEQ_BYTE_POS]); +# endif +#endif /* RETRANS */ + } + + if (packet != NULL) { + AdpErrs dev_err; + +#ifdef FAKE_BAD_LINE_TX + fake_bad_line_tx(); +#endif + + dev_err = DevSW_Write(deviceToUse, packet, DC_DBUG); + if (dev_err == adp_ok) { +#ifdef RETRANS + if (resending) { + /* check to see if we've recovered yet */ + if ((packet->pk_next) == NULL){ +# ifdef RET_DEBUG + printf("we have recovered\n"); +# endif + resending = FALSE; + } + else { + resend_pkt = resend_pkt->pk_next; + } + } + else { + /* + * move the packet we just sent from the send queue to the root + */ + Packet *tmp_pkt, *tmp; + +# ifdef FAKE_BAD_LINE_TX + unfake_bad_line_tx(); +# endif + + tmp_pkt = writeQueueSend; + writeQueueSend = writeQueueSend->pk_next; + tmp_pkt->pk_next = NULL; + if (writeQueueRoot == NULL) + writeQueueRoot = tmp_pkt; + else { + tmp = writeQueueRoot; + while (tmp->pk_next != NULL) { + tmp = tmp->pk_next; + } + tmp->pk_next = tmp_pkt; + } + } +#else /* not RETRANS */ + /* + * switcher has taken the write, so remove it from the + * queue, and free its resources + */ + DevSW_FreePacket(Adp_removeFromQueue(&writeQueueSend)); +#endif /* if RETRANS ... else ... */ + + if (mode == async_block_on_write) + *finished = DevSW_WriteFinished(deviceToUse); + + } /* endif write ok */ + } + else /* packet == NULL */ + { + if (mode == async_block_on_write) + *finished = DevSW_WriteFinished(deviceToUse); + } +} + +static void async_process_heartbeat( void ) +{ + /* check to see whether we need to send a heartbeat */ + gettimeofday(&time_now, NULL); + + if (tv_diff(&time_now, &time_lastalive) >= HEARTRATE) + { + /* + * if we've not booted then don't do send a heartrate the link + * must be reliable enough for us to boot without any clever stuff, + * if we can't do this then theres little chance of the link staying + * together even with the resends etc + */ + if (heartbeat_enabled) { + gettimeofday(&time_lastalive, NULL); + pacemaker(); + } + } +} + +static void async_process_callbacks( void ) +{ + /* call any registered asynchronous callbacks */ + unsigned int i; + for ( i = 0; i < num_async_callbacks; ++i ) + async_callbacks[i]( deviceToUse, &time_now ); +} + +void Adp_AsynchronousProcessing(const AsyncMode mode) +{ + bool finished = FALSE; +#ifdef DEBUG + unsigned int wc = 0, dc = 0, ac = 0, hc = 0; +# define INC_COUNT(x) ((x)++) +#else +# define INC_COUNT(x) +#endif + + if ((time_lastalive.tv_sec == 0) && (time_lastalive.tv_usec == 0)) { + /* first time through, needs initing */ + gettimeofday(&time_lastalive, NULL); + } + + /* main loop */ + do + { + async_process_write( mode, &finished ); + INC_COUNT(wc); + + if ( ! finished && mode != async_block_on_write ) + { + async_process_dbug_read( mode, &finished ); + INC_COUNT(dc); + } + + if ( ! finished && mode != async_block_on_write ) + { + async_process_appl_read(); + INC_COUNT(ac); + } + + if ( ! finished ) + { + if (heartbeat_configured) + async_process_heartbeat(); + async_process_callbacks(); + INC_COUNT(hc); + } + + } while (!finished && mode != async_block_on_nothing); + +#ifdef DEBUG + if ( mode != async_block_on_nothing ) + printf( "Async: %s - w %d, d %d, a %d, h %d\n", + mode == async_block_on_write ? "blk_write" : "blk_read", + wc, dc, ac, hc ); +#endif +} + +/* + * install a handler for DC_APPL packets (can be NULL), returning old one. + */ +DC_Appl_Handler Adp_Install_DC_Appl_Handler(const DC_Appl_Handler handler) +{ + DC_Appl_Handler old_handler = dc_appl_handler; + +#ifdef DEBUG + printf( "Installing DC_APPL handler %x (old %x)\n", handler, old_handler ); +#endif + + dc_appl_handler = handler; + return old_handler; +} + + +/* + * add an asynchronous processing callback to the list + * TRUE == okay, FALSE == no more async processing slots + */ +bool Adp_Install_Async_Callback( const Adp_Async_Callback callback_proc ) +{ + if ( num_async_callbacks < MAX_ASYNC_CALLBACKS && callback_proc != NULL ) + { + async_callbacks[num_async_callbacks] = callback_proc; + ++num_async_callbacks; + return TRUE; + } + else + return FALSE; +} + + +/* + * delay for a given period (in microseconds) + */ +void Adp_delay(unsigned int period) +{ + struct timeval tv; + +#ifdef DEBUG + printf("delaying for %d microseconds\n", period); +#endif + tv.tv_sec = (period / 1000000); + tv.tv_usec = (period % 1000000); + + (void)select(0, NULL, NULL, NULL, &tv); +} + +/* EOF hostchan.c */ diff --git a/gdb/rdi-share/hostchan.h b/gdb/rdi-share/hostchan.h new file mode 100644 index 00000000000..db313dca168 --- /dev/null +++ b/gdb/rdi-share/hostchan.h @@ -0,0 +1,300 @@ +/* + * Copyright (C) 1995 Advanced RISC Machines Limited. All rights reserved. + * + * This software may be freely used, copied, modified, and distributed + * provided that the above copyright notice is preserved in all copies of the + * software. + */ + +/* -*-C-*- + * + * $Revision$ + * $Date$ + * + */ +#ifndef angsd_hostchan_h +#define angsd_hostchan_h + +/* struct timeval */ +#if defined(__unix) || defined(__CYGWIN32__) +# include +#else +# include "winsock.h" +# include "time.h" +#endif + +#include "chandefs.h" +#include "adperr.h" +#include "devsw.h" + +/* + * asynchronous processing modes + */ +enum AsyncMode +{ + async_block_on_nothing, + async_block_on_read, + async_block_on_write +}; + +#ifndef __cplusplus +typedef enum AsyncMode AsyncMode; +#endif + +/* + * prototype for channels callback function + */ +typedef void (*ChannelCallback)(Packet *packet, void *state); + +/* + * Function: Adp_initSeq + * Purpose: initialise the channel protocol and sequence numbers + * + * Params: none + * + * Returns: Nothing + */ +extern void Adp_initSeq(void); + +/* + * Function: Adp_addToQueue + * Purpose: chain a Packet to the end of a linked list of such structures + * + * Params: + * In/Out: head Head of the linked list + * + * newpkt Packet to be chained onto the list + * + * Returns: Nothing + */ +extern void Adp_addToQueue(Packet **head, Packet *newpkt); + +/* + * Function: removeFromQueue + * Purpose: remove a Packet from the head of a linked list of such structures + * + * Params: + * In/Out: head Head of the linked list + * + * Returns: Old head from the linked list + * + * Post-conditions: Second element in the list will be the new head. + */ + +extern Packet *Adp_removeFromQueue(Packet **head); + +/* + * Function: Adp_OpenDevice + * Purpose: Open a device to use for channels communication. This is a + * very thin veneer to the device drivers: what hostchan.c + * will do is call DeviceMatch for each device driver until it + * finds a driver that will accept name and arg, then call + * DeviceOpen for that device. + * + * Pre-conditions: No previous open is still active + * + * Params: + * Input: name Identifies which device to open. This can either be + * a host specific identifier (e.g. "/dev/ttya", + * "COM1:"), or a number which is used to refer to + * `standard' interfaces, so "1" would be the first host + * interface, "2" the second, and so on. + * + * arg Driver specific arguments. For example, some serial + * drivers accept speed and control arguments such as + * "9600" or "19200/NO_BREAK". These arguments are + * completely free-form: it is the individual drivers + * which do the necessary interpretation. + * + * heartbeat_on Incicates if the heartbeat is configured to be + * used or not, true if it is, false otherwise + * + * Returns: + * OK: adp_ok + * Error: adp_device_not_known, + * adp_device_open_failed + * adp_device_already_open + */ +AdpErrs Adp_OpenDevice(const char *name, const char *arg, + unsigned int heartbeat_on); + +/* + * Function: Adp_CloseDevice + * Purpose: Close the device used for channels communication. + * + * Params: None + * + * Returns: + * OK: adp_ok + * Error: adp_device_not_open + */ +AdpErrs Adp_CloseDevice(void); + +/* + * Function: Adp_Ioctl + * Purpose: Perform miscellaneous control operations on + * the device used for channels communication. + * This is a minimal veneer to DevSW_Ioctl. + * + * Params: + * Input: opcode Reason code indicating the operation to perform. + * In/Out: args Pointer to opcode-sensitive arguments/result space. + * + * + * Returns: + * OK: adp_ok + * Error: adp_device_not_open, adp_failed + */ +AdpErrs Adp_Ioctl(int opcode, void *args); + +/* + * Function: Adp_ChannelRegisterRead + * Purpose: Register a callback function for received packets on a given + * channel + * + * Params: + * Input: chan The channel the callback function is for. + * + * cbfunc The callback function. If NULL, then the current + * callback is removed. + * + * cbstate State pointer to pass into the callback function + * + * Returns: + * OK: adp_ok + * Error: adp_device_not_open + * adp_bad_channel_id + * + * Post-conditions: The callback function is responsible for freeing the + * packet that is passed to it, when that packet is + * no longer needed. + */ +#ifdef __cplusplus + extern "C" { +#endif + + +extern AdpErrs Adp_ChannelRegisterRead(const ChannelID chan, + const ChannelCallback cbfunc, + void *cbstate); + +#ifdef __cplusplus + } +#endif +/* + * Function: Adp_ChannelRead + * Purpose: Wait until a packet has been read for a given channel, and + * then return it. Callbacks for other channels are still + * active while this read is blocking. + * + * Pre-conditions: No callback has been already been registered for + * the channel. + * + * Params: + * Input: chan The channel to read. + * + * Output: packet The received packet. + * + * Returns: + * OK: adp_ok + * Error: adp_device_not_open + * adp_bad_channel_id + * adp_callback_already_registered + * + * Post-conditions: The calling function is responsible for freeing the + * received packet, when that packet is no longer + * needed. + */ +AdpErrs Adp_ChannelRead(const ChannelID chan, Packet **packet); + +/* + * Function: Adp_ChannelWrite + * Purpose: Write a packet to the given channel + * + * Pre-conditions: Channel must have been previously opened. + * + * Params: + * Input: chan The channel to write. + * + * packet The packet to write. + * + * Returns: + * OK: adp_ok + * Error: adp_device_not_open + * adp_bad_channel_id + * + * Post-conditions: The packet being written becomes the "property" of + * Adp_ChannelWrite, which is responsible for freeing + * the packet when it is no longer needed. + */ +AdpErrs Adp_ChannelWrite(const ChannelID chan, Packet *packet); + +/* + * Function: Adp_ChannelWriteAsync + * Purpose: Write a packet to the given channel, but don't wait + * for the write to complete before returning. + * + * Pre-conditions: Channel must have been previously opened. + * + * Params: + * Input: chan The channel to write. + * + * packet The packet to write. + * + * Returns: + * OK: adp_ok + * Error: adp_device_not_open + * adp_bad_channel_id + * + * Post-conditions: The packet being written becomes the "property" of + * Adp_ChannelWrite, which is responsible for freeing + * the packet when it is no longer needed. + */ +AdpErrs Adp_ChannelWriteAsync(const ChannelID chan, Packet *packet); + +/* + * Function: Adp_AsynchronousProcessing + * Purpose: This routine should be called from persistent any idle loop + * to give the data I/O routines a chance to poll for packet + * activity. Depending upon the requested mode, this routine + * may, or may not, block. + * + * Params: + * Input: mode Specifies whether to block until a complete packet + * has been read, all pending writes have completed, + * or not to block at all. + * + * Returns: Nothing. + */ +void Adp_AsynchronousProcessing(const AsyncMode mode); + +/* + * prototype for DC_APPL packet handler + */ +typedef void (*DC_Appl_Handler)(const DeviceDescr *device, Packet *packet); + +/* + * install a handler for DC_APPL packets (can be NULL), returning old one. + */ +DC_Appl_Handler Adp_Install_DC_Appl_Handler(const DC_Appl_Handler handler); + +/* + * prototype for asynchronous processing callback + */ +typedef void (*Adp_Async_Callback)(const DeviceDescr *device, + const struct timeval *const time_now); + +/* + * add an asynchronous processing callback to the list + * TRUE == okay, FALSE == no more async processing slots + */ +bool Adp_Install_Async_Callback( const Adp_Async_Callback callback_proc ); + +/* + * delay for a given period (in microseconds) + */ +void Adp_delay(unsigned int period); + +#endif /* ndef angsd_hostchan_h */ + +/* EOF hostchan.h */ diff --git a/gdb/rdi-share/hsys.c b/gdb/rdi-share/hsys.c new file mode 100644 index 00000000000..ef42a309b94 --- /dev/null +++ b/gdb/rdi-share/hsys.c @@ -0,0 +1,915 @@ +/* + * Copyright (C) 1995 Advanced RISC Machines Limited. All rights reserved. + * + * This software may be freely used, copied, modified, and distributed + * provided that the above copyright notice is preserved in all copies of the + * software. + */ + +/* + * Host C Library support functions. + * + * $Revision$ + * $Date$ + */ + +#ifdef DEBUG +# include +#endif + +#include +#include +#include +#include +#include +#include + +#include "adp.h" +#include "host.h" +#include "ardi.h" +#include "buffers.h" +#include "channels.h" /* Channel interface. */ +#include "endian.h" +#include "logging.h" /* Angel support functions. */ +#include "msgbuild.h" +#include "sys.h" +#include "hsys.h" /* Function and structure declarations. */ +#include "hostchan.h" + +#define FILEHANDLE int + +/* Note: no statics allowed. All globals must be malloc()ed on the heap. + The state struct is used for this purpose. See 'hsys.h'. */ +/* This is the message handler function passed to the channel manager in + HostSysInit. It is called whenever a message is received. 'buffptr' + points to the message body. Functionality is provided by the debugger + toolkit. The routine is very loosely based on the HandleSWI routine from + armos.c in the armulator source. */ +/* These routines could be tested by providing a simple interface to armsd, + and running them in that. */ + + +/* taken staight from armulator source */ +#ifdef __riscos + extern int _fisatty(FILE *); +# define isatty_(f) _fisatty(f) +# define EMFILE -1 +# define EBADF -1 + int _kernel_escape_seen(void) { return 0 ;} +#else +# if defined(_WINDOWS) || defined(_CONSOLE) +# define isatty_(f) (f == stdin || f == stdout) +# else +# ifdef __ZTC__ +# include +# define isatty_(f) isatty((f)->_file) +# else +# ifdef macintosh +# include +# define isatty_(f) (~ioctl((f)->_file,FIOINTERACTIVE,NULL)) +# else +# define isatty_(f) isatty(fileno(f)) +# endif +# endif +# endif +#endif + +/* Set up the state block, filetable and register the C lib callback fn */ +int HostSysInit(const struct Dbg_HostosInterface *hostif, char **cmdline, + hsys_state **stateptr) +{ + ChannelCallback HandleMessageFPtr = (ChannelCallback) HandleSysMessage; + int i; + *stateptr = (hsys_state *)malloc(sizeof(hsys_state)); + + if (*stateptr == NULL) return RDIError_OutOfStore; + + (*stateptr)->hostif=hostif; + (*stateptr)->last_errno=0; + (*stateptr)->OSptr=(OSblock *)malloc(sizeof(OSblock)); + if ((*stateptr)->OSptr == NULL) return RDIError_OutOfStore; + for (i=0; iOSptr->TempNames[i]=NULL; + for (i=0; iOSptr->FileTable[i]=NULL; + (*stateptr)->OSptr->FileFlags[i]=0; + } + (*stateptr)->CommandLine=cmdline; + + return Adp_ChannelRegisterRead(CI_CLIB, (ChannelCallback)HandleMessageFPtr, + *stateptr); +} + +/* Shut down the Clib support, this will probably never get called though */ +int HostSysExit(hsys_state *stateptr) +{ + free(stateptr->OSptr); + free(stateptr); + return RDIError_NoError; +} + +#ifdef DEBUG +static void DebugCheckNullTermString(char *prefix, bool nl, + unsigned int len, unsigned char *strp) +{ + printf("%s: %d: ", prefix, len); + if (strp[len]=='\0') + printf("\"%s\"", strp); + else + printf("NOT NULL TERMINATED"); + if (nl) + printf("\n"); + else + { + printf(" "); + fflush(stdout); + } +} + +extern int sys_nerr; +extern char *sys_errlist[]; + +static char *DebugStrError(int last_errno) +{ + if (last_errno < sys_nerr) + return sys_errlist[last_errno]; + else + return "NO MSG (errno>sys_nerr)"; +} + +static void DebugCheckErr(char *prefix, bool nl, int err, int last_errno) +{ + printf("\t%s: returned ", prefix); + if (err == 0) + printf("okay"); + else + printf("%d, errno = %d \"%s\"", err, last_errno, + DebugStrError(last_errno)); + if (nl) + printf("\n"); + else + { + printf(" "); + fflush(stdout); + } +} + +static void DebugCheckNonNull(char *prefix, bool nl, + void *handle, int last_errno) +{ + printf("\t%s: returned ", prefix); + if (handle != NULL) + printf("okay [%08x]", (unsigned int)handle); + else + printf("NULL, errno = %d \"%s\"", last_errno, + DebugStrError(last_errno)); + if (nl) + printf("\n"); + else + { + printf(" "); + fflush(stdout); + } +} + +#define DebugPrintF(c) printf c; + +#else + +#define DebugCheckNullTermString(p, n, l, s) ((void)(0)) +#define DebugCheckErr(p, n, e, l) ((void)(0)) +#define DebugCheckNonNull(p, n, h, l) ((void)(0)) +#define DebugPrintF(c) ((void)(0)) + +#endif /* ifdef DEBUG ... else */ + +static FILE *hsysGetRealFileHandle(hsys_state *stateptr, int fh, char *flags) +{ + FILE *file_p = NULL; + + if (fh < 0 || fh >= HSYS_FOPEN_MAX) + { + stateptr->last_errno = EBADF; + DebugPrintF(("\tfh %d out-of-bounds!\n", fh)); + return NULL; + } + else + { + file_p = stateptr->OSptr->FileTable[fh]; + if (file_p != NULL) { + if (flags != NULL) + *flags = stateptr->OSptr->FileFlags[fh]; + } + else { + stateptr->last_errno = EBADF; + DebugPrintF(("\tFileTable[%d] is NULL\n", fh)); + } + + return file_p; + } +} + +int HandleSysMessage(Packet *packet, hsys_state *stateptr) +{ + unsigned int reason_code, mode, len, c, nbytes, nbtotal, nbtogo = 0; + long posn, fl; + char character; + int err; + + /* Note: We must not free the buffer passed in as the callback handler */ + /* expects to do this. Freeing any other buffers we have malloced */ + /* ourselves is acceptable */ + + unsigned char *buffp = ((unsigned char *)BUFFERDATA(packet->pk_buffer))+16; + /* buffp points to the parameters*/ + /* the invidual messages, excluding*/ + /* standard SYS fields (debugID, */ + /* osinfo and reasoncode) */ + unsigned char *buffhead = (unsigned char *)(packet->pk_buffer); + + int DebugID, OSInfo1, OSInfo2, count; + + const char* fmode[] = {"r","rb","r+","r+b", + "w","wb","w+","w+b", + "a","ab","a+","a+b", + "r","r","r","r"} /* last 4 are illegal */ ; + + FILEHANDLE fh; /* fh is used as an index to the real file handle + * in OSptr */ + FILE *fhreal; + unpack_message(BUFFERDATA(buffhead), "%w%w%w%w", &reason_code, + &DebugID, &OSInfo1, &OSInfo2); + /* Extract reason code from buffer. */ + reason_code &= 0xFFFF; /* Strip away direction bit, OSInfo and */ + /* DebugInfo fields. Will want to do some */ + /* sort of validation on this later. */ + + switch(reason_code) + { + + case CL_WriteC: /* Write a character to the terminal. */ + /* byte data -> word status */ + { +#ifdef DEBUG + int c = (int)(*buffp); + printf("CL_WriteC: [%02x]>%c<", c, isprint(c) ? c : '.'); +#endif + stateptr->hostif->writec(stateptr->hostif->hostosarg, (int)(*buffp)); + DevSW_FreePacket(packet); + return msgsend(CI_CLIB,"%w%w%w%w%w", CL_WriteC|HtoT, + DebugID, OSInfo1, OSInfo2, NoError); + } + + case CL_Write0: /* Write a null terminated string to the terminal. */ + { + unpack_message(buffp, "%w", &len); + DebugCheckNullTermString("CL_Write0", TRUE, len, buffp+4); + stateptr->hostif->write(stateptr->hostif->hostosarg, + (char *) buffp+4, len); + DevSW_FreePacket(packet); + return msgsend(CI_CLIB, "%w%w%w%w%w", CL_Write0|HtoT, DebugID, + OSInfo1, OSInfo2, NoError); + } + + case CL_ReadC: /* Read a byte from the terminal */ + { + DebugPrintF(("CL_ReadC: ")); + DevSW_FreePacket(packet); + + character = stateptr->hostif->readc(stateptr->hostif->hostosarg); + DebugPrintF(("\nCL_ReadC returning [%02x]>%c<\n", character, + isprint(character) ? character : '.')); + + return msgsend(CI_CLIB, "%w%w%w%w%w%b", CL_ReadC|HtoT, + DebugID, OSInfo1, OSInfo2, NoError, character); + } + + case CL_System: /* Pass NULL terminated string to the hosts command + * interpreter. As it is nULL terminated we dont need + * the length + */ + { + unpack_message(buffp, "%w", &len); + DebugCheckNullTermString("CL_System", TRUE, len, buffp+4); + + err = system((char *)buffp+4); /* Use the string in the buffer */ + stateptr->last_errno = errno; + DebugCheckErr("system", TRUE, err, stateptr->last_errno); + + err = msgsend(CI_CLIB, "%w%w%w%w%w%w", CL_System|HtoT, + DebugID, OSInfo1, OSInfo2, NoError, err); + DevSW_FreePacket(packet); + return err; + } + + case CL_GetCmdLine: /* Returns the command line used to call the program */ + { + /* Note: we reuse the packet here, this may not always be desirable */ + /* /* TODO: Use long buffers if possible */ + DebugPrintF(("CL_GetCmdLine: \"%s\"\n", *(stateptr->CommandLine))); + + if (buffhead!=NULL) { + len = strlen(*(stateptr->CommandLine)); + if (len > Armsd_BufferSize-24) len = Armsd_BufferSize-24; + packet->pk_length = len + msgbuild(BUFFERDATA(buffhead), + "%w%w%w%w%w%w", CL_GetCmdLine|HtoT, + DebugID, OSInfo1, OSInfo2, + NoError, len); + strncpy((char *) BUFFERDATA(buffhead)+24,*(stateptr->CommandLine), + len); + + Adp_ChannelWrite(CI_CLIB, packet);/* Send message. */ + return 0; + } + else return -1; + } + + case CL_Clock: /* Return the number of centiseconds since the support */ + /* code started executing */ + { + time_t retTime = time(NULL); + if (retTime == (time_t)-1) + stateptr->last_errno = errno; + else + retTime *=100; + + DebugPrintF(("CL_Clock: %lu\n", retTime)); + DebugCheckErr("time", TRUE, (retTime == (time_t)-1), + stateptr->last_errno); + + DevSW_FreePacket(packet); + return msgsend(CI_CLIB, "%w%w%w%w%w%w",CL_Clock|HtoT, + DebugID, OSInfo1, OSInfo2, NoError, retTime); + } + + case CL_Time: /* return time, in seconds since the start of 1970 */ + { + time_t retTime = time(NULL); + if (retTime == (time_t)-1) + stateptr->last_errno = errno; + + DebugPrintF(("CL_Time: %lu\n", retTime)); + DebugCheckErr("time", TRUE, (retTime == (time_t)-1), + stateptr->last_errno); + + DevSW_FreePacket(packet); + return msgsend(CI_CLIB,"%w%w%w%w%w%w",CL_Time|HtoT, + DebugID, OSInfo1, OSInfo2, NoError, retTime); + } + + case CL_Remove: /* delete named in the null terminated string */ + { + /* Removing an open file will cause problems but once again + * its not our problem, likely result is a tangled FileTable */ + /* As the filename is passed with a null terminator we can use it + * straight out of the buffer without copying it.*/ + + unpack_message(buffp, "%w", &len); + DebugCheckNullTermString("CL_Remove", TRUE, len, buffp+4); + + err=remove((char *)buffp+4); + stateptr->last_errno = errno; + DevSW_FreePacket(packet); + DebugCheckErr("remove", TRUE, err, stateptr->last_errno); + + return msgsend(CI_CLIB, "%w%w%w%w%w", CL_Remove|HtoT, + DebugID, OSInfo1, OSInfo2, err?-1:NoError); + } + + case CL_Rename: /* rename file */ + { + /* Rename(word nbytes, bytes oname, word nbytes, bytes nname) + * return(byte status) + */ + unsigned int len2; + + unpack_message(buffp, "%w", &len); + DebugCheckNullTermString("CL_Rename", FALSE, len, buffp+4); + unpack_message(buffp+5+len, "%w", &len2); + DebugCheckNullTermString("to", TRUE, len2, buffp+9+len); + + /* Both names are passed with null terminators so we can use them + * directly from the buffer. */ + err = rename((char *)buffp+4, (char *)buffp+9+len); + stateptr->last_errno = errno; + DebugCheckErr("rename", TRUE, err, stateptr->last_errno); + DevSW_FreePacket(packet); + + return msgsend(CI_CLIB, "%w%w%w%w%w", CL_Rename|HtoT, + DebugID, OSInfo1, OSInfo2, (err==0)? NoError : -1); + } + + case CL_Open: /* open the file */ + { + /* Open(word nbytes, bytes name, byte mode) + * return(word handle) + */ + unpack_message(buffp, "%w", &len); + /* get the open mode */ + unpack_message((buffp)+4+len+1, "%w", &mode); + DebugCheckNullTermString("CL_Open", FALSE, len, buffp+4); + DebugPrintF(("mode: %d\n", mode)); + + /* do some checking on the file first? */ + /* check if its a tty */ + if (strcmp((char *)buffp+4, ":tt")==0 && (mode==0||mode==1)) { + /* opening tty "r" */ + fhreal = stdin; + stateptr->last_errno = errno; + DebugPrintF(("\tstdin ")); + } + else if (strcmp((char *)buffp+4, ":tt")== 0 && (mode==4||mode==5)) { + /* opening tty "w" */ + fhreal = stdout; + stateptr->last_errno = errno; + DebugPrintF(("\tstdout ")); + } + else + { + fhreal = fopen((char *)buffp+4, fmode[mode&0xFF]); + stateptr->last_errno = errno; + DebugCheckNonNull("fopen", FALSE, fhreal, stateptr->last_errno); + } + DevSW_FreePacket(packet); + + c = NONHANDLE; + if (fhreal != NULL) { + /* update filetable */ + for (c=3; c < HSYS_FOPEN_MAX; c++) { + /* allow for stdin, stdout, stderr (!!! WHY? MJG) */ + if (stateptr->OSptr->FileTable[c] == NULL) { + stateptr->OSptr->FileTable[c]= fhreal; + stateptr->OSptr->FileFlags[c]= mode & 1; + DebugPrintF(("fh: %d\n", c)); + break; + } + else if (c == HSYS_FOPEN_MAX) { + /* no filehandles free */ + DebugPrintF(("no free fh: %d\n", c)); + stateptr->last_errno = EMFILE; + } + } + } + else { + /* c = NULL;*/ + DebugPrintF(("error fh: %d\n", c)); + } + (void) msgsend(CI_CLIB, "%w%w%w%w%w", CL_Open|HtoT, + DebugID, OSInfo1, OSInfo2, c); + return 0; + } + + case CL_Close: /* close the file pointed to by the filehandle */ + { + unpack_message(buffp, "%w", &fh); + DebugPrintF(("CL_Close: fh %d\n", fh)); + DevSW_FreePacket(packet); + + fhreal = hsysGetRealFileHandle(stateptr, fh, NULL); + if (fhreal == NULL) + err = -1; + else { + if (fhreal == stdin || fhreal == stdout || fhreal == stderr) { + stateptr->last_errno = errno; + DebugPrintF(("\tskipping close of std*\n")); + err = 0; + } + else { + err = fclose(fhreal); + if (err == 0) + stateptr->OSptr->FileTable[fh]=NULL; + stateptr->last_errno = errno; + DebugCheckErr("fclose", TRUE, err, stateptr->last_errno); + } + } + return msgsend(CI_CLIB,"%w%w%w%w%w", CL_Close|HtoT, DebugID, + OSInfo1, OSInfo2, err); + } + + case CL_Write: + { + /* Write(word handle, word nbtotal, word nbytes, bytes data) + * return(word nbytes) + * WriteX(word nbytes, bytes data) + * return(word nbytes) + */ + unsigned char *rwdata = NULL, *rwhead = NULL; + unsigned char *write_source = NULL; + char flags; + FILE *fhreal; + unsigned int ack_reason = CL_Write; /* first ack is for CL_Write */ + + err = -1; /* err == 0 is fwrite() error indication */ + unpack_message(buffp, "%w%w%w", &fh, &nbtotal, &nbytes); + DebugPrintF(("CL_Write: fh %d nbtotal %u nbytes %u\n", + fh, nbtotal, nbytes)); + + fhreal = hsysGetRealFileHandle(stateptr, fh, &flags); + nbtogo = nbtotal; + + /* deal with the file handle */ + if (fhreal == NULL) + err = 0; + else { + if (flags & READOP) + fseek(fhreal,0,SEEK_CUR); + stateptr->OSptr->FileFlags[fh] = (flags & BINARY) | WRITEOP; + + nbtogo -= nbytes; + + if (nbtogo > 0) { + write_source = rwdata = rwhead = (unsigned char *)malloc(nbtotal); + if (rwhead == NULL) { + fprintf(stderr, "OUT OF MEMORY at line %d in %s\n", + __LINE__, __FILE__); + return -1; + } + memcpy(rwdata, buffp+12, nbytes); + rwdata += nbytes; + } + else + write_source = buffp+12; + } + + do { + /* at least once!! */ + + if (nbtogo == 0 && err != 0) { + /* Do the actual write! */ + if (fhreal == stdout || fhreal == stderr) { + stateptr->hostif->write(stateptr->hostif->hostosarg, + (char *)write_source, nbtotal); + } + else + err = fwrite(write_source, 1, nbtotal, fhreal); + stateptr->last_errno = errno; + DebugCheckErr("fwrite", TRUE, (err == 0), stateptr->last_errno); + } + + DevSW_FreePacket(packet); + if (msgsend(CI_CLIB,"%w%w%w%w%w%w", ack_reason|HtoT, + DebugID, OSInfo1, OSInfo2, (err == 0), nbtogo)) + { + fprintf(stderr, "COULD NOT REPLY at line %d in %s\n", + __LINE__, __FILE__); + if (rwhead != NULL) + free(rwhead); + return -1; + } + + if (nbtogo == 0 || err == 0) { + DebugPrintF(("\twrite complete - returning\n")); + if (rwhead != NULL) + free(rwhead); + return 0; + } + else { + /* await extension */ + ack_reason = CL_WriteX; + + packet = DevSW_AllocatePacket(Armsd_BufferSize); + if (packet == NULL) + { + fprintf(stderr, "COULD NOT ALLOC PACKET at line %d in %s\n", + __LINE__, __FILE__); + if (rwhead != NULL) + free(rwhead); + return -1; + } + Adp_ChannelRegisterRead(CI_CLIB, NULL, NULL); + Adp_ChannelRead(CI_CLIB, &packet); + Adp_ChannelRegisterRead(CI_CLIB, + (ChannelCallback)HandleSysMessage, + stateptr); + + buffhead = packet->pk_buffer; + unpack_message(BUFFERDATA(buffhead), "%w%w%w%w%w", &reason_code, + &DebugID, &OSInfo1, &OSInfo2, &nbytes); + if (reason_code != (CL_WriteX|TtoH)) { + DevSW_FreePacket(packet); + free(rwhead); + fprintf(stderr, "EXPECTING CL_WriteX GOT %u at line %d in %s\n", + reason_code, __LINE__, __FILE__); + return -1; + } + + DebugPrintF(("CL_WriteX: nbytes %u\n", nbytes)); + memcpy(rwdata, BUFFERDATA(buffhead)+20, nbytes); + rwdata += nbytes; + nbtogo -= nbytes; + } + + } while (TRUE); /* will return when done */ + } + + case CL_WriteX: /* + * NOTE: if we've got here something has gone wrong + * CL_WriteX's should all be picked up within the + * CL_Write loop, probably best to return an error here + * do this for the moment just so we do actually return + */ + fprintf(stderr, "ERROR: unexpected CL_WriteX message received\n"); + return -1; + + case CL_Read: + { + /* Read(word handle, word nbtotal) + * return(word nbytes, word nbmore, bytes data) + */ + /* ReadX() + * return(word nbytes, word nbmore, bytes data) */ + unsigned char *rwdata, *rwhead; + int gotlen; + unsigned int max_data_in_buffer=Armsd_BufferSize-28; + char flags; + FILE *fhreal; + unsigned int nbleft = 0, reason = CL_Read; + + err = NoError; + + unpack_message(buffp, "%w%w", &fh, &nbtotal); + DebugPrintF(("CL_Read: fh %d, nbtotal %d: ", fh, nbtotal)); + + rwdata = rwhead = (unsigned char *)malloc(nbtotal); + if (rwdata == NULL) { + fprintf(stderr, "OUT OF MEMORY at line %d in %s\n", + __LINE__, __FILE__); + DevSW_FreePacket(packet); + return -1; + } + + /* perform the actual read */ + fhreal = hsysGetRealFileHandle(stateptr, fh, &flags); + if (fhreal == NULL) + { + /* bad file handle */ + err = -1; + nbytes = 0; + gotlen = 0; + } + else + { + if (flags & WRITEOP) + fseek(fhreal,0,SEEK_CUR); + stateptr->OSptr->FileFlags[fh] = (flags & BINARY) | WRITEOP; + if (isatty_(fhreal)) { + /* reading from a tty, so do some nasty stuff, reading into rwdata */ + if (angel_hostif->gets(stateptr->hostif->hostosarg, (char *)rwdata, + nbtotal) != 0) + gotlen = strlen((char *)rwdata); + else + gotlen = 0; + stateptr->last_errno = errno; + DebugPrintF(("ttyread %d\n", gotlen)); + } + else { + /* not a tty, reading from a real file */ + gotlen = fread(rwdata, 1, nbtotal, fhreal); + stateptr->last_errno = errno; + DebugCheckErr("fread", FALSE, (gotlen == 0), stateptr->last_errno); + DebugPrintF(("(%d)\n", gotlen)); + } + } + + nbtogo = gotlen; + + do { + /* at least once */ + + if ((unsigned int) nbtogo <= max_data_in_buffer) + nbytes = nbtogo; + else + nbytes = max_data_in_buffer; + nbtogo -= nbytes; + + /* last ReadX needs subtle adjustment to returned nbtogo */ + if (nbtogo == 0 && err == NoError && reason == CL_ReadX) + nbleft = nbtotal - gotlen; + else + nbleft = nbtogo; + + count = msgbuild(BUFFERDATA(buffhead), "%w%w%w%w%w%w%w", + reason|HtoT, 0, ADP_HandleUnknown, + ADP_HandleUnknown, err, nbytes, nbleft); + + if (err == NoError) { + /* copy data into buffptr */ + memcpy(BUFFERDATA(buffhead)+28, rwdata, nbytes); + rwdata += nbytes; + count += nbytes; + } + + DebugPrintF(("\treplying err %d, nbytes %d, nbtogo %d\n", + err, nbytes, nbtogo)); + + packet->pk_length = count; + Adp_ChannelWrite(CI_CLIB, packet); + + if (nbtogo == 0 || err != NoError) { + /* done */ + free(rwhead); + return 0; + } + else { + /* await extension */ + reason = CL_ReadX; + + packet = DevSW_AllocatePacket(Armsd_BufferSize); + if (packet == NULL) { + fprintf(stderr, "COULD NOT ALLOC PACKET at line %d in %s\n", + __LINE__, __FILE__); + free(rwhead); + return -1; + } + Adp_ChannelRegisterRead(CI_CLIB, NULL, NULL); + Adp_ChannelRead(CI_CLIB, &packet); + Adp_ChannelRegisterRead(CI_CLIB, + (ChannelCallback)HandleSysMessage, + stateptr); + buffhead = packet->pk_buffer; + unpack_message(BUFFERDATA(buffhead),"%w", &reason_code); + if (reason_code != (CL_ReadX|TtoH)) { + fprintf(stderr, "EXPECTING CL_ReadX GOT %u at line %d in %s\n", + reason_code, __LINE__, __FILE__); + DevSW_FreePacket(packet); + free(rwdata); + return -1; + } + } + + } while (TRUE); /* will return above on error or when done */ + } + + case CL_ReadX: /* If we're here something has probably gone wrong */ + fprintf(stderr, "ERROR: Got unexpected CL_ReadX message\n"); + return -1; + + case CL_Seek: + { + unpack_message(buffp, "%w%w", &fh, &posn); + DebugPrintF(("CL_Seek: fh %d, posn %ld\n", fh, posn)); + DevSW_FreePacket(packet); + + fhreal = hsysGetRealFileHandle(stateptr, fh, NULL); + if (fhreal == NULL) + err = -1; + else { + err = fseek(fhreal, posn, SEEK_SET); + stateptr->last_errno = errno; + DebugCheckErr("fseek", TRUE, err, stateptr->last_errno); + } + + return msgsend(CI_CLIB, "%w%w%w%w%w", CL_Seek|HtoT, + DebugID, OSInfo1, OSInfo2, err); + } + + case CL_Flen: + { + unpack_message(buffp, "%w", &fh); + DebugPrintF(("CL_Flen: fh %d ", fh)); + DevSW_FreePacket(packet); + + fhreal = hsysGetRealFileHandle(stateptr, fh, NULL); + if (fhreal == NULL) + fl = -1; + else { + posn = ftell(fhreal); + if (fseek(fhreal, 0L, SEEK_END) < 0) { + fl=-1; + } + else { + fl = ftell(fhreal); + fseek(fhreal, posn, SEEK_SET); + } + stateptr->last_errno = errno; + } + DebugPrintF(("returning len %ld\n", fl)); + return msgsend(CI_CLIB, "%w%w%w%w%w", CL_Flen|HtoT, DebugID, OSInfo1, + OSInfo2, fl); + } + + case CL_IsTTY: + { + int ttyOrNot; + unpack_message(buffp, "%w", &fh); + DebugPrintF(("CL_IsTTY: fh %d ", fh)); + DevSW_FreePacket(packet); + + fhreal = hsysGetRealFileHandle(stateptr, fh, NULL); + if (fhreal == NULL) + ttyOrNot = FALSE; + else { + ttyOrNot = isatty_(fhreal); + stateptr->last_errno = errno; + } + DebugPrintF(("returning %s\n", ttyOrNot ? "tty (1)" : "not (0)")); + + return msgsend(CI_CLIB, "%w%w%w%w%w",CL_IsTTY|HtoT, + DebugID, OSInfo1, OSInfo2, ttyOrNot); + } + + case CL_TmpNam: + { + char *name; + unsigned int tnamelen, TargetID; + unpack_message(buffp, "%w%w", &tnamelen, &TargetID); + DebugPrintF(("CL_TmpNam: tnamelen %d TargetID %d: ", + tnamelen, TargetID)); + DevSW_FreePacket(packet); + + TargetID = TargetID & 0xFF; + if (stateptr->OSptr->TempNames[TargetID] == NULL) { + if ((stateptr->OSptr->TempNames[TargetID] = + (char *)malloc(L_tmpnam)) == NULL) + { + fprintf(stderr, "OUT OF MEMORY at line %d in %s\n", + __LINE__, __FILE__); + return -1; + } + tmpnam(stateptr->OSptr->TempNames[TargetID]); + } + name = stateptr->OSptr->TempNames[TargetID]; + len = strlen(name) + 1; + packet = DevSW_AllocatePacket(Armsd_BufferSize); + if (packet == NULL) + { + fprintf(stderr, "COULD NOT ALLOC PACKET at line %d in %s\n", + __LINE__, __FILE__); + return -1; + } + buffhead = packet->pk_buffer; + if (len > tnamelen) { + DebugPrintF(("TMPNAME TOO LONG!\n")); + count = msgbuild(BUFFERDATA(buffhead), "%w%w%w%w%w", + CL_TmpNam|HtoT, DebugID, OSInfo1, OSInfo2, -1); + } + else { + DebugPrintF(("returning \"%s\"\n", name)); + count = msgbuild(BUFFERDATA(buffhead), "%w%w%w%w%w%w", CL_TmpNam|HtoT, + DebugID, OSInfo1, OSInfo2, 0, len); + strcpy((char *)BUFFERDATA(buffhead)+count, name); + count +=len+1; + } + packet->pk_length = count; + Adp_ChannelWrite(CI_CLIB, packet);/* Send message. */ + return 0; + } + + case CL_Unrecognised: + DebugPrintF(("CL_Unrecognised!!\n")); + return 0; + + default: + fprintf(stderr, "UNRECOGNISED CL code %08x\n", reason_code); + break; +/* Need some sort of error handling here. */ +/* A call to CL_Unrecognised should suffice */ + } + return -1; /* Stop a potential compiler warning */ +} + +#ifdef COMPILING_ON_WINDOWS + +#include + +extern HWND hwndParent; + +void panic(const char *format, ...) +{ + char buf[2048]; + va_list args; + + Adp_CloseDevice(); + + va_start(args, format); + vsprintf(buf, format, args); + + MessageBox(hwndParent, (LPCTSTR)buf, (LPCTSTR)"Fatal Error:", MB_OK); + + /* SJ - Not the proper way to shutdown the app */ + exit(EXIT_FAILURE); + +/* + if (hwndParent != NULL) + SendMessage(hwndParent, WM_QUIT, 0, 0); +*/ + + va_end(args); +} + +#else + +void panic(const char *format, ...) +{ + va_list args; + + va_start(args, format); + fprintf(stderr, "Fatal error: "); + vfprintf(stderr, format, args); + fprintf(stderr,"\n"); + + exit(EXIT_FAILURE); +} + +#endif + +/* EOF hsys.c */ diff --git a/gdb/rdi-share/hsys.h b/gdb/rdi-share/hsys.h new file mode 100644 index 00000000000..7f63d0103d1 --- /dev/null +++ b/gdb/rdi-share/hsys.h @@ -0,0 +1,101 @@ +/* + * Copyright (C) 1995 Advanced RISC Machines Limited. All rights reserved. + * + * This software may be freely used, copied, modified, and distributed + * provided that the above copyright notice is preserved in all copies of the + * software. + */ + +/* + * Host C library support header file. + * + * $Revision$ + * $Date$ + * + */ + +#ifndef angsd_hsys_h +#define angsd_hsys_h + +#define HSYS_FOPEN_MAX 256 +#define NONHANDLE -1 +#define UNIQUETEMPS 256 + +#include "dbg_hif.h" +#include "hostchan.h" + +typedef struct { + FILE *FileTable[HSYS_FOPEN_MAX] ; + char FileFlags[HSYS_FOPEN_MAX] ; + char *TempNames[UNIQUETEMPS]; +} OSblock; + +#define NOOP 0 +#define BINARY 1 +#define READOP 2 +#define WRITEOP 4 + +typedef struct { + const struct Dbg_HostosInterface *hostif; /* Interface to debug toolkit. */ + int last_errno; /* Number of the last error. */ + OSblock *OSptr; + char **CommandLine ; /* Ptr to cmd line d`string held by ardi.c */ +} hsys_state; + +/* + * Function: HostSysInit + * Purpose: Set up the state block, filetable and register the and C lib + * callback fn + * + * Params: + * Input: hostif, the host interface from the debug toolbox + * cmdline, the command line used to call the image + * state, the status block for the C lib + * + * Returns: + * OK: an RDIError_* valuee + */ +extern int HostSysInit( + const struct Dbg_HostosInterface *hostif, char **cmdline, hsys_state **state +); + +/* + * Function: HostSysExit + * Purpose: Close down the host side C library support + * + * Params: + * Input: hstate, the status block for the C lib + * + * Returns: an RDIError_* valuee + */ +extern int HostSysExit(hsys_state *hstate); + +/* + * Function: HandleSysMessage + * Purpose: Handle an incoming C library message as a callback + * + * Params: + * Input: packet is the incoming data packet as described in devsw.h + * hstate, the status block for the C lib + * + * Returns: an RDIError_* valuee + */ +extern int HandleSysMessage(Packet *packet, hsys_state* stateptr); + +/* + * Function: panic + * Purpose: Print a fatal error message + * + * Params: + * Input: format printf() style message describing the problem + * ... extra arguments for printf(). + * + * Returns: This routine does not return + * + * Post-conditions: Will have called exit(1); + */ +extern void panic(const char *format, ...); + +#endif /* ndef angsd_hsys_h */ + +/* EOF hsys.h */ diff --git a/gdb/rdi-share/logging.c b/gdb/rdi-share/logging.c new file mode 100644 index 00000000000..79b70ef348f --- /dev/null +++ b/gdb/rdi-share/logging.c @@ -0,0 +1,369 @@ +/* + * Copyright (C) 1995 Advanced RISC Machines Limited. All rights reserved. + * + * This software may be freely used, copied, modified, and distributed + * provided that the above copyright notice is preserved in all copies of the + * software. + */ + +/* -*-C-*- + * + * $Revision$ + * $Date$ + * + * + * logging.c - methods for logging warnings, errors and trace info + * + */ + +#include /* ANSI varargs support */ + +#ifdef TARGET +# include "angel.h" +# include "devconf.h" +#else +# include "host.h" +#endif + +#include "logging.h" /* Header file for this source code */ + +#ifndef UNUSED +# define UNUSED(x) ((x)=(x)) +#endif + +/* + * __rt_warning + * ------------ + * This routine is provided as a standard method of generating + * run-time system warnings. The actual action taken by this code can + * be board or target application specific, e.g. internal logging, + * debug message, etc. + */ + +#ifdef DEBUG + +# ifdef DEBUG_METHOD + +# define STRINGIFY2(x) #x +# define STRINGIFY(x) STRINGIFY2(x) +# define DEBUG_METHOD_HEADER STRINGIFY(DEBUG_METHOD##.h) + +# include DEBUG_METHOD_HEADER + +# define METHOD_EXPAND_2(m, p, c) m##p(c) +# define METHOD_EXPAND(m, p, c) METHOD_EXPAND_2(m, p, c) + +# define CHAROUT(c) METHOD_EXPAND(DEBUG_METHOD, _PutChar, (c)) +# define PRE_DEBUG(l) METHOD_EXPAND(DEBUG_METHOD, _PreWarn, (l)) +# define POST_DEBUG(n) METHOD_EXPAND(DEBUG_METHOD, _PostWarn, (n)) + +# else +# error Must define DEBUG_METHOD +# endif + +#endif /* def DEBUG */ + +/* + * the guts of __rt_warning + */ + +#pragma no_check_stack +#ifdef DEBUG + +static const char hextab[] = "0123456789ABCDEF"; + +/* + * If debugging, then we break va_warn into sub-functions which + * allow us to get an easy breakpoint on the formatted string + */ +static int va_warn0(char *format, va_list args) +{ + int len = 0; + + while ((format != NULL) && (*format != '\0')) + { + if (*format == '%') + { + char fch = *(++format); /* get format character (skipping '%') */ + int ival; /* holder for integer arguments */ + char *string; /* holder for string arguments */ + int width = 0; /* No field width by default */ + int padzero = FALSE; /* By default we pad with spaces */ + + /* + * Check if the format has a width specified. NOTE: We do + * not use the "isdigit" function here, since it will + * require run-time support. The current ARM Ltd header + * defines "isdigit" as a macro, that uses a fixed + * character description table. + */ + if ((fch >= '0') && (fch <= '9')) + { + if (fch == '0') + { + /* Leading zeroes padding */ + padzero = TRUE; + fch = *(++format); + } + + while ((fch >= '0') && (fch <= '9')) + { + width = ((width * 10) + (fch - '0')); + fch = *(++format); + } + } + + if (fch == 'l') + /* skip 'l' in "%lx", etc. */ + fch = *(++format); + + switch (fch) + { + case 'c': + /* char */ + ival = va_arg(args, int); + CHAROUT((char)ival); + len++; + break; + + case 'x': + case 'X': + { + /* hexadecimal */ + unsigned int uval = va_arg(args, unsigned int); + int loop; + + UNUSED(uval); + + if ((width == 0) || (width > 8)) + width = 8; + + for(loop = (width * 4); (loop != 0); loop -= 4) + { + CHAROUT(hextab[(uval >> (loop - 4)) & 0xF]); + len++; + } + } + + break; + + case 'd': + /* decimal */ + ival = va_arg(args, int); + + if (ival < 0) + { + ival = -ival; + CHAROUT('-'); + len++; + } + + if (ival == 0) + { + CHAROUT('0'); + len++; + } + else + { + /* + * The simplest method of displaying numbers is + * to provide a small recursive routine, that + * nests until the most-significant digit is + * reached, and then falls back out displaying + * individual digits. However, we want to avoid + * using recursive code within the lo-level + * parts of Angel (to minimise the stack + * usage). The following number conversion is a + * non-recursive solution. + */ + char buffer[16]; /* stack space used to hold number */ + int count = 0; /* pointer into buffer */ + + /* + * Place the conversion into the buffer in + * reverse order: + */ + while (ival != 0) + { + buffer[count++] = ('0' + ((unsigned int)ival % 10)); + ival = ((unsigned int)ival / 10); + } + + /* + * Check if we are placing the data in a + * fixed width field: + */ + if (width != 0) + { + width -= count; + + for (; (width != 0); width--) + { + CHAROUT(padzero ? '0': ' '); + len++; + } + } + + /* then display the buffer in reverse order */ + for (; (count != 0); count--) + { + CHAROUT(buffer[count - 1]); + len++; + } + } + + break; + + case 's': + /* string */ + string = va_arg(args, char *); + + /* we only need this test once */ + if (string != NULL) + /* whilst we check this for every character */ + while (*string) + { + CHAROUT(*string); + len++; + string++; + + /* + * NOTE: We do not use "*string++" as the macro + * parameter, since we do not know how many times + *the parameter may be expanded within the macro. + */ + } + + break; + + case '\0': + /* + * string terminated by '%' character, bodge things + * to prepare for default "format++" below + */ + format--; + + break; + + default: + /* just display the character */ + CHAROUT(*format); + len++; + + break; + } + + format++; /* step over format character */ + } + else + { + CHAROUT(*format); + len++; + format++; + } + } + return len; +} + +/* + * this routine is simply here as a good breakpoint for dumping msg - + * can be used by DEBUG_METHOD macros or functions, if required. + */ +# ifdef DEBUG_NEED_VA_WARN1 +static void va_warn1(int len, char *msg) +{ + UNUSED(len); UNUSED(msg); +} +# endif + +void va_warn(WarnLevel level, char *format, va_list args) +{ + int len; + + if ( PRE_DEBUG( level ) ) + { + len = va_warn0(format, args); + POST_DEBUG( len ); + } +} + +#else /* ndef DEBUG */ + +void va_warn(WarnLevel level, char *format, va_list args) +{ + UNUSED(level); UNUSED(format); UNUSED(args); +} + +#endif /* ... else ndef(DEBUG) ... */ +#pragma check_stack + +#pragma no_check_stack +void __rt_warning(char *format, ...) +{ + va_list args; + + /* + * For a multi-threaded system we should provide a lock at this point + * to ensure that the warning messages are sequenced properly. + */ + + va_start(args, format); + va_warn(WL_WARN, format, args); + va_end(args); + + return; +} +#pragma check_stack + +#ifdef TARGET + +#pragma no_check_stack +void __rt_uninterruptable_loop( void ); /* in suppasm.s */ + +void __rt_error(char *format, ...) +{ + va_list args; + + va_start(args, format); + + /* Display warning message */ + va_warn(WL_ERROR, format, args); + + __rt_uninterruptable_loop(); + + va_end(args); + return; +} +#pragma check_stack + +#endif /* def TARGET */ + +#ifdef DO_TRACE + +static bool trace_on = FALSE; /* must be set true in debugger if req'd */ + +#pragma no_check_stack +void __rt_trace(char *format, ...) +{ + va_list args; + + /* + * For a multi-threaded system we should provide a lock at this point + * to ensure that the warning messages are sequenced properly. + */ + + if (trace_on) + { + va_start(args, format); + va_warn(WL_TRACE, format, args); + va_end(args); + } + + return; +} +#pragma check_stack + +#endif /* def DO_TRACE */ + + +/* EOF logging.c */ diff --git a/gdb/rdi-share/logging.h b/gdb/rdi-share/logging.h new file mode 100644 index 00000000000..97bf902ad1a --- /dev/null +++ b/gdb/rdi-share/logging.h @@ -0,0 +1,121 @@ +/* + * Copyright (C) 1995 Advanced RISC Machines Limited. All rights reserved. + * + * This software may be freely used, copied, modified, and distributed + * provided that the above copyright notice is preserved in all copies of the + * software. + */ + +/* -*-C-*- + * + * $Revision$ + * $Date$ + * + * + * logging.h - methods for logging warnings, errors and trace info + */ + +#ifndef angel_logging_h +#define angel_logging_h + +#include + +/* + * __rt_warning + * ------------ + * Provides a standard method of generating run-time system + * warnings. The actual action taken by this code can be board or + * target application specific, e.g. internal logging, debug message, + * etc. + */ +extern void __rt_warning(char *format, ...); + +/*---------------------------------------------------------------------------*/ + +/* + * __rt_error + * ---------- + * Raise an internal Angel error. The parameters are passed directly + * to "__rt_warning" for display, and the code then raises a debugger + * event and stops the target processing. + */ +extern void __rt_error(char *format, ...); + +/* + * Some macros for debugging and warning messages + */ + +typedef enum WarnLevel { + WL_TRACE, + WL_WARN, + WL_ERROR +} WarnLevel; + +void va_warn(WarnLevel level, char *format, va_list args); + +#ifdef _WINGDI_ +/* stupidity in MSVC (in in ) */ +# undef ERROR +#endif + +#ifndef ERROR +# define ERROR_FORMAT "Error \"%s\" in %s at line %d\n" +# define ERROR(e) __rt_error(ERROR_FORMAT, (e), __FILE__, __LINE__) +#endif + +#ifndef ASSERT +# ifdef ASSERTIONS_ENABLED +# define ASSERT(x, y) ((x) ? (void)(0) : ERROR((y))) +# else +# define ASSERT(x, y) ((void)(0)) +# endif +#endif + +#ifndef WARN +# ifdef ASSERTIONS_ENABLED +# define WARN_FORMAT "Warning \"%s\" in %s at line %d\n" +# define WARN(w) __rt_warning(WARN_FORMAT, (w), __FILE__, __LINE__) +# else +# define WARN(w) ((void)(0)) +# endif +#endif + + +#ifdef NO_INFO_MESSAGES +# define __rt_info (void) +# ifndef INFO +# define INFO(w) +# endif +#else +# define __rt_info __rt_warning +# ifndef INFO +# ifdef DEBUG +# define INFO(w) __rt_warning("%s\n", (w)) +# else +# define INFO(w) ((void)(0)) +# endif +# endif +#endif + + +#if defined(DEBUG) && !defined(NO_IDLE_CHITCHAT) +# ifndef DO_TRACE +# define DO_TRACE (1) +# endif +#endif + +#ifdef DO_TRACE +extern void __rt_trace(char *format, ...); +#endif + +#ifndef TRACE +# ifdef DO_TRACE +# define TRACE(w) __rt_trace("%s ", (w)) +# else +# define TRACE(w) ((void)(0)) +# endif +#endif + +#endif /* ndef angel_logging_h */ + +/* EOF logging.h */ diff --git a/gdb/rdi-share/msgbuild.c b/gdb/rdi-share/msgbuild.c new file mode 100644 index 00000000000..e2db2cc0576 --- /dev/null +++ b/gdb/rdi-share/msgbuild.c @@ -0,0 +1,282 @@ +/* + * Copyright (C) 1995 Advanced RISC Machines Limited. All rights reserved. + * + * This software may be freely used, copied, modified, and distributed + * provided that the above copyright notice is preserved in all copies of the + * software. + */ + +/* -*-C-*- + * + * $Revision$ + * $Date$ + * + * + * msgbuild.c - utilities for assembling and interpreting ADP messages + * + */ + +#include /* ANSI varargs support */ + +#ifdef TARGET +# include "angel.h" +# include "devconf.h" +#else +# include "host.h" +# include "hostchan.h" +#endif + +#include "channels.h" +#include "buffers.h" +#include "endian.h" /* Endianness support macros */ +#include "msgbuild.h" /* Header file for this source code */ + +#ifndef UNUSED +# define UNUSED(x) ((x)=(x)) +#endif + +#ifndef TARGET + +extern unsigned int Armsd_BufferSize; + +#endif /* ndef TARGET */ + + +unsigned int vmsgbuild(unsigned char *buffer, const char *format, va_list args) +{ + unsigned int blen = 0; + int ch; + + /* Step through the format string */ + while ((ch = *format++) != '\0') + { + if (ch != '%') + { + if (buffer != NULL) + *buffer++ = (unsigned char)ch; + + blen++; + } + else + { + switch (ch = *format++) + { + case 'w': + case 'W': + /* 32bit pointer */ + case 'p': + case 'P': + { + /* 32bit word / 32bit pointer */ + unsigned int na = va_arg(args, unsigned int); + + if (buffer != NULL) + { + PUT32LE(buffer, na); + buffer += sizeof(unsigned int); + } + + blen += sizeof(unsigned int); + + break; + } + + case 'h': + case 'H': + { + /* 16bit value */ + unsigned int na = va_arg(args, unsigned int); + + if (buffer != NULL) + { + PUT16LE(buffer, na); + buffer += sizeof(unsigned short); + } + + blen += sizeof(unsigned short); + + break; + } + + case 'c': + case 'C': + case 'b': + case 'B': + /* 8bit character / 8bit byte */ + ch = va_arg(args, int); + + /* + * XXX + * + * fall through to the normal character processing + */ + + case '%': + default: + /* normal '%' character, or a different normal character */ + if (buffer != NULL) + *buffer++ = (unsigned char)ch; + + blen++; + break; + } + } + } + + return blen; +} + +/* + * msgbuild + * -------- + * Simple routine to aid in construction of Angel messages. See the + * "msgbuild.h" header file for a detailed description of the operation + * of this routine. + */ +unsigned int msgbuild(unsigned char *buffer, const char *format, ...) +{ + va_list args; + unsigned int blen; + + va_start(args, format); + blen = vmsgbuild(buffer, format, args); + va_end(args); + + return blen; +} + +#if !defined(JTAG_ADP_SUPPORTED) && !defined(MSG_UTILS_ONLY) +/* + * This routine allocates a buffer, puts the data supplied as + * parameters into the buffer and sends the message. It does *NOT* + * wait for a reply. + */ +extern int msgsend(ChannelID chan, const char *format,...) +{ + unsigned int length; + p_Buffer buffer; + va_list args; +# ifndef TARGET + Packet *packet; + + packet = DevSW_AllocatePacket(Armsd_BufferSize); + buffer = packet->pk_buffer; +# else + buffer = angel_ChannelAllocBuffer(Angel_ChanBuffSize); +# endif + + if (buffer != NULL) + { + va_start(args, format); + + length = vmsgbuild(BUFFERDATA(buffer), format, args); + +# ifdef TARGET + angel_ChannelSend(CH_DEFAULT_DEV, chan, buffer, length); +# else + packet->pk_length = length; + Adp_ChannelWrite(chan, packet); +# endif + + va_end(args); + return 0; + } + else + return -1; +} + +#endif /* ndef JTAG_ADP_SUPPORTED && ndef MSG_UTILS_ONLY */ + +/* + * unpack_message + * -------------- + */ +extern unsigned int unpack_message(unsigned char *buffer, const char *format, ...) +{ + va_list args; + unsigned int blen = 0; + int ch; + char *chp = NULL; + + va_start(args, format); + + /* Step through the format string. */ + while ((ch = *format++) != '\0') + { + if (ch != '%') + { + if (buffer != NULL) + ch = (unsigned char)*buffer++; + + blen++; + } + else + { + switch (ch = *format++) + { + case 'w': + case 'W': + { + /* 32bit word. */ + unsigned int *nap = va_arg(args, unsigned int*); + + if (buffer != NULL) + { + *nap = PREAD32(LE, buffer); + buffer += sizeof(unsigned int); + } + + blen += sizeof(unsigned int); + + break; + } + + case 'h': + case 'H': + { + /* 16bit value. */ + unsigned int *nap = va_arg(args, unsigned int*); + + if (buffer != NULL) + { + *nap = PREAD16(LE,buffer); + buffer += sizeof(unsigned short); + } + + blen += sizeof(unsigned short); + + break; + } + + case 'c': + case 'C': + case 'b': + case 'B': + /* 8-bit character, or 8-bit byte */ + chp = va_arg(args, char*); + + /* + * XXX + * + * fall through to the normal character processing. + */ + + case '%': + default: + /* normal '%' character, or a different normal character */ + if (buffer != NULL) + *chp = (unsigned char)*buffer++; + + blen++; + + break; + } + } + } + + va_end(args); + return(blen); +} + + +/* EOF msgbuild.c */ diff --git a/gdb/rdi-share/msgbuild.h b/gdb/rdi-share/msgbuild.h new file mode 100644 index 00000000000..ac2436c1391 --- /dev/null +++ b/gdb/rdi-share/msgbuild.h @@ -0,0 +1,75 @@ +/* + * Copyright (C) 1995 Advanced RISC Machines Limited. All rights reserved. + * + * This software may be freely used, copied, modified, and distributed + * provided that the above copyright notice is preserved in all copies of the + * software. + */ + +/* -*-C-*- + * + * $Revision$ + * $Date$ + * + * + * msgbuild.h - utilities for assembling and interpreting ADP messages + */ + +#ifndef angel_msgbuild_h +#define angel_msgbuild_h +#include +#include "channels.h" + +/* + * msgbuild + * -------- + * We use a "varargs" function to enable a description of how the + * final message should look to be provided. We use a function rather + * than in-line macros to keep the size of Angel small. + * + * The "buffer" pointer is the starting point from where the data will + * be written. Note: If a NULL pointer is passed then no data will be + * written, but the size information will be returned. This allows + * code to call this routine with a NULL "buffer" pointer to ascertain + * whether the pointer they are passing contains enough space for the + * message being constructed. + * + * The "format" string should contain sequences of the following + * tokens: + * %w - insert 32bit word value + * %p - insert 32bit target pointer value + * %h - insert 16bit value + * %b - insert 8bit byte value + * + * The return parameter is the final byte length of the data written. + */ +unsigned int msgbuild(unsigned char *buffer, const char *format, ...); +unsigned int vmsgbuild(unsigned char *buffer, const char *format, + va_list args); + +/*---------------------------------------------------------------------------*/ + +/* + * msgsend + * ------- + * As for msgbuild except that it allocates a buffer, formats the data as + * for msgbuild and transmits the packet. Returns 0 if successful non 0 if ot + * fails. + * Not for use on cooked channels e.g. debug channels only. + */ +extern int msgsend(ChannelID chan, const char *format, ...); + +/*---------------------------------------------------------------------------*/ + +/* + * Unpack_message + * -------------- + * This basically does the opposite of msg_build, it takes a message, and + * a scanf type format string (but much cut down functionality) and returns + * the arguments in the message. + */ +extern unsigned int unpack_message(unsigned char *buffer, const char *format, ...); + +#endif /* ndef angel_msgbuild_h */ + +/* EOF msgbuild.h */ diff --git a/gdb/rdi-share/params.c b/gdb/rdi-share/params.c new file mode 100644 index 00000000000..2c781887c19 --- /dev/null +++ b/gdb/rdi-share/params.c @@ -0,0 +1,325 @@ +/* + * Copyright (C) 1995 Advanced RISC Machines Limited. All rights reserved. + * + * This software may be freely used, copied, modified, and distributed + * provided that the above copyright notice is preserved in all copies of the + * software. + */ + +/* -*-C-*- + * + * $Revision$ + * $Date$ + * + * + * Project: ANGEL + * + * Title: Parameter negotiation utility functions + */ + +#include "params.h" + +#include "endian.h" +#include "logging.h" + + +/* + * Function: Angel_FindParam + * Purpose: find the value of a given parameter from a config. + * + * see params.h for details + */ +bool Angel_FindParam( ADP_Parameter type, + const ParameterConfig *config, + unsigned int *value ) +{ + unsigned int i; + + for ( i = 0; i < config->num_parameters; ++i ) + if ( config->param[i].type == type ) + { + *value = config->param[i].value; + return TRUE; + } + + return FALSE; +} + + +#if !defined(TARGET) || !defined(MINIMAL_ANGEL) || MINIMAL_ANGEL == 0 + +ParameterList *Angel_FindParamList( const ParameterOptions *options, + ADP_Parameter type ) +{ + unsigned int i; + + for ( i = 0; i < options->num_param_lists; ++i ) + if ( options->param_list[i].type == type ) + return &options->param_list[i]; + + return NULL; +} + + +#if defined(TARGET) || defined(TEST_PARAMS) +/* + * Function: Angel_MatchParams + * Purpose: find a configuration from the requested options which is + * the best match from the supported options. + * + * see params.h for details + */ +const ParameterConfig *Angel_MatchParams( const ParameterOptions *requested, + const ParameterOptions *supported ) +{ + static Parameter chosen_params[AP_NUM_PARAMS]; + static ParameterConfig chosen_config = { + AP_NUM_PARAMS, + chosen_params + }; + unsigned int i; + + ASSERT( requested != NULL, "requested is NULL" ); + ASSERT( requested != NULL, "requested is NULL" ); + ASSERT( supported->num_param_lists <= AP_NUM_PARAMS, "supp_num too big" ); + + if ( requested->num_param_lists > supported->num_param_lists ) + { + WARN( "req_num exceeds supp_num" ); + return NULL; + } + + for ( i = 0; i < requested->num_param_lists; ++i ) + { + bool match; + unsigned int j; + + const ParameterList *req_list = &requested->param_list[i]; + ADP_Parameter req_type = req_list->type; + const ParameterList *sup_list = Angel_FindParamList( + supported, req_type ); + + if ( sup_list == NULL ) + { +#ifdef ASSERTIONS_ENABLED + __rt_warning( "option %x not supported\n", req_type ); +#endif + return NULL; + } + + for ( j = 0, match = FALSE; + (j < req_list->num_options) && !match; + ++j + ) + { + unsigned int k; + + for ( k = 0; + (k < sup_list->num_options) && !match; + ++k + ) + { + if ( req_list->option[j] == sup_list->option[k] ) + { +#ifdef DEBUG + __rt_info( "chose value %d for option %x\n", + req_list->option[j], req_type ); +#endif + match = TRUE; + chosen_config.param[i].type = req_type; + chosen_config.param[i].value = req_list->option[j]; + } + } + } + + if ( !match ) + { +#ifdef ASSERTIONS_ENABLED + __rt_warning( "no match found for option %x\n", req_type ); +#endif + return NULL; + } + } + + chosen_config.num_parameters = i; + INFO( "match succeeded" ); + return &chosen_config; +} +#endif /* defined(TARGET) || defined(TEST_PARAMS) */ + + +#if !defined(TARGET) || defined(TEST_PARAMS) +/* + * Function: Angel_StoreParam + * Purpose: store the value of a given parameter to a config. + * + * see params.h for details + */ +bool Angel_StoreParam( ParameterConfig *config, + ADP_Parameter type, + unsigned int value ) +{ + unsigned int i; + + for ( i = 0; i < config->num_parameters; ++i ) + if ( config->param[i].type == type ) + { + config->param[i].value = value; + return TRUE; + } + + return FALSE; +} +#endif /* !defined(TARGET) || defined(TEST_PARAMS) */ + + +#if defined(TARGET) || defined(LINK_RECOVERY) || defined(TEST_PARAMS) +/* + * Function: Angel_BuildParamConfigMessage + * Purpose: write a parameter config to a buffer in ADP format. + * + * see params.h for details + */ +unsigned int Angel_BuildParamConfigMessage( unsigned char *buffer, + const ParameterConfig *config ) +{ + unsigned char *start = buffer; + unsigned int i; + + PUT32LE( buffer, config->num_parameters ); + buffer += sizeof( word ); + + for ( i = 0; i < config->num_parameters; ++i ) + { + PUT32LE( buffer, config->param[i].type ); + buffer += sizeof( word ); + PUT32LE( buffer, config->param[i].value ); + buffer += sizeof( word ); + } + + return (buffer - start); +} +#endif /* defined(TARGET) || defined(LINK_RECOVERY) || defined(TEST_PARAMS) */ + + +#if !defined(TARGET) || defined(TEST_PARAMS) +/* + * Function: Angel_BuildParamOptionsMessage + * Purpose: write a parameter Options to a buffer in ADP format. + * + * see params.h for details + */ +unsigned int Angel_BuildParamOptionsMessage( unsigned char *buffer, + const ParameterOptions *options ) +{ + unsigned char *start = buffer; + unsigned int i, j; + + PUT32LE( buffer, options->num_param_lists ); + buffer += sizeof( word ); + + for ( i = 0; i < options->num_param_lists; ++i ) + { + PUT32LE( buffer, options->param_list[i].type ); + buffer += sizeof( word ); + PUT32LE( buffer, options->param_list[i].num_options ); + buffer += sizeof( word ); + for ( j = 0; j < options->param_list[i].num_options; ++j ) + { + PUT32LE( buffer, options->param_list[i].option[j] ); + buffer += sizeof( word ); + } + } + + return (buffer - start); +} +#endif /* !defined(TARGET) || defined(TEST_PARAMS) */ + + +#if !defined(TARGET) || defined(LINK_RECOVERY) || defined(TEST_PARAMS) +/* + * Function: Angel_ReadParamConfigMessage + * Purpose: read a parameter config from a buffer where it is in ADP format. + * + * see params.h for details + */ +bool Angel_ReadParamConfigMessage( const unsigned char *buffer, + ParameterConfig *config ) +{ + unsigned int word; + unsigned int i; + + word = GET32LE( buffer ); + buffer += sizeof( word ); + if ( word > config->num_parameters ) + { + WARN( "not enough space" ); + return FALSE; + } + config->num_parameters = word; + + for ( i = 0; i < config->num_parameters; ++i ) + { + config->param[i].type = (ADP_Parameter)GET32LE( buffer ); + buffer += sizeof( word ); + config->param[i].value = GET32LE( buffer ); + buffer += sizeof( word ); + } + + return TRUE; +} +#endif /* !defined(TARGET) || defined(LINK_RECOVERY) || defined(TEST_PARAMS) */ + + +#if defined(TARGET) || defined(TEST_PARAMS) +/* + * Function: Angel_ReadParamOptionsMessage + * Purpose: read a parameter options block from a buffer + * where it is in ADP format. + * + * see params.h for details + */ +bool Angel_ReadParamOptionsMessage( const unsigned char *buffer, + ParameterOptions *options ) +{ + unsigned int word; + unsigned int i, j; + + word = GET32LE( buffer ); + buffer += sizeof( word ); + if ( word > options->num_param_lists ) + { + WARN( "not enough space" ); + return FALSE; + } + options->num_param_lists = word; + + for ( i = 0; i < options->num_param_lists; ++i ) + { + ParameterList *list = &options->param_list[i]; + + list->type = (ADP_Parameter)GET32LE( buffer ); + buffer += sizeof( word ); + word = GET32LE( buffer ); + buffer += sizeof( word ); + if ( word > list->num_options ) + { + WARN( "not enough list space" ); + return FALSE; + } + list->num_options = word; + + for ( j = 0; j < list->num_options; ++j ) + { + list->option[j] = GET32LE( buffer ); + buffer += sizeof( word ); + } + } + + return TRUE; +} +#endif /* defined(TARGET) || defined(TEST_PARAMS) */ + +#endif /* !define(TARGET) || !defined(MINIMAL_ANGEL) || MINIMAL_ANGEL == 0 */ + +/* EOF params.c */ diff --git a/gdb/rdi-share/params.h b/gdb/rdi-share/params.h new file mode 100644 index 00000000000..5b0757bc92d --- /dev/null +++ b/gdb/rdi-share/params.h @@ -0,0 +1,181 @@ +/* + * Copyright (C) 1995 Advanced RISC Machines Limited. All rights reserved. + * + * This software may be freely used, copied, modified, and distributed + * provided that the above copyright notice is preserved in all copies of the + * software. + */ + +/* -*-C-*- + * + * $Revision$ + * $Date$ + * + * + * Project: ANGEL + * + * Title: Parameter negotiation structures and utilities + */ + +#ifndef angel_params_h +#define angel_params_h + +#include "angel.h" +#include "adp.h" + +#ifndef TARGET +# include "host.h" +#endif + +/* A single parameter, with tag */ +typedef struct Parameter { + ADP_Parameter type; + unsigned int value; +} Parameter; + +/* A list of parameter values, with tag */ +typedef struct ParameterList { + ADP_Parameter type; + unsigned int num_options; + unsigned int *option; /* points to array of values */ +} ParameterList; + +/* A configuration of one or more parameters */ +typedef struct ParameterConfig { + unsigned int num_parameters; + Parameter *param; /* pointer to array of Parameters */ +} ParameterConfig; + +/* A set of parameter options */ +typedef struct ParameterOptions { + unsigned int num_param_lists; + ParameterList *param_list; /* pointer to array of ParamLists */ +} ParameterOptions; + +/* + * Function: Angel_MatchParams + * Purpose: find a configuration from the requested options which is + * the best match from the supported options. + * + * Params: + * Input: requested The offered set of parameters. + * supported The supported set of parameters. + * + * Returns: ptr to config A match has been made, ptr to result + * will remain valid until next call to + * this function. + * NULL Match not possible + */ +const ParameterConfig *Angel_MatchParams( const ParameterOptions *requested, + const ParameterOptions *supported ); + +/* + * Function: Angel_FindParam + * Purpose: find the value of a given parameter from a config. + * + * Params: + * Input: type parameter type to find + * config config to search + * Output: value parameter value if found + * + * Returns: TRUE parameter found + * FALSE parameter not found + */ +bool Angel_FindParam( ADP_Parameter type, + const ParameterConfig *config, + unsigned int *value ); + +/* + * Function: Angel_StoreParam + * Purpose: store the value of a given parameter in a config. + * + * Params: + * In/Out: config config to store in + * Input: type parameter type to store + * value parameter value if found + * + * Returns: TRUE parameter found and new value stored + * FALSE parameter not found + */ +bool Angel_StoreParam( ParameterConfig *config, + ADP_Parameter type, + unsigned int value ); + +/* + * Function: Angel_FindParamList + * Purpose: find the parameter list of a given parameter from an options. + * + * Params: + * Input: type parameter type to find + * options options block to search + * + * Returns: pointer to list + * NULL parameter not found + */ +ParameterList *Angel_FindParamList( const ParameterOptions *options, + ADP_Parameter type ); + +/* + * Function: Angel_BuildParamConfigMessage + * Purpose: write a parameter config to a buffer in ADP format. + * + * Params: + * Input: buffer where to write to + * config the parameter config to write + * + * Returns: number of characters written to buffer + */ +unsigned int Angel_BuildParamConfigMessage( unsigned char *buffer, + const ParameterConfig *config ); + +/* + * Function: Angel_BuildParamOptionsMessage + * Purpose: write a parameter Options to a buffer in ADP format. + * + * Params: + * Input: buffer where to write to + * options the options block to write + * + * Returns: number of characters written to buffer + */ +unsigned int Angel_BuildParamOptionsMessage( unsigned char *buffer, + const ParameterOptions *options ); + +/* + * Function: Angel_ReadParamConfigMessage + * Purpose: read a parameter config from a buffer where it is in ADP format. + * + * Params: + * Input: buffer where to read from + * In/Out: config the parameter config to read to, which must + * be set up on entry with a valid array, and + * the size of the array in num_parameters. + * + * Returns: TRUE okay + * FALSE not enough space in config + */ +bool Angel_ReadParamConfigMessage( const unsigned char *buffer, + ParameterConfig *config ); + +/* + * Function: Angel_ReadParamOptionsMessage + * Purpose: read a parameter options from a buffer + * where it is in ADP format. + * + * Params: + * Input: buffer where to read from + * In/Out: options the parameter options block to read to, + * which must be set up on entry with a valid + * array, and the size of the array in + * num_parameters. Each param_list must + * also be set up in the same way. + * + * Returns: TRUE okay + * FALSE not enough space in options + */ +bool Angel_ReadParamOptionsMessage( const unsigned char *buffer, + ParameterOptions *options ); + +#endif /* ndef angel_params_h */ + +/* EOF params.h */ diff --git a/gdb/rdi-share/rx.c b/gdb/rdi-share/rx.c new file mode 100644 index 00000000000..4f434f0cbd6 --- /dev/null +++ b/gdb/rdi-share/rx.c @@ -0,0 +1,361 @@ +/* + * Copyright (C) 1995 Advanced RISC Machines Limited. All rights reserved. + * + * This software may be freely used, copied, modified, and distributed + * provided that the above copyright notice is preserved in all copies of the + * software. + */ + +/*-*-C-*- + * + * $Revision$ + * $Date$ + * + * + * Project: ANGEL + * + * Title: Character reception engine + */ + +#include /* ANSI varargs support */ +#include "angel.h" /* Angel system definitions */ +#include "endian.h" /* Endian independant memory access macros */ +#include "crc.h" /* crc generation definitions and headers */ +#include "rxtx.h" +#include "channels.h" +#include "buffers.h" +#ifdef TARGET +# include "devdriv.h" +#endif +#include "logging.h" + +static re_status unexp_stx(struct re_state *rxstate); +static re_status unexp_etx(struct re_state *rxstate); + +/* bitfield for the rx_engine state */ +typedef enum rx_state_flag{ + RST_STX, + RST_TYP, + RST_LEN, + RST_DAT, + RST_CRC, + RST_ETX, + RST_ESC = (0x1 << 0x3) +} rx_state_flag; + +void Angel_RxEngineInit(const struct re_config *rxconfig, + struct re_state *rxstate) +{ + rxstate->rx_state = RST_STX; + rxstate->field_c = 0; + rxstate->index = 0; + rxstate->crc = 0; + rxstate->error = RE_OKAY; + rxstate->config = rxconfig; +} + +re_status Angel_RxEngine(unsigned char new_ch, struct data_packet *packet, + struct re_state *rxstate) +{ + /* + * TODO: add the flow control bits in + * Note: We test for the data field in a seperate case so we can + * completely avoid entering the switch for most chars + */ + + /* see if we're expecting a escaped char */ + if ((rxstate->rx_state & RST_ESC) == RST_ESC) + { + /* unescape the char and unset the flag*/ + new_ch &= ~serial_ESCAPE; +#ifdef DO_TRACE + __rt_trace("rxe-echar-%2x ", new_ch); +#endif + rxstate->rx_state &= ~RST_ESC; + } + else if ( (1 << new_ch) & rxstate->config->esc_set ) + { + /* see if the incoming char is a special one */ + if (new_ch == rxstate->config->esc) + { +#ifdef DO_TRACE + __rt_trace("rxe-esc "); +#endif + rxstate->rx_state |= RST_ESC; + return RS_IN_PKT; + } + else + { + /* + * must be a normal packet so do some unexpected etx/stx checking + * we haven't been told to escape or received an escape so unless + * we are expecting an stx or etx then we can take the unexpected + * stx/etx trap + */ + if ((new_ch == (rxstate->config->stx)) && (rxstate->rx_state != RST_STX)) + return unexp_stx(rxstate); + if ((new_ch == (rxstate->config->etx)) && (rxstate->rx_state != RST_ETX)) + return unexp_etx(rxstate); + } + } + + if (rxstate->rx_state == RST_DAT) + { + /* + * do this to speed up the common case, no real penalty for + * other cases + */ +#ifdef DO_TRACE + __rt_trace("rxe-dat "); +#endif + + rxstate->crc = crc32(&new_ch, 1, rxstate->crc); + (packet->data)[rxstate->index++] = (unsigned int)new_ch & 0xff; + + if (rxstate->index == packet->len) + rxstate->rx_state = RST_CRC; + + return RS_IN_PKT; + } + + /* + * Now that the common case is out of the way we can test for everything + * else without worrying quite so much about the speed, changing the + * order to len,crc,stx,etx,typ might gain a tiny bit of speed but lets + * leave that for the moment + */ + switch (rxstate->rx_state) + { + case RST_STX: + if (new_ch == rxstate->config->stx) + { + rxstate->rx_state = RST_TYP; + rxstate->error = RE_OKAY; + rxstate->crc = startCRC32; + rxstate->index = 0; + return RS_IN_PKT; + } + else + { + rxstate->error = RE_OKAY; + return RS_WAIT_PKT; + } + + case RST_TYP: + packet->type = (DevChanID)new_ch; + rxstate->rx_state = RST_LEN; + rxstate->error = RE_OKAY; + rxstate->field_c = 0; /* set up here for the length that follows */ +#ifdef DO_TRACE + __rt_trace("rxe-type-%2x ", packet->type); +#endif + rxstate->crc = crc32(&new_ch, 1, rxstate->crc); + + return RS_IN_PKT; + + case RST_LEN: + rxstate->crc = crc32(&new_ch, 1, rxstate->crc); + + if (rxstate->field_c++ == 0) + { + /* first length byte */ + packet->len = ((unsigned int)new_ch) << 8; + return RS_IN_PKT; + } + else + { + /* got the whole legth */ + packet->len |= new_ch; +#ifdef DO_TRACE + __rt_trace("rxe-len-%4x\n", packet->len); +#endif + + /* check that the length is ok */ + if (packet->len == 0) + { + /* empty pkt */ + rxstate->field_c = 0; + rxstate->rx_state = RST_CRC; + return RS_IN_PKT; + } + else + { + if (packet->data == NULL) + { + /* need to alloc the data buffer */ + if (!rxstate->config->ba_callback( + packet, rxstate->config->ba_data)) { + rxstate->rx_state = RST_STX; + rxstate->error = RE_INTERNAL; + return RS_BAD_PKT; + } + } + + if (packet->len > packet->buf_len) + { + /* pkt bigger than buffer */ + rxstate->field_c = 0; + rxstate->rx_state = RST_STX; + rxstate->error = RE_LEN; + return RS_BAD_PKT; + } + else + { + /* packet ok */ + rxstate->field_c = 0; + rxstate->rx_state = RST_DAT; + return RS_IN_PKT; + } + } + } + + case RST_DAT: + /* dummy case (dealt with earlier) */ +#ifdef ASSERTIONS_ENABLED + __rt_warning("ERROR: hit RST_dat in switch\n"); +#endif + rxstate->rx_state = RST_STX; + rxstate->error = RE_INTERNAL; + return RS_BAD_PKT; + + case RST_CRC: + if (rxstate->field_c == 0) + packet->crc = 0; + + packet->crc |= (new_ch & 0xFF) << ((3 - rxstate->field_c) * 8); + rxstate->field_c++; + + if (rxstate->field_c == 4) + { + /* last crc field */ + rxstate->field_c = 0; + rxstate->rx_state = RST_ETX; +#ifdef DO_TRACE + __rt_trace("rxe-rcrc-%8x ", packet->crc); +#endif + } + + return RS_IN_PKT; + + case RST_ETX: + if (new_ch == rxstate->config->etx) + { +#if defined(DEBUG) && !defined(NO_PKT_DATA) + { + int c; +# ifdef DO_TRACE + __rt_trace("\n"); +# endif + __rt_info("RXE Data ="); + for (c=0; c < packet->len; c++) + __rt_info("%02x", packet->data[c]); + __rt_info("\n"); + } +#endif + + /* check crc */ + if (rxstate->crc == packet->crc) + { + /* crc ok */ + rxstate->rx_state = RST_STX; + rxstate->field_c = 0; + return RS_GOOD_PKT; + } + else + { +#ifdef ASSERTIONS_ENABLED + __rt_warning("Bad crc, rx calculates it should be 0x%x\n", rxstate->crc); +#endif + rxstate->rx_state = RST_STX; + rxstate->error = RE_CRC; + return RS_BAD_PKT; + } + } + else if (new_ch == rxstate->config->stx) + return unexp_stx(rxstate); + else + { + rxstate->rx_state = RST_STX; + rxstate->error = RE_NETX; + return RS_BAD_PKT; + } + + default: +#ifdef ASSERTIONS_ENABLED + __rt_warning("ERROR fell through rxengine\n"); +#endif + rxstate->rx_state = RST_STX; + rxstate->error = RE_INTERNAL; + return RS_BAD_PKT; + } +} + +static re_status unexp_stx(struct re_state *rxstate) +{ +#ifdef ASSERTIONS_ENABLED + __rt_warning("Unexpected stx\n"); +#endif + rxstate->crc = startCRC32; + rxstate->index = 0; + rxstate->rx_state = RST_TYP; + rxstate->error = RE_U_STX; + rxstate->field_c = 0; + return RS_BAD_PKT; +} + +static re_status unexp_etx(struct re_state *rxstate) +{ +#ifdef ASSERTIONS_ENABLED + __rt_warning("Unexpected etx, rxstate: index= 0x%2x, field_c=0x%2x, state=0x%2x\n", rxstate->index, rxstate->field_c, rxstate->rx_state); +#endif + rxstate->crc = 0; + rxstate->index = 0; + rxstate->rx_state = RST_STX; + rxstate->error = RE_U_ETX; + rxstate->field_c = 0; + return RS_BAD_PKT; +} + +/* + * This can be used as the buffer allocation callback for the rx engine, + * and makes use of angel_DD_GetBuffer() [in devdrv.h]. + * + * Saves duplicating this callback function in every device driver that + * uses the rx engine. + * + * Note that this REQUIRES that the device id is installed as ba_data + * in the rx engine config structure for the driver. + */ +bool angel_DD_RxEng_BufferAlloc( struct data_packet *packet, void *cb_data ) +{ +#ifdef TARGET + DeviceID devid = (DeviceID)cb_data; +#else + IGNORE(cb_data); +#endif + + if ( packet->type < DC_NUM_CHANNELS ) + { + /* request a buffer down from the channels layer */ +#ifdef TARGET + packet->data = angel_DD_GetBuffer( devid, packet->type, + packet->len ); +#else + packet->data = malloc(packet->len); +#endif + if ( packet->data == NULL ) + return FALSE; + else + { + packet->buf_len = packet->len; + return TRUE; + } + } + else + { + /* bad type field */ + return FALSE; + } +} + +/* EOF rx.c */ diff --git a/gdb/rdi-share/rxtx.h b/gdb/rdi-share/rxtx.h new file mode 100644 index 00000000000..204e99870fa --- /dev/null +++ b/gdb/rdi-share/rxtx.h @@ -0,0 +1,263 @@ +/* + * Copyright (C) 1995 Advanced RISC Machines Limited. All rights reserved. + * + * This software may be freely used, copied, modified, and distributed + * provided that the above copyright notice is preserved in all copies of the + * software. + */ + +/*-*-C-*- + * + * $Revision$ + * $Date$ + * + * + * Project: ANGEL + * + * Title: Definitions required for the rx and tx engines + */ + +#ifndef angel_rxtx_h +#define angel_rxtx_h + + +/* + * we need a definition for bool, which is "system" dependent + */ +#ifdef TARGET +# include "angel.h" +#else +# include "host.h" +#endif + +#include "devclnt.h" + +/* return status codes for the rx engine */ +typedef enum re_status { + RS_WAIT_PKT, + RS_IN_PKT, + RS_BAD_PKT, + RS_GOOD_PKT +} re_status; + +/* return status codes for the tx engine */ +typedef enum te_status { + TS_IDLE, + TS_IN_PKT, + TS_DONE_PKT +} te_status; + + +/* + * required serial definitions, they should all be <32, refer to the + * re_config struct comments for more details + */ +#define serial_STX (0x1c) /* data packet start */ +#define serial_ETX (0x1d) /* packet end */ +#define serial_ESC (0x1b) /* standard escape character */ +#define serial_XON (0x11) /* software flow control - enable transmission */ +#define serial_XOFF (0x13) /* software flow control - disable transmission */ + +/* + * All other characters are transmitted clean. If any of the above + * characters need to be transmitted as part of the serial data stream + * then the character will be preceded by the "serial_ESC" character, + * and then the required character transmitted (OR-ed with the + * "serial_ESCAPE" value, to ensure that the serial stream never has + * any of the exceptional characters generated by data transfers). + */ + +#define serial_ESCAPE (0x40) /* OR-ed with escaped characters */ + +/* bad packet error codes */ +typedef enum re_error { + RE_OKAY, + RE_U_STX, + RE_U_ETX, + RE_LEN, + RE_CRC, + RE_NETX, + RE_INTERNAL +} re_error; + +/* a decoded packet */ +struct data_packet { + unsigned short buf_len; /* should be set by caller */ + DevChanID type; /* valid when status is RS_GOOD_PKT */ + unsigned short len; /* --"-- */ + unsigned int crc; /* crc for the unescaped pkt */ + unsigned char *data; /* should be set by caller */ +}; + +/* + * Purpose: typedef for flow control function + * + * Params: + * Input: fc_char the flow control character in question + * In/Out: cb_data callback data as set in the fc_data + * field of re_config, typically device id + * + * This callback would tpyically respond to received XON and XOFF + * characters by controlling the transmit side of the device. + */ +typedef void (*fc_cb_func)(char fc_char, void *cb_data); + + +/* + * Purpose: typedef for the function to alloc the data buffer + * + * Params: + * In/Out: packet the data packet: len and type will be set on + * entry, and buf_len and data should + * be set by this routine if successful. + * cb_data callback data as set in the ba_data + * field of re_config, typically device id + * + * Returns: TRUE buffer allocated okay + * FALSE couldn't allocate buffer of required size + * for given type + * + * This callback should attempt to acquire a buffer for the data portion + * of the packet which is currently being received, based on the len and + * type fields supplied in packet. + * + * angel_DD_RxEng_BufferAlloc() is supplied for use as this callback, + * and will be sufficient for most devices. + */ +typedef bool (*BufferAlloc_CB_Fn)(struct data_packet *packet, void *cb_data); + + +/* + * The static info needed by the engine, may vary per device. + * + * fc_set and esc_set are bitmaps, e.g. bit 3 == charcode 3 == ASCII ETX. + * Thus any of the first 32 charcodes can be set for flow control or to + * be escaped. + * + * Note that esc_set should include all of fc_set, and should have bits + * set for stx, etx and esc, as a minimum. + * + * If character codes > 31 need to be used then fc_set and esc_set + * and their handling can be extended to use arrays and bit manipulation + * macros, potentially up to the full 256 possible chars. + * + * Note too that this could/should be shared with the tx engine. + */ + +struct re_config { + unsigned char stx; /* the STX char for this device */ + unsigned char etx; /* the ETX --"-- */ + unsigned char esc; /* the ESC --"-- */ + unsigned int fc_set; /* bitmap of flow control chars */ + unsigned int esc_set; /* bitmap of special chars */ + fc_cb_func fc_callback; /* flow control callback func */ + void *fc_data; /* data to pass to fc_callback */ + BufferAlloc_CB_Fn ba_callback; /* buffer alloc callback */ + void *ba_data; /* data to pass to ba_calback */ +}; + +/* the dynamic info needed by the rx engine */ +struct re_state { + unsigned char rx_state; /* 3 bits pkt state, 1 prepro state */ + unsigned short field_c; /* chars left in current field */ + unsigned short index; /* index into buffer */ + unsigned int crc; /* crc accumulator */ + re_error error; /* valid only if status is RS_BAD_PKT */ + const struct re_config *config; /* pointer to static config */ +}; + +/* dynamic state info needed by the tx engine */ +struct te_state { + unsigned short field_c; /* position in current field */ + unsigned char tx_state; /* encodes n,e, and f (2+1+2=5 bits) */ + unsigned char encoded; /* escape-encoded char for transmission */ + const struct re_config *config; /* pointer to static config */ + unsigned int crc; /* space for CRC (before escaping) */ +}; + +/* + * Function: Angel_RxEngineInit + * Purpose: Initialise state (during device init) for engine. + * + * Params: + * Input: config static config info + * In/Out: state internal state + */ + +void Angel_RxEngineInit(const struct re_config *config, + struct re_state *state); + +/* + * Function: Angel_RxEngine + * Purpose: Rx Engine for character-based devices + * + * Params: + * Input: new_ch the latest character + * + * In/Out: packet details of packet + * packet.buf_len and packet.data must + * be set on entry! + * state internal state, intially set by + * angel_RxEngineInit() + * + * Returns: re_status (see above) + * + */ + +re_status Angel_RxEngine(unsigned char new_ch, struct data_packet *packet, + struct re_state *state); + +/* + * This can be used as the buffer allocation callback for the rx engine, + * and will make use of angel_DD_GetBuffer() [in devdrv.h]. + * + * Saves duplicating this callback function in every device driver that + * uses the rx engine. + * + * Note that this REQUIRES that the device id is installed as ba_data + * in the rx engine config structure for the driver. + */ +bool angel_DD_RxEng_BufferAlloc( struct data_packet *packet, void *cb_data ); + +/* + * Function: Angel_TxEngineInit + * Purpose: Set up tx engine at start of new packet, calculate CRC etc. + * (This should perform the actions described under + * "Initialisation" above) + * + * Params: + * Input: config static config info + * packet the packet to transmit + * In/Out: state internal state + */ + +void Angel_TxEngineInit(const struct re_config *config, + const struct data_packet *packet, + struct te_state *state); + +/* + * Function: Angel_TxEngine + * Purpose: Tx Engine for character-based devices + * + * Params: + * Input: packet details of packet + * packet.len, packet.data and + * packet.type must + * be set on entry! + * In/Out: state internal state, intially set by + * angel_TxEngineStart() + * Output: tx_ch the character to be transmitted + * (NOT SET if return code is TS_IDLE) + * + * Returns: te_status (see above) + */ + +te_status Angel_TxEngine(const struct data_packet *packet, + struct te_state *state, + unsigned char *tx_ch); + + + +#endif /* !defined(angel_rxtx_h) */ + +/* EOF rxtx.h */ diff --git a/gdb/rdi-share/serdrv.c b/gdb/rdi-share/serdrv.c new file mode 100644 index 00000000000..43fd5a00f22 --- /dev/null +++ b/gdb/rdi-share/serdrv.c @@ -0,0 +1,649 @@ +/* + * Copyright (C) 1995 Advanced RISC Machines Limited. All rights reserved. + * + * This software may be freely used, copied, modified, and distributed + * provided that the above copyright notice is preserved in all copies of the + * software. + */ + +/* -*-C-*- + * + * $Revision$ + * $Date$ + * + * + * serdrv.c - Synchronous Serial Driver for Angel. + * This is nice and simple just to get something going. + */ + +#ifdef __hpux +# define _POSIX_SOURCE 1 +#endif + +#include +#include +#include + +#include "crc.h" +#include "devices.h" +#include "buffers.h" +#include "rxtx.h" +#include "hostchan.h" +#include "params.h" +#include "logging.h" + +#ifdef COMPILING_ON_WINDOWS +# undef ERROR +# undef IGNORE +# include +# include "angeldll.h" +# include "comb_api.h" +#else +# ifdef __hpux +# define _TERMIOS_INCLUDED +# include +# undef _TERMIOS_INCLUDED +# else +# include +# endif +# include "unixcomm.h" +#endif + +#ifndef UNUSED +# define UNUSED(x) (x = x) /* Silence compiler warnings */ +#endif + +#define MAXREADSIZE 512 +#define MAXWRITESIZE 512 + +#define SERIAL_FC_SET ((1<num_options; ++i ) + if ( target_baud_rate >= full_list->option[i] ) + { + /* copy remaining */ + for ( j = 0; j < (full_list->num_options - i); ++j ) + user_list->option[j] = full_list->option[i+j]; + user_list->num_options = j; + + /* check this is not the default */ + Angel_FindParam( AP_BAUD_RATE, &serial_defaults, &def_baud ); + if ( (j == 1) && (user_list->option[0] == def_baud) ) + { +#ifdef DEBUG + printf( "user selected default\n" ); +#endif + } + else + { + user_options_set = TRUE; +#ifdef DEBUG + printf( "user options are: " ); + for ( j = 0; j < user_list->num_options; ++j ) + printf( "%u ", user_list->option[j] ); + printf( "\n" ); +#endif + } + + break; /* out of i loop */ + } + +#ifdef DEBUG + if ( i >= full_list->num_options ) + printf( "couldn't match baud rate %u\n", target_baud_rate ); +#endif + } +#ifdef DEBUG + else + printf( "failed to find lists\n" ); +#endif +} + +static int SerialOpen(const char *name, const char *arg) +{ + const char *port_name = name; + +#ifdef DEBUG + printf("SerialOpen: name %s arg %s\n", name, arg ? arg : ""); +#endif + +#ifdef COMPILING_ON_WINDOWS + if (IsOpenSerial()) return -1; +#else + if (Unix_IsSerialInUse()) return -1; +#endif + +#ifdef COMPILING_ON_WINDOWS + if (SerialMatch(name, arg) != adp_ok) + return adp_failed; +#else + port_name = Unix_MatchValidSerialDevice(port_name); +# ifdef DEBUG + printf("translated port to %s\n", port_name == 0 ? "NULL" : port_name); +# endif + if (port_name == 0) return adp_failed; +#endif + + user_options_set = FALSE; + + /* interpret and store the arguments */ + if ( arg != NULL ) + { + unsigned int target_baud_rate; + target_baud_rate = (unsigned int)strtoul(arg, NULL, 10); + if (target_baud_rate > 0) + { +#ifdef DEBUG + printf( "user selected baud rate %u\n", target_baud_rate ); +#endif + process_baud_rate( target_baud_rate ); + } +#ifdef DEBUG + else + printf( "could not understand baud rate %s\n", arg ); +#endif + } + +#ifdef COMPILING_ON_WINDOWS + { + int port = IsValidDevice(name); + if (OpenSerial(port, FALSE) != COM_OK) + return -1; + } +#else + if (Unix_OpenSerial(port_name) < 0) + return -1; +#endif + + serial_reset(); + +#if defined(__unix) || defined(__CYGWIN32__) + Unix_ioctlNonBlocking(); +#endif + + Angel_RxEngineInit(&config, &rxstate); + /* + * DANGER!: passing in NULL as the packet is ok for now as it is just + * IGNOREd but this may well change + */ + Angel_TxEngineInit(&config, NULL, &wstate.txstate); + return 0; +} + +static int SerialMatch(const char *name, const char *arg) +{ + UNUSED(arg); +#ifdef COMPILING_ON_WINDOWS + if (IsValidDevice(name) == COM_DEVICENOTVALID) + return -1; + else + return 0; +#else + return Unix_MatchValidSerialDevice(name) == 0 ? -1 : 0; +#endif +} + +static void SerialClose(void) +{ +#ifdef DO_TRACE + printf("SerialClose()\n"); +#endif + +#ifdef COMPILING_ON_WINDOWS + CloseSerial(); +#else + Unix_CloseSerial(); +#endif +} + +static int SerialRead(DriverCall *dc, bool block) { + static unsigned char readbuf[MAXREADSIZE]; + static int rbindex=0; + + int nread; + int read_errno; + int c=0; + re_status restatus; + int ret_code = -1; /* assume bad packet or error */ + + /* must not overflow buffer and must start after the existing data */ +#ifdef COMPILING_ON_WINDOWS + { + BOOL dummy = FALSE; + nread = BytesInRXBufferSerial(); + + if (nread > MAXREADSIZE - rbindex) + nread = MAXREADSIZE - rbindex; + + if ((read_errno = ReadSerial(readbuf+rbindex, nread, &dummy)) == COM_READFAIL) + { + MessageBox(GetFocus(), "Read error\n", "Angel", MB_OK | MB_ICONSTOP); + return -1; /* SJ - This really needs to return a value, which is picked up in */ + /* DevSW_Read as meaning stop debugger but don't kill. */ + } + else if (pfnProgressCallback != NULL && read_errno == COM_OK) + { + progressInfo.nRead += nread; + (*pfnProgressCallback)(&progressInfo); + } + } +#else + nread = Unix_ReadSerial(readbuf+rbindex, MAXREADSIZE-rbindex, block); + read_errno = errno; +#endif + + if ((nread > 0) || (rbindex > 0)) { + +#ifdef DO_TRACE + printf("[%d@%d] ", nread, rbindex); +#endif + + if (nread>0) + rbindex = rbindex+nread; + + do { + restatus = Angel_RxEngine(readbuf[c], &(dc->dc_packet), &rxstate); +#ifdef DO_TRACE + printf("<%02X ",readbuf[c]); + if (!(++c % 16)) + printf("\n"); +#else + c++; +#endif + } while (cdc_context == NULL) { + Angel_TxEngineInit(&config, &(dc->dc_packet), &(wstate.txstate)); + wstate.wbindex = 0; + dc->dc_context = &wstate; + } + + while ((testatus == TS_IN_PKT) && (wstate.wbindex < MAXWRITESIZE)) + { + /* send the raw data through the tx engine to escape and encapsulate */ + testatus = Angel_TxEngine(&(dc->dc_packet), &(wstate.txstate), + &(wstate.writebuf)[wstate.wbindex]); + if (testatus != TS_IDLE) wstate.wbindex++; + } + + if (testatus == TS_IDLE) { +#ifdef DEBUG + printf("SerialWrite: testatus is TS_IDLE during preprocessing\n"); +#endif + } + +#ifdef DO_TRACE + { + int i = 0; + + while (i%02X ",wstate.writebuf[i]); + + if (!(++i % 16)) + printf("\n"); + } + if (i % 16) + printf("\n"); + } +#endif + +#ifdef COMPILING_ON_WINDOWS + if (WriteSerial(wstate.writebuf, wstate.wbindex) == COM_OK) + { + nwritten = wstate.wbindex; + if (pfnProgressCallback != NULL) + { + progressInfo.nWritten += nwritten; + (*pfnProgressCallback)(&progressInfo); + } + } + else + { + MessageBox(GetFocus(), "Write error\n", "Angel", MB_OK | MB_ICONSTOP); + return -1; /* SJ - This really needs to return a value, which is picked up in */ + /* DevSW_Read as meaning stop debugger but don't kill. */ + } +#else + nwritten = Unix_WriteSerial(wstate.writebuf, wstate.wbindex); + + if (nwritten < 0) { + nwritten=0; + } +#endif + +#ifdef DEBUG + if (nwritten > 0) + printf("Wrote %#04x bytes\n", nwritten); +#endif + + if ((unsigned) nwritten == wstate.wbindex && + (testatus == TS_DONE_PKT || testatus == TS_IDLE)) { + + /* finished sending the packet */ + +#ifdef DEBUG + printf("SerialWrite: calling Angel_TxEngineInit after sending packet (len=%i)\n",wstate.wbindex); +#endif + testatus = TS_IN_PKT; + wstate.wbindex = 0; + return 1; + } + else { +#ifdef DEBUG + printf("SerialWrite: Wrote part of packet wbindex=%i, nwritten=%i\n", + wstate.wbindex, nwritten); +#endif + + /* + * still some data left to send shuffle whats left down and reset + * the ptr + */ + memmove((char *) wstate.writebuf, (char *) (wstate.writebuf+nwritten), + wstate.wbindex-nwritten); + wstate.wbindex -= nwritten; + return 0; + } + return -1; +} + + +static int serial_reset( void ) +{ +#ifdef DEBUG + printf( "serial_reset\n" ); +#endif + +#ifdef COMPILING_ON_WINDOWS + FlushSerial(); +#else + Unix_ResetSerial(); +#endif + + return serial_set_params( &serial_defaults ); +} + + +static int find_baud_rate( unsigned int *speed ) +{ + static struct { + unsigned int baud; + int termiosValue; + } possibleBaudRates[] = { +#if defined(__hpux) + {115200,_B115200}, {57600,_B57600}, +#endif +#ifdef COMPILING_ON_WINDOWS + {38400,CBR_38400}, {19200,CBR_19200}, {9600, CBR_9600}, {0,0} +#else + {38400,B38400}, {19200,B19200}, {9600, B9600}, {0,0} +#endif + }; + unsigned int i; + + /* look for lower or matching -- will always terminate at 0 end marker */ + for ( i = 0; possibleBaudRates[i].baud > *speed; ++i ) + /* do nothing */ ; + + if ( possibleBaudRates[i].baud > 0 ) + *speed = possibleBaudRates[i].baud; + + return possibleBaudRates[i].termiosValue; +} + + +static int serial_set_params( const ParameterConfig *config ) +{ + unsigned int speed; + int termios_value; + +#ifdef DEBUG + printf( "serial_set_params\n" ); +#endif + + if ( ! Angel_FindParam( AP_BAUD_RATE, config, &speed ) ) + { +#ifdef DEBUG + printf( "speed not found in config\n" ); +#endif + return DE_OKAY; + } + + termios_value = find_baud_rate( &speed ); + if ( termios_value == 0 ) + { +#ifdef DEBUG + printf( "speed not valid: %u\n", speed ); +#endif + return DE_OKAY; + } + +#ifdef DEBUG + printf( "setting speed to %u\n", speed ); +#endif + +#ifdef COMPILING_ON_WINDOWS + SetBaudRate((WORD)termios_value); +#else + Unix_SetSerialBaudRate(termios_value); +#endif + + return DE_OKAY; +} + + +static int serial_get_user_params( ParameterOptions **p_options ) +{ +#ifdef DEBUG + printf( "serial_get_user_params\n" ); +#endif + + if ( user_options_set ) + { + *p_options = &user_options; + } + else + { + *p_options = NULL; + } + + return DE_OKAY; +} + + +static int serial_get_default_params( ParameterConfig **p_config ) +{ +#ifdef DEBUG + printf( "serial_get_default_params\n" ); +#endif + + *p_config = (ParameterConfig *) &serial_defaults; + return DE_OKAY; +} + + +static int SerialIoctl(const int opcode, void *args) { + + int ret_code; + +#ifdef DEBUG + printf( "SerialIoctl: op %d arg %p\n", opcode, args ? args : ""); +#endif + + switch (opcode) + { + case DC_RESET: + ret_code = serial_reset(); + break; + + case DC_SET_PARAMS: + ret_code = serial_set_params((const ParameterConfig *)args); + break; + + case DC_GET_USER_PARAMS: + ret_code = serial_get_user_params((ParameterOptions **)args); + break; + + case DC_GET_DEFAULT_PARAMS: + ret_code = serial_get_default_params((ParameterConfig **)args); + break; + + default: + ret_code = DE_BAD_OP; + break; + } + + return ret_code; +} + +DeviceDescr angel_SerialDevice = { + "SERIAL", + SerialOpen, + SerialMatch, + SerialClose, + SerialRead, + SerialWrite, + SerialIoctl +}; diff --git a/gdb/rdi-share/serpardr.c b/gdb/rdi-share/serpardr.c new file mode 100644 index 00000000000..604d0480613 --- /dev/null +++ b/gdb/rdi-share/serpardr.c @@ -0,0 +1,730 @@ +/* + * Copyright (C) 1995 Advanced RISC Machines Limited. All rights reserved. + * + * This software may be freely used, copied, modified, and distributed + * provided that the above copyright notice is preserved in all copies of the + * software. + */ + +/* -*-C-*- + * + * $Revision$ + * $Date$ + * + * + * serpardv.c - Serial/Parallel Driver for Angel. + */ +#include +#include +#include + +#include "crc.h" +#include "devices.h" +#include "buffers.h" +#include "rxtx.h" +#include "hostchan.h" +#include "params.h" +#include "logging.h" +#include "hsys.h" + +#ifdef COMPILING_ON_WINDOWS +# undef ERROR +# undef IGNORE +# include +# include "angeldll.h" +# include "comb_api.h" +#else +# ifdef __hpux +# define _TERMIOS_INCLUDED +# include +# undef _TERMIOS_INCLUDED +# else +# include +# endif +# include "unixcomm.h" +#endif + +#ifndef UNUSED +# define UNUSED(x) (x = x) /* Silence compiler warnings */ +#endif + +#define MAXREADSIZE 512 +#define MAXWRITESIZE 512 + +#define SERPAR_FC_SET ((1 << serial_XON) | (1 << serial_XOFF)) +#define SERPAR_CTL_SET ((1 << serial_STX) | (1 << serial_ETX) | \ + (1 << serial_ESC)) +#define SERPAR_ESC_SET (SERPAR_FC_SET | SERPAR_CTL_SET) + +static const struct re_config config = { + serial_STX, serial_ETX, serial_ESC, /* self-explanatory? */ + SERPAR_FC_SET, /* set of flow-control characters */ + SERPAR_ESC_SET, /* set of characters to be escaped */ + NULL, /* serial_flow_control */ + NULL, /* what to do with FC chars */ + angel_DD_RxEng_BufferAlloc, NULL /* how to get a buffer */ +}; + +static struct re_state rxstate; + +/* + * structure used for manipulating transmit data + */ +typedef struct TxState +{ + struct te_state state; + unsigned int index; + unsigned char writebuf[MAXWRITESIZE]; +} TxState; + +/* + * The set of parameter options supported by the device + */ +static unsigned int baud_options[] = +{ +#ifdef __hpux + 115200, 57600, +#endif + 38400, 19200, 9600 +}; + +static ParameterList param_list[] = +{ + { + AP_BAUD_RATE, + sizeof(baud_options) / sizeof(unsigned int), + baud_options + } +}; + +static const ParameterOptions serpar_options = +{ + sizeof(param_list) / sizeof(ParameterList), + param_list +}; + +/* + * The default parameter config for the device + */ +static Parameter param_default[] = +{ + { AP_BAUD_RATE, 9600 } +}; + +static const ParameterConfig serpar_defaults = +{ + sizeof(param_default)/sizeof(Parameter), + param_default +}; + +/* + * The user-modified options for the device + */ +static unsigned int user_baud_options[sizeof(baud_options) / + sizeof(unsigned int)]; + +static ParameterList param_user_list[] = +{ + { + AP_BAUD_RATE, + sizeof(user_baud_options) / sizeof(unsigned), + user_baud_options + } +}; + +static ParameterOptions user_options = +{ + sizeof(param_user_list) / sizeof(ParameterList), + param_user_list +}; + +static bool user_options_set; + +/* forward declarations */ +static int serpar_reset(void); +static int serpar_set_params(const ParameterConfig *config); +static int SerparMatch(const char *name, const char *arg); + +static void process_baud_rate(unsigned int target_baud_rate) +{ + const ParameterList *full_list; + ParameterList *user_list; + + /* create subset of full options */ + full_list = Angel_FindParamList(&serpar_options, AP_BAUD_RATE); + user_list = Angel_FindParamList(&user_options, AP_BAUD_RATE); + + if (full_list != NULL && user_list != NULL) + { + unsigned int i, j; + unsigned int def_baud = 0; + + /* find lower or equal to */ + for (i = 0; i < full_list->num_options; ++i) + if (target_baud_rate >= full_list->option[i]) + { + /* copy remaining */ + for (j = 0; j < (full_list->num_options - i); ++j) + user_list->option[j] = full_list->option[i+j]; + user_list->num_options = j; + + /* check this is not the default */ + Angel_FindParam(AP_BAUD_RATE, &serpar_defaults, &def_baud); + if ((j == 1) && (user_list->option[0] == def_baud)) + { +#ifdef DEBUG + printf("user selected default\n"); +#endif + } + else + { + user_options_set = TRUE; +#ifdef DEBUG + printf("user options are: "); + for (j = 0; j < user_list->num_options; ++j) + printf("%u ", user_list->option[j]); + printf("\n"); +#endif + } + + break; /* out of i loop */ + } + +#ifdef DEBUG + if (i >= full_list->num_options) + printf("couldn't match baud rate %u\n", target_baud_rate); +#endif + } +#ifdef DEBUG + else + printf("failed to find lists\n"); +#endif +} + +static int SerparOpen(const char *name, const char *arg) +{ + char *sername = NULL; + char *parname = NULL; + +#ifdef DEBUG + printf("SerparOpen: name %s arg %s\n", name, arg ? arg : ""); +#endif + +#ifdef COMPILING_ON_WINDOWS + if (IsOpenSerial() || IsOpenParallel()) return -1; +#else + if (Unix_IsSerialInUse() || Unix_IsParallelInUse()) return -1; +#endif + +#ifdef COMPILING_ON_WINDOWS + if (SerparMatch(name, arg) == -1) + return -1; +#else + Unix_IsValidParallelDevice(name,&sername,&parname); +# ifdef DEBUG + printf("translated %s to serial %s and parallel %s\n", + name==0 ? "NULL" : name, + sername==0 ? "NULL" : sername, + parname==0 ? "NULL" : parname); +# endif + if (sername==NULL || parname==NULL) return -1; +#endif + + user_options_set = FALSE; + + /* interpret and store the arguments */ + if (arg != NULL) + { + unsigned int target_baud_rate; + + target_baud_rate = (unsigned int)strtoul(arg, NULL, 10); + + if (target_baud_rate > 0) + { +#ifdef DEBUG + printf("user selected baud rate %u\n", target_baud_rate); +#endif + process_baud_rate(target_baud_rate); + } +#ifdef DEBUG + else + printf("could not understand baud rate %s\n", arg); +#endif + } + +#ifdef COMPILING_ON_WINDOWS + { + /* + * The serial port number is in name[0] followed by + * the parallel port number in name[1] + */ + + int sport = name[0] - '0'; + int pport = name[1] - '0'; + + if (OpenParallel(pport) != COM_OK) + return -1; + + if (OpenSerial(sport, FALSE) != COM_OK) + { + CloseParallel(); + return -1; + } + } +#else + Unix_OpenParallel(parname); + Unix_OpenSerial(sername); +#endif + + serpar_reset(); + +#if defined(__unix) || defined(__CYGWIN32__) + Unix_ioctlNonBlocking(); +#endif + + Angel_RxEngineInit(&config, &rxstate); + + return 0; +} + +#ifdef COMPILING_ON_WINDOWS +static int SerparMatch(const char *name, const char *arg) +{ + char sername[2]; + char parname[2]; + + UNUSED(arg); + + sername[0] = name[0]; + parname[0] = name[1]; + sername[1] = parname[1] = 0; + + if (IsValidDevice(sername) == COM_DEVICENOTVALID || + IsValidDevice(parname) == COM_DEVICENOTVALID) + return -1; + else + return 0; +} +#else +static int SerparMatch(const char *portstring, const char *arg) +{ + char *sername=NULL, *parname=NULL; + UNUSED(arg); + + Unix_IsValidParallelDevice(portstring,&sername,&parname); + + /* Match failed if either sername or parname are still NULL */ + if (sername==NULL || parname==NULL) return -1; + return 0; +} +#endif + +static void SerparClose(void) +{ +#ifdef COMPILING_ON_WINDOWS + CloseParallel(); + CloseSerial(); +#else + Unix_CloseParallel(); + Unix_CloseSerial(); +#endif +} + +static int SerparRead(DriverCall *dc, bool block) +{ + static unsigned char readbuf[MAXREADSIZE]; + static int rbindex = 0; + + int nread; + int read_errno; + int c = 0; + re_status restatus; + int ret_code = -1; /* assume bad packet or error */ + + /* + * we must not overflow buffer, and must start after + * the existing data + */ +#ifdef COMPILING_ON_WINDOWS + { + BOOL dummy = FALSE; + nread = BytesInRXBufferSerial(); + + if (nread > MAXREADSIZE - rbindex) + nread = MAXREADSIZE - rbindex; + read_errno = ReadSerial(readbuf+rbindex, nread, &dummy); + if (pfnProgressCallback != NULL && read_errno == COM_OK) + { + progressInfo.nRead += nread; + (*pfnProgressCallback)(&progressInfo); + } + } +#else + nread = Unix_ReadSerial(readbuf+rbindex, MAXREADSIZE-rbindex, block); + read_errno = errno; +#endif + + if ((nread > 0) || (rbindex > 0)) + { +#ifdef DO_TRACE + printf("[%d@%d] ", nread, rbindex); +#endif + + if (nread > 0) + rbindex = rbindex + nread; + + do + { + restatus = Angel_RxEngine(readbuf[c], &(dc->dc_packet), &rxstate); + +#ifdef DO_TRACE + printf("<%02X ",readbuf[c]); +#endif + c++; + } while (c < rbindex && + ((restatus == RS_IN_PKT) || (restatus == RS_WAIT_PKT))); + +#ifdef DO_TRACE + printf("\n"); +#endif + + switch(restatus) + { + case RS_GOOD_PKT: + ret_code = 1; + /* fall through to: */ + + case RS_BAD_PKT: + /* + * We now need to shuffle any left over data down to the + * beginning of our private buffer ready to be used + *for the next packet + */ +#ifdef DO_TRACE + printf("SerparRead() processed %d, moving down %d\n", + c, rbindex - c); +#endif + + if (c != rbindex) + memmove((char *) readbuf, (char *) (readbuf + c), rbindex - c); + + rbindex -= c; + + break; + + case RS_IN_PKT: + case RS_WAIT_PKT: + rbindex = 0; /* will have processed all we had */ + ret_code = 0; + break; + + default: +#ifdef DEBUG + printf("Bad re_status in SerparRead()\n"); +#endif + break; + } + } + else if (nread == 0) + /* nothing to read */ + ret_code = 0; + else if (read_errno == ERRNO_FOR_BLOCKED_IO) /* nread < 0 */ + ret_code = 0; + +#ifdef DEBUG + if ((nread < 0) && (read_errno != ERRNO_FOR_BLOCKED_IO)) + perror("read() error in SerparRead()"); +#endif + + return ret_code; +} + +/* + * Function: send_packet + * Purpose: Send a stream of bytes to Angel through the parallel port + * + * Algorithm: We need to present the data in a form that all boards can + * swallow. With the PID board, this is a problem: for reasons + * described in the driver (angel/pid/st16c552.c), data are + * sent a nybble at a time on D0-D2 and D4; D3 is wired to ACK, + * which generates an interrupt when it goes low. This routine + * fills in an array of nybbles, with ACK clear in all but the + * last one. If, for whatever reason, the write fails, then + * ACK is forced high (thereby enabling the next write a chance + * to be noticed when the falling edge of ACK generates an + * interrupt (hopefully). + * + * Params: + * Input: txstate Contains the packet to be sent + * + * Returns: Number of *complete* bytes written + */ + +static int SerparWrite(DriverCall *dc) +{ + te_status status; + int nwritten = 0; + static TxState txstate; + + /* + * is this a new packet? + */ + if (dc->dc_context == NULL) + { + /* + * yes - initialise TxEngine + */ + Angel_TxEngineInit(&config, &dc->dc_packet, &txstate.state); + + txstate.index = 0; + dc->dc_context = &txstate; + } + + /* + * fill the buffer using the Tx Engine + */ + do + { + status = Angel_TxEngine(&dc->dc_packet, &txstate.state, + &txstate.writebuf[txstate.index]); + if (status != TS_IDLE) txstate.index++; + + } while (status == TS_IN_PKT && txstate.index < MAXWRITESIZE); + +#ifdef DO_TRACE + { + unsigned int i = 0; + + while (i < txstate.index) + { + printf(">%02X ", txstate.writebuf[i]); + + if (!(++i % 16)) + putc('\n', stdout); + } + + if (i % 16) + putc('\n', stdout); + } +#endif + + /* + * the data are ready, all we need now is to send them out + * in a form that Angel can swallow. + */ +#ifdef COMPILING_ON_WINDOWS + if (WriteParallel(txstate.writebuf, txstate.index) == COM_OK) + { + nwritten = txstate.index; + if (pfnProgressCallback != NULL) + { + progressInfo.nWritten += nwritten; + (*pfnProgressCallback)(&progressInfo); + } + } + else + { + MessageBox(GetFocus(), "Write error\n", "Angel", MB_OK | MB_ICONSTOP); + return -1; /* SJ - This really needs to return a value, which is picked up in */ + /* DevSW_Read as meaning stop debugger but don't kill. */ + } +#else + nwritten = Unix_WriteParallel(txstate.writebuf, txstate.index); +#endif + + if (nwritten < 0) nwritten = 0; + +#ifdef DO_TRACE + printf("SerparWrite: wrote %d out of %d bytes\n", + nwritten, txstate.index); +#endif + + /* + * has the whole packet gone? + */ + if (nwritten == (int)txstate.index && + (status == TS_DONE_PKT || status == TS_IDLE)) + /* + * yes it has + */ + return 1; + else + { + /* + * if some data are left, shuffle them + * to the start of the buffer + */ + if (nwritten != (int)txstate.index && nwritten != 0) + { + txstate.index -= nwritten; + (void)memmove((char *) txstate.writebuf, + (char *) (txstate.writebuf + nwritten), + txstate.index); + } + else if (nwritten == (int)txstate.index) + txstate.index = 0; + + return 0; + } +} + +static int serpar_reset(void) +{ +#ifdef COMPILING_ON_WINDOWS + FlushParallel(); + FlushSerial(); +#else + Unix_ResetParallel(); + Unix_ResetSerial(); +#endif + + return serpar_set_params(&serpar_defaults); +} + +static int find_baud_rate(unsigned int *speed) +{ + static struct + { + unsigned int baud; + int termiosValue; + } possibleBaudRates[] = + { +#if defined(__hpux) + {115200, _B115200}, {57600, _B57600}, +#endif +#ifdef COMPILING_ON_WINDOWS + {38400, CBR_38400}, {19200, CBR_19200}, {9600, CBR_9600}, {0, 0} +#else + {38400, B38400}, {19200, B19200}, {9600, B9600}, {0, 0} +#endif + }; + unsigned int i; + + /* look for lower or matching -- will always terminate at 0 end marker */ + for (i = 0; possibleBaudRates[i].baud > *speed; ++i) + /* do nothing */ + ; + + if (possibleBaudRates[i].baud > 0) + *speed = possibleBaudRates[i].baud; + + return possibleBaudRates[i].termiosValue; +} + +static int serpar_set_params(const ParameterConfig *config) +{ + unsigned int speed; + int termios_value; + +#ifdef DEBUG + printf("serpar_set_params\n"); +#endif + + if (!Angel_FindParam(AP_BAUD_RATE, config, &speed)) + { +#ifdef DEBUG + printf("speed not found in config\n"); +#endif + return DE_OKAY; + } + + termios_value = find_baud_rate(&speed); + if (termios_value == 0) + { +#ifdef DEBUG + printf("speed not valid: %u\n", speed); +#endif + return DE_OKAY; + } + +#ifdef DEBUG + printf("setting speed to %u\n", speed); +#endif + +#ifdef COMPILING_ON_WINDOWS + SetBaudRate((WORD)termios_value); +#else + Unix_SetSerialBaudRate(termios_value); +#endif + + return DE_OKAY; +} + + +static int serpar_get_user_params(ParameterOptions **p_options) +{ +#ifdef DEBUG + printf("serpar_get_user_params\n"); +#endif + + if (user_options_set) + { + *p_options = &user_options; + } + else + { + *p_options = NULL; + } + + return DE_OKAY; +} + + +static int serial_get_default_params( const ParameterConfig **p_config ) +{ +#ifdef DEBUG + printf( "serial_get_default_params\n" ); +#endif + + *p_config = &serpar_defaults; + return DE_OKAY; +} + + +static int SerparIoctl(const int opcode, void *args) +{ + int ret_code; + +#ifdef DEBUG + printf("SerparIoctl: op %d arg %p\n", opcode, args ? args : ""); +#endif + + switch (opcode) + { + case DC_RESET: + ret_code = serpar_reset(); + break; + + case DC_SET_PARAMS: + ret_code = serpar_set_params((const ParameterConfig *)args); + break; + + case DC_GET_USER_PARAMS: + ret_code = serpar_get_user_params((ParameterOptions **)args); + break; + + case DC_GET_DEFAULT_PARAMS: + ret_code = + serial_get_default_params((const ParameterConfig **)args); + break; + + default: + ret_code = DE_BAD_OP; + break; + } + + return ret_code; +} + +DeviceDescr angel_SerparDevice = +{ + "SERPAR", + SerparOpen, + SerparMatch, + SerparClose, + SerparRead, + SerparWrite, + SerparIoctl +}; + +/* EOF serpardr.c */ diff --git a/gdb/rdi-share/sys.h b/gdb/rdi-share/sys.h new file mode 100644 index 00000000000..b68ac785cd6 --- /dev/null +++ b/gdb/rdi-share/sys.h @@ -0,0 +1,319 @@ +/* + * Copyright (C) 1995 Advanced RISC Machines Limited. All rights reserved. + * + * This software may be freely used, copied, modified, and distributed + * provided that the above copyright notice is preserved in all copies of the + * software. + */ + +/* sys.h + *********************************************************************** + * Angel C Libary support channel protocol definitions + * + * $Revision$ + * $Date$ + * + * + * + * + * MESSAGE FORMAT + * -------------- + * Format of the "data" section of C Lib Support Channel Messages. + * You will notice that the format is much the same as the format + * of ADP messages - this is so that multi-threaded C Libraries can + * be supported. + * + * unsigned32 reason - Main C Library reason code. + * unsigned32 debugID - Info. describing host debug world; + * private to host and used in any target + * initiated messages. + * unsigned32 OSinfo1 \ Target OS information to identify process/thread + * unsigned32 OSinfo2 / world, etc. These two fields are target defined. + * byte args[n] - Data for message "reason" code. + * + * The "debugID" is defined by the host-end of the protocol, and is used + * by the host to ensure that messages are routed to the correct handler + * program/veneer (eg. imagine several threads having opened stdout and + * each writing to a different window in a windowed debugger). + * + * NOTE: The reason that there is no "size" information, is that the + * message IDs themselves encode the format of any arguments. + * + * For further discussion of the format see adp.h + * + * N.B. All streams are little endian. + * + * CLIB REASON CODE + * ---------------- + * The message reason codes contain some information that ties them to + * the channel and direction that the message will be used with. This + * will ensure that even if the message "#define name" is not + * completely descriptive, the message reason code is. + * + * b31 = direction. 0=Host-to-Target; 1=Target-to-Host; + * b30-16 = reserved. should be zero + * b15-0 = message reason code. + * + * Note that typically a request will be initiated by the target side, and + * that the host will then respond with either an acknowledgement or some + * data. In either case the same reason code will be used, but the direction + * bit will be reveresed. + */ + +#ifndef __sys_h +#define __sys_h + +#ifndef HtoT +#define HtoT ((unsigned)0 << 31) /* Host-to-Target message */ +#define TtoH ((unsigned)1 << 31) /* Target-to-Host message */ +#endif + +/* + * The following are error codes used in the status field returned on + * sending a message. 0 represents no error having occurred, non-zero + * represents a general error. More codes should be added as required. + */ + +#ifndef ErrCode +#define NoError 0x0 +#endif + +/*************************************************************************/ +/* The following are direct conversions of the DeMon SWI's */ +/* NB: nbytes is the number of bytes INCLUDING THE NULL character where */ +/* applicable. */ + +/* This message is used as a response to a packet whose message + * was not understood. The return parameter, code is the reason + * code which was not understood. Although intended for use as a + * default case on a received message switch it can also be used + * as a proper message*/ +#define CL_Unrecognised 0x00 + /* Unrecognised() + * return(word code) + */ + +/* Write a character to the terminal. + */ +#define CL_WriteC 0x01 + /* WriteC(byte data) + * return(word status) + */ + +/* Write a NULL terminated string of characters to the terminal. The length + * of the string excluding the NULL terminating character is passed in + * 'nbytes'. + */ +#define CL_Write0 0x02 + /* Write0(word nbytes, bytes data) + * return(word status) + */ + +/* Read a character from the terminal - probably the keyboard. + */ +#define CL_ReadC 0x04 + /* ReadC(void) + * return(word status, byte data) + */ + +/* Perform system call, pass NULL terminated string to host's command + * line interpreter(NOT AVAILABLE IN PC/DOS RELEASE). The data byte + * returned holds the return code from the system call. + */ +#define CL_System 0x05 + /* CLI(word nbytes, bytes data) + * return(word status, word data) + */ + +/* It returns the address of the null terminated command line string used to + * invoke the program. status will be set to NoError if the command line + * can be returned. Other status values will be treated as error conditions. + */ +#define CL_GetCmdLine 0x10 + /* GetCmdLine(void) + * return(word status, word nbytes, bytes argline) + */ + +/* Return the number of centi-seconds since the support code began + * execution. Only the difference between successive calls can be + * meaningful. + */ +#define CL_Clock 0x61 + /* Clock(void) + * return(word status, word clks) + */ + +/* Return the number of seconds since the beginning of 1970. + */ +#define CL_Time 0x63 + /* Time(void) + * return(word status, word time) + */ + +/* Delete(remove, un-link, wipe, destroy) the file named by the + * NULL-terminated string 'name'. + */ +#define CL_Remove 0x64 + /* Remove(word nbytes, bytes name) + * return(word status) + */ + +/* Rename the file specified by the NULL-terminated string 'oname' + * to 'nname'. + */ +#define CL_Rename 0x65 + /* Rename(word nbytes, bytes oname, word nbytes, bytes nname) + * return(word status) + */ + +/* 'name' specifies a NULL-terminated string containing a file name or a + * device name. Opens the file/device and returns a non-zero handle on + * success that can be quoted to CL_Close, CL_Read, CL_Write, CL_Seek, + * CL_Flen or CL_IsTTY. The mode is an integer in the range 0-11:- + * + * Mode: 0 1 2 3 4 5 6 7 8 9 10 11 + * ANSI C fopen mode: r rb r+ r+b w wb w+ w+b a ab a+ a+b + * + * Values 12-15 are illegal. If 'name' is ":tt" the stdin/stdout is + * opened depending on whether 'mode' is read or write. + */ +#define CL_Open 0x66 + /* Open(word nbytes, bytes name, word mode) + * return(word handle) + */ + +/* 'handle' is a file handle previously returned by CL_Open. CL_Close + * closes the file. + */ +#define CL_Close 0x68 + /* Close(word handle) + * return(word status) + */ + +/* Writes data of length nbytes to the file/device specified by + * handle. nbtotal represents the total number of bytes to be + * written, whereas nbytes is the number of bytes in this packet + * + * If nbtotal is <= DATASIZE - CL_Write message header size in the + * packet then nbytes = nbtotal and the number of bytes not written + * is returned. If nbtotal is > the packet size then the CL_Write + * must be followed by a number of CL_WriteX's to complete the write, + * the nbytes returned by CL_Write can be ignored + * If the status word returned is non zero, an error has occurred and + * the write request has been aborted. + * + */ +#define CL_Write 0x69 + /* Write(word handle, word nbtotal, word nbytes, bytes data) + * return(word status, word nbytes) + */ + +/* Write Extension is a reads a continuation of data from a CL_Write + * which was too big to fit in a single packet. + * nbytes is the number of bytes of data in this packet, the + * returned value of nbytes can be ignored except if it is the + * last packet, in which case it is the number of bytes that were NOT + * written + */ +#define CL_WriteX 0x6A + /* WriteX(word nbytes, bytes data) + * return(word status, word nbytes) + */ + +/* Reads 'nbytes' from the file/device specified by 'handle'. + * + * If nbytes <= DATASIZE then the read will occur in a single packet + * and the returned value of nbytes will be the number of bytes actually + * read and nbmore will be 0. If nbytes> DATASIZE then multiple packets + * will have to be used ie CL_Read followed by 1 or more CL_ReadX + * packets. In this case CL_Read will return nbytes read in the current + * packet and nbmore representing how many more bytes are expected to be + * read + * If the status word is non zero then the request has completed with an + * error. If the status word is 0xFFFFFFFF (-1) then an EOF condition + * has been reached. + */ +#define CL_Read 0x6B + /* Read(word handle, word nbytes) + * return(word status, word nbytes, word nbmore, bytes data) + */ + +/* Read eXtension returns a continuation of the data that was opened for + * read in the earlier CL_Read. The return value nbytes is the number of + * data bytes in the packet, nbmore is the number of bytes more that are + * expected to be read in subsequent packets. + */ +#define CL_ReadX 0x6C + /* ReadX() + * return(word status, word nbytes, word nbmore, bytes data) + */ + +/* Seeks to byte position 'posn' in the file/device specified by 'handle'. + */ +#define CL_Seek 0x6D + /* Seek(word handle, word posn) + * return(word status) + */ + +/* Returns the current length of the file specified by 'handle' in 'len'. + * If an error occurs 'len' is set to -1. + */ +#define CL_Flen 0x6E + /* Flen(word handle) + * return(word len) + */ + +/* Returns NoError if 'handle' specifies an interactive device, otherwise + * returns GenError + */ +#define CL_IsTTY 0x6F + /* IsTTY(word handle) + * return(word status) + */ + +/* Returns a temporary host file name. The maximum length of a file name + * is passed to the host. The TargetID is some identifier from the target + * for this particular temporary filename. This value is could be used + * directly in the generation of the filename. + * + * If the host cannot create a suitable name or the generated name is too + * long then status is non zero. status will be NoError if the host can create + * a name. + */ +#define CL_TmpNam 0x70 + /* TmpNam(word maxlength, word TargetID) + * return(word status, word nbytes, bytes fname) + */ + +/* Note there is no message for Exit, EnterOS, InstallHandler or + * GenerateError as these will be supported entirely at the host end, + * or by the underlying Operating system. + */ + +#define CL_UnknownReason (-1) + +extern unsigned int GetRaiseHandler( void ); +extern unsigned int SysLibraryHandler(unsigned int sysCode, unsigned int *args); +extern void angel_SysLibraryInit(void); + +/* + * Function: Angel_IsSysHandlerRunning + * Purpose: return whether or not SysLibraryHandler is running + * + * No paramaters + * + * Returns 1 if SysLibraryHandler is running + * 0 otherwise + */ +extern int Angel_IsSysHandlerRunning(void); + +#ifdef ICEMAN2 +/* This function exists in an ICEman2 system only, and can be called by + * debug support code when the debugger tells it how much memory the + * target has. This will then be used to deal with the HEAPINFO SWI + */ +extern void angel_SetTopMem(unsigned addr); +#endif + +#endif + diff --git a/gdb/rdi-share/tx.c b/gdb/rdi-share/tx.c new file mode 100644 index 00000000000..a52286c12b5 --- /dev/null +++ b/gdb/rdi-share/tx.c @@ -0,0 +1,176 @@ +/* + * Copyright (C) 1995 Advanced RISC Machines Limited. All rights reserved. + * + * This software may be freely used, copied, modified, and distributed + * provided that the above copyright notice is preserved in all copies of the + * software. + */ + +/*-*-C-*- + * + * $Revision$ + * $Date$ + * + * Project: ANGEL + * + * Title: Character based packet transmission engine + */ + +#include /* ANSI varargs support */ +#include "angel.h" /* Angel system definitions */ +#include "endian.h" /* Endian independant memory access macros */ +#include "crc.h" /* crc generation definitions and headers */ +#include "rxtx.h" +#include "channels.h" +#include "buffers.h" +#include "logging.h" + +/* definitions to describe the engines state */ +#define N_STX 0x0 /* first 2 bits for N_ */ +#define N_BODY 0x1 +#define N_ETX 0x2 +#define N_IDLE 0x3 +#define N_MASK 0x3 /* mask for the Encapsulator state */ + +#define E_PLAIN (0x0 << 2) /* 3rd bit for E_ */ +#define E_ESC (0x1 << 2) /* 3rd bit for E_ */ +#define E_MASK (0x1 << 2) /* mask for the Escaper state */ + +#define F_HEAD (0x0 << 3) /* 4th and 5th bits for F_ */ +#define F_DATA (0x1 << 3) +#define F_CRC (0x1 << 4) +#define F_MASK (0x3 << 3) /* mask for the Escaper state */ + +static unsigned char escape(unsigned char ch_in, struct te_state *txstate); + +void Angel_TxEngineInit(const struct re_config *txconfig, + const struct data_packet *packet, + struct te_state *txstate){ + IGNORE(packet); + txstate->tx_state = N_STX | E_PLAIN | F_HEAD; + txstate->field_c = 0; + txstate->encoded = 0; + txstate->config = txconfig; + txstate->crc = 0; +} + +te_status Angel_TxEngine(const struct data_packet *packet, + struct te_state *txstate, + unsigned char *tx_ch){ + /* TODO: gaurd on long/bad packets */ + /* + * encapsulate the packet, framing has been moved from a seperate + * function into the encapsulation routine as it needed too much + * inherited state for it to be sensibly located elsewhere + */ + switch ((txstate->tx_state) & N_MASK){ + case N_STX: +#ifdef DO_TRACE + __rt_trace("txe-stx "); +#endif + txstate->tx_state = (txstate->tx_state & ~N_MASK) | N_BODY; + *tx_ch = txstate->config->stx; + txstate->field_c = 3; /* set up for the header */ + txstate->crc = startCRC32; /* set up basic crc */ + return TS_IN_PKT; + case N_BODY:{ + switch (txstate->tx_state & F_MASK) { + case F_HEAD: +#ifdef DO_TRACE + __rt_trace("txe-head "); +#endif + if (txstate->field_c == 3) { + /* send type */ + *tx_ch = escape(packet->type, txstate); + return TS_IN_PKT; + } + else { + *tx_ch = escape((packet->len >> (txstate->field_c - 1) * 8) & 0xff, + txstate); + if (txstate->field_c == 0) { + /* move on to the next state */ + txstate->tx_state = (txstate->tx_state & ~F_MASK) | F_DATA; + txstate->field_c = packet->len; + } + return TS_IN_PKT; + } + case F_DATA: +#ifdef DO_TRACE + __rt_trace("txe-data "); +#endif + *tx_ch = escape(packet->data[packet->len - txstate->field_c], txstate); + if (txstate->field_c == 0) { + /* move on to the next state */ + txstate->tx_state = (txstate->tx_state & ~F_MASK) | F_CRC; + txstate->field_c = 4; + } + return TS_IN_PKT; + case F_CRC: +#ifdef DO_TRACE + __rt_trace("txe-crc "); +#endif + *tx_ch = escape((txstate->crc >> ((txstate->field_c - 1) * 8)) & 0xff, + txstate); + + if (txstate->field_c == 0) { +#ifdef DO_TRACE + __rt_trace("txe crc = 0x%x\n", txstate->crc); +#endif + /* move on to the next state */ + txstate->tx_state = (txstate->tx_state & ~N_MASK) | N_ETX; + } + return TS_IN_PKT; + } + } + case N_ETX: +#ifdef DO_TRACE + __rt_trace("txe-etx\n"); +#endif + txstate->tx_state = (txstate->tx_state & ~N_MASK) | N_IDLE; + *tx_ch = txstate->config->etx; + return TS_DONE_PKT; + default: +#ifdef DEBUG + __rt_info("tx default\n"); +#endif + txstate->tx_state = (txstate->tx_state & ~N_MASK) | N_IDLE; + return TS_IDLE; + } + /* stop a silly -Wall warning */ + return (te_status)-1; +} + +/* + * crc generation occurs in the escape function because it is the only + * place where we know that we're putting a real char into the buffer + * rather than an escaped one. + * We must be careful here not to update the crc when we're sending it + */ +static unsigned char escape(unsigned char ch_in, struct te_state *txstate) { + if (((txstate->tx_state) & E_MASK) == E_ESC) { + /* char has been escaped so send the real char */ +#ifdef DO_TRACE + __rt_trace("txe-echar "); +#endif + txstate->tx_state = (txstate->tx_state & ~E_MASK) | E_PLAIN; + txstate->field_c--; + if ((txstate->tx_state & F_MASK) != F_CRC) + txstate->crc = crc32( &ch_in, 1, txstate->crc); + return ch_in | serial_ESCAPE; + } + if ((ch_in < 32) && ((txstate->config->esc_set & (1 << ch_in)) != 0)) { + /* char needs escaping */ +#ifdef DO_TRACE + __rt_trace("txe-esc "); +#endif + txstate->tx_state = (txstate->tx_state & ~E_MASK) | E_ESC; + return txstate->config->esc; + } + /* must be a char that can be sent plain */ + txstate->field_c--; + if ((txstate->tx_state & F_MASK) != F_CRC) + txstate->crc = crc32(&ch_in, 1, txstate->crc); + return ch_in; +} + +/* EOF tx.c */ diff --git a/gdb/rdi-share/unixcomm.c b/gdb/rdi-share/unixcomm.c new file mode 100644 index 00000000000..7cb55e6c8d5 --- /dev/null +++ b/gdb/rdi-share/unixcomm.c @@ -0,0 +1,535 @@ +/* + * Copyright (C) 1995 Advanced RISC Machines Limited. All rights reserved. + * + * This software may be freely used, copied, modified, and distributed + * provided that the above copyright notice is preserved in all copies of the + * software. + */ + +/* -*-C-*- + * + * $Revision$ + * $Date$ + * + */ + +#ifdef __hpux +# define _POSIX_SOURCE 1 +#endif + +#include +#include +#include + +#ifdef __hpux +# define _TERMIOS_INCLUDED +# include +# undef _TERMIOS_INCLUDED +#else +# include +#endif + +#include +#include +#include +#include +#include +#include + +#ifdef sun +# include +# ifdef __svr4__ +# include +# else +# include +# endif +#endif + +#ifdef BSD +# ifdef sun +# include +# endif +# ifdef __alpha +# include +# else +# include +# endif +#endif + +#ifdef __hpux +# define _INCLUDE_HPUX_SOURCE +# include +# undef _INCLUDE_HPUX_SOURCE +#endif + +#include "host.h" +#include "unixcomm.h" + +#define PP_TIMEOUT 1 /* seconds */ + +#ifdef sun +#define SERPORT1 "/dev/ttya" +#define SERPORT2 "/dev/ttyb" +#define PARPORT1 "/dev/bpp0" +#define PARPORT2 "/dev/bpp1" +#endif + +#ifdef __hpux +#define SERPORT1 "/dev/tty00" +#define SERPORT2 "/dev/tty01" +#define PARPORT1 "/dev/ptr_parallel" +#define PARPORT2 "/dev/ptr_parallel" +#endif + +#ifdef __linux__ +#define SERPORT1 "/dev/cua0" +#define SERPORT2 "/dev/cua1" +#define PARPORT1 "/dev/par0" +#define PARPORT2 "/dev/par1" +#endif + +#ifdef _WIN32 +#define SERPORT1 "com1" +#define SERPORT2 "com2" +#define PARPORT1 "lpt1" +#define PARPORT2 "lpt2" +#endif + +/* + * Parallel port output pins, used for signalling to target + */ + +#ifdef sun +struct bpp_pins bp; +#endif + +static int serpfd = -1; +static int parpfd = -1; + +extern const char *Unix_MatchValidSerialDevice(const char *name) +{ + int i=0; + char *sername=NULL; + + /* Accept no name as the default serial port */ + if (name == NULL) { + return SERPORT1; + } + + /* Look for the simple cases - 1,2,s,S,/dev/... first, and + * afterwards look for S=... clauses, which need parsing properly. + */ + + /* Accept /dev/tty* where * is limited */ + if (strlen(name) == strlen(SERPORT1) && strncmp(name, "/dev/tty", 8) == 0) return name; + + /* Accept "1" or "2" or "S" - S is equivalent to "1" */ + if (strcmp(name, "1") == 0 || + strcmp(name, "S") == 0 || strcmp(name, "s") == 0) { + return SERPORT1; + } + if (strcmp(name, "2") == 0) return SERPORT2; + + /* It wasn't one of the simple cases, so now we have to parse it + * properly + */ + + do { + switch (name[i]) { + case ',': + /* Skip over commas */ + i++; + break; + + default: + return 0; + /* Unexpected character => error - not matched */ + + case 0: + /* End of string means return whatever we have matched */ + return sername; + + case 's': + case 'S': + case 'h': + case 'H': { + char ch = tolower(name[i]); + int j, continue_from, len; + + /* If the next character is a comma or a NULL then this is + * a request for the default Serial port + */ + if (name[++i] == 0 || name[i] == ',') { + if (ch=='s') + sername=SERPORT1; + break; + } + + /* Next character must be an = */ + if (name[i] != '=') return 0; + /* Search for the end of the port spec. (ends in NULL or ,) */ + for (j= ++i; name[j] != 0 && name[j] != ','; j++) + ; /* Do nothing */ + /* Notice whether this is the last thing to parse or not + * and also calaculate the length of the string + */ + if (name[j] == '0') continue_from = -1; + else continue_from = j; + len=(j-i); + + /* And now try to match the serial / parallel port */ + switch (ch) { + case 's': { + /* Match serial port */ + if (len==1) { + if (name[i]=='1') + sername=SERPORT1; + else if (name[i]=='2') + sername=SERPORT2; + } else if (len==strlen(SERPORT1)) { + if (strncmp(name+i,SERPORT1,strlen(SERPORT1)) == 0) + sername=SERPORT1; + else if (strncmp(name+i,SERPORT2,strlen(SERPORT2)) == 0) + sername=SERPORT2; + } + + break; + } + + case 'h': + /* We don't actually deal with the H case here, we just + * match it and allow it through. + */ + break; + } + + if (continue_from == -1) return sername; + i = continue_from; + break; + } + } + } while (1); + + return 0; +} + + +extern int Unix_IsSerialInUse(void) +{ + if (serpfd >= 0) + return -1; + + return 0; +} + +extern int Unix_OpenSerial(const char *name) +{ +#if defined(BSD) + serpfd = open(name, O_RDWR); +#else + serpfd = open(name, O_RDWR | O_NONBLOCK); +#endif + + if (serpfd < 0) { + perror("open"); + return -1; + } + + return 0; +} + +extern void Unix_CloseSerial(void) +{ + if (serpfd >= 0) + { + (void)close(serpfd); + serpfd = -1; + } +} + +extern int Unix_ReadSerial(unsigned char *buf, int n, bool block) +{ + fd_set fdset; + struct timeval tv; + int err; + + FD_ZERO(&fdset); + FD_SET(serpfd, &fdset); + + tv.tv_sec = 0; + tv.tv_usec = (block ? 10000 : 0); + + err = select(serpfd + 1, &fdset, NULL, NULL, &tv); + + if (err < 0 && errno != EINTR) + { +#ifdef DEBUG + perror("select"); +#endif + panic("select failure"); + return -1; + } + else if (err > 0 && FD_ISSET(serpfd, &fdset)) + return read(serpfd, buf, n); + else /* err == 0 || FD_CLR(serpfd, &fdset) */ + { + errno = ERRNO_FOR_BLOCKED_IO; + return -1; + } +} + +extern int Unix_WriteSerial(unsigned char *buf, int n) +{ + return write(serpfd, buf, n); +} + +extern void Unix_ResetSerial(void) +{ + struct termios terminfo; + + tcgetattr(serpfd, &terminfo); +#ifdef __CYGWIN32__ + /* Expedient, but it works. */ + terminfo.c_iflag = 0; + terminfo.c_oflag = 0; + terminfo.c_cflag = 48; + terminfo.c_lflag = 0; + terminfo.c_cc[VMIN] = 0; + terminfo.c_cc[VTIME] = 1; +#else + terminfo.c_lflag &= ~(ICANON | ISIG | ECHO | IEXTEN); + terminfo.c_iflag &= ~(IGNCR | INPCK | ISTRIP | ICRNL | BRKINT); + terminfo.c_iflag |= (IXON | IXOFF | IGNBRK); + terminfo.c_cflag = (terminfo.c_cflag & ~CSIZE) | CS8 | CREAD; + terminfo.c_cflag &= ~PARENB; + terminfo.c_cc[VMIN] = 1; + terminfo.c_cc[VTIME] = 0; + terminfo.c_oflag &= ~OPOST; +#endif + tcsetattr(serpfd, TCSAFLUSH, &terminfo); +} + +extern void Unix_SetSerialBaudRate(int baudrate) +{ + struct termios terminfo; + + tcgetattr(serpfd, &terminfo); + cfsetospeed(&terminfo, baudrate); + cfsetispeed(&terminfo, baudrate); + tcsetattr(serpfd, TCSAFLUSH, &terminfo); +} + +extern void Unix_ioctlNonBlocking(void) +{ +#if defined(BSD) + int nonblockingIO = 1; + (void)ioctl(serpfd, FIONBIO, &nonblockingIO); + + if (parpfd != -1) + (void)ioctl(parpfd, FIONBIO, &nonblockingIO); +#endif +} + +extern void Unix_IsValidParallelDevice( + const char *portstring, char **sername, char **parname) +{ + int i=0; + *sername=NULL; + *parname=NULL; + + /* Do not recognise a NULL portstring */ + if (portstring==NULL) return; + + do { + switch (portstring[i]) { + case ',': + /* Skip over commas */ + i++; + break; + + default: + case 0: + /* End of string or bad characcter means we have finished */ + return; + + case 's': + case 'S': + case 'p': + case 'P': + case 'h': + case 'H': { + char ch = tolower(portstring[i]); + int j, continue_from, len; + + /* If the next character is a comma or a NULL then this is + * a request for the default Serial or Parallel port + */ + if (portstring[++i] == 0 || portstring[i] == ',') { + if (ch=='s') *sername=SERPORT1; + else if (ch=='p') *parname=PARPORT1; + break; + } + + /* Next character must be an = */ + if (portstring[i] != '=') return; + /* Search for the end of the port spec. (ends in NULL or ,) */ + for (j= ++i; portstring[j] != 0 && portstring[j] != ','; j++) + ; /* Do nothing */ + /* Notice whether this is the last thing to parse or not + * and also calaculate the length of the string + */ + if (portstring[j] == '0') continue_from = -1; + else continue_from = j; + len=(j-i); + + /* And now try to match the serial / parallel port */ + switch (ch) { + case 's': { + /* Match serial port */ + if (len==1) { + if (portstring[i]=='1') *sername=SERPORT1; + else if (portstring[i]=='2') *sername=SERPORT2; + } else if (len==strlen(SERPORT1)) { + if (strncmp(portstring+i,SERPORT1,strlen(SERPORT1)) == 0) + *sername=SERPORT1; + else if (strncmp(portstring+i,SERPORT2,strlen(SERPORT2)) == 0) + *sername=SERPORT2; + } + break; + } + + case 'p': { + /* Match parallel port */ + if (len==1) { + if (portstring[i]=='1') *parname=PARPORT1; + else if (portstring[i]=='2') *parname=PARPORT2; + } else if (len==strlen(PARPORT1)) { + if (strncmp(portstring+i,PARPORT1,strlen(PARPORT1)) == 0) + *parname=PARPORT1; + else if (strncmp(portstring+i,PARPORT2,strlen(PARPORT2)) == 0) + *parname=PARPORT2; + } + break; + } + + case 'h': + /* We don't actually deal with the H case here, we just + * match it and allow it through. + */ + break; + } + + if (continue_from == -1) return; + i = continue_from; + break; + } + } + } while (1); + return; /* Will never get here */ +} + +extern int Unix_IsParallelInUse(void) +{ + if (parpfd >= 0) + return -1; + + return 0; +} + +extern int Unix_OpenParallel(const char *name) +{ +#if defined(BSD) + parpfd = open(name, O_RDWR); +#else + parpfd = open(name, O_RDWR | O_NONBLOCK); +#endif + + if (parpfd < 0) + { + char errbuf[256]; + + sprintf(errbuf, "open %s", name); + perror(errbuf); + + return -1; + } + + return 0; +} + +extern void Unix_CloseParallel(void) +{ + if (parpfd >= 0) + { + (void)close(parpfd); + parpfd = -1; + } +} + + +extern unsigned int Unix_WriteParallel(unsigned char *buf, int n) +{ + int ngone; + + if ((ngone = write(parpfd, buf, n)) < 0) + { + /* + * we ignore errors (except for debug purposes) + */ +#ifdef DEBUG + char errbuf[256]; + + sprintf(errbuf, "send_packet: write"); + perror(errbuf); +#endif + ngone = 0; + } + + /* finished */ + return (unsigned int)ngone; +} + + +#ifdef sun +extern void Unix_ResetParallel(void) +{ + struct bpp_transfer_parms tp; + +#ifdef DEBUG + printf("serpar_reset\n"); +#endif + + /* + * we need to set the parallel port up for BUSY handshaking, + * and select the timeout + */ + if (ioctl(parpfd, BPPIOC_GETPARMS, &tp) < 0) + { +#ifdef DEBUG + perror("ioctl(BPPIOCGETPARMS)"); +#endif + panic("serpar_reset: cannot get BPP parameters"); + } + + tp.write_handshake = BPP_BUSY_HS; + tp.write_timeout = PP_TIMEOUT; + + if (ioctl(parpfd, BPPIOC_SETPARMS, &tp) < 0) + { +#ifdef DEBUG + perror("ioctl(BPPIOC_SETPARMS)"); +#endif + panic("serpar_reset: cannot set BPP parameters"); + } +} + +#else + +/* Parallel not supported on HP */ + +extern void Unix_ResetParallel(void) +{ +} + +#endif + diff --git a/gdb/rdi-share/unixcomm.h b/gdb/rdi-share/unixcomm.h new file mode 100644 index 00000000000..baa65520392 --- /dev/null +++ b/gdb/rdi-share/unixcomm.h @@ -0,0 +1,212 @@ +/* + * Copyright (C) 1995 Advanced RISC Machines Limited. All rights reserved. + * + * This software may be freely used, copied, modified, and distributed + * provided that the above copyright notice is preserved in all copies of the + * software. + */ + +/* -*-C-*- + * + * $Revision$ + * $Date$ + * + */ +#ifndef angsd_unixcomm_h +#define angsd_unixcomm_h + +#include + +#if defined(BSD) +# define ERRNO_FOR_BLOCKED_IO EWOULDBLOCK +#else +# define ERRNO_FOR_BLOCKED_IO EAGAIN +#endif + +/* + * Function: Unix_MatchValidSerialDevice + * Purpose: check that the serial driver/port name is valid + * and return the actual device name if it is. + * + * Params: + * Input: name Name of device going to be used + * + * Returns: + * OK: Pointer to name of the device matched + * Error or unrecognised deivce: 0 + */ +extern const char *Unix_MatchValidSerialDevice(const char *name); + +/* + * Function: Unix_IsSerialInUse + * Purpose: check whether the serial port is in use + * + * Params: + * Input: Nothing + * + * Returns: + * OK: 0 Serial device not in use + * Error: -1 Serial device in use + */ +extern int Unix_IsSerialInUse(void); + +/* + * Function: Unix_OpenSerial + * Purpose: open the serial port + * + * Params: + * Input: name Name of device to open + * + * Returns: Unix 'open' returns + */ +extern int Unix_OpenSerial(const char *name); + +/* + * Function: Unix_CloseSerial + * Purpose: close the serial port + * + * Params: + * Input: Nothing + * + * Returns: Nothing + */ +extern void Unix_CloseSerial(void); + +/* + * Function: Unix_ReadSerial + * Purpose: reads a specified number of bytes (or less) from the serial port + * + * Params: + * Input: buf Buffer to store read bytes + * n Maximum number of bytes to read + * + * Returns: Unix 'read' returns + */ +extern int Unix_ReadSerial(unsigned char *buf, int n, bool block); + +/* + * Function: Unix_WriteSerial + * Purpose: writes a specified number of bytes (or less) to the serial port + * + * Params: + * Input: buf Buffer to write bytes from + * n Maximum number of bytes to write + * + * Returns: Unix 'write' returns + */ +extern int Unix_WriteSerial(unsigned char *buf, int n); + +/* + * Function: Unix_ResetSerial + * Purpose: resets the serial port for another operation + * + * Params: + * Input: Nothing + * + * Returns: Nothing + */ +extern void Unix_ResetSerial(void); + +/* + * Function: Unix_SetSerialBaudRate + * Purpose: check that the serial driver/port name is valid + * + * Params: + * Input: baudrate termios value for baud rate + * + * Returns: Nothing + */ +extern void Unix_SetSerialBaudRate(int baudrate); + +/* + * Function: Unix_ioctlNonBlocking + * Purpose: sets the serial port to non-blocking IO + * + * Params: + * Input: Nothing + * + * Returns: Nothing + */ +extern void Unix_ioctlNonBlocking(void); + +/* + * Function: Unix_IsValidParallelDevice + * Purpose: check whether the combined serial and parallel device specification + * is ok, and return the ports selected + * + * Params: + * Input: portstring - is a string which specifies which serial + * and parallel ports are to be used. Can + * include s= and p= separated by a + * comma. + * + * Returns: + * Output: *sername - returns the device name of the chosen serial port + * *parname - returns the device name of the chosen parallel port + * If either of these is NULL on return then the match failed. + */ +extern void Unix_IsValidParallelDevice( + const char *portstring, char **sername, char **parname +); + +/* + * Function: Unix_IsParallelInUse + * Purpose: check whether the parallel port is in use + * + * Params: + * Input: Nothing + * + * Returns: + * OK: 0 Parallel device not in use + * Error: -1 Parallel device in use + */ +extern int Unix_IsParallelInUse(void); + +/* + * Function: Unix_OpenParallel + * Purpose: open the parallel port + * + * Params: + * Input: name Name of device to open + * + * Returns: Unix 'open' returns + */ +extern int Unix_OpenParallel(const char *name); + +/* + * Function: Unix_CloseParallel + * Purpose: close the parallel port + * + * Params: + * Input: Nothing + * + * Returns: Nothing + */ +extern void Unix_CloseParallel(void); + +/* + * Function: Unix_WriteParallel + * Purpose: writes a specified number of bytes (or less) to the parallel port + * + * Params: + * Input: buf Buffer to write bytes from + * n Maximum number of bytes to write + * + * Returns: Unix 'write' returns + */ +extern unsigned int Unix_WriteParallel(unsigned char *buf, int n); + +/* + * Function: Unix_ResetParallel + * Purpose: resets the parallel port for another operation + * + * Params: + * Input: Nothing + * + * Returns: Nothing + */ +extern void Unix_ResetParallel(void); + +#endif /* ndef angsd_unixcomm_h */ + +/* EOF unixcomm.h */ diff --git a/gdb/remote-rdi.c b/gdb/remote-rdi.c new file mode 100644 index 00000000000..19cedd312c5 --- /dev/null +++ b/gdb/remote-rdi.c @@ -0,0 +1,966 @@ +/* GDB interface to ARM RDI library. + Copyright 1997 Free Software Foundation, Inc. + +This file is part of GDB. + +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. */ + + +#include "defs.h" +#include "gdb_string.h" +#include +#include "frame.h" +#include "inferior.h" +#include "bfd.h" +#include "symfile.h" +#include "target.h" +#include "wait.h" +#include "gdbcmd.h" +#include "objfiles.h" +#include "gdb-stabs.h" +#include "gdbthread.h" +#include "gdbcore.h" + +#ifdef USG +#include +#endif + +#include + +#include "rdi-share/ardi.h" +#include "rdi-share/adp.h" +#include "rdi-share/hsys.h" + +/* Prototypes for local functions */ + +static void arm_rdi_files_info PARAMS ((struct target_ops *ignore)); + +static int arm_rdi_xfer_memory PARAMS ((CORE_ADDR memaddr, char *myaddr, + int len, int should_write, + struct target_ops *target)); + +static void arm_rdi_prepare_to_store PARAMS ((void)); + +static void arm_rdi_fetch_registers PARAMS ((int regno)); + +static void arm_rdi_resume PARAMS ((int pid, int step, + enum target_signal siggnal)); + +static int arm_rdi_start_remote PARAMS ((char *dummy)); + +static void arm_rdi_open PARAMS ((char *name, int from_tty)); + +static void arm_rdi_create_inferior PARAMS ((char *exec_file, char *args, + char **env)); + +static void arm_rdi_close PARAMS ((int quitting)); + +static void arm_rdi_store_registers PARAMS ((int regno)); + +static void arm_rdi_mourn PARAMS ((void)); + +static void arm_rdi_send PARAMS ((char *buf)); + +static int arm_rdi_wait PARAMS ((int pid, struct target_waitstatus *status)); + +static void arm_rdi_kill PARAMS ((void)); + +static void arm_rdi_detach PARAMS ((char *args, int from_tty)); + +static void arm_rdi_interrupt PARAMS ((int signo)); + +static void arm_rdi_interrupt_twice PARAMS ((int signo)); + +static void interrupt_query PARAMS ((void)); + +static int arm_rdi_insert_breakpoint PARAMS ((CORE_ADDR, char *)); + +static int arm_rdi_remove_breakpoint PARAMS ((CORE_ADDR, char *)); + +static char *rdi_error_message PARAMS ((int err)); + +static enum target_signal rdi_error_signal PARAMS ((int err)); + +extern struct target_ops arm_rdi_ops; /* Forward decl */ + +static struct Dbg_ConfigBlock gdb_config; + +static struct Dbg_HostosInterface gdb_hostif; + +static int max_load_size; + +static int execute_status; + +/* A little list of breakpoints that have been set. */ + +static struct local_bp_list_entry { + CORE_ADDR addr; + PointHandle point; + struct local_bp_list_entry *next; +} *local_bp_list; + + +/* Stub for catch_errors. */ + +static int +arm_rdi_start_remote (dummy) + char *dummy; +{ + return 1; +} + +/* Helper callbacks for the "host interface" structure. RDI functions call + these to forward output from the target system and so forth. */ + +void +voiddummy() +{ + printf("void dummy\n"); +} + +static void +myprint (arg, format, ap) + PTR arg; + const char *format; + va_list ap; +{ + vfprintf (stdout, format, ap); +} + +static void +mywritec (arg, c) + PTR arg; + int c; +{ + fputc (c, (FILE *) arg); +} + +static int +mywrite (arg, buffer, len) + PTR arg; + char const *buffer; + int len; +{ + return fwrite (buffer, 1, len, stdout); +} + +static void +mypause (arg) + PTR arg; +{ +} + +/* These last two are tricky as we have to handle the special case of + being interrupted more carefully */ + +static int +myreadc (arg) + PTR arg; +{ + return fgetc (stdin); +} + +static char * +mygets (arg, buffer, len) + PTR arg; + char *buffer; + int len; +{ + return fgets(buffer, len, stdin); +} + +/* Open a connection to a remote debugger. NAME is the filename used + for communication. */ + +static void +arm_rdi_open (name, from_tty) + char *name; + int from_tty; +{ + int rslt, i; + unsigned long arg1, arg2; + + if (name == NULL) + error ("To open an RDI connection, you need to specify what serial\n\ +device is attached to the remote system (e.g. /dev/ttya)."); + + /* Make the basic low-level connection. */ + + rslt = Adp_OpenDevice (NULL, NULL, 1); + + if (rslt != adp_ok) + error ("Could not open port"); + + gdb_config.bytesex = 2 | (target_byte_order == BIG_ENDIAN ? 1 : 0); + gdb_config.fpe = 1; + gdb_config.rditype = 2; + gdb_config.heartbeat_on = 1; + gdb_config.flags = 2; + + gdb_hostif.dbgprint = myprint; + gdb_hostif.dbgpause = mypause; + gdb_hostif.dbgarg = stdout; + gdb_hostif.writec = mywritec; + gdb_hostif.readc = myreadc; + gdb_hostif.write = mywrite; + gdb_hostif.gets = mygets; + gdb_hostif.hostosarg = stdout; + gdb_hostif.reset = voiddummy; + + rslt = angel_RDI_open (10, &gdb_config, &gdb_hostif, NULL); + if (rslt == RDIError_BigEndian || rslt == RDIError_LittleEndian) + ; /* do nothing, this is the expected return */ + else if (rslt) + { + printf_filtered ("RDI_open: %s\n", rdi_error_message (rslt)); + } + + rslt = angel_RDI_info (RDIInfo_Target, &arg1, &arg2); + if (rslt) + { + printf_filtered ("RDI_info: %s\n", rdi_error_message (rslt)); + } + rslt = angel_RDI_info (RDIInfo_Points, &arg1, &arg2); + if (rslt) + { + printf_filtered ("RDI_info: %s\n", rdi_error_message (rslt)); + } + rslt = angel_RDI_info (RDIInfo_Step, &arg1, &arg2); + if (rslt) + { + printf_filtered ("RDI_info: %s\n", rdi_error_message (rslt)); + } + rslt = angel_RDI_info (RDIInfo_CoPro, &arg1, &arg2); + if (rslt) + { + printf_filtered ("RDI_info: %s\n", rdi_error_message (rslt)); + } + rslt = angel_RDI_info (RDIInfo_SemiHosting, &arg1, &arg2); + if (rslt) + { + printf_filtered ("RDI_info: %s\n", rdi_error_message (rslt)); + } + rslt = angel_RDI_info (RDIInfo_Icebreaker, &arg1, &arg2); + if (rslt) + { + printf_filtered ("RDI_info: %s\n", rdi_error_message (rslt)); + } + rslt = angel_RDI_info (RDIInfo_DownLoad, &arg1, &arg2); + if (rslt) + { + printf_filtered ("RDI_info: %s\n", rdi_error_message (rslt)); + } + rslt = angel_RDI_info (RDIInfo_GetLoadSize, &arg1, &arg2); + if (rslt) + { + printf_filtered ("RDI_info: %s\n", rdi_error_message (rslt)); + } + max_load_size = arg1; + + push_target (&arm_rdi_ops); + + target_fetch_registers (-1); + + rslt = angel_RDI_open (1, &gdb_config, NULL, NULL); + if (rslt) + { + printf_filtered ("RDI_open: %s\n", rdi_error_message (rslt)); + } + + arg1 = 0x13b; + rslt = angel_RDI_info (RDIVector_Catch, &arg1, &arg2); + if (rslt) + { + printf_filtered ("RDI_info: %s\n", rdi_error_message (rslt)); + } + + arg1 = (unsigned long) ""; + rslt = angel_RDI_info (RDISet_Cmdline, &arg1, &arg2); + if (rslt) + { + printf_filtered ("RDI_info: %s\n", rdi_error_message (rslt)); + } + + /* Clear out any existing records of breakpoints. */ + { + struct local_bp_list_entry *entry, *preventry = NULL; + + for (entry = local_bp_list; entry != NULL; entry = entry->next) + { + if (preventry) + free (preventry); + } + } + + printf_filtered ("Connected to ARM RDI target.\n"); +} + +/* Start an inferior process and set inferior_pid to its pid. + EXEC_FILE is the file to run. + ARGS is a string containing the arguments to the program. + ENV is the environment vector to pass. Errors reported with error(). + On VxWorks and various standalone systems, we ignore exec_file. */ +/* This is called not only when we first attach, but also when the + user types "run" after having attached. */ + +static void +arm_rdi_create_inferior (exec_file, args, env) + char *exec_file; + char *args; + char **env; +{ + int len, rslt; + unsigned long arg1, arg2; + char *arg_buf; + CORE_ADDR entry_point; + + if (exec_file == 0 || exec_bfd == 0) + error ("No exec file specified."); + + entry_point = (CORE_ADDR) bfd_get_start_address (exec_bfd); + + arm_rdi_kill (); + remove_breakpoints (); + init_wait_for_inferior (); + + len = strlen (exec_file) + 1 + strlen (args) + 1 + /*slop*/ 10; + arg_buf = (char *) alloca (len); + arg_buf[0] = '\0'; + strcat (arg_buf, exec_file); + strcat (arg_buf, " "); + strcat (arg_buf, args); + + inferior_pid = 42; + insert_breakpoints (); /* Needed to get correct instruction in cache */ + + if ( env != NULL) + { + while (*env) + { + if (strncmp(*env, "MEMSIZE=", sizeof("MEMSIZE=")-1)==0) + { + unsigned long top_of_memory; + char *end_of_num; + + /* Set up memory limit */ + top_of_memory = strtoul(*env + sizeof("MEMSIZE=")-1, + &end_of_num, 0); + printf_filtered ("Setting top-of-memory to 0x%x\n", + top_of_memory); + + rslt=angel_RDI_info (RDIInfo_SetTopMem, &top_of_memory, &arg2); + if (rslt) + { + printf_filtered ("RDI_info: %s\n", rdi_error_message (rslt)); + } + } + env++; + } + } + + arg1 = (unsigned long) arg_buf; + rslt = angel_RDI_info (RDISet_Cmdline, /* &arg1 */ (unsigned long *)arg_buf, &arg2); + if (rslt) + { + printf_filtered ("RDI_info: %s\n", rdi_error_message (rslt)); + } + + proceed (entry_point, TARGET_SIGNAL_DEFAULT, 0); +} + +/* This takes a program previously attached to and detaches it. After + this is done, GDB can be used to debug some other program. We + better not have left any breakpoints in the target program or it'll + die when it hits one. */ + +static void +arm_rdi_detach (args, from_tty) + char *args; + int from_tty; +{ + /* (anything to do?) */ +} + +/* Clean up connection to a remote debugger. */ + +static void +arm_rdi_close (quitting) + int quitting; +{ + int rslt; + + rslt = angel_RDI_close (); + if (rslt) + { + printf_filtered ("RDI_close: %s\n", rdi_error_message (rslt)); + } +} + +/* Tell the remote machine to resume. */ + +static void +arm_rdi_resume (pid, step, siggnal) + int pid, step; + enum target_signal siggnal; +{ + int rslt; + PointHandle point; + + if (0 /* turn on when hardware supports single-stepping */) + { + rslt = angel_RDI_step (1, &point); + if (rslt) + { + printf_filtered ("RDI_step: %s\n", rdi_error_message (rslt)); + } + } + else + { + char handle[4]; + CORE_ADDR pc; + + if (step) + { + pc = read_register (PC_REGNUM); + pc = arm_get_next_pc (pc); + arm_rdi_insert_breakpoint (pc, handle); + } + execute_status = rslt = angel_RDI_execute (&point); + if (rslt == RDIError_BreakpointReached) + ; + else if (rslt) + { + printf_filtered ("RDI_execute: %s\n", rdi_error_message (rslt)); + } + if (step) + { + arm_rdi_remove_breakpoint (pc, handle); + } + } +} + +/* Send ^C to target to halt it. Target will respond, and send us a + packet. */ + +static void +arm_rdi_interrupt (signo) + int signo; +{ +} + +static void (*ofunc)(); + +/* The user typed ^C twice. */ +static void +arm_rdi_interrupt_twice (signo) + int signo; +{ +} + +/* Ask the user what to do when an interrupt is received. */ + +static void +interrupt_query () +{ +} + +/* Wait until the remote machine stops, then return, storing status in + STATUS just as `wait' would. Returns "pid" (though it's not clear + what, if anything, that means in the case of this target). */ + +static int +arm_rdi_wait (pid, status) + int pid; + struct target_waitstatus *status; +{ + status->kind = execute_status == RDIError_NoError ? + TARGET_WAITKIND_EXITED : TARGET_WAITKIND_STOPPED; + + /* convert stopped code from target into right signal */ + status->value.sig = rdi_error_signal ( execute_status ); + + return inferior_pid; +} + +/* Read the remote registers into the block REGS. */ + +/* ARGSUSED */ +static void +arm_rdi_fetch_registers (regno) + int regno; +{ + int rslt, rdi_regmask; + unsigned long rawreg, rawregs[32]; + char cookedreg[4]; + + if (regno == -1) + { + rslt = angel_RDI_CPUread (255, 0x27fff, rawregs); + if (rslt) + { + printf_filtered ("RDI_CPUread: %s\n", rdi_error_message (rslt)); + } + + for (regno = 0; regno < 15; regno++) + { + store_unsigned_integer (cookedreg, 4, rawregs[regno]); + supply_register (regno, (char *) cookedreg); + } + store_unsigned_integer (cookedreg, 4, rawregs[15]); + supply_register (PS_REGNUM, (char *) cookedreg); + arm_rdi_fetch_registers (PC_REGNUM); + } + else + { + if (regno == PC_REGNUM) + rdi_regmask = RDIReg_PC; + else if (regno == PS_REGNUM) + rdi_regmask = RDIReg_CPSR; + else if (regno < 0 || regno > 15) + { + rawreg = 0; + supply_register (regno, (char *) &rawreg); + return; + } + else + rdi_regmask = 1 << regno; + + rslt = angel_RDI_CPUread (255, rdi_regmask, &rawreg); + if (rslt) + { + printf_filtered ("RDI_CPUread: %s\n", rdi_error_message (rslt)); + } + store_unsigned_integer (cookedreg, 4, rawreg); + supply_register (regno, (char *) cookedreg); + } +} + +static void +arm_rdi_prepare_to_store () +{ + /* Nothing to do. */ +} + +/* Store register REGNO, or all registers if REGNO == -1, from the contents + of REGISTERS. FIXME: ignores errors. */ + +static void +arm_rdi_store_registers (regno) + int regno; +{ + int rslt, rdi_regmask; + + /* These need to be able to take 'floating point register' contents */ + unsigned long rawreg[3], rawerreg[3]; + + if (regno == -1) + { + for (regno = 0; regno < NUM_REGS; regno++) + arm_rdi_store_registers (regno); + } + else + { + read_register_gen (regno, (char *) rawreg); + /* RDI manipulates data in host byte order, so convert now. */ + store_unsigned_integer (rawerreg, 4, rawreg[0]); + + if (regno == PC_REGNUM) + rdi_regmask = RDIReg_PC; + else if (regno == PS_REGNUM) + rdi_regmask = RDIReg_CPSR; + else if (regno < 0 || regno > 15) + return; + else + rdi_regmask = 1 << regno; + + rslt = angel_RDI_CPUwrite (255, rdi_regmask, rawerreg); + if (rslt) + { + printf_filtered ("RDI_CPUwrite: %s\n", rdi_error_message (rslt)); + } + } +} + +/* Read or write LEN bytes from inferior memory at MEMADDR, + transferring to or from debugger address MYADDR. Write to inferior + if SHOULD_WRITE is nonzero. Returns length of data written or + read; 0 for error. */ + +/* ARGSUSED */ +static int +arm_rdi_xfer_memory(memaddr, myaddr, len, should_write, target) + CORE_ADDR memaddr; + char *myaddr; + int len; + int should_write; + struct target_ops *target; /* ignored */ +{ + int rslt, i; + + if (should_write) + { + rslt = angel_RDI_write (myaddr, memaddr, &len); + if (rslt) + { + printf_filtered ("RDI_write: %s\n", rdi_error_message (rslt)); + } + } + else + { + rslt = angel_RDI_read (memaddr, myaddr, &len); + if (rslt) + { + printf_filtered ("RDI_read: %s\n", rdi_error_message (rslt)); + len = 0; + } + } + return len; +} + +/* Display random info collected from the target. */ + +static void +arm_rdi_files_info (ignore) + struct target_ops *ignore; +{ + char *file = "nothing"; + int rslt; + unsigned long arg1, arg2; + + rslt = angel_RDI_info (RDIInfo_Target, &arg1, &arg2); + if (rslt) + { + printf_filtered ("RDI_info: %s\n", rdi_error_message (rslt)); + } + if (arg1 & (1 << 15)) + printf_filtered ("Target supports Thumb code.\n"); + if (arg1 & (1 << 14)) + printf_filtered ("Target can do profiling.\n"); + if (arg1 & (1 << 4)) + printf_filtered ("Target is real hardware.\n"); + + rslt = angel_RDI_info (RDIInfo_Step, &arg1, &arg2); + if (rslt) + { + printf_filtered ("RDI_info: %s\n", rdi_error_message (rslt)); + } + printf_filtered ("Target can%s single-step.\n", (arg1 & 0x4 ? "" : "not")); + + rslt = angel_RDI_info (RDIInfo_Icebreaker, &arg1, &arg2); + if (rslt) + { + printf_filtered ("RDI_info: %s\n", rdi_error_message (rslt)); + } + else + printf_filtered ("Target includes an EmbeddedICE.\n"); +} + +static void +arm_rdi_kill () +{ + int rslt; + + rslt = angel_RDI_open (1, &gdb_config, NULL, NULL); + if (rslt) + { + printf_filtered ("RDI_open: %s\n", rdi_error_message (rslt)); + } +} + +static void +arm_rdi_mourn_inferior () +{ + unpush_target (&arm_rdi_ops); + generic_mourn_inferior (); +} + +/* While the RDI library keeps track of its own breakpoints, we need + to remember "handles" so that we can delete them later. Since + breakpoints get used for stepping, be careful not to leak memory + here. */ + +static int +arm_rdi_insert_breakpoint (addr, contents_cache) + CORE_ADDR addr; + char *contents_cache; +{ + int rslt; + PointHandle point; + struct local_bp_list_entry *entry; + int type = RDIPoint_EQ; + + if (arm_pc_is_thumb (addr) || arm_pc_is_thumb_dummy (addr)) + type |= RDIPoint_16Bit; + rslt = angel_RDI_setbreak (addr, type, 0, &point); + if (rslt) + { + printf_filtered ("RDI_setbreak: %s\n", rdi_error_message (rslt)); + } + entry = + (struct local_bp_list_entry *) xmalloc (sizeof (struct local_bp_list_entry)); + entry->addr = addr; + entry->point = point; + entry->next = local_bp_list; + local_bp_list = entry; + return rslt; +} + +static int +arm_rdi_remove_breakpoint (addr, contents_cache) + CORE_ADDR addr; + char *contents_cache; +{ + int rslt; + PointHandle point; + struct local_bp_list_entry *entry, *preventry; + + for (entry = local_bp_list; entry != NULL; entry = entry->next) + { + if (entry->addr == addr) + { + break; + } + preventry = entry; + } + if (entry) + { + rslt = angel_RDI_clearbreak (entry->point); + if (rslt) + { + printf_filtered ("RDI_clearbreak: %s\n", rdi_error_message (rslt)); + } + /* Delete the breakpoint entry locally. */ + if (entry == local_bp_list) + { + local_bp_list = entry->next; + } + else + { + preventry->next = entry->next; + } + free (entry); + } + return 0; +} + +static char * +rdi_error_message (err) + int err; +{ + switch (err) + { + case RDIError_NoError: + return "no error"; + case RDIError_Reset: + return "debuggee reset"; + case RDIError_UndefinedInstruction: + return "undefined instruction"; + case RDIError_SoftwareInterrupt: + return "SWI trapped"; + case RDIError_PrefetchAbort: + return "prefetch abort, execution ran into unmapped memory?"; + case RDIError_DataAbort: + return "data abort, no memory at specified address?"; + case RDIError_AddressException: + return "address exception, access >26bit in 26bit mode"; + case RDIError_IRQ: + return "IRQ, interrupt trapped"; + case RDIError_FIQ: + return "FIQ, fast interrupt trapped"; + case RDIError_Error: + return "a miscellaneous type of error"; + case RDIError_BranchThrough0: + return "branch through location 0"; + case RDIError_NotInitialised: + return "internal error, RDI_open not called first"; + case RDIError_UnableToInitialise: + return "internal error, target world is broken"; + case RDIError_WrongByteSex: + return "See Operator: WrongByteSex"; + case RDIError_UnableToTerminate: + return "See Operator: Unable to Terminate"; + case RDIError_BadInstruction: + return "bad instruction, illegal to execute this instruction"; + case RDIError_IllegalInstruction: + return "illegal instruction, the effect of executing it is undefined"; + case RDIError_BadCPUStateSetting: + return "internal error, tried to set SPSR of user mode"; + case RDIError_UnknownCoPro: + return "unknown co-processor"; + case RDIError_UnknownCoProState: + return "cannot execute co-processor request"; + case RDIError_BadCoProState: + return "recognizably broken co-processor request"; + case RDIError_BadPointType: + return "internal error, bad point yype"; + case RDIError_UnimplementedType: + return "internal error, unimplemented type"; + case RDIError_BadPointSize: + return "internal error, bad point size"; + case RDIError_UnimplementedSize: + return "internal error, unimplemented size"; + case RDIError_NoMorePoints: + return "last break/watch point was used"; + case RDIError_BreakpointReached: + return "breakpoint reached"; + case RDIError_WatchpointAccessed: + return "watchpoint accessed"; + case RDIError_NoSuchPoint: + return "attempted to clear non-existent break/watch point"; + case RDIError_ProgramFinishedInStep: + return "end of the program reached while stepping"; + case RDIError_UserInterrupt: + return "you pressed Escape"; + case RDIError_CantSetPoint: + return "no more break/watch points available"; + case RDIError_IncompatibleRDILevels: + return "incompatible RDI levels"; + case RDIError_LittleEndian: + return "debuggee is little endian"; + case RDIError_BigEndian: + return "debuggee is big endian"; + case RDIError_SoftInitialiseError: + return "recoverable error in RDI initialization"; + case RDIError_InsufficientPrivilege: + return "internal error, supervisor state not accessible to monitor"; + case RDIError_UnimplementedMessage: + return "internal error, unimplemented message"; + case RDIError_UndefinedMessage: + return "internal error, undefined message"; + default: + return "undefined error message, should reset target"; + } +} + +/* Convert the ARM error messages to signals that GDB knows about. */ + +static enum target_signal +rdi_error_signal (err) + int err; +{ + switch (err) + { + case RDIError_NoError: + return 0; + case RDIError_Reset: + return TARGET_SIGNAL_TERM; /* ??? */ + case RDIError_UndefinedInstruction: + return TARGET_SIGNAL_ILL; + case RDIError_SoftwareInterrupt: + case RDIError_PrefetchAbort: + case RDIError_DataAbort: + return TARGET_SIGNAL_TRAP; + case RDIError_AddressException: + return TARGET_SIGNAL_SEGV; + case RDIError_IRQ: + case RDIError_FIQ: + return TARGET_SIGNAL_TRAP; + case RDIError_Error: + return TARGET_SIGNAL_TERM; + case RDIError_BranchThrough0: + return TARGET_SIGNAL_TRAP; + case RDIError_NotInitialised: + case RDIError_UnableToInitialise: + case RDIError_WrongByteSex: + case RDIError_UnableToTerminate: + return TARGET_SIGNAL_UNKNOWN; + case RDIError_BadInstruction: + case RDIError_IllegalInstruction: + return TARGET_SIGNAL_ILL; + case RDIError_BadCPUStateSetting: + case RDIError_UnknownCoPro: + case RDIError_UnknownCoProState: + case RDIError_BadCoProState: + case RDIError_BadPointType: + case RDIError_UnimplementedType: + case RDIError_BadPointSize: + case RDIError_UnimplementedSize: + case RDIError_NoMorePoints: + return TARGET_SIGNAL_UNKNOWN; + case RDIError_BreakpointReached: + case RDIError_WatchpointAccessed: + return TARGET_SIGNAL_TRAP; + case RDIError_NoSuchPoint: + case RDIError_ProgramFinishedInStep: + return TARGET_SIGNAL_UNKNOWN; + case RDIError_UserInterrupt: + return TARGET_SIGNAL_INT; + case RDIError_IncompatibleRDILevels: + case RDIError_LittleEndian: + case RDIError_BigEndian: + case RDIError_SoftInitialiseError: + case RDIError_InsufficientPrivilege: + case RDIError_UnimplementedMessage: + case RDIError_UndefinedMessage: + default: + return TARGET_SIGNAL_UNKNOWN; + } +} + +/* Define the target operations structure. */ + +struct target_ops arm_rdi_ops = { + "rdi", /* to_shortname */ + "ARM RDI", /* to_longname */ + "Use a remote ARM-based computer, via the RDI library.\n\ +Specify the serial device it is connected to (e.g. /dev/ttya).", /* to_doc */ + arm_rdi_open, /* to_open */ + arm_rdi_close, /* to_close */ + NULL, /* to_attach */ + arm_rdi_detach, /* to_detach */ + arm_rdi_resume, /* to_resume */ + arm_rdi_wait, /* to_wait */ + arm_rdi_fetch_registers, /* to_fetch_registers */ + arm_rdi_store_registers, /* to_store_registers */ + arm_rdi_prepare_to_store, /* to_prepare_to_store */ + arm_rdi_xfer_memory, /* to_xfer_memory */ + arm_rdi_files_info, /* to_files_info */ + arm_rdi_insert_breakpoint, /* to_insert_breakpoint */ + arm_rdi_remove_breakpoint, /* to_remove_breakpoint */ + NULL, /* to_terminal_init */ + NULL, /* to_terminal_inferior */ + NULL, /* to_terminal_ours_for_output */ + NULL, /* to_terminal_ours */ + NULL, /* to_terminal_info */ + arm_rdi_kill, /* to_kill */ + generic_load, /* to_load */ + NULL, /* to_lookup_symbol */ + arm_rdi_create_inferior, /* to_create_inferior */ + arm_rdi_mourn_inferior, /* to_mourn_inferior */ + 0, /* to_can_run */ + 0, /* to_notice_signals */ + 0, /* to_thread_alive */ + 0, /* to_stop */ + process_stratum, /* to_stratum */ + NULL, /* to_next */ + 1, /* to_has_all_memory */ + 1, /* to_has_memory */ + 1, /* to_has_stack */ + 1, /* to_has_registers */ + 1, /* to_has_execution */ + NULL, /* sections */ + NULL, /* sections_end */ + OPS_MAGIC /* to_magic */ +}; + +void +_initialize_remote_rdi () +{ + add_target (&arm_rdi_ops); +} + +/* A little dummy to make linking with the library succeed. */ + +Fail() {} diff --git a/gdb/remote-rdp.c b/gdb/remote-rdp.c index 3cc4c4eed2d..04a9473b0a7 100644 --- a/gdb/remote-rdp.c +++ b/gdb/remote-rdp.c @@ -54,6 +54,7 @@ #ifdef HAVE_UNISTD_H #include #endif +#include "gdbcore.h" extern struct target_ops remote_rdp_ops; @@ -138,6 +139,16 @@ ds; #define RDP_INFO_ABOUT_BREAK_THREAD_BREAK (1<<9) #define RDP_INFO_ABOUT_BREAK_THREAD_WATCH (1<<10) #define RDP_INFO_ABOUT_BREAK_COND (1<<11) +#define RDP_INFO_VECTOR_CATCH (0x180) +#define RDP_INFO_ICEBREAKER (7) +#define RDP_INFO_SET_CMDLINE (0x300) + +#define RDP_SELECT_CONFIG (0x16) +#define RDI_ConfigCPU 0 +#define RDI_ConfigSystem 1 +#define RDI_MatchAny 0 +#define RDI_MatchExactly 1 +#define RDI_MatchNoEarlier 2 #define RDP_RESET 0x7f @@ -157,6 +168,8 @@ ds; static int timeout = 2; +static char * commandline = NULL; + static int remote_rdp_xfer_inferior_memory PARAMS ((CORE_ADDR memaddr, char *myaddr, @@ -263,9 +276,39 @@ rdp_init (cold, tty) if (tty) printf_unfiltered ("Trying to connect at %d baud.\n", baudtry); + + /* + ** It seems necessary to reset an EmbeddedICE to get it going. + ** This has the side benefit of displaying the startup banner. + */ + if (cold) + { + put_byte (RDP_RESET); + while ((restype = SERIAL_READCHAR (io, 1)) > 0) + { + switch (restype) + { + case SERIAL_TIMEOUT: + break; + case RDP_RESET: + /* Sent at start of reset process: ignore */ + break; + default: + printf_unfiltered ("%c", isgraph (restype) ? restype : ' '); + break; + } + } + + if (restype == 0) + { + /* Got end-of-banner mark */ + printf_filtered ("\n"); + } + } + put_byte (RDP_OPEN); - put_byte (type | RDP_OPEN_TYPE_RETURN_SEX); + put_byte (type | RDP_OPEN_TYPE_RETURN_SEX ); put_word (0); while (!sync && (restype = SERIAL_READCHAR (io, 1)) > 0) @@ -300,6 +343,10 @@ rdp_init (cold, tty) case RDP_RES_VALUE: { int resval = SERIAL_READCHAR (io, 1); + + if (remote_debug) + printf_unfiltered ("[%02x]\n", resval); + switch (resval) { case SERIAL_TIMEOUT: @@ -384,9 +431,27 @@ send_rdp (char *template, va_alist) } break; case 'Z': - /* Check the result code, error if not zero */ - if (get_byte ()) - error ("Command garbled"); + /* Check the result code */ + switch (get_byte ()) + { + case 0: + /* Success */ + break; + case 253: + /* Target can't do it; never mind */ + printf_unfiltered ("RDP: Insufficient privilege\n"); + return; + case 254: + /* Target can't do it; never mind */ + printf_unfiltered ("RDP: Unimplemented message\n"); + return; + case 255: + error ("Command garbled"); + break; + default: + error ("Corrupt reply from target"); + break; + } break; case 'W': /* Read a word from the target */ @@ -652,6 +717,50 @@ rdp_execute_start () } +static void +rdp_set_command_line (command, args) + char * command; + char * args; +{ + /* + ** We could use RDP_INFO_SET_CMDLINE to send this, but EmbeddedICE systems + ** don't implement that, and get all confused at the unexpected text. + ** Instead, just keep a copy, and send it when the target does a SWI_GetEnv + */ + + if (commandline != NULL) + free (commandline); + + commandline = malloc (strlen (command) + strlen (args) + 2); + if (commandline != NULL) + { + strcpy (commandline, command); + strcat (commandline, " "); + strcat (commandline, args); + } +} + +static void +rdp_catch_vectors () +{ + /* + ** We want the target monitor to intercept the abort vectors + ** i.e. stop the program if any of these are used. + */ + send_rdp ("bww-SZ", RDP_INFO, RDP_INFO_VECTOR_CATCH, + /* + ** Specify a bitmask including + ** the reset vector + ** the undefined instruction vector + ** the prefetch abort vector + ** the data abort vector + ** the address exception vector + */ + (1<<0)|(1<<1)|(1<<3)|(1<<4)|(1<<5) + ); +} + + #define a_byte 1 #define a_word 2 @@ -786,6 +895,22 @@ exec_swi (swi, args) args->n = callback->isatty (callback, args->n); return 1; + case SWI_GetEnv: + if (commandline != NULL) + { + int len = strlen (commandline); + if (len > 255) + { + len = 255; + commandline [255]='\0'; + } + remote_rdp_xfer_inferior_memory (args[0].n, + commandline, len+1, 1, 0); + } + else + remote_rdp_xfer_inferior_memory (args[0].n, "", 1, 1, 0); + return 1; + default: return 0; } @@ -986,6 +1111,8 @@ remote_rdp_open (args, from_tty) char *args; int from_tty; { + int not_icebreaker; + if (!args) error_no_arg ("serial port device name"); @@ -1010,7 +1137,33 @@ remote_rdp_open (args, from_tty) rdp_info (); - push_target (&remote_rdp_ops); + /* Need to set up the vector interception state */ + rdp_catch_vectors(); + + /* + ** If it's an EmbeddedICE, we need to set the processor config. + ** Assume we can always have ARM7TDI... + */ + send_rdp ("bw-SB", RDP_INFO, RDP_INFO_ICEBREAKER, & not_icebreaker); + if (!not_icebreaker) + { + const char * CPU = "ARM7TDI"; + int ICEversion; + int len = strlen (CPU); + + send_rdp ("bbbbw-p-SWZ", + RDP_SELECT_CONFIG, + RDI_ConfigCPU, /* Aspect: set the CPU */ + len, /* The number of bytes in the name */ + RDI_MatchAny, /* We'll take whatever we get */ + 0, /* We'll take whatever version's there */ + CPU,len, + & ICEversion); + } + + /* command line initialised on 'run'*/ + + push_target (& remote_rdp_ops); callback->init (callback); flush_cached_frames (); @@ -1192,6 +1345,54 @@ remote_rdp_files_info (target) } +static void +remote_rdp_create_inferior (exec_file, allargs, env) + char * exec_file; + char * allargs; + char ** env; +{ + CORE_ADDR entry_point; + + if (exec_file == 0 || exec_bfd == 0) + error ("No exec file specified."); + + entry_point = (CORE_ADDR) bfd_get_start_address (exec_bfd); + + remote_rdp_kill (); + remove_breakpoints (); + init_wait_for_inferior (); + + /* This gives us a chance to set up the command line */ + rdp_set_command_line (exec_file, allargs); + + inferior_pid = 42; + insert_breakpoints (); /* Needed to get correct instruction in cache */ + + /* + ** RDP targets don't provide any facility to set the top of memory, + ** so we don't bother to look for MEMSIZE in the environment. + */ + + /* Let's go! */ + proceed (entry_point, TARGET_SIGNAL_DEFAULT, 0); +} + +/* Accept any stray run/attach commands */ +static int +remote_rdp_can_run() +{ + return 1; +} + +/* Attach doesn't need to do anything */ +static void +remote_rdp_attach(args, from_tty) + char * args; + int from_tty; +{ + return; +} + /* Define the target subroutine names */ struct target_ops remote_rdp_ops = @@ -1203,7 +1404,7 @@ struct target_ops remote_rdp_ops = "Use a remote ARM system which uses the ARM Remote Debugging Protocol", remote_rdp_open, /* to_open */ remote_rdp_close, /* to_close */ - NULL, /* to_attach */ + remote_rdp_attach, /* to_attach */ NULL, /* to_detach */ remote_rdp_resume, /* to_resume */ remote_rdp_wait, /* to_wait */ @@ -1222,9 +1423,9 @@ struct target_ops remote_rdp_ops = remote_rdp_kill, /* to_kill */ generic_load, /* to_load */ NULL, /* to_lookup_symbol */ - NULL, /* to_create_inferior */ + remote_rdp_create_inferior, /* to_create_inferior */ generic_mourn_inferior, /* to_mourn_inferior */ - 0, /* to_can_run */ + remote_rdp_can_run, /* to_can_run */ 0, /* to_notice_signals */ 0, /* to_thread_alive */ 0, /* to_stop */