diff options
Diffstat (limited to 'SrcShared/Marshal.h')
-rw-r--r-- | SrcShared/Marshal.h | 755 |
1 files changed, 755 insertions, 0 deletions
diff --git a/SrcShared/Marshal.h b/SrcShared/Marshal.h new file mode 100644 index 0000000..4da60f6 --- /dev/null +++ b/SrcShared/Marshal.h @@ -0,0 +1,755 @@ +/* -*- mode: C++; tab-width: 4 -*- */ +/* ===================================================================== *\ + Copyright (c) 1999-2001 Palm, Inc. or its subsidiaries. + All rights reserved. + + This file is part of the Palm OS Emulator. + + 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. +\* ===================================================================== */ + +#ifndef _MARSHAL_H_ +#define _MARSHAL_H_ + +#include "EmBankMapped.h" // UnmapPhysicalMemory +#include "EmMemory.h" // EmMemGet32, EmMemGet16, EmMemGet8, EmMem_memcpy +#include "EmPalmStructs.h" // EmProxy +#include "EmSubroutine.h" // EmSubroutine +#include "Platform.h" // Platform::AllocateMemory + + +/* =========================================================================== + + Functions and macros for helping with marshaling and unmarshaling + parameters from and to the emulated process's stack. First, the stack + is described with a class called EmSubroutine which lists the function's + parameters in order. For example, the definition for NetLibDmReceive is + as follows: + + EmSubroutine sub ("Int16", "UInt16 libRefNum, NetSocketRef socket," + "void *recordP, UInt32 recordOffset, UInt16 rcvLen, UInt16 flags, " + "void *fromAddrP, UInt16 *fromLenP, Int32 timeout, Err *errP"); + + This class describes the format of the parameters on the stack. You + then use one of several macros to fetch and possibly return values from + and to those parameters. + + Use PARAM_VAL to manage pass-by-value parameter, such as a Long or a + Word. Example: + + PARAM_VAL(Word, libRefNum); + + This defines a local variable called libRefNum that contains the value + passed on the stack. The variable is an instance of a class that can + produce a Word, and so can be passed to functions that take a Word. + + Use PARAM_REF to manage a pass-by-reference parameter, such as a Long* + or a Word*. Example: + + PARAM_REF(Word, fromLenP, kInput); + + This defines a local variable called fromLenP that contains the pointer + passed on the stack as well as a copy of the value that it points to. + The variable is an instance of a class that can produce a Word*, and so + can be passed to functions that take a Word*. If the parameter + reference was NULL, then the class produces NULL as well. The third + parameter to the macro describes whether or not the value passed in is + an input parameter (kInput), output parameter (kOutput) or both + (kInOut). If kInput or kInOut, the referenced value is fetched and + converted to host format. Otherwise, it is assumed that the parameter + references uninitialized contents. If kOutput or kInOut, the value is + copied back into the memory specified by the parameter reference. + Values are explicitly copied back to emulated memory by calling + fromLenP's Put() method. + + Use PARAM_PTR to manage an arbitrary block of data pointed to by a + function parameter, such as a void* or BytePtr. Example: + + PARAM_PTR(void, recordP, len, kInOut); + + This defines a local variable called recordP that points to a block of + data "len" bytes long. If the fourth parameter is kInput or kInOut, the + memory pointed to by the function parameter is copied into this block of + data. If the fourth parameter is kOutput or kInOut, the contents of the + buffer are copied back to the emulated memory when the Put() method is + called. NULL pointers are handled. + + Use PARAM_STR as a special kind of PARAM_PTR where the length is not + explicitly known, but the referenced data is NULL terminated. Example: + + PARAM_STR(Char, nameP); + + This defines a local variable called nameP that contains a pointer to a + string, the contents of which are copied from emulated memory. These + variables are actually like PARAM_STRs with kInput as the third + parameter, but there's no real need for that restriction. + + The above macros expand to variable definitions. The name of the + variable is given by the second macro parameter, and the type of the + variable is determined by the first parameter. The type of variable is + actually created from a class template. There are four class templates: + ParamVal, ParamRef, ParamPtr, and ParamStr. + + The constructors for these classes fetch the the appropriate values from + memory, allocating any necessary buffers. Their destructors do nothing + (which really saves in terms of exception handling overhead). + + When the fetched values have been used and it's time to return any + changed values back to the emulated stack/heap, all the classes (except + ParamVal) have Put methods. You must call this method when you are done + with the values. The Put method writes back any altered values and + releases any memory allocated in the constructor. + +=========================================================================== */ + +struct HostGremlinInfoType; +struct HostStatType; +struct HostTmType; +struct HostUTimeType; + +typedef struct ExgSocketType* ExgSocketPtr; +typedef UInt8* UInt8Ptr; + + +#define CALLED_SETUP(return_decl, parameter_decl) \ + static EmSubroutine sub; \ + \ + static Bool initialized; \ + if (!initialized) \ + { \ + initialized = true; \ + sub.DescribeDecl (return_decl, parameter_decl); \ + } \ + \ + sub.PrepareStack (kForBeingCalled, false) + + +#define CALLED_SETUP_HC(return_decl, parameter_decl) \ + static EmSubroutine sub; \ + \ + static Bool initialized; \ + if (!initialized) \ + { \ + initialized = true; \ + sub.DescribeDecl (return_decl, "HostControlSelectorType _selector, " parameter_decl); \ + } \ + \ + sub.PrepareStack (kForBeingCalled, false) + + +#define CALLED_SETUP_STDARG(return_decl, parameter_decl) \ + EmSubroutine sub; \ + sub.DescribeDecl (return_decl, parameter_decl); \ + sub.PrepareStack (kForBeingCalled, true) + + +#define CALLED_SETUP_STDARG_HC(return_decl, parameter_decl) \ + EmSubroutine sub; \ + sub.DescribeDecl (return_decl, "HostControlSelectorType selector, " parameter_decl); \ + sub.PrepareStack (kForBeingCalled, true) + + +#define CALLER_SETUP(return_decl, parameter_decl) \ + static EmSubroutine sub; \ + \ + static Bool initialized; \ + if (!initialized) \ + { \ + initialized = true; \ + sub.DescribeDecl (return_decl, parameter_decl); \ + } \ + \ + sub.PrepareStack (kForCalling, false) + + +#define GET_RESULT_VAL(type) \ + type result; \ + Marshal::GetReturnVal (sub, result); + + +#define GET_RESULT_PTR() \ + emuptr result; \ + Marshal::GetReturnVal (sub, result); + + +#define PUT_RESULT_VAL(type, val) \ + Marshal::PutReturnVal (sub, (type) val); + + +#define PUT_RESULT_PTR(type, val) \ + Marshal::PutReturnVal (sub, (type) val); + + +#define RETURN_RESULT_VAL(type) \ + GET_RESULT_VAL (type); \ + return result + + +#define RETURN_RESULT_PTR(type) \ + GET_RESULT_PTR (); \ + return (type) result + + + +// Macros used when being called by emulated code +// (e.g., from trap patches). + +#define CALLED_GET_PARAM_VAL(type, name) \ + ParamVal<type> name (sub, #name) + +#define CALLED_GET_PARAM_REF(type, name, io) \ + ParamRef<type, io> name (sub, #name) + +#define CALLED_GET_PARAM_PTR(type, name, len, io) \ + ParamPtr<type, io> name (sub, #name, len) + +#define CALLED_GET_PARAM_STR(type, name) \ + ParamStr<type> name (sub, #name) + +#define CALLED_PUT_PARAM_REF(name) \ + name.Put () + + +// Macros used when calling emulated code +// (e.g., the stuff in ROMStubs.cpp) + +#define CALLER_PUT_PARAM_VAL(type, name) \ + PushParamVal<type> _##name (sub, #name, (type) name); \ + /* *Use* the variable this way. GCC will complain that the */ \ + /* PushParamVal variable is unused otherwise. */ \ + ((void) _##name) + +#define CALLER_PUT_PARAM_REF(type, name, io) \ + PushParamRef<type, io> _##name (sub, #name, (type*) name) + +#define CALLER_PUT_PARAM_PTR(type, name, len, io) \ + PushParamPtr<type, io> _##name (sub, #name, name, len) + +#define CALLER_PUT_PARAM_STR(type, name) \ + PushParamStr<type> _##name (sub, #name, name) + +#define CALLER_GET_PARAM_REF(name) \ + _##name.Get () + + +class Marshal +{ + public: + // VC++ is a bit medieval here... +// static const int kInput = 0x01; +// static const int kOutput = 0x02; +// static const int kInOut = kInput | kOutput; + enum + { + kInput = 0x01, + kOutput = 0x02, + kInOut = kInput | kOutput + }; + + #define INPUT(io) (((io) & Marshal::kInput) != 0) + #define OUTPUT(io) (((io) & Marshal::kOutput) != 0) + + static void* GetBuffer (emuptr p, long len); +#if (__GNUC__ == 2) + static void PutBuffer (emuptr p, unsigned char* const buf, long len) + { + if (p) + { + EmMem_memcpy (p, (void*) buf, len); + void* b = buf; + Platform::DisposeMemory (b); + } + } +#else + template <class T> + static void PutBuffer (emuptr p, T* const buf, long len) + { + if (p) + { + EmMem_memcpy (p, (void*) buf, len); + void* b = buf; + Platform::DisposeMemory (b); + } + } +#endif + + + /* =========================================================================== + The ParamFoo classes are templatized on the type of values they are to + fetch. In order to perform the actual fetching, they call GetParamVal + (and put the value back with PutParamVal). In order for those calls to + succeed, we have to have overloaded versions of that function for each + type we ever fetch. Those overloaded functions appear below. + =========================================================================== */ + +#define DECLARE_POINTER_MARSHALLER(type) \ + inline static void GetParamVal (EmSubroutine& sub, EmParamNameArg name, type*& v) \ + { sub.GetParamVal (name, (emuptr&) v); } \ + \ + inline static void PutParamVal (EmSubroutine& sub, EmParamNameArg name, const type* v) \ + { sub.SetParamVal (name, (emuptr) v); } \ + \ + inline static void PutReturnVal (EmSubroutine& sub, const type* v) \ + { sub.SetReturnVal ((emuptr) v); } + + + DECLARE_POINTER_MARSHALLER (void) + DECLARE_POINTER_MARSHALLER (FormType) + DECLARE_POINTER_MARSHALLER (ExgSocketType) + DECLARE_POINTER_MARSHALLER (_opaque) + + +#define DECLARE_SCALAR_MARSHALLER(type, asType, num_bits) \ + inline static void GetParamVal (EmSubroutine& sub, EmParamNameArg name, type& v) \ + { \ + asType temp; \ + sub.GetParamVal (name, temp); \ + v = (type) temp; \ + } \ + \ + inline static void PutParamVal (EmSubroutine& sub, EmParamNameArg name, type v) \ + { sub.SetParamVal (name, (asType) v); } \ + \ + inline static void GetParamRef (emuptr p, type& v) \ + { v = (type) EmMemGet##num_bits (p); } \ + \ + inline static void PutParamRef (emuptr p, const type& v) \ + { EmMemPut##num_bits (p, (asType) v); } \ + \ + inline static void GetReturnVal (EmSubroutine& sub, type& v) \ + { \ + asType temp; \ + sub.GetReturnVal (temp); \ + v = (type) temp; \ + } \ + \ + inline static void PutReturnVal (EmSubroutine& sub, type v) \ + { sub.SetReturnVal ((asType&) v); } \ + \ + inline static long GetBufSize (const type&) \ + { return sizeof(asType); } + + + DECLARE_SCALAR_MARSHALLER (int8, int8, 8) + DECLARE_SCALAR_MARSHALLER (uint8, uint8, 8) + DECLARE_SCALAR_MARSHALLER (int16, int16, 16) + DECLARE_SCALAR_MARSHALLER (uint16, uint16, 16) + DECLARE_SCALAR_MARSHALLER (int32, int32, 32) + DECLARE_SCALAR_MARSHALLER (uint32, uint32, 32) + + DECLARE_SCALAR_MARSHALLER (ClipboardFormatType, uint8, 8) + DECLARE_SCALAR_MARSHALLER (DlkSyncStateType, uint8, 8) + DECLARE_SCALAR_MARSHALLER (FormObjectKind, uint8, 8) + DECLARE_SCALAR_MARSHALLER (LocalIDKind, uint8, 8) + DECLARE_SCALAR_MARSHALLER (NetSocketAddrEnum, uint8, 8) + DECLARE_SCALAR_MARSHALLER (NetSocketTypeEnum, uint8, 8) + DECLARE_SCALAR_MARSHALLER (SystemPreferencesChoice, uint8, 8) + + DECLARE_SCALAR_MARSHALLER (SysAppInfoPtr, uint32, 32) + DECLARE_SCALAR_MARSHALLER (UInt8Ptr, uint32, 32) + + +#define DECLARE_STRUCT_MARSHALLER(type) \ + static void Get##type (emuptr p, type&); \ + static void Put##type (emuptr p, const type&); \ + \ + static long GetBufSize (const type&) \ + { return EmProxy##type::GetSize (); } \ + \ + inline static void GetParamRef (emuptr p, type& v) \ + { Get##type (p, v); } \ + \ + inline static void PutParamRef (emuptr p, const type& v) \ + { Put##type (p, v); } + + + DECLARE_STRUCT_MARSHALLER (DlkServerSessionType) + DECLARE_STRUCT_MARSHALLER (DmSearchStateType) + DECLARE_STRUCT_MARSHALLER (EventType) + DECLARE_STRUCT_MARSHALLER (FieldAttrType) + DECLARE_STRUCT_MARSHALLER (HostGremlinInfoType) + DECLARE_STRUCT_MARSHALLER (HostStatType) + DECLARE_STRUCT_MARSHALLER (HostTmType) + DECLARE_STRUCT_MARSHALLER (HostUTimeType) + DECLARE_STRUCT_MARSHALLER (HwrBatCmdReadType) + DECLARE_STRUCT_MARSHALLER (NetSocketAddrType) + DECLARE_STRUCT_MARSHALLER (NetIOParamType) + DECLARE_STRUCT_MARSHALLER (NetHostInfoBufType) + DECLARE_STRUCT_MARSHALLER (NetServInfoBufType) + DECLARE_STRUCT_MARSHALLER (PointType) + DECLARE_STRUCT_MARSHALLER (RectangleType) + DECLARE_STRUCT_MARSHALLER (SndCommandType) + DECLARE_STRUCT_MARSHALLER (SysAppInfoType) + DECLARE_STRUCT_MARSHALLER (SysKernelInfoType) + DECLARE_STRUCT_MARSHALLER (SysNVParamsType) +}; + + +/* =========================================================================== + Class that manages an immediate value from the emulated stack. This + class can fetch the value from the stack and produce that value via a + type operator. The value cannot be changed, you can't take the address + of it, nor can the value be written back to the stack. +=========================================================================== */ + +template <typename T> +class ParamVal +{ + public: + ParamVal (EmSubroutine& sub, EmParamNameArg name) + { + Marshal::GetParamVal (sub, name, fVal); + } + + operator T(void) { return fVal; } + + private: + T fVal; +}; + + +/* =========================================================================== + Class that manages a value passed by reference on the emulated stack. + This class can fetch the pointer to the value and make a copy of the + value pointed to if the pointer was NULL. The class can produce a + pointer to the local copy of the value, or NULL if the parameter was + NULL. The class has a Put method which copies the local copy back to + the emulated memory the original came from. Whether or not the + referenced value is fetched or returned is determined by the inOut + template parameter. If the kInput bit is set, the value is copied from + emulated memory to a local copy. If the kOutput bit is set, the local + copy is copied back to emulated memory when the Put method is called. +=========================================================================== */ + +template <typename T, long inOut> +class ParamRef +{ + public: + ParamRef (EmSubroutine& sub, EmParamNameArg name) : + fSub (&sub), + fName (name), + fPtr (EmMemNULL) + { + // Get and cache the pointer to the data. + + fSub->GetParamVal (fName.c_str (), fPtr); + + // If there's a pointer and this is an input + // variable, get the data. + + if (fPtr && INPUT(inOut)) + { + Marshal::GetParamRef (fPtr, fVal); + } + } + + void Put (void) + { + // If there's a pointer and this is an output + // variable, store the data. + + if (fPtr && OUTPUT(inOut)) + { + Marshal::PutParamRef (fPtr, fVal); + } + } + + operator T*(void) { return fPtr ? &fVal : NULL; } + const T& operator *(void) const { return fVal; } + T& operator *(void) { return fVal; } + + operator emuptr (void) { return fPtr; } + + private: + EmSubroutine* fSub; + EmParamName fName; + emuptr fPtr; + T fVal; +}; + + +/* =========================================================================== + Class that manages a block of memory pointed to by a pointer on the + emulated stack. If the pointer is non-NULL, a local block of memory is + allocated. If the kInput bit of the inOut template parameter is set, + the range of emulated memory is copied into the local buffer. This class + can produce a pointer to the local block of memory on demand (if the + stack parameter was NULL, this class produces NULL). If the kOutput bit + of the inOut template paraemter is set, the local block's contents are + copied back into emulated memory when the Put method is called. + Regardless of inOut values, the Put method must be called in order to + release the lock block of memory. +=========================================================================== */ + +template <typename T, long inOut> +class ParamPtr +{ + public: + ParamPtr (EmSubroutine& sub, EmParamNameArg name, long len) : + fSub (&sub), + fName (name), + fPtr (EmMemNULL), + fLen (len), + fVal (NULL) + { + // Get and cache the pointer to the data. + + fSub->GetParamVal (fName.c_str (), fPtr); + + if (fPtr) + { + fVal = (T*) Platform::AllocateMemory (fLen); + if (fVal && INPUT(inOut)) + { + EmMem_memcpy ((void*) fVal, fPtr, fLen); + } + } + } + + ~ParamPtr () // !!! Update comments about d'tors and disposing memory + { + Platform::DisposeMemory (fVal); + } + + void Put (void) + { + if (fPtr && fVal && OUTPUT(inOut)) + { + EmMem_memcpy (fPtr, (const void*) fVal, fLen); + } + } + + operator T*(void) { return fVal; } + + operator emuptr (void) { return fPtr; } + + private: + EmSubroutine* fSub; + EmParamName fName; + emuptr fPtr; + long fLen; + T* fVal; +}; + + +/* =========================================================================== + Class that manages a NULL-terminated range of memory pointed to by a + pointer on the emulated stack. The input pointer can be NULL. The + elements of the string can be anything, but will normally be Char + (actually, they may *have* to be Char, since I get the length of the + string by calling EmMem_strlen). The string is modifiable in-place, but + any changes are not copied back to emulated memory (this behavior can be + changed if needed). +=========================================================================== */ + +template <typename T> +class ParamStr +{ + public: + ParamStr (EmSubroutine& sub, EmParamNameArg name) : + fSub (&sub), + fName (name), + fPtr (EmMemNULL), + fVal (NULL) + { + fSub->GetParamVal (fName.c_str (), fPtr); + + if (fPtr) + { + fVal = (T*) Platform::AllocateMemory (EmMem_strlen (fPtr) + 1); + if (fVal) + { + EmMem_strcpy (fVal, fPtr); + } + } + } + + ~ParamStr () // !!! Update comments about d'tors and disposing memory + { + Platform::DisposeMemory (fVal); + } + + void Put (void) + { + } + + operator T*(void) { return fVal; } + + operator emuptr (void) { return fPtr; } + + private: + EmSubroutine* fSub; + EmParamName fName; + emuptr fPtr; + T* fVal; +}; + + +template <typename T> +class PushParamVal +{ + public: + PushParamVal (EmSubroutine& sub, EmParamNameArg name, T val) + { + Marshal::PutParamVal (sub, name, val); + } +}; + +template <typename T, long inOut> +class PushParamRef +{ + public: + PushParamRef (EmSubroutine& sub, EmParamNameArg name, T* ptr) : + fSub (&sub), + fName (name), + fHostPtr (ptr), + fMappedData (NULL), + fMappedPtr (EmMemNULL) + { + if (fHostPtr) + { + // Allocate a buffer big enough for the mapped/translated data. + + long size = Marshal::GetBufSize (*fHostPtr); + fMappedData = Platform::AllocateMemory (size); + + // Map the buffer + + EmBankMapped::MapPhysicalMemory (fMappedData, size); + fMappedPtr = EmBankMapped::GetEmulatedAddress (fMappedData); + + // Copy/translate the data into it. + + if (INPUT(inOut)) + { + Marshal::PutParamRef (fMappedPtr, *fHostPtr); + } + + // Pass the pointer to the data. + + fSub->SetParamVal (fName.c_str (), fMappedPtr); + } + else + { + fMappedPtr = EmMemNULL; + } + + // Pass the pointer to the data. + + fSub->SetParamVal (fName.c_str (), fMappedPtr); + } + + ~PushParamRef (void) + { + if (fMappedData) + { + EmBankMapped::UnmapPhysicalMemory (fMappedData); + Platform::FreeMemory (fMappedData); + } + } + + void Get (void) + { + if (fHostPtr && OUTPUT(inOut)) + { + Marshal::GetParamRef (fMappedPtr, *fHostPtr); + } + } + + private: + EmSubroutine* fSub; + EmParamName fName; + T* fHostPtr; + void* fMappedData; + emuptr fMappedPtr; +}; + +template <typename T, long inOut> +class PushParamPtr +{ + public: + PushParamPtr (EmSubroutine& sub, EmParamNameArg name, const T* ptr, long size) : + fSub (&sub), + fName (name), + fHostPtr (ptr), + fMappedPtr (EmMemNULL) + { + if (fHostPtr) + { + // Map the buffer + + EmBankMapped::MapPhysicalMemory (fHostPtr, size); + fMappedPtr = EmBankMapped::GetEmulatedAddress (fHostPtr); + } + else + { + fMappedPtr = EmMemNULL; + } + + // Pass the pointer to the data. + + fSub->SetParamVal (fName.c_str (), fMappedPtr); + } + + ~PushParamPtr (void) + { + if (fHostPtr) + { + EmBankMapped::UnmapPhysicalMemory (fHostPtr); + } + } + + private: + EmSubroutine* fSub; + EmParamName fName; + const T* fHostPtr; + emuptr fMappedPtr; +}; + +template <typename T> +class PushParamStr +{ + public: + PushParamStr (EmSubroutine& sub, EmParamNameArg name, const T * const ptr) : + fSub (&sub), + fName (name), + fHostPtr (ptr), + fMappedPtr (EmMemNULL) + { + if (fHostPtr) + { + // Map the buffer + + long size = strlen (ptr) + 1; + EmBankMapped::MapPhysicalMemory (fHostPtr, size); + fMappedPtr = EmBankMapped::GetEmulatedAddress (fHostPtr); + } + else + { + fMappedPtr = EmMemNULL; + } + + // Pass the pointer to the data. + + fSub->SetParamVal (fName.c_str (), fMappedPtr); + } + + ~PushParamStr (void) + { + if (fHostPtr) + { + EmBankMapped::UnmapPhysicalMemory (fHostPtr); + } + } + + private: + EmSubroutine* fSub; + EmParamName fName; + const T* const fHostPtr; + emuptr fMappedPtr; +}; + +#endif // _MARSHAL_H_ |