Norost IPC packets format - version 1

This is technically the third IPC packet format I came up with. However, the first one was never used much and I consider the second to be v0 since it was still a rather quick & hacky implementation that happened to work well enough at first.

The text below is what I typed in “notes.txt” while also sketching on paper. I don’t intend to upload the sketches as I don’t have a scanner.

Revision 2

fields (32/64 bit):
  ( 4/ 8)  data: ptr
  ( 4/ 8)  name: ptr
  ( 8/ .)  data_offset: u64
  ( 4/ .)  data_length: u32
  ( 4/ .)  address: u32
  ( 2/ .)  flags_kernel: u16
  ( 2/ .)  flags_user: u16
  ( 2/ .)  name_length: u16
  ( 2/ .)  id: u16

total:
  (32/40)  packed
  (../..)  padded

flags_kernel (used by kernel):
  ( 2)   0- 1: Page size (4 levels: 4k/2M/1G/0.5T. More is likely (hopefully) not needed)
  ( 2)   2- 3: Data type (copy/share/move/inline)
  ( 2)   4- 5: Name type (copy/share/move/inline)
  ( 3)   6- 8: RWX flag data mapping
  ...

flags_user (ignored by kernel);
  ( 1)   0- 0: name (0) vs slot (1) name
  ( 1)   1- 1: byte (0) vs page (1) offset
  ( 1)   2- 2: ok (0) or err (1) (kernel-agnostic)
  ...
  ( 5)  11-15: Opcode (-16 to 15 ]signed (+request, -response))

opcodes:
  request:
     0: OPEN       (make server allocate slot->object mapping)
     1: CLOSE      (remove slot->object mapping)
     2: MAP        (map page)
     3: FLUSH      (flush modified mapped data)
     4: STAT       (get object info)
     5: LIST       (list child objects)
     6: CREATE     (create object)
     7: DESTROY    (destroy object)
  response:
    -1: OK         (operation successful)
    -2: EXISTS     (object already exist)
    -3: NOPERM     (insufficient permissions)
    -4: UNAVAIL    (object could or can not be created)

transfer:
  with ASID: just context switch, it's cheap
  without ASID: map IPC pages inside kernel to avoid switch

copy:
  copy directly to userspace
  userspace buffer: linked list of free blocks.
    each block is 2^n bytes large
    can be split into 2^(n-1), 2^(n-2), ... 16
      16 bytes min seems reasonable?
      256 bytes max seems reasonable too.
    if 2^m blocks not available, split in 2^(m-1)
      use one half, put other in list
      recursive
  max 2^16 free blocks of each size.
    more blocks can't be used in one go anyways.

move/share:
  map PPN[0] of self with A
    map PPN[1]
      map PPN[2]
        ...
  map PPN[0] of other page with B
    map PPN[1]
      map PPN[2]
        ...
  no context switch!
  can be even faster with idempotent mapping

Revision 1

fields (32/64 bit):
  ( 4/ 8)  address: usize
  ( 4/ 8)  name: ptr
  ( 4/ 8)  data: ptr
  ( 6/ .)  data_offset: u48
  ( 2/ .)  name_length: u16
  ( 4/ .)  data_length: u32
  ( 2/ .)  flags: u16
  ( 2/ .)  id: u16

total:
  (28/40)  packed
  (../..)  padded

flags:
  ( 2)   0- 1: Page size (4 levels: 4k/2M/1G/0.5T.
               More is likely (hopefully) not needed).
  ( 2)   2- 3: Data type (copy/share/move/inline)
  ( 2)   4- 5: Name type (copy/share/move/inline)
  ( 2)   6- 7: R/RW/RX/RWX flag data mapping
  ( 1)   8- 8: name (0) vs slot (1) name (kernel-agnostic)
  ( 1)   9- 9: byte (0) vs page (1) offset (kernel-agnostic)
  ( 1)  10-10: ok (0) or err (1) (kernel-agnostic)
  ( 5)  11-15: Opcode (32 kernel-agnostic, signed (+request, -response))

opcodes:
  request:
     0: OPEN       (make server allocate slot->object mapping)
     1: CLOSE      (remove slot->object mapping)
     2: MAP        (map page)
     3: FLUSH      (flush modified mapped data)
     4: STAT       (get object info)
     5: LIST       (list child objects)
     6: CREATE     (create object)
     7: DESTROY    (destroy object)
  response:
    -1: OK         (operation successful)
    -2: EXISTS     (object already exist)
    -3: NOPERM     (insufficient permissions)
    -4: UNAVAIL    (object could or can not be created)

transfer:
  with ASID: just context switch, it's cheap
  without ASID: map IPC pages inside kernel to avoid switch

copy:
  copy directly to userspace
  userspace buffer: linked list of free blocks.
    each block is 2^n bytes large
    can be split into 2^(n-1), 2^(n-2), ... 16
      16 bytes min seems reasonable?
      256 bytes max seems reasonable too.
    if 2^m blocks not available, split in 2^(m-1)
      use one half, put other in list
      recursive
  max 2^16 free blocks of each size.
    more blocks can't be used in one go anyways.

move/share:
  map PPN[0] of self with A
    map PPN[1]
      map PPN[2]
        ...
  map PPN[0] of other page with B
    map PPN[1]
      map PPN[2]
        ...
  no context switch!
  can be even faster with idempotent mapping