|
|
|
|
|
|
|
|
|
|
| pragma SPARK_Mode (On);
|
|
|
| with SEB_Types;
|
| use SEB_Types;
|
| with Interfaces.C;
|
| with Interfaces.C.Strings;
|
|
|
| package body SEB_WAL is
|
|
|
| package C renames Interfaces.C;
|
| use Interfaces.C.Strings;
|
|
|
| PROT_READ : constant C.int := 1;
|
| PROT_WRITE : constant C.int := 2;
|
| MAP_SHARED : constant C.int := 1;
|
| MS_SYNC : constant C.int := 4;
|
|
|
| function mmap
|
| (addr : C.Strings.chars_ptr;
|
| len : C.size_t;
|
| prot : C.int;
|
| flags : C.int;
|
| fd : C.int;
|
| offset : C.long)
|
| return C.Strings.chars_ptr
|
| with Import => True, Convention => C, External_Name => "mmap";
|
|
|
| function munmap
|
| (addr : C.Strings.chars_ptr;
|
| len : C.size_t)
|
| return C.int
|
| with Import => True, Convention => C, External_Name => "munmap";
|
|
|
| function msync
|
| (addr : C.Strings.chars_ptr;
|
| len : C.size_t;
|
| flags : C.int)
|
| return C.int
|
| with Import => True, Convention => C, External_Name => "msync";
|
|
|
| function blake3_hash
|
| (data : C.Strings.chars_ptr;
|
| data_len : C.size_t;
|
| hash_out : C.Strings.chars_ptr)
|
| return C.int
|
| with Import => True, Convention => C, External_Name => "blake3_hash";
|
|
|
| function ed25519_verify
|
| (message : C.Strings.chars_ptr;
|
| msg_len : C.size_t;
|
| signature : C.Strings.chars_ptr;
|
| public_key : C.Strings.chars_ptr)
|
| return C.int
|
| with Import => True, Convention => C, External_Name => "ed25519_verify";
|
|
|
| type Segment_Mapping is record
|
| Segment_Id : Unsigned_64;
|
| Sequence : Unsigned_64;
|
| Fd : C.int;
|
| Mapped : C.Strings.chars_ptr;
|
| Used : Unsigned_64;
|
| Max_Size : Unsigned_64;
|
| end record;
|
|
|
| Max_Segments : constant := 1024;
|
| type Segment_Array is array (1 .. Max_Segments) of Segment_Mapping;
|
|
|
| protected type Kernel_State_Protected is
|
| procedure Initialize
|
| (Initial_Segment_Id : Unsigned_64;
|
| Initial_Sequence : Unsigned_64);
|
| procedure Append_Event_Internal
|
| (Header : Event_Header;
|
| Payload : Unsigned_8_Array;
|
| Footer : Event_Footer;
|
| Committed_Offset : out Segment_Offset;
|
| Status : out Verification_Status);
|
| procedure Rotate_Segment_Internal
|
| (New_Segment_Id : Unsigned_64;
|
| New_Sequence : Unsigned_64;
|
| Rotation_Offset : out Segment_Offset;
|
| Status : out Verification_Status);
|
| procedure WORM_Flush_Internal;
|
| procedure Verify_Chain_Internal
|
| (Valid : out Boolean;
|
| Events_Checked : out Unsigned_64);
|
| function Get_Segment_Id return Unsigned_64;
|
| function Get_Sequence return Unsigned_64;
|
| function Get_Tip_Hash return Hash_Type;
|
| function Get_Tip_Offset return Segment_Offset;
|
| function Get_Events_Sealed return Unsigned_64;
|
| function Get_Segs_Rotated return Unsigned_64;
|
| private
|
| Segments : Segment_Array;
|
| Seg_Index : Natural := 0;
|
| Cur_Segment_Id : Unsigned_64 := 0;
|
| Cur_Sequence : Unsigned_64 := 0;
|
| Tip_Hash : Hash_Type := (others => 0);
|
| Tip_Offset : Segment_Offset := 0;
|
| Events_Sealed : Unsigned_64 := 0;
|
| Segments_Rotated : Unsigned_64 := 0;
|
| end Kernel_State_Protected;
|
|
|
| Global_State : Kernel_State_Protected;
|
|
|
| protected body Kernel_State_Protected is
|
|
|
| procedure Initialize
|
| (Initial_Segment_Id : Unsigned_64;
|
| Initial_Sequence : Unsigned_64) is
|
| begin
|
| Cur_Segment_Id := Initial_Segment_Id;
|
| Cur_Sequence := Initial_Sequence;
|
| Seg_Index := 1;
|
| Tip_Hash := (others => 0);
|
| Tip_Offset := 0;
|
| Events_Sealed := 0;
|
| Segments_Rotated := 0;
|
| end Initialize;
|
|
|
| procedure Append_Event_Internal
|
| (Header : Event_Header;
|
| Payload : Unsigned_8_Array;
|
| Footer : Event_Footer;
|
| Committed_Offset : out Segment_Offset;
|
| Status : out Verification_Status) is
|
| begin
|
|
|
| Status := Valid;
|
|
|
|
|
| if Events_Sealed > 0 and Footer.Prev_Hash /= Tip_Hash then
|
| Status := Invalid_Hash;
|
| Committed_Offset := 0;
|
| return;
|
| end if;
|
|
|
|
|
| if Unsigned_64 (Header.Prev_Offset) >= Unsigned_64 (Tip_Offset)
|
| and Events_Sealed > 0
|
| then
|
| Status := Invalid_Offset;
|
| Committed_Offset := 0;
|
| return;
|
| end if;
|
|
|
| declare
|
| Event_Size : constant Unsigned_64 := Event_Total_Size (Header);
|
| New_Offset : constant Unsigned_64 :=
|
| Unsigned_64 (Tip_Offset) + Event_Size;
|
| begin
|
|
|
| if New_Offset > Unsigned_64 (Max_Offset) then
|
| Status := Segment_Full;
|
| Committed_Offset := 0;
|
| return;
|
| end if;
|
|
|
| Committed_Offset := Tip_Offset;
|
| Tip_Hash := Footer.Event_Hash;
|
| Tip_Offset := Segment_Offset (New_Offset);
|
| Events_Sealed := Events_Sealed + 1;
|
| end;
|
| end Append_Event_Internal;
|
|
|
| procedure Rotate_Segment_Internal
|
| (New_Segment_Id : Unsigned_64;
|
| New_Sequence : Unsigned_64;
|
| Rotation_Offset : out Segment_Offset;
|
| Status : out Verification_Status) is
|
| begin
|
|
|
| if Seg_Index >= Max_Segments then
|
| Status := Unknown_Error;
|
| Rotation_Offset := 0;
|
| return;
|
| end if;
|
|
|
| Seg_Index := Seg_Index + 1;
|
| Cur_Segment_Id := New_Segment_Id;
|
| Cur_Sequence := New_Sequence;
|
| Tip_Offset := 0;
|
| Segments_Rotated := Segments_Rotated + 1;
|
| Rotation_Offset := 0;
|
| Status := Valid;
|
| end Rotate_Segment_Internal;
|
|
|
| procedure WORM_Flush_Internal is
|
| begin
|
|
|
| null;
|
| end WORM_Flush_Internal;
|
|
|
| procedure Verify_Chain_Internal
|
| (Valid : out Boolean; Events_Checked : out Unsigned_64) is
|
| begin
|
| Valid := True;
|
| Events_Checked := Events_Sealed;
|
| end Verify_Chain_Internal;
|
|
|
| function Get_Segment_Id return Unsigned_64 is (Cur_Segment_Id);
|
| function Get_Sequence return Unsigned_64 is (Cur_Sequence);
|
| function Get_Tip_Hash return Hash_Type is (Tip_Hash);
|
| function Get_Tip_Offset return Segment_Offset is (Tip_Offset);
|
| function Get_Events_Sealed return Unsigned_64 is (Events_Sealed);
|
| function Get_Segs_Rotated return Unsigned_64 is (Segments_Rotated);
|
|
|
| end Kernel_State_Protected;
|
|
|
|
|
|
|
| procedure Initialize_Kernel
|
| (Initial_Segment_Id : Unsigned_64; Initial_Sequence : Unsigned_64) is
|
| begin
|
| Global_State.Initialize (Initial_Segment_Id, Initial_Sequence);
|
| end Initialize_Kernel;
|
|
|
| procedure Append_Event
|
| (Header : Event_Header;
|
| Payload : Unsigned_8_Array;
|
| Footer : Event_Footer;
|
| Committed_Offset : out Segment_Offset;
|
| Status : out Verification_Status) is
|
| begin
|
| Global_State.Append_Event_Internal
|
| (Header, Payload, Footer, Committed_Offset, Status);
|
| end Append_Event;
|
|
|
| procedure Rotate_Segment
|
| (New_Segment_Id : Unsigned_64;
|
| New_Sequence : Unsigned_64;
|
| Rotation_Offset : out Segment_Offset;
|
| Status : out Verification_Status) is
|
| begin
|
| Global_State.Rotate_Segment_Internal
|
| (New_Segment_Id, New_Sequence, Rotation_Offset, Status);
|
| end Rotate_Segment;
|
|
|
| procedure WORM_Flush is
|
| begin
|
| Global_State.WORM_Flush_Internal;
|
| end WORM_Flush;
|
|
|
| procedure Verify_Chain
|
| (Valid : out Boolean; Events_Checked : out Unsigned_64) is
|
| begin
|
| Global_State.Verify_Chain_Internal (Valid, Events_Checked);
|
| end Verify_Chain;
|
|
|
| function Get_Segment_Id return Unsigned_64 is (Global_State.Get_Segment_Id);
|
| function Get_Sequence return Unsigned_64 is (Global_State.Get_Sequence);
|
| function Get_Tip_Hash return Hash_Type is (Global_State.Get_Tip_Hash);
|
| function Get_Tip_Offset return Segment_Offset is (Global_State.Get_Tip_Offset);
|
| function Get_Events_Sealed return Unsigned_64 is (Global_State.Get_Events_Sealed);
|
| function Get_Segs_Rotated return Unsigned_64 is (Global_State.Get_Segs_Rotated);
|
|
|
| end SEB_WAL;
|
|
|