Upon return:
ebx, esi, edi, ebp, esp: preserved
- eax: pointer to exception, or NULL if none.
+ eax: pointer to exception, or NULL if none
If there is an exception, the user part of the syscall
function will search for an exception handling function
that covers the calling address. If none is found,
Callee:
eax: pointer to PIB
edx: pointer to caller information struct, or NULL if not
- requested.
+ requested
esp: NULL.
Jump to the 32-bit address stored at 0x7fff0004 to return.
Upon return:
- eax: pointer to exception, or NULL if none.
+ eax: pointer to exception, or NULL if none
edx: length of exception segment, if any
ebx, esi, edi, ebp, esp: may be clobbered
+
+Object registration:
+ eax: number of objects to register with initial refcount 1
+ edx: pointer to list of NewObject structs
+
+ Call the 32-bit address stored at 0x7fff0008.
+
+ Upon return:
+ eax: pointer to exception, or NULL if none
+ edx: length of exception segment, if any
+
+GUID hash retrieval:
+ eax: object id
+ edx: 16-byte buffer
+
+ Call the 32-bit address stored at 0x7fff000c.
+
+ Upon return:
+ eax: pointer to exception, or NULL if none
+ edx: length of exception segment, if any
-segment 0, byte 0 is a request code. Codes are:
+Segment 0, byte 0 is a request code. Currently defined codes are:
0: Invoke Method
1: Get Interface List
2: Return Interface List
Bytes 1-3 (32-bit) and 1-7 (64-bit) are reserved, and must be zero.
All offsets described in the rest of this file are relative to the
-first non-reserved byte (a.k.a. the message payload). The reserved
-bytes do not need to be included in the message if the payload is
-empty.
+first non-reserved byte (a.k.a. the message payload); however,
+offsets encoded in the message are relative to the beginning of the
+segment, not the payload. The reserved bytes do not need to be
+included in the message if the payload is empty.
Op0: Invoke Method
------------------
-The segment 0 payload contains the method's arguments as if they were
-a struct, followed by a depth-first traversal of any referenced
-structs, excluding references which could potentially lead to loops
-(i.e. references to types that exist in a parent node in the
-traversal, or their supertypes) or aliases (i.e. references to types
-that exist elsewhere in the traversal, or their supertypes). Where
-loops or aliases are possible, the reference is encoded as a
-segment/offset pair (a 32-bit word, segment is upper 6 bits), and the
-data may be placed wherever the sender wishes. Non-inline arrays are
-also encoded with segment/offset pairs. Object references are
-encoded as 16-bit offsets into the objlist array.
+The payload begins with the index of the interface being used,
+followed by the index of the method. Both are 32-bit integers.
+
+After that, the payload contains the method's arguments as if they
+were a struct.
+
+Non-inline structs and arrays (hereafter referred to as data chunks)
+which contain object ids and/or references to other data chunks are
+stored at arbitrary locations in segment 0, and are referenced as an
+offset into the segment.
+
+Data chunks which do not contain object id or references to other
+data chunks (i.e. they are pure data, and do not need to be altered
+for marshalling) are stored at arbitrary locations in arbitrary
+segments. References to these pure data chunks are encoded as a
+pointer-sized integer, with the upper N bits holding the segment and
+the remaining bits holding the offset into that segment. The value
+of N is architecture-defined, but should generally be 6 (this may
+change once enough of the system is in place to do some benchmarks)
+for 32-bit architectures and 32 for 64-bit architectures.
+
+Object references are encoded as pointer-sized offsets into the
+objlist array.
Op1: Get Interface List
-----------------------
For async requests, objlist[1] is the object whose interfaces were
requested.
-The payload consists of a list of GUIDs of interfaces that the object
+Segment 1 consists of a list of GUIDs of interfaces that the object
supports.
--- /dev/null
+struct NewObject {
+ u32 guid_hash[4]; // Interface GUID checksum
+ u32 id; // Filled in by ORB
+ u32 reserved[3]; // must be zero
+};
-Parameter Info Block (PIB), all offsets in pointer-length words
- Name Offset Meaning
- buffer_size 0 Size of the destination buffer, excluding
+Parameter Info Block (PIB)
+ Name Size Meaning
+ buffer_size 32-bit Size of the destination buffer, excluding
Copy segments.
The total number of bytes in all of the segments that require a
for the duration of the call. Copy segments are handled
separately.
- copy_size 1 Size of all Copy segments.
+ copy_size 32-bit Size of all Copy segments.
This is like buffer_size, but for Copy segments.
- objlist_ptr 2 Pointer to the object list
- objlist_len 3 Length of the object list, in IDs
+ objlist_ptr pointer Pointer to the object list
+ objlist_len 32-bit Length of the object list, in IDs
The object list is a special segment that contains object IDs
rather than arbitrary data. Each object ID will be translated
regardless of the pointer size. The first object in the list
is the object to receive the message.
- num_segments 4 Number of data segments
- segment.ptr 5+n*4 Pointer to data segment
- segment.len 6+n*4 Length of data segment in bytes
- segment.flags 7+n*4 Attributes of data segment
- reserved 8+n*4 Reserved for future use, and for
- power-of-two indexing
+ num_segments 32-bit Number of data segments
+
+ segment.ptr pointer Pointer to data segment
+ segment.len 32-bit Length of data segment in bytes
+ segment.flags 32-bit Attributes of data segment
+ reserved Reserved for future use, and for
+ power-of-two indexing -- pad to
+ 32 bytes.
Each segment describes data being transmitted to and/or from the
callee. For out segments, the caller may designate a buffer to hold
char[] exp immutable;
};
+struct InternalFailure : SystemException {
+ guid: "52819E26-1791-11DC-931E-00112431A05E";
+
+ char[] exp immutable;
+};
+
// GeneralFailure, as the name implies, is a general purpose exception
// to indicate failure conditions not covered by existing exceptions.
// It is generally preferable to define a specific exception for
int refs, released;
};
+
+// Thrown when an ORB message is malformed.
+// FIXME: Move into orb namespace
+
+struct BadMessage : SystemException {
+ guid: "5347B217-1790-11DC-A89E-00112431A05E";
+};
+
+struct ShortMessage : BadMessage {
+ guid: "5DA142FA-1791-11DC-A3BE-00112431A05E";
+
+ int segment; // Short segment, or -1 for objlist
+ int len, expected;
+};
+
+struct InvalidOpcode : BadMessage {
+ guid: "5708BF7E-1791-11DC-B1D3-00112431A05E";
+
+ int opcode;
+};
can only be used when invoked as a sync in-process method; the method
implementation can check to see how it was invoked, and use the out
parameters to avoid having to make a completion callback.
+
+Vstructs need a length field.
// Length of inheritance chain; 1 for System.VStruct
const int chainlen;
+
+ // Size of concrete vstruct
+
+ const int structlen;
};
uintptr_t downcast(::System::_i_Object *obj,
const unsigned long *new_guid);
+ typedef u64 GUID[2];
+
+ // FIXME: use above typedef
static inline bool guids_equal(const unsigned long *guid1,
const unsigned long *guid2)
{
guid1[3] == guid2[3])));
}
- // Return the caller's PC. It'd be nice if GCC had a builtin for
- // the current PC, so that a simple relocation could be used rather
- // than a function call. OPT: put this in lowlevel-lib, so that
- // architectures can provide a faster version.
-
- unsigned long get_pc();
-
+ typedef uint32_t ID;
struct ParamInfoBlock {
- uintptr_t buffer_size;
- uintptr_t copy_size;
- uintptr_t *objlist;
- uintptr_t objlist_len;
- uintptr_t num_segments;
+ uint32_t buffer_size;
+ uint32_t copy_size;
+ ID *objlist;
+ uint32_t objlist_len;
+ uint32_t num_segments;
struct Segment {
- unsigned char *ptr;
+ uint8_t *ptr;
uintptr_t len;
uintptr_t flags;
uintptr_t reserved;
};
} segments[0];
};
- }
+
+ struct Segment0 {
+ enum {
+ InvokeMethod = 0,
+ GetIFaces = 1,
+ ReturnIFaces = 2,
+ };
+
+ union {
+ struct {
+ uint8_t opcode;
+ };
+
+ unsigned long pad;
+ };
+ };
+
+ struct InvokeMethod {
+ Segment0 seg0;
+ uint32_t iface;
+ uint32_t method;
+ uint8_t args[0];
+ };
+
+ union Message {
+ Segment0 seg0;
+ InvokeMethod invoke;
+ };
- namespace Priv {
- static inline bool in_kernel()
- {
+ namespace Priv {
+ // Return the caller's PC. It'd be nice if GCC had a builtin for
+ // the current PC, so that a simple relocation could be used rather
+ // than a function call. OPT: put this in lowlevel-lib, so that
+ // architectures can provide a faster version.
+
+ unsigned long get_pc();
+
+ static inline bool in_kernel()
+ {
#ifdef _KERNEL
- return true;
+ return true;
#else
- return false;
+ return false;
#endif
+ }
+
+ typedef void (*MethodEntry)(ParamInfoBlock *pib);
+
+ struct Object {
+ MethodEntry entry;
+ void *ptr; // pointer to the class interface
+ };
+
+ typedef Util::RadixTree<Object, ID, 6> ObjTable;
}
};
}
new(::System::RunTime::orbmm) \
::System::Exceptions::NativeCodeExceptionOriginInfo \
(::System::RunTime::get_pc()), \
- ::System::Priv::in_kernel(), ##args); \
+ ::System::RunTime::Priv::in_kernel(), ##args); \
} while (0)
#define rethrow_idl(oldex, T, args...) do { \
new(::System::RunTime::orbmm) \
::System::Exceptions::NativeCodeExceptionOriginInfo \
(::System::RunTime::get_pc()), \
- ::System::Priv::in_kernel(), ##args); \
+ ::System::RunTime::Priv::in_kernel(), ##args); \
} while (0)
#endif
#include <System.h>
namespace System {
- namespace RunTime {
- // This function could be made to do a binary search if we can
- // manage to somehow sort the IFaceTables...
+namespace RunTime {
+ using ::System::Exceptions::Std;
- uintptr_t downcast(::System::_i_Object *obj,
- const unsigned long *new_guid)
- {
- if (!obj)
- return 0;
+ // This function could be made to do a binary search if we can
+ // manage to somehow sort the IFaceTables...
- void unsupported_long_size();
-
- if (sizeof(long) != 4 && sizeof(long) != 8)
- unsupported_long_size();
-
- IFaceTable *tbl = obj->info->concrete_IFaceTable;
- unsigned long new_guid_first = *new_guid;
-
- // This doesn't use guids_equal(), as that would eliminate the
- // ability to cache the first word of new_guid. The compiler
- // *might* do it anyway, but this code was written before
- // guids_equal existed, and I don't want to risk removing an
- // optimization by changing it now without testing how GCC
- // behaves.
-
- while (true) {
- if (tbl->guid[0] == new_guid_first &&
- tbl->guid[1] == new_guid[1] &&
- (sizeof(long) == 8 ||
- (tbl->guid[2] == new_guid[2] &&
- tbl->guid[3] == new_guid[3])))
- break;
-
- tbl++;
- if (__builtin_expect(!tbl->guid, 0))
- return 0;
- }
+ uintptr_t downcast(::System::_i_Object *obj,
+ const unsigned long *new_guid)
+ {
+ if (!obj)
+ return 0;
+
+ void unsupported_long_size();
+
+ if (sizeof(long) != 4 && sizeof(long) != 8)
+ unsupported_long_size();
+
+ IFaceTable *tbl = obj->info->concrete_IFaceTable;
+ unsigned long new_guid_first = *new_guid;
- uintptr_t ptr = reinterpret_cast<uintptr_t>(obj);
-
- ptr += obj->info->concrete;
- ptr += tbl->offset;
-
- return ptr;
- };
+ // This doesn't use guids_equal(), as that would eliminate the
+ // ability to cache the first word of new_guid. The compiler
+ // *might* do it anyway, but this code was written before
+ // guids_equal existed, and I don't want to risk removing an
+ // optimization by changing it now without testing how GCC
+ // behaves.
+ while (true) {
+ if (tbl->guid[0] == new_guid_first &&
+ tbl->guid[1] == new_guid[1] &&
+ (sizeof(long) == 8 ||
+ (tbl->guid[2] == new_guid[2] &&
+ tbl->guid[3] == new_guid[3])))
+ break;
+
+ tbl++;
+ if (__builtin_expect(!tbl->guid, 0))
+ return 0;
+ }
+
+ uintptr_t ptr = reinterpret_cast<uintptr_t>(obj);
+
+ ptr += obj->info->concrete;
+ ptr += tbl->offset;
+
+ return ptr;
+ };
+
+
+ namespace Priv {
+ ObjTable objtable;
+
unsigned long get_pc()
{
return reinterpret_cast<unsigned long>(__builtin_return_address(0));
}
+
+ void exception_to_array(::System::VStruct *ex, Array<uint8_t> *ar)
+ {
+ ar->ptr = reinterpret_cast<uint8_t *>(ex);
+ ar->count = ex->_infoptr->structlen;
+ }
+
+ void handle_message(ParameterInfoBlock *pib)
+ {
+ Message *msg = reinterpret_cast<Message *>(pib->segments[0].ptr);
+
+ switch (seg0->opcode) {
+ case Segment0::InvokeMethod: {
+ if (pib->segments[0].len < sizeof(InvokeMessage))
+ throw_idl(ShortMessage, 0, pib->segments[0].len,
+ sizeof(InvokeMessage));
+
+ ID obj = pib->objlist[0];
+
+
+ break;
+ }
+
+ default:
+ throw_idl(InvalidOpcode, seg0->opcode);
+ }
+ }
+ }
+}}
+
+extern "C" handle_message(ParameterInfoaBlock *pib, Array<uint8_t> *ex_arr)
+{
+ try {
+ ::System::RunTime::handle_message(pib);
+ }
+
+ catch (::System::Exception *ex) {
+ exception_to_array(ex, ex_arr);
+ }
+
+ catch (...) {
+ assertl(0, Assert::Always);
}
}