rax, rdi, rsi, rdx are in/out paramters.
rbx, rbp, rsp, r12-r15 are preserved.
rcx, rflags, r8-r11 are clobbered.

interrupts (including the timer!) are disabled during system calls.

a "mibisecond" is a 1024th of a second

stream result:
   0 = success
   1 = bad handle
   2 = io error
   3 = out of bounds
   4 = does not exist
   5 = not a regular file
   6 = not an executable
   7 = not writable
   8 = not seekable
   9 = socket id already used
  10 = socket id not in use
  11 = socket listener closed
  12 = other end closed
  13 = already exists
  14 = not sized
  15 = not readable

encode color:
  rax in: 0
  edi in: r + g * 256 + b * 65536
  eax out: encoded color

get framebuffer:
  rax in: 1
  rax out: pointer to framebuffer
  rdi out: width + height * 2 ** 32
  esi out: pitch
  framebuffer is always 32 bpp. use the encode color syscall
  to encode colors. pitch is in dwords, not in bytes.

open file:
  rax in: 2
  rdi in: pointer to file path
  rsi in: file path length
  rdx in:
    bit 0: allow creation
    bit 1: only allow creation
  rax out: stream result
  rdi out: stream handle (if rax = success)

end this thread:
  rax in: 3
  edi in: exit code (signed, only used if this was last thread)

get new pages:
  rax in: 4
  rdi in: number of pages to allocate
  rax out: start of first page
  the allocated pages are next to each other, writable, and not executable.

get input packet:
  rax in: 5
  al out:
    bit 7: was mouse packet
    if bit 7:
      bit 0: left mouse button down
      bit 1: right mouse button down
      bit 2: middle mouse button down
  if bit 7:
    di out: mouse x change (signed)
    si out: mouse y change (signed)
  else:
    edi out: key packet

create private socket:
  rax in: 6
  rax out: end 1 stream handle
  rdi out: end 2 stream handle

create socket listener:
  rax in: 7
  rdi in: pointer to id string
  rsi in: id string length
  rax out: stream result
  rdi out: listener handle (if rax = 0)

stop socket listener:
  rax in: 8
  rdi in: listener handle

accept socket connection:
  rax in: 9
  rdi in: listener handle
  rax out: stream result
  rdi out: stream handle

connect to socket:
  rax in: 10
  rdi in: pointer to id string
  rsi in: id string length
  rax out: stream result
  rdi out: stream handle (if rax = 0)

close stream:
  rax in: 11
  rdi in: stream handle

seek stream:
  returns "not seekable" for sockets
  rax in: 12
  rdi in: stream handle
  sil in:
    0 = relative to beginning
    1 = relative to end
    2 = relative to current position
  rdx in: offset (signed)
  rax out: stream result

read from stream:
  rax in: 13
  rdi in: stream handle
  rsi in: count
  rdx in: pointer to buffer
  rax out: stream result

write to stream:
  rax in: 14
  rdi in: stream handle
  rsi in: count
  rdx in: pointer to buffer
  rax out: stream result

get stream length:
  returns "not sized" for sockets
  rax in: 15
  rdi in: stream handle
  rax out: stream result
  rdi out: stream length (if rax = success)

start process:
  rax in: 16
  rdi in: pointer to process start info struct
  rax out: stream result
  rdi out: process handle (if rax = success)
  process start info struct:
    qword: file path length
    qword: pointer to file path
    qword: count of environment variables
    qword: pointer to array of environment variable structs
    qword: count of gifted stream ends
    qword: pointer to array of gifted stream structs
  environment variable struct:
    qword: name length
    qword: pointer to name
    qword: value length
    qword: pointer to value
  gifted stream struct:
    qword: stream handle here
    qword: new stream handle in child
      new handle must be < 65536
  any gifted streams must not have threads waiting to read from our end

end this process:
  rax in: 17
  edi in: exit code (signed)

set stream length:
  returns "not sized" for sockets
  rax in: 18
  rdi in: stream handle
  rsi in: new length
  rax out: stream result

get other end process handle:
  returns "other end closed" for files
  rax in: 19
  rdi in: stream handle
  rax out: stream result
  rdi out: process handle (if rax = success)

start thread:
  rax in: 20
  rdi in: entry point
  rsi in: argument
  at entry, rsp is set to the top of a new stack, rdi is set
  to the argument, and the other registers are undefined.

clear socket read queue:
  rax in: 21
  rdi in: stream handle
  rax out: number of bytes cleared (0 on bad handle or not a socket)

get environment variable length:
  rax in: 22
  rdi in: pointer to variable name
  rsi in: variable name length
  rax out: variable value length, or -1 if unset

get environment variable value:
  rax in: 23
  rdi in: pointer to variable name
  rsi in: variable name length
  rdx in: pointer to buffer for variable value

set thread name:
  rax in: 24
  rdi in: pointer to thread name
  rsi in: thread name length

sleep:
  rax in: 25
  rdi in: "mibiseconds" to sleep for

get time:
  rax in: 26
  rax out: "mibiseconds" since january 1st 2000
