---------------------------
-A port is a non-0 64-bit integer, that refers to another port that could be a part of the same
-or a different process (however, since threads don't exist, sending a message through a port to
-your own process will block it forever).
-It allows for sending and receiving data through to its other side.
+The port is the IPC method of this kernel. There are two types of ports.
+Server ports are points where a server will receive a message. They can receive
+ a message from any number of client ports.
+Client ports are points where a client can send a message. A client port always points
+ to a single, specific, server port.
---------------------------
Data types:
port_t = uint64_t;
-byte = unsigned char;
---------------------------
The system calls:
-If a syscall fails, it will return a negative value in %rax between -255 and -1, and the error code is -%rax. (like Linux)
-If it succeeds, if it returns a value, it returns it, otherwise it returns 0.
-Errors:
- 1: too many ports // The process has reached it's maximumwatching number of allowed ports.
- 2: port doesn't exist // This port isn't allocated in this process, or has already been closed on this side.
- 3: closed port // The port has been closed on the other side.
- 4: other side refusal // Error sent by the other side's program. Won't ever be generated by the kernel.
-
-// Create two connected infinite-use ports.
-// Possible errors:
-// too many ports
-void mkport(port_t* port_a, port_t* port_b);
-
-// Closes a port. This port now doesn't exist and its id is available for recycling.
-// If the other side tries any operation but a close on this port, it shall fail with 'closed port'
-// The port on the other side isn't closed, and can't be recycled, until the other side also calls close.
-// Possible errors:
-// port doesn't exist
-void close(port_t port);
-
-// Send a message to the other side of the port. Block until you receive an answer.
-// Returns the actual length of the reply (which can be more than what was written in
-// the reply buffer, if it was too short for it).
-// If no port was replied, *reply_port = 0.
-// While you technically cannot reply without a message, a 0 length message is the same
-// as no message (and allows for NULL as a pointer to the message).
-// Possible errors:
-// port doesn't exist
-// closed port
-// other side refusal
-size_t call(port_t port, byte const* message, size_t message_size, byte* reply_message, size_t reply_message_size, port_t* reply_port);
-
-// Block until a message is being sent to port, then return it's length.
-// Possible errors:
-// port doesn't exist
-// closed port
-size_t recv_len(port_t port);
-
-// Block until a message is being sent to port, then copy its contents to message.
-// This should only be used after recv_len, lest you risk a buffer overflow.
-// Possible errors:
-// port doesn't exist
-// closed port
-void recv(byte* message);
-
-// Unblock the other side, loading up the corresponding values in the call arguments.
-// Doesn't block this side at all, unless it is sent without the other side having called.
-// If a port (!= 0) is sent, it no longer exists in this program.
-// If reply_message_size is 0, reply_message is allowed to be NULL.
-// reply_port is allowed to be a port closed on the other side, but it must be 0 or a port
-// that still exists in this process.
-// Possible errors:
-// port doesn't exist
-// closed port
-void reply(port_t port, byte const* reply_message, size_t reply_message_size, port_t reply_port);
-
-// Unblock the other side, erroring with error code "other side refusal"
-// Doesn't block this side at all, unless it is sent without the other side having called.
-// Possible errors:
-// port doesn't exist
-// closed port
-void reply_error(port_t port);
-
-// Block until any port receives a message, or is closed on the other side.
-// Returns the corresponding port_t.
-// No possible errors.
-port_t wait();
-
-
-Without comments:
- void mkport(port_t* port_a, port_t* port_b);
- void close(port_t port);
- size_t call(port_t port, byte const* message, size_t message_size, byte* reply_message, size_t reply_message_size, port_t* reply_port);
- size_t recv_len(port_t port);
- void recv(byte* message);
- void reply(port_t port, byte const* reply_message, size_t reply_message_size, port_t reply_port);
- void reply_error(port_t port);
- port_t wait();
+Input and output registers in order: %rdi, %rsi, %rdx, %r10, %r8, %r9.
+In %rax, the error code of the operation is stored. If it is non-zero,
+ none of the other registers have defined values.
+
+Error codes:
+ 0: ERR_NONE: no error
+ 1: ERR_MANY_P: too many ports
+ 2: ERR_NOT_P: port doesn't exist -- developper error, i.e. a program bug
+ 3: ERR_CLOSED_P: port closed
+ 4: ERR_WRONG_P: wrong port type -- developper error, i.e. a program bug
+ 5: ERR_MEM_NOT_OWNED: send non-owned vaddr -- developper error, i.e. a program bug
+ 6: ERR_IN_HANDLER: recv without reply -- developper error, i.e. a program bug
+ 6: ERR_NIN_HANDLER: reply without recv -- developper error, i.e. a program bug
+
+mksport: () -> port_t
+ Creates a server port, with no associated clients. This absence of
+ clients does *not* cause any wait calls to end their wait.
+ *Possible errors:* ERR_MANY_P
+mkcport: port_t -> port_t
+ Creates a client port associated with the given server port.
+ *Possible errors:* ERR_MANY_P, ERR_NOT_P, ERR_WRONG_P
+cpcport: port_t -> port_t
+ Takes a client port, and returns a new client port that points to the same server port.
+ *Possible errors:* ERR_MANY_P, ERR_NOT_P, ERR_WRONG_P
+close: p: port_t -> ()
+ Close a port. It no longer exists in this process.
+ If it was a server port, any use of any of its client ports for the purpose
+ of communication will fail with ERR_CLOSED_P.
+ If it was a client port,
+ If it wasn't the server's last client, nothing happens.
+ If it was, however, the server will be notified by way of unfreezing
+ a wait call (but that's it).
+ *Possible errors:* ERR_NOT_P
+call: (port_t, d1: uint64_t, d2: uint64_t, tp: port_t, mem: void*, mem_len: uint64_t)
+ -> (d1: uint64_t, d2: uint64_t, tp: port_t, mem: void*, mem_len: uint64_t)
+ Takes a client port, and sends data to the corresponding server port.
+ d1 and d2 are copied.
+ The argument tp must be either 0 or a client port.
+ If it is 0, then the value transmitted is simply 0.
+ If it is non-0, then it is removed from the current process' namespace
+ and added (without necessarily the same id) to the called process. The
+ value transmitted will be that new port id.
+ If mem_len is 0, there are no restrictions on the value of mem. In that case,
+ nothing happens, and then transmitted values are mem = NULL and mem_len = 0.
+ If mem_len is greater than 0, then it is required that the pages containing vadresses
+ [mem; mem + mem_len[ be all owned by the calling process. They are removed from
+ its page mappings, and added to the called process'. The new virtual address is
+ transmitted in mem, with the same mem_len.
+ *Possible errors:* ERR_NOT_P, ERR_CLOSED_P, ERR_WRONG_P, ERR_MEM_NOT_OWNED
+recv: port_t -> (d1: uint64_t, d2: uint64_t, tp: port_t, mem: void*, mem_len: uint64_t)
+ Takes a server port. Blocks until this server port is called, then receives the
+ message as described in call.
+ *Possible errors:* ERR_NOT_P, ERR_WRONG_P, ERR_IN_HANDLER
+reply: (d1: uint64_t, d2: uint64_t, tp: port_t, mem: void*, mem_len: uint64_t) -> ()
+ Sends a message back to the port that the latest recv got its message from,
+ as described in call.
+ *Possible errors:* ERR_NOT_P, ERR_WRONG_P, ERR_MEM_NOT_OWNED, ERR_NIN_HANDLER
+wait: () -> port_t
+ Block until one of the server ports of this process is called or loses its last client.
+ Returns the server port in question.
+ *This syscall cannot fail.*
+hascports: port_t -> bool
+ Takes a server port, and returns the number of clients linked to it.
+ *Possible errors:* ERR_NOT_P, ERR_WRONG_P