From: Scott Wood Date: Tue, 12 Jun 2007 03:46:46 +0000 (-0500) Subject: xfer to odin X-Git-Url: http://git.buserror.net/cgi-bin/gitweb.cgi?p=polintos%2Fscott%2Fpriv.git;a=commitdiff_plain;h=d32da4b91b9a403ae9d65c48fbb25c1abbb5083f xfer to odin --- diff --git a/doc/abi/x86 b/doc/abi/x86 index c62911d..805eb76 100644 --- a/doc/abi/x86 +++ b/doc/abi/x86 @@ -8,7 +8,7 @@ Out-of-Process Method Invocation: 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, @@ -20,12 +20,32 @@ Out-of-Process Method Invocation: 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 diff --git a/doc/orb/marshalling b/doc/orb/marshalling index a400d88..ab429bb 100644 --- a/doc/orb/marshalling +++ b/doc/orb/marshalling @@ -1,28 +1,41 @@ -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 ----------------------- @@ -37,5 +50,5 @@ Op2: Return 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. diff --git a/doc/orb/newobject b/doc/orb/newobject new file mode 100644 index 0000000..7b1c4c5 --- /dev/null +++ b/doc/orb/newobject @@ -0,0 +1,5 @@ +struct NewObject { + u32 guid_hash[4]; // Interface GUID checksum + u32 id; // Filled in by ORB + u32 reserved[3]; // must be zero +}; diff --git a/doc/orb/parameter-info-block b/doc/orb/parameter-info-block index 0c5281d..a39372b 100644 --- a/doc/orb/parameter-info-block +++ b/doc/orb/parameter-info-block @@ -1,6 +1,6 @@ -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 @@ -19,12 +19,12 @@ Parameter Info Block (PIB), all offsets in pointer-length words 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 @@ -33,12 +33,14 @@ Parameter Info Block (PIB), all offsets in pointer-length words 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 diff --git a/idl/exceptions.idl b/idl/exceptions.idl index f32e597..d0f2a2e 100644 --- a/idl/exceptions.idl +++ b/idl/exceptions.idl @@ -235,6 +235,12 @@ struct InvalidArgument : SystemException { 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 @@ -297,3 +303,23 @@ struct RefCountException : SystemException { 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; +}; diff --git a/idlcomp/TODO b/idlcomp/TODO index a8206fa..36123ad 100644 --- a/idlcomp/TODO +++ b/idlcomp/TODO @@ -51,3 +51,5 @@ Possibly implement out parameters on remote-only async methods that 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. diff --git a/include/c++/orb.h b/include/c++/orb.h index 1078555..076f1dd 100644 --- a/include/c++/orb.h +++ b/include/c++/orb.h @@ -254,11 +254,18 @@ namespace System { // 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) { @@ -269,22 +276,16 @@ namespace System { 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; @@ -297,16 +298,60 @@ namespace System { }; } 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 ObjTable; } }; } @@ -349,7 +394,7 @@ inline void operator delete[](void *ptr, ::System::RunTime::ORBMM *orbmm, 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 { \ @@ -357,7 +402,7 @@ inline void operator delete[](void *ptr, ::System::RunTime::ORBMM *orbmm, 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 diff --git a/lib/c++/orb.cc b/lib/c++/orb.cc index a1f10a5..26f3fc2 100644 --- a/lib/c++/orb.cc +++ b/lib/c++/orb.cc @@ -1,55 +1,103 @@ #include 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(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(obj); + + ptr += obj->info->concrete; + ptr += tbl->offset; + + return ptr; + }; + + + namespace Priv { + ObjTable objtable; + unsigned long get_pc() { return reinterpret_cast(__builtin_return_address(0)); } + + void exception_to_array(::System::VStruct *ex, Array *ar) + { + ar->ptr = reinterpret_cast(ex); + ar->count = ex->_infoptr->structlen; + } + + void handle_message(ParameterInfoBlock *pib) + { + Message *msg = reinterpret_cast(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 *ex_arr) +{ + try { + ::System::RunTime::handle_message(pib); + } + + catch (::System::Exception *ex) { + exception_to_array(ex, ex_arr); + } + + catch (...) { + assertl(0, Assert::Always); } }