#include <Uefi.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/UefiLib.h>
#include <Library/BaseLib.h>
#include <Library/PrintLib.h>
#include <Protocol/LoadedImage.h>
#include <Protocol/BlockIo.h>
#include <Protocol/SimpleFileSystem.h>
#include <Protocol/GraphicsOutput.h>
#include <Protocol/PartitionInfo.h>
#include <Guid/FileInfo.h>
#include "libs/include/debug.h"
#include "libs/include/cpu.h"
#include "libs/include/disk.h"
#include "libs/include/console.h"
#include "libs/include/conf.h"
#include "libs/include/crypto.h"
#include "libs/include/font.h"
#include "libs/include/graphic.h"
#include "libs/include/ui.h"
#include "libs/include/initfs.h"
#include "libs/include/vyx.h"
#include "libs/include/key.h"
#define ARGON2_NO_THREADS
const CHAR16 blastproof_files_path[]=L"\\EFI\\BlastProofFiles\\";
const CHAR16 blastproof_sign_path[]=L"\\EFI\\BlastProofSign\\";
BOOLEAN allow_debugging=FALSE;
BOOLEAN allow_erroring=FALSE;
EFI_GUID gEfiLoadedImageProtocolGuid=EFI_LOADED_IMAGE_PROTOCOL_GUID;
EFI_GUID gEfiBlockIoProtocolGuid=EFI_BLOCK_IO_PROTOCOL_GUID;
EFI_GUID gEfiFileInfoGuid=EFI_FILE_INFO_ID;
EFI_GUID gEfiSerialIoProtocolGuid=EFI_SERIAL_IO_PROTOCOL_GUID;
EFI_GUID gEfiPartitionInfoProtocolGuid=EFI_PARTITION_INFO_PROTOCOL_GUID;
UINT16 binary_version=0x0001;
EFI_STATUS
EFIAPI
UefiMain (IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE *SystemTable) {
  gST->ConOut->ClearScreen(gST->ConOut);
  EFI_SERIAL_IO_PROTOCOL *serial;
  gBS->LocateProtocol(&gEfiSerialIoProtocolGuid,NULL,(void**)&serial);
  Print(L"[BlastBoot] Blastproof v0.1\n");
  Print(L"[BlastBoot] Firmware Vendor: %s\n",gST->FirmwareVendor);
  Print(L"[BlastBoot] Firmware Revision: %u (0x%08x)\n",gST->FirmwareRevision,gST->FirmwareRevision);
  Print(L"[BlastCPU] --- CPU Info ---\n");
  bp_cpu_CPU_INFO booting_cpu_info;
  bp_cpu_fill_cpu_info(&booting_cpu_info);
  Print(L"[BlastCPU] CPU Vendor ID: %a\n",booting_cpu_info.vendor);
  Print(L"[BlastCPU] Max basic CPUID level: 0x%x\n",booting_cpu_info.max_cpuid_level);
  Print(L"[BlastCPU] CPU Family: %u\n[BlastCPU] CPU Model: %u\n[BlastCPU] CPU Stepping: %u\n",booting_cpu_info.display_family,booting_cpu_info.display_model,booting_cpu_info.stepping);
  Print(L"[BlastCPU] CPU Feature from Ecx: %s\n",booting_cpu_info.ecx_bin);
  Print(L"[BlastCPU] CPU Feature from Edx: %s\n",booting_cpu_info.edx_bin);
  EFI_STATUS status;
  bp_console_PASSWORD *password;
  status=bp_console_read_password(L"[BlastConsole] Please enter boot password: ",&password,L'*');
  if (EFI_ERROR(status)) {
    Print(L"[BlastConsole] Error: an error happened during password typing.\n");
    while (TRUE) {};
  }
  bp_crypto_HASH_DIGEST *seed;
  bp_crypto_ARGON2_CONTEXT context;
  context.hash_size=96;
  context.salt=bp_key_pwdsalt;
  context.salt_size=sizeof(bp_key_pwdsalt);
  context.memory_cost=262144;
  context.time_cost=3;
  context.password=*password;
  status=bp_crypto_argon2id_raw(&context,&seed);
  if (EFI_ERROR(status)) {
    Print(L"[BlastCrypto] Something went wrong when hashing password.");
    while (TRUE) {};
  }
  bp_crypto_SPHINCSPLUS_KEYPAIR *keypair;
  keypair->erase_sk=TRUE;
  status=bp_crypto_sphincsplus_keypair_seed(seed->digest,seed->size_bytes,TRUE,FALSE,&keypair);
  if (!EFI_ERROR(status)) {
    Print(L"[BlastCrypto] Generated keypair successfully.\n");
  } else {
    Print(L"[BlastCrypto] An error happened during keypair generation.\n");
    while (TRUE) {};
  }
  status=bp_crypto_sphincsplus_verify(bp_key_mainsig,sizeof(bp_key_mainsig),bp_key_pkblob,sizeof(bp_key_pkblob),keypair->pk);
  if (!EFI_ERROR(status)) {
    Print(L"[BlastCrypto] Verification passed. Password was good.\n");
  } else {
    Print(L"[BlastCrypto] Verification failed. Password was wrong.\n");
    Print(L"[BlastCrypto] Please reboot your computer to retry.\n");
    while (TRUE) {};
  }
  Print(L"[BlastDisk] Acquiring loaded image.\n");
  EFI_LOADED_IMAGE_PROTOCOL *loaded_image;
  status=gBS->HandleProtocol(ImageHandle,&gEfiLoadedImageProtocolGuid,(VOID**)&loaded_image);
  if (EFI_ERROR(status)) {
    Print(L"[BlastDisk] Error: can't get LoadedImage.\n");
    while (TRUE) {};
  } else {
    Print(L"[BlastDisk] LoadedImage acquired.\n");
  }
  EFI_BLOCK_IO_PROTOCOL *block_io_loaded_image=NULL;
  status=gBS->HandleProtocol(loaded_image->DeviceHandle,&gEfiBlockIoProtocolGuid,(VOID **)&block_io_loaded_image);
  if (EFI_ERROR(status)) {
    Print(L"[BlastDisk] Error: can't get BlockIo.\n");
    while (TRUE) {};
  } else {
    Print(L"[BlastDisk] BlockIo on LoadedImage acquired.\n");
  }
  if (!block_io_loaded_image->Media->LogicalPartition) {
    Print(L"[BlastDisk] Error: BlockIo on LoadedImage isn't a partition.");
    while (TRUE) {};
  }
  EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *fs;
  EFI_FILE_PROTOCOL *root;
  status=gBS->HandleProtocol(loaded_image->DeviceHandle,&gEfiSimpleFileSystemProtocolGuid,(VOID**)&fs);
  if (EFI_ERROR(status)) {
    Print(L"[BlastDisk] Error: No filesystem on this BlockIo.\n");
    while (TRUE) {};
  } else {
    Print(L"[BlastDisk] Filesystem on BlockIo acquired.\n");
  }
  status=fs->OpenVolume(fs,&root);
  if (EFI_ERROR(status)) {
    Print(L"[BlastDisk] Error: can't open root directory.\n");
    while (TRUE) {};
  } else {
    Print(L"[BlastDisk] Root directory opened.\n");
  }
  CHAR16 file_full_path[250];
  CHAR16 sign_full_path[250];
  UINT8 pk[CRYPTO_PUBLICKEYBYTES];
  for (INTN i=0;i<sizeof(bp_key_files)/sizeof(bp_key_files[0]);++i) {
    CopyMem(pk,bp_key_pkblob+i*CRYPTO_PUBLICKEYBYTES,CRYPTO_PUBLICKEYBYTES);
    UnicodeSPrint(file_full_path,sizeof(file_full_path),L"%s%s",blastproof_files_path,bp_key_files[i]);
    UnicodeSPrint(sign_full_path,sizeof(sign_full_path),L"%s%s.sig",blastproof_sign_path,bp_key_files[i]);
    status=bp_crypto_sphincsplus_verify_file(root,file_full_path,sign_full_path,pk);
    bp_crypto_secure_erase(pk,CRYPTO_PUBLICKEYBYTES);
    if (status==EFI_SECURITY_VIOLATION) {
      Print(L"[BlastCrypto] Error: critical security violation in boot process:\n");
      Print(L"[BlastCrypto] File \"%s\" couldn't be verified successfully.\n",file_full_path);
      while (TRUE) {};
    } else if (EFI_ERROR(status)) {
      Print(L"[BlastCrypto] Error: couldn't verify file: \"%s\"\n",file_full_path);
      while (TRUE) {};
    } else {
      Print(L"[BlastCrypto] Successfully verified %d/%d file(s).\n",i+1,sizeof(bp_key_files)/sizeof(bp_key_files[0]));
    }
  }
  if (EFI_ERROR(bp_disk_check_file_existence(root,L"\\EFI\\BlastProofFiles\\bp.conf"))) {
    Print(L"[BlastDisk] Error: Config not found.");
    while (TRUE) {};
  } else {
    Print(L"[BlastDisk] Config found.\n");
  }
  bp_disk_FILE *bp_conf_content=NULL;
  EFI_FILE_PROTOCOL *initfs_conf_file;
  status=bp_disk_open_file(root,L"\\EFI\\BlastProofFiles\\bp.conf",&initfs_conf_file);
  if (EFI_ERROR(status)) {
    Print(L"[BlastDisk] Error: can't open config.");
    while (TRUE) {};
  } else {
    Print(L"[BlastDisk] Config opened.\n");
  }
  status=bp_disk_read_file(initfs_conf_file,&bp_conf_content);
  if (EFI_ERROR(status)) {
    Print(L"[BlastDisk] Error: can't read config.");
    while (TRUE) {};
  } else {
    Print(L"[BlastDisk] Readed config.\n");
  }
  UINTN line_number;
  status=bp_conf_get_lines_number(bp_conf_content,&line_number);
  if (!EFI_ERROR(status)) {
    Print(L"[BlastConf] Configuration contain %u lines.\n",line_number);
  } else {
    Print(L"[BlastConf] Error: can't read configuration lines number.\n",line_number);
    while (TRUE) {};
  }
  bp_conf_LINED_FILE *lined_file=NULL;
  status=bp_conf_parse_file_lines(bp_conf_content,&lined_file);
  if (!EFI_ERROR(status)) {
    Print(L"[BlastConf] Configuration line-parsed sucessfully.\n");
  } else {
    Print(L"[BlastConf] Error: can't line-parse configuration.\n",line_number);
    while (TRUE) {};
  }
  bp_conf_CONF *conf=NULL;
  status=bp_conf_parse_conf(lined_file,&conf);
  if (!EFI_ERROR(status)) {
    Print(L"[BlastConf] Configuration parsed sucessfully.\n");
    Print(L"[BlastConf] Configuration pair amount: %u.\n",conf->count);
  } else {
    Print(L"[BlastConf] Error: can't parse configuration.\n",line_number);
    while (TRUE) {};
  }
  bp_conf_BOOT_CONF *boot_conf=NULL;
  status=bp_conf_fill_default_boot_conf(&boot_conf);
  if (EFI_ERROR(status)) {
    Print(L"[BlastConf] Error: can't set default boot configuration.\n",line_number);
    while (TRUE) {};
  } else {
    Print(L"[BlastConf] Default boot configuration applied. Overriding with given configuration:\n");
  }
  status=bp_conf_fill_boot_conf(conf,&boot_conf);
  if (status==EFI_INVALID_PARAMETER) {
    while (TRUE) {};
  } else if (EFI_ERROR(status)) {
    Print(L"[BlastConf] Error: can't get boot configuration.\n",line_number);
    while (TRUE) {};
  } else {
    Print(L"[BlastConf] Boot configuration obtained.\n");
  }
  allow_debugging=boot_conf->serial_port_enabled && boot_conf->serial_port_debuging;
  allow_erroring=boot_conf->serial_port_enabled && boot_conf->serial_port_erroring;
  EFI_GRAPHICS_OUTPUT_PROTOCOL *gop;
  status=gBS->LocateProtocol(&gEfiGraphicsOutputProtocolGuid,NULL,(void **)&gop);
  if (EFI_ERROR(status)) {
    Print(L"[BlastBoot] Error: can't locate Graphics Output Protocol.\n");
    while (TRUE) {};
  }
  UINT32 mode_index;
  if (boot_conf->default_horizontal_resolution==0 && boot_conf->default_vertical_resolution==0) {
    status=bp_graphic_get_highest_resolution_index(gop,&mode_index);
    if (EFI_ERROR(status)) {
      Print(L"[BlastGraphic] Error: can't identify biggest resolution mode.\n");
      while (TRUE) {};
    } else {
      EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *info_mode;
      UINTN info_size;
      status=gop->QueryMode(gop,mode_index,&info_size,&info_mode);
      if (EFI_ERROR(status)) {
        Print(L"[BlastGraphic] Error: can't get information about biggest resolution mode.\n");
        while (TRUE) {};
      }
      Print(L"[BlastGraphic] Using mode %d with %dx%d pixels (biggest mode selected by configuration choice).\n",mode_index,info_mode->HorizontalResolution,info_mode->VerticalResolution);
    }
  } else {
    status=bp_graphic_get_index_by_resolution(gop,(*boot_conf).default_horizontal_resolution,(*boot_conf).default_vertical_resolution,&mode_index);
    if (status==EFI_SUCCESS) {
      EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *info_mode;
      UINTN info_size;
      status=gop->QueryMode(gop,mode_index,&info_size,&info_mode);
      if (EFI_ERROR(status)) {
        Print(L"[BlastGraphic] Error: can't get information about requested resolution mode.\n");
        while (TRUE) {};
      }
      Print(L"[BlastGraphic] Using mode %d with %dx%d pixels (mode selected by using resolution from config).\n",mode_index,info_mode->HorizontalResolution,info_mode->VerticalResolution);
    } else if (status==EFI_NOT_FOUND) {
      Print(L"[BlastGraphic] Warning: requested graphic mode (%dx%d) provided by config isn't available on this platform. Falling back on biggest resolution available.\n",(*boot_conf).default_horizontal_resolution,(*boot_conf).default_vertical_resolution);
      status=bp_graphic_get_highest_resolution_index(gop,&mode_index);
      if (EFI_ERROR(status)) {
        Print(L"[BlastGraphic] Error: can't identify biggest resolution mode.\n");
        while (TRUE) {};
      } else {
        EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *info_mode;
        UINTN info_size;
        status=gop->QueryMode(gop,mode_index,&info_size,&info_mode);
        if (EFI_ERROR(status)) {
          Print(L"[BlastGraphic] Error: can't get information about biggest resolution mode.\n");
          while (TRUE) {};
        }
        Print(L"[BlastGraphic] Using mode %d with %dx%d pixels (biggest mode selected because resolution provided by configuration isn't available).\n",mode_index,info_mode->HorizontalResolution,info_mode->VerticalResolution);
      }
    } else {
      Print(L"[BlastGraphic] Warning: requested graphic mode (%dx%d) provided by config couldn't be obtained. Trying to fall back on biggest resolution available.\n",(*boot_conf).default_horizontal_resolution,(*boot_conf).default_vertical_resolution);
      status=bp_graphic_get_highest_resolution_index(gop,&mode_index);
      if (EFI_ERROR(status)) {
        Print(L"[BlastGraphic] Error: can't identify biggest resolution mode.\n");
        while (TRUE) {};
      } else {
        EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *info_mode;
        UINTN info_size;
        status=gop->QueryMode(gop,mode_index,&info_size,&info_mode);
        if (EFI_ERROR(status)) {
          Print(L"[BlastGraphic] Error: can't get information about biggest resolution mode.\n");
          while (TRUE) {};
        }
        Print(L"[BlastGraphic] Using mode %d with %dx%d pixels (biggest mode selected because resolution provided by configuration couldn't be obtained).\n",mode_index,info_mode->HorizontalResolution,info_mode->VerticalResolution);
      }
    }
  }
  EFI_FILE_PROTOCOL *fbm_font;
  CHAR16 temp_buffer[256];
  Print(L"[BlastFont] Attempting to use font %s as font.\n",boot_conf->font);
  UnicodeSPrint(temp_buffer,256,L"\\EFI\\BlastProofFiles\\%s",boot_conf->font);
  status=bp_disk_open_file(root,temp_buffer,&fbm_font);
  if (EFI_ERROR(status)) {
    Print(L"[BlastFont] Error: can't open font.\n");
    while (TRUE) {};
  } else {
    Print(L"[BlastFont] Font opened.\n");
  }
  bp_disk_FILE *fbm_font_content=NULL;
  status=bp_disk_read_file(fbm_font,&fbm_font_content);
  if (EFI_ERROR(status)) {
    Print(L"[BlastFont] Error: can't read font.\n");
    while (TRUE) {};
  } else {
    Print(L"[BlastFont] Readed font.\n");
  }
  bp_font_FBM_HEADER *font_header;
  status=bp_font_get_header(fbm_font_content,&font_header);
  if (EFI_ERROR(font_header)) {
    Print(L"[BlastFont] Error: couldn't read font header.\n");
    while (TRUE) {};
  } else {
    Print(L"[BlastFont] Font header readed.\n");
  }
  if (font_header->encoding!=0x01) {
    Print(L"[BlastFont] Error: font isn't encoded in ASCII.\n");
    while (TRUE) {};
  } else {
    Print(L"[BlastFont] Font is %d by %d pixels, encoded in ASCII and contain %d glyphs.\n",font_header->width,font_header->height,font_header->entries_count);
  }
  bp_font_FBM_FONT *loaded_font;
  status=bp_font_load_font(fbm_font_content,&loaded_font);
  if (EFI_ERROR(status)) {
    Print(L"[BlastFont] Error: can't load font.\n",font_header->width,font_header->width,font_header->entries_count);
    while (TRUE) {};
  } else {
    Print(L"[BlastFont] Successfully loaded font.\n",font_header->width,font_header->width,font_header->entries_count);
  }
  status=bp_font_check_font(loaded_font,font_header);
  if (status==EFI_VOLUME_CORRUPTED) {
    Print(L"[BlastFont] Error: font is corrupted.\n",font_header->width,font_header->width,font_header->entries_count);
    while (TRUE) {};
  } else if (EFI_ERROR(status)) {
    Print(L"[BlastFont] Error: couldn't check font.\n",font_header->width,font_header->width,font_header->entries_count);
    while (TRUE) {};
  } else {
    Print(L"[BlastFont] Successfully checked font.\n",font_header->width,font_header->width,font_header->entries_count);
  }
  bp_font_FBM_FONT_BUFFER *font_buffer;
  status=bp_font_parse_font(loaded_font,font_header,&font_buffer);
  if (EFI_ERROR(status)) {
    Print(L"[BlastFont] Error: can't parse font.\n",font_header->width,font_header->width,font_header->entries_count);
    while (TRUE) {};
  } else {
    Print(L"[BlastFont] Successfully parsed font.\n",font_header->width,font_header->width,font_header->entries_count);
  }
  bp_font_FBM_FONT_RENDER *font_render;
  bp_font_FBM_RENDERER_SETTING settings;
  EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *info_mode;
  UINTN info_size;
  status=gop->QueryMode(gop,mode_index,&info_size,&info_mode);
  if (EFI_ERROR(status)) {
    Print(L"[BlastFont] Error: can't get information about selected graphic mode for rendering font.\n");
    while (TRUE) {};
  }
  if (info_mode->PixelFormat==PixelRedGreenBlueReserved8BitPerColor) {
    settings.red_bits=0x00FF0000;
    settings.green_bits=0x0000FF00;
    settings.blue_bits=0x000000FF;
    Print(L"[BlastFont] Using PixelRedGreenBlueReserved8BitPerColor pixel format.\n");
  } else if (info_mode->PixelFormat==PixelBlueGreenRedReserved8BitPerColor) {
    settings.blue_bits=0x000000FF;
    settings.green_bits=0x0000FF00;
    settings.red_bits=0x00FF0000;
    Print(L"[BlastFont] Using PixelBlueGreenRedReserved8BitPerColor pixel format.\n");
  } else if (info_mode->PixelFormat==PixelBitMask) {
    settings.red_bits=info_mode->PixelInformation.RedMask;
    settings.green_bits=info_mode->PixelInformation.GreenMask;
    settings.blue_bits=info_mode->PixelInformation.BlueMask;
    Print(L"[BlastFont] Using custom pixel format.\n");
  } else {
    Print(L"[BlastFont] Error: GoP mode without a physical framebuffer isn't supported for the moment.\n");
    while (TRUE) {};
  }
  bp_graphic_COLOR_RGB background_color;
  background_color.r=0x00;
  background_color.g=0x00;
  background_color.b=0x00;
  bp_graphic_COLOR_RGB text_color;
  text_color.r=0xFF;
  text_color.g=0xFF;
  text_color.b=0xFF;
  settings.background_color=background_color;
  settings.text_color=text_color;
  status=bp_font_render_font(font_buffer,font_header,settings,&font_render);
  if (EFI_ERROR(status)) {
    Print(L"[BlastFont] Error: rendering font failed.\n");
    while (TRUE) {};
  } else {
    Print(L"[BlastFont] Successfully rendered font.\n");
  }
  Print(L"[BlastGraphic] Switching to graphical user interface.\n");
  status=gop->SetMode(gop,mode_index);
  if (EFI_ERROR(status)) {
    Print(L"[BlastGraphic] Error: an error happened during graphic mode change.\n");
    while (TRUE) {};
  }
  bp_debug_write_line(serial,"[BlastDebug] If you can see this message, that mean that you're reading on the serial port or that something has gone horribly wrong in the switch to graphical user interface.",allow_debugging);
  EFI_PHYSICAL_ADDRESS framebuf_base=gop->Mode->FrameBufferBase;
  UINT32 *fb=(UINT32 *)(UINTN)framebuf_base;
  EFI_FILE_PROTOCOL *bootanim_file;
  status=bp_disk_open_file(root,L"\\EFI\\BlastProofFiles\\bootanim.bin",&bootanim_file);
  if (EFI_ERROR(status)) {
    bp_debug_write_line(serial,"[BlastDebug:BlastUi] Error: can't open boot animation.",allow_erroring);
    while (TRUE) {};
  } else {
    bp_debug_write_line(serial,"[BlastDebug:BlastUi] Opened boot animation.",allow_debugging);
  }
  bp_disk_FILE *bootanim_content=NULL;
  status=bp_disk_read_file(bootanim_file,&bootanim_content);
  if (EFI_ERROR(status)) {
    bp_debug_write_line(serial,"[BlastDebug:BlastUi] Error: can't read boot animation.",allow_erroring);
    while (TRUE) {};
  } else {
    bp_debug_write_line(serial,"[BlastDebug:BlastUi] Readed boot animation.",allow_debugging);
  }
  CHAR8 temp[256];
  if (!boot_conf->disable_boot_animation) {
    UINT64 frames_count=0;
    CopyMem(&frames_count,bootanim_content->content+24,8);
    for (UINT64 i=0;i<frames_count-1;++i) {
      bp_ui_BOOT_ANIMATION *boot_animation=NULL;
      status=bp_ui_render_boot_animation_4frames(bootanim_content,info_mode->HorizontalResolution,info_mode->VerticalResolution,i,&boot_animation);
      if (EFI_ERROR(status)) {
        AsciiSPrint(temp,256,"[BlastDebug:BlastUi] Error: a frame from the boot animation didn't render properly: frame number %d",i+1);
        bp_debug_write_line(serial,temp,allow_erroring);
        while (TRUE) {};
      } else {
        CopyMem((VOID *)gop->Mode->FrameBufferBase,boot_animation->frames[0].pixels,sizeof(UINT32)*info_mode->HorizontalResolution*info_mode->VerticalResolution);
        gBS->Stall(16666);
        CopyMem((VOID *)gop->Mode->FrameBufferBase,boot_animation->frames[1].pixels,sizeof(UINT32)*info_mode->HorizontalResolution*info_mode->VerticalResolution);
        gBS->Stall(16666);
        CopyMem((VOID *)gop->Mode->FrameBufferBase,boot_animation->frames[2].pixels,sizeof(UINT32)*info_mode->HorizontalResolution*info_mode->VerticalResolution);
        gBS->Stall(16666);
        CopyMem((VOID *)gop->Mode->FrameBufferBase,boot_animation->frames[3].pixels,sizeof(UINT32)*info_mode->HorizontalResolution*info_mode->VerticalResolution);
        gBS->Stall(16666);
        FreePool(boot_animation->frames[0].pixels);
        FreePool(boot_animation->frames[1].pixels);
        FreePool(boot_animation->frames[2].pixels);
        FreePool(boot_animation->frames[3].pixels);
        FreePool(boot_animation->frames);
        FreePool(boot_animation);
      }
    }
  }
  bp_ui_BOOT_ANIMATION_FRAME *final_frame=NULL;
  status=bp_ui_render_boot_animation_last_frame(bootanim_content,info_mode->HorizontalResolution,info_mode->VerticalResolution,&final_frame);
  if (EFI_ERROR(status)) {
    AsciiSPrint(temp,256,"[BlastDebug:BlastUi] Error: can't render last frame.");
    bp_debug_write_line(serial,temp,allow_erroring);
    while (TRUE) {};
  }
  CopyMem((VOID *)gop->Mode->FrameBufferBase,final_frame->pixels,sizeof(UINT32)*info_mode->HorizontalResolution*info_mode->VerticalResolution);
  AsciiSPrint(temp,256,"[BlastDebug:BlastUi] Successfully played boot animation.");
  bp_debug_write_line(serial,temp,allow_debugging);
  bp_ui_BOOT_ANIMATION_FRAME *error_frame=NULL;
  status=bp_ui_render_boot_animation_last_frame_color(bootanim_content,info_mode->HorizontalResolution,info_mode->VerticalResolution,settings.red_bits,&error_frame);
  if (EFI_ERROR(status)) {
    bp_debug_write_line(serial,"[BlastDebug:BlastUi] Error: can't render error frame.",allow_erroring);
    while (TRUE) {};
  }
  bp_ui_TEXT_BOX *text_box;
  status=bp_ui_draw_text_ascii(fb,font_render,-1,(UINTN)info_mode->VerticalResolution*0.9,info_mode->HorizontalResolution,info_mode->VerticalResolution,"Locating Filesystems...",&text_box);
  if (EFI_ERROR(status)) {
    bp_debug_write_line(serial,"[BlastDebug:BlastUi] Error: placing text on framebuffer doesn't work.",allow_erroring);
    while (TRUE) {};
  }
  UINTN num_handle;
  EFI_HANDLE *handles=NULL;
  status=gBS->LocateHandleBuffer(ByProtocol,&gEfiBlockIoProtocolGuid,NULL,&num_handle,&handles);
  if (EFI_ERROR(status)) {
    bp_debug_write_line(serial,"[BlastDebug:BlastDisk] Error: can't obtain all handles for BlockIO protocol.",allow_erroring);
    bp_ui_show_error_screen(serial,"BP_ERROR_NO_BLOCKIO_PROTOCOL\0",fb,font_render,info_mode->HorizontalResolution,info_mode->VerticalResolution,error_frame,allow_erroring);
    while (TRUE) {};
  }
  AsciiSPrint(temp,sizeof(temp),"[BlastDebug:BlastDisk] Managed to obtain %d handles.",num_handle);
  bp_debug_write_line(serial,temp,allow_debugging);
  BOOLEAN found_initfs=FALSE;
  BOOLEAN found_signsyst=FALSE;
  UINTN initfs_index;
  UINTN signsyst_index;
  for (UINTN i=0;i<num_handle;i++) {
    EFI_BLOCK_IO_PROTOCOL *blockio;
    status=gBS->HandleProtocol(handles[i],&gEfiBlockIoProtocolGuid,(VOID **)&blockio);
    if (EFI_ERROR(status)) continue;
    if (!blockio->Media->LogicalPartition) continue;
    EFI_PARTITION_INFO_PROTOCOL *part_info;
    status=gBS->HandleProtocol(handles[i],&gEfiPartitionInfoProtocolGuid,(VOID **)&part_info);
    if (EFI_ERROR(status)) continue;
    EFI_GUID efi_type_guid=part_info->Info.Gpt.PartitionTypeGUID;
    EFI_GUID efi_unique_guid=part_info->Info.Gpt.UniquePartitionGUID;
    UINT8 type_guid[16];
    UINT8 unique_guid[16];
    type_guid[0]=(efi_type_guid.Data1>>24)&0xFF;
    type_guid[1]=(efi_type_guid.Data1>>16)&0xFF;
    type_guid[2]=(efi_type_guid.Data1>>8)&0xFF;
    type_guid[3]=efi_type_guid.Data1&0xFF;
    type_guid[4]=(efi_type_guid.Data2>>8)&0xFF;
    type_guid[5]=efi_type_guid.Data2&0xFF;
    type_guid[6]=(efi_type_guid.Data3>>8)&0xFF;
    type_guid[7]=efi_type_guid.Data3&0xFF;
    CopyMem(type_guid+8,efi_type_guid.Data4,8);
    unique_guid[0]=(efi_unique_guid.Data1>>24)&0xFF;
    unique_guid[1]=(efi_unique_guid.Data1>>16)&0xFF;
    unique_guid[2]=(efi_unique_guid.Data1>>8)&0xFF;
    unique_guid[3]=efi_unique_guid.Data1&0xFF;
    unique_guid[4]=(efi_unique_guid.Data2>>8)&0xFF;
    unique_guid[5]=efi_unique_guid.Data2&0xFF;
    unique_guid[6]=(efi_unique_guid.Data3>>8)&0xFF;
    unique_guid[7]=efi_unique_guid.Data3&0xFF;
    CopyMem(unique_guid+8,efi_unique_guid.Data4,8);
    if (CompareMem(type_guid,boot_conf->initfs_partition_type_guid,16)==0 && CompareMem(unique_guid,boot_conf->initfs_partition_guid,16)==0 && StrCmp(part_info->Info.Gpt.PartitionName,L"InitFS")==0) {
      if (part_info->Info.Gpt.EndingLBA-part_info->Info.Gpt.StartingLBA<=0) {
        bp_debug_write_line(serial,"[BlastDebug:BlastDisk] Error: found too small InitFS.",allow_erroring);
        bp_ui_show_error_screen(serial,"BP_ERROR_INITFS_TOO_SMALL\0",fb,font_render,info_mode->HorizontalResolution,info_mode->VerticalResolution,error_frame,allow_erroring);
        if (handles) FreePool(handles);
        while (TRUE) {};
      }
      found_initfs=TRUE;
      initfs_index=i;
    } else if (CompareMem(type_guid,boot_conf->signsyst_partition_type_guid,16)==0 && CompareMem(unique_guid,boot_conf->signsyst_partition_guid,16)==0 && StrCmp(part_info->Info.Gpt.PartitionName,L"SignSyst")==0) {
      if (part_info->Info.Gpt.EndingLBA-part_info->Info.Gpt.StartingLBA<=0) {
        bp_debug_write_line(serial,"[BlastDebug:BlastDisk] Error: found too small SignSyst.",allow_erroring);
        bp_ui_show_error_screen(serial,"BP_ERROR_SIGNSYST_TOO_SMALL\0",fb,font_render,info_mode->HorizontalResolution,info_mode->VerticalResolution,error_frame,allow_erroring);
        if (handles) FreePool(handles);
        while (TRUE) {};
      }
      found_signsyst=TRUE;
      signsyst_index=i;
    }
  }
  if (!found_initfs && !found_signsyst) {
    bp_debug_write_line(serial,"[BlastDebug:BlastDisk] Error: couldn't found InitFS and SignSyst.",allow_erroring);
    bp_ui_show_error_screen(serial,"BP_ERROR_VYSTEM_FS_NOT_FOUND\0",fb,font_render,info_mode->HorizontalResolution,info_mode->VerticalResolution,error_frame,allow_erroring);
    if (handles) FreePool(handles);
    while (TRUE) {};
  } else if (!found_initfs) {
    bp_debug_write_line(serial,"[BlastDebug:BlastDisk] Error: couldn't found InitFS.",allow_erroring);
    bp_ui_show_error_screen(serial,"BP_ERROR_INITFS_NOT_FOUND\0",fb,font_render,info_mode->HorizontalResolution,info_mode->VerticalResolution,error_frame,allow_erroring);
    if (handles) FreePool(handles);
    while (TRUE) {};
  } else if (!found_signsyst) {
    bp_debug_write_line(serial,"[BlastDebug:BlastDisk] Error: couldn't found SignSyst.",allow_erroring);
    bp_ui_show_error_screen(serial,"BP_ERROR_SIGNSYST_NOT_FOUND\0",fb,font_render,info_mode->HorizontalResolution,info_mode->VerticalResolution,error_frame,allow_erroring);
    if (handles) FreePool(handles);
    while (TRUE) {};
  }
  bp_debug_write_line(serial,"[BlastDebug:BlastDisk] Found InitFS and SignSyst.",allow_debugging);
  bp_ui_erase_text(fb,info_mode->HorizontalResolution,info_mode->VerticalResolution,text_box);
  status=bp_ui_draw_text_ascii(fb,font_render,-1,(UINTN)info_mode->VerticalResolution*0.9,info_mode->HorizontalResolution,info_mode->VerticalResolution,"Loading Filesystems Headers...",&text_box);
  EFI_BLOCK_IO_PROTOCOL *initfs_blockio;
  status=gBS->HandleProtocol(handles[initfs_index],&gEfiBlockIoProtocolGuid,(VOID **)&initfs_blockio);
  if (EFI_ERROR(status)) {
    bp_debug_write_line(serial,"[BlastDebug:BlastDisk] Error: can't get InitFS BlockIO protocol.",allow_erroring);
    bp_ui_show_error_screen(serial,"BP_ERROR_INITFS_NO_BLOCK_IO\0",fb,font_render,info_mode->HorizontalResolution,info_mode->VerticalResolution,error_frame,allow_erroring);
    if (handles) FreePool(handles);
    while (TRUE) {};
  }
  EFI_BLOCK_IO_PROTOCOL *signsyst_blockio;
  status=gBS->HandleProtocol(handles[signsyst_index],&gEfiBlockIoProtocolGuid,(VOID **)&signsyst_blockio);
  if (EFI_ERROR(status)) {
    bp_debug_write_line(serial,"[BlastDebug:BlastDisk] Error: can't get SignSyst BlockIO protocol.",allow_erroring);
    bp_ui_show_error_screen(serial,"BP_ERROR_SIGNSYST_NO_BLOCK_IO\0",fb,font_render,info_mode->HorizontalResolution,info_mode->VerticalResolution,error_frame,allow_erroring);
    if (handles) FreePool(handles);
    while (TRUE) {};
  }
  bp_debug_write_line(serial,"[BlastDebug:BlastDisk] Obtained both BlockIO protocol.",allow_debugging);
  UINTN initfs_block_size=initfs_blockio->Media->BlockSize;
  UINT8 *initfs_first_lba=AllocatePool(initfs_block_size);
  if (!initfs_first_lba) {
    bp_debug_write_line(serial,"[BlastDebug:BlastDisk] Error: allocating memory for InitFS first LBA failed.",allow_erroring);
    bp_ui_show_error_screen(serial,"BP_ERROR_INITFS_FIRST_LBA_NO_MEMORY\0",fb,font_render,info_mode->HorizontalResolution,info_mode->VerticalResolution,error_frame,allow_erroring);
    while (TRUE) {};
  }
  if (!initfs_blockio->Media->MediaPresent) {
    bp_debug_write_line(serial,"[BlastDebug:BlastDisk] Error: InitFS mysteriously disappeared.",allow_erroring);
    bp_ui_show_error_screen(serial,"BP_ERROR_INITFS_NOT_HERE\0",fb,font_render,info_mode->HorizontalResolution,info_mode->VerticalResolution,error_frame,allow_erroring);
    FreePool(initfs_first_lba);
    while (TRUE) {};
  }
  status=initfs_blockio->ReadBlocks(initfs_blockio,initfs_blockio->Media->MediaId,0,initfs_block_size,initfs_first_lba);
  if (EFI_ERROR(status)) {
    bp_debug_write_line(serial,"[BlastDebug:BlastDisk] Error: can't read InitFS first LBA.",allow_erroring);
    bp_ui_show_error_screen(serial,"BP_ERROR_INITFS_FIRST_LBA_NO_READ\0",fb,font_render,info_mode->HorizontalResolution,info_mode->VerticalResolution,error_frame,allow_erroring);
    FreePool(initfs_first_lba);
    while (TRUE) {};
  }
  bp_debug_write_line(serial,"[BlastDebug:BlastDisk] Readed first LBA for InitFS.",allow_debugging);
  UINTN signsyst_block_size=signsyst_blockio->Media->BlockSize;
  UINT8 *signsyst_first_lba=AllocatePool(signsyst_block_size);
  if (!signsyst_first_lba) {
    bp_debug_write_line(serial,"[BlastDebug:BlastDisk] Error: allocating memory for SignSyst first LBA failed.",allow_erroring);
    bp_ui_show_error_screen(serial,"BP_ERROR_SIGNSYST_FIRST_LBA_NO_MEMORY\0",fb,font_render,info_mode->HorizontalResolution,info_mode->VerticalResolution,error_frame,allow_erroring);
    while (TRUE) {};
  }
  if (!signsyst_blockio->Media->MediaPresent) {
    bp_debug_write_line(serial,"[BlastDebug:BlastDisk] Error: SignSyst mysteriously disappeared.",allow_erroring);
    bp_ui_show_error_screen(serial,"BP_ERROR_SIGNSYST_NOT_HERE\0",fb,font_render,info_mode->HorizontalResolution,info_mode->VerticalResolution,error_frame,allow_erroring);
    FreePool(signsyst_first_lba);
    while (TRUE) {};
  }
  status=signsyst_blockio->ReadBlocks(signsyst_blockio,signsyst_blockio->Media->MediaId,0,signsyst_block_size,signsyst_first_lba);
  if (EFI_ERROR(status)) {
    bp_debug_write_line(serial,"[BlastDebug:BlastDisk] Error: can't read SignSyst first LBA.",allow_erroring);
    bp_ui_show_error_screen(serial,"BP_ERROR_SIGNSYST_FIRST_LBA_NO_READ\0",fb,font_render,info_mode->HorizontalResolution,info_mode->VerticalResolution,error_frame,allow_erroring);
    FreePool(signsyst_first_lba);
    while (TRUE) {};
  }
  bp_debug_write_line(serial,"[BlastDebug:BlastDisk] Readed first LBA for SignSyst.",allow_debugging);
  bp_ui_erase_text(fb,info_mode->HorizontalResolution,info_mode->VerticalResolution,text_box);
  status=bp_ui_draw_text_ascii(fb,font_render,-1,(UINTN)info_mode->VerticalResolution*0.9,info_mode->HorizontalResolution,info_mode->VerticalResolution,"Parsing Filesystems Headers...",&text_box);
  bp_initfs_INITFS_HEADER *initfs_header=NULL;
  status=bp_initfs_parse_initfs_header(initfs_first_lba,initfs_block_size,&initfs_header);
  if (status==EFI_UNSUPPORTED) {
    bp_debug_write_line(serial,"[BlastDebug:BlastInitFS] Error: provided InitFS isn't compatible with InitFS driver.",allow_erroring);
    bp_ui_show_error_screen(serial,"BP_ERROR_INITFS_WRONG_VERSION\0",fb,font_render,info_mode->HorizontalResolution,info_mode->VerticalResolution,error_frame,allow_erroring);
    FreePool(initfs_first_lba);
    while (TRUE) {};
  } else if (status==EFI_COMPROMISED_DATA) {
    bp_debug_write_line(serial,"[BlastDebug:BlastInitFS] Error: provided InitFS doesn't have the InitFS signature.",allow_erroring);
    bp_ui_show_error_screen(serial,"BP_ERROR_INITFS_WRONG_SIGNATURE\0",fb,font_render,info_mode->HorizontalResolution,info_mode->VerticalResolution,error_frame,allow_erroring);
    FreePool(initfs_first_lba);
    while (TRUE) {};
  } else if (EFI_ERROR(status)) {
    bp_debug_write_line(serial,"[BlastDebug:BlastInitFS] Error: can't read InitFS header.",allow_erroring);
    bp_ui_show_error_screen(serial,"BP_ERROR_INITFS_HEADER_READ_ERROR\0",fb,font_render,info_mode->HorizontalResolution,info_mode->VerticalResolution,error_frame,allow_erroring);
    FreePool(initfs_first_lba);
    while (TRUE) {};
  }
  bp_debug_write_line(serial,"[BlastDebug:BlastInitFS] Parsed InitFS header.",allow_debugging);
  AsciiSPrint(temp,sizeof(temp),"[BlastDebug:BlastInitFS] Bootloader version: 0x%04x; InitFS version: 0x%04x; OS version: 0x%08x",initfs_header->bootloader_version,initfs_header->bootloader_version,initfs_header->os_version);
  bp_debug_write_line(serial,temp,allow_debugging);
  AsciiSPrint(temp,sizeof(temp),"[BlastDebug:BlastInitFS] InitFS Size: %d bytes; Table size: %d bytes; Files area size: %d bytes",initfs_header->initfs_size,initfs_header->table_size,initfs_header->files_area_size);
  bp_debug_write_line(serial,temp,allow_debugging);
  AsciiSPrint(temp,sizeof(temp),"[BlastDebug:BlastInitFS] Entry width: %d bytes; Entries count: %d; Files area offset: %d bytes",initfs_header->entries_width,initfs_header->entries_count,initfs_header->files_area_offset);
  bp_debug_write_line(serial,temp,allow_debugging);
  bp_initfs_SIGNSYST_HEADER *signsyst_header=NULL;
  status=bp_initfs_parse_signsyst_header(signsyst_first_lba,signsyst_block_size,&signsyst_header);
  if (status==EFI_UNSUPPORTED) {
    bp_debug_write_line(serial,"[BlastDebug:BlastInitFS] Error: provided SignSyst isn't compatible with InitFS driver.",allow_erroring);
    bp_ui_show_error_screen(serial,"BP_ERROR_SIGNSYST_WRONG_VERSION\0",fb,font_render,info_mode->HorizontalResolution,info_mode->VerticalResolution,error_frame,allow_erroring);
    FreePool(signsyst_first_lba);
    while (TRUE) {};
  } else if (status==EFI_COMPROMISED_DATA) {
    bp_debug_write_line(serial,"[BlastDebug:BlastInitFS] Error: provided SignSyst doesn't have the SignSyst signature.",allow_erroring);
    bp_ui_show_error_screen(serial,"BP_ERROR_SIGNSYST_WRONG_SIGNATURE\0",fb,font_render,info_mode->HorizontalResolution,info_mode->VerticalResolution,error_frame,allow_erroring);
    FreePool(signsyst_first_lba);
    while (TRUE) {};
  } else if (EFI_ERROR(status)) {
    bp_debug_write_line(serial,"[BlastDebug:BlastInitFS] Error: can't read SignSyst header.",allow_erroring);
    bp_ui_show_error_screen(serial,"BP_ERROR_SIGNSYST_HEADER_READ_ERROR\0",fb,font_render,info_mode->HorizontalResolution,info_mode->VerticalResolution,error_frame,allow_erroring);
    FreePool(signsyst_first_lba);
    while (TRUE) {};
  }
  bp_debug_write_line(serial,"[BlastDebug:BlastInitFS] Parsed SignSyst header.",allow_debugging);
  AsciiSPrint(temp,sizeof(temp),"[BlastDebug:BlastInitFS] Bootloader version: 0x%04x; InitFS version: 0x%04x; OS version: 0x%08x",signsyst_header->bootloader_version,signsyst_header->bootloader_version,signsyst_header->os_version);
  bp_debug_write_line(serial,temp,allow_debugging);
  AsciiSPrint(temp,sizeof(temp),"[BlastDebug:BlastInitFS] Signature size: %d bytes; Signature count: %d",signsyst_header->signature_size,signsyst_header->signature_count);
  bp_debug_write_line(serial,temp,allow_debugging);
  AsciiSPrint(temp,sizeof(temp),"[BlastDebug:BlastInitFS] SignSyst size: %d bytes; Signatures blocks size: %d",signsyst_header->signsyst_size,signsyst_header->signature_block_size);
  bp_debug_write_line(serial,temp,allow_debugging);
  bp_ui_erase_text(fb,info_mode->HorizontalResolution,info_mode->VerticalResolution,text_box);
  status=bp_ui_draw_text_ascii(fb,font_render,-1,(UINTN)info_mode->VerticalResolution*0.9,info_mode->HorizontalResolution,info_mode->VerticalResolution,"Verifying Filesystems Headers...",&text_box);
  status=bp_initfs_check_initfs_header(initfs_header,root);
  if (status==EFI_SECURITY_VIOLATION) {
    bp_debug_write_line(serial,"[BlastDebug:BlastInitFS] Error: critical security violation in boot process:",allow_erroring);
    bp_debug_write_line(serial,"[BlastDebug:BlastInitFS] InitFS header isn't valid.",allow_erroring);
    bp_ui_show_error_screen(serial,"BP_ERROR_INITFS_HEADER_NOT_VALID\0",fb,font_render,info_mode->HorizontalResolution,info_mode->VerticalResolution,error_frame,allow_erroring);
    FreePool(initfs_first_lba);
    while (TRUE) {};
  } else if (EFI_ERROR(status)) {
    bp_debug_write_line(serial,"[BlastDebug:BlastInitFS] Error: InitFS header couldn't be verified.",allow_erroring);
    bp_ui_show_error_screen(serial,"BP_ERROR_INITFS_HEADER_NOT_VERIFIABLE\0",fb,font_render,info_mode->HorizontalResolution,info_mode->VerticalResolution,error_frame,allow_erroring);
    FreePool(initfs_first_lba);
    while (TRUE) {};
  }
  bp_debug_write_line(serial,"[BlastDebug:BlastInitFS] Successfully verified InitFS header.",allow_debugging);
  status=bp_initfs_check_signsyst_header(signsyst_header,root);
  if (status==EFI_SECURITY_VIOLATION) {
    bp_debug_write_line(serial,"[BlastDebug:BlastInitFS] Error: critical security violation in boot process:",allow_erroring);
    bp_debug_write_line(serial,"[BlastDebug:BlastInitFS] SignSyst header isn't valid.",allow_erroring);
    bp_ui_show_error_screen(serial,"BP_ERROR_SIGNSYST_HEADER_NOT_VALID\0",fb,font_render,info_mode->HorizontalResolution,info_mode->VerticalResolution,error_frame,allow_erroring);
    FreePool(signsyst_first_lba);
    while (TRUE) {};
  } else if (EFI_ERROR(status)) {
    bp_debug_write_line(serial,"[BlastDebug:BlastInitFS] Error: SignSyst header couldn't be verified.",allow_erroring);
    bp_ui_show_error_screen(serial,"BP_ERROR_SIGNSYST_HEADER_NOT_VERIFIABLE\0",fb,font_render,info_mode->HorizontalResolution,info_mode->VerticalResolution,error_frame,allow_erroring);
    FreePool(signsyst_first_lba);
    while (TRUE) {};
  }
  bp_debug_write_line(serial,"[BlastDebug:BlastInitFS] Successfully verified SignSyst header.",allow_debugging);
  status=bp_initfs_cross_check_headers(initfs_header,signsyst_header);
  if (status==EFI_SECURITY_VIOLATION) {
    bp_debug_write_line(serial,"[BlastDebug:BlastInitFS] Error: critical security violation in boot process:",allow_erroring);
    bp_debug_write_line(serial,"[BlastDebug:BlastInitFS] Provided InitFS and SignSyst doesn't match.",allow_erroring);
    bp_ui_show_error_screen(serial,"BP_ERROR_FS_NO_MATCH\0",fb,font_render,info_mode->HorizontalResolution,info_mode->VerticalResolution,error_frame,allow_erroring);
    FreePool(initfs_first_lba);
    FreePool(signsyst_first_lba);
    while (TRUE) {};
  } else if (EFI_ERROR(status)) {
    bp_debug_write_line(serial,"[BlastDebug:BlastInitFS] Error: can't verified that provided filesystems match.",allow_erroring);
    bp_ui_show_error_screen(serial,"BP_ERROR_FS_NOT_MATCHABLE\0",fb,font_render,info_mode->HorizontalResolution,info_mode->VerticalResolution,error_frame,allow_erroring);
    FreePool(initfs_first_lba);
    FreePool(signsyst_first_lba);
    while (TRUE) {};
  }
  bp_debug_write_line(serial,"[BlastDebug:BlastInitFS] Both filesystems match.",allow_debugging);
  UINTN initfs_block_count=initfs_blockio->Media->LastBlock+1;
  UINTN initfs_size_bytes=initfs_block_count*initfs_block_size;
  if (initfs_header->initfs_size>initfs_size_bytes) {
    bp_debug_write_line(serial,"[BlastDebug:BlastInitFS] Error: InitFS size provided in header is bigger than partition size.",allow_erroring);
    bp_ui_show_error_screen(serial,"BP_ERROR_INITFS_SIZE\0",fb,font_render,info_mode->HorizontalResolution,info_mode->VerticalResolution,error_frame,allow_erroring);
    while (TRUE) {};
  }
  UINTN signsyst_block_count=signsyst_blockio->Media->LastBlock+1;
  UINTN signsyst_size_bytes=signsyst_block_count*signsyst_block_size;
  if (signsyst_header->signsyst_size>signsyst_size_bytes) {
    bp_debug_write_line(serial,"[BlastDebug:BlastInitFS] Error: SignSyst size provided in header is bigger than partition size.",allow_erroring);
    bp_ui_show_error_screen(serial,"BP_ERROR_SIGNSYST_SIZE\0",fb,font_render,info_mode->HorizontalResolution,info_mode->VerticalResolution,error_frame,allow_erroring);
    while (TRUE) {};
  }
  bp_ui_erase_text(fb,info_mode->HorizontalResolution,info_mode->VerticalResolution,text_box);
  status=bp_ui_draw_text_ascii(fb,font_render,-1,(UINTN)info_mode->VerticalResolution*0.9,info_mode->HorizontalResolution,info_mode->VerticalResolution,"Loading Filesystems...",&text_box);
  bp_debug_write_line(serial,"[BlastDebug:BlastInitFS] Allocating memory for InitFS...",allow_debugging);
  UINTN initfs_page_count=(initfs_size_bytes+EFI_PAGE_SIZE-1)/EFI_PAGE_SIZE;
  EFI_PHYSICAL_ADDRESS initfs_ptr;
  status=gBS->AllocatePages(AllocateAnyPages,EfiLoaderData,initfs_page_count,&initfs_ptr);
  if (status==EFI_OUT_OF_RESOURCES) {
    bp_debug_write_line(serial,"[BlastDebug:BlastInitFS] Error: InitFS couldn't be loaded because the system doesn't have enough memory.",allow_erroring);
    bp_ui_show_error_screen(serial,"BP_ERROR_INITFS_NO_MEMORY\0",fb,font_render,info_mode->HorizontalResolution,info_mode->VerticalResolution,error_frame,allow_erroring);
    while (TRUE) {};
  } else if (EFI_ERROR(status)) {
    bp_debug_write_line(serial,"[BlastDebug:BlastInitFS] Error: InitFS couldn't be loaded because of a page allocation error.",allow_erroring);
    bp_ui_show_error_screen(serial,"BP_ERROR_INITFS_MEMORY\0",fb,font_render,info_mode->HorizontalResolution,info_mode->VerticalResolution,error_frame,allow_erroring);
    while (TRUE) {};
  }
  bp_debug_write_line(serial,"[BlastDebug:BlastInitFS] Loading InitFS from disk...",allow_debugging);
  status=initfs_blockio->ReadBlocks(initfs_blockio,initfs_blockio->Media->MediaId,0,initfs_size_bytes,(VOID *)initfs_ptr);
  if (EFI_ERROR(status)) {
    bp_debug_write_line(serial,"[BlastDebug:BlastInitFS] Error: InitFS couldn't be loaded.",allow_erroring);
    bp_ui_show_error_screen(serial,"BP_ERROR_INITFS_LOAD_ERROR\0",fb,font_render,info_mode->HorizontalResolution,info_mode->VerticalResolution,error_frame,allow_erroring);
    while (TRUE) {};
  }
  bp_debug_write_line(serial,"[BlastDebug:BlastInitFS] Successfully loaded InitFS.",allow_debugging);
  bp_debug_write_line(serial,"[BlastDebug:BlastInitFS] Allocating memory for SignSyst...",allow_debugging);
  UINTN signsyst_page_count=(signsyst_size_bytes+EFI_PAGE_SIZE-1)/EFI_PAGE_SIZE;
  EFI_PHYSICAL_ADDRESS signsyst_ptr;
  status=gBS->AllocatePages(AllocateAnyPages,EfiLoaderData,signsyst_page_count,&signsyst_ptr);
  if (status==EFI_OUT_OF_RESOURCES) {
    bp_debug_write_line(serial,"[BlastDebug:BlastInitFS] Error: SignSyst couldn't be loaded because the system doesn't have enough memory.",allow_erroring);
    bp_ui_show_error_screen(serial,"BP_ERROR_SIGNSYST_NO_MEMORY\0",fb,font_render,info_mode->HorizontalResolution,info_mode->VerticalResolution,error_frame,allow_erroring);
    while (TRUE) {};
  } else if (EFI_ERROR(status)) {
    bp_debug_write_line(serial,"[BlastDebug:BlastInitFS] Error: SignSyst couldn't be loaded because of a page allocation error.",allow_erroring);
    bp_ui_show_error_screen(serial,"BP_ERROR_SIGNSYST_MEMORY\0",fb,font_render,info_mode->HorizontalResolution,info_mode->VerticalResolution,error_frame,allow_erroring);
    while (TRUE) {};
  }
  bp_debug_write_line(serial,"[BlastDebug:BlastInitFS] Loading SignSyst from disk...",allow_debugging);
  status=initfs_blockio->ReadBlocks(signsyst_blockio,signsyst_blockio->Media->MediaId,0,signsyst_size_bytes,(VOID *)signsyst_ptr);
  if (EFI_ERROR(status)) {
    bp_debug_write_line(serial,"[BlastDebug:BlastInitFS] Error: SignSyst couldn't be loaded.",allow_erroring);
    bp_ui_show_error_screen(serial,"BP_ERROR_SIGNSYST_LOAD_ERROR\0",fb,font_render,info_mode->HorizontalResolution,info_mode->VerticalResolution,error_frame,allow_erroring);
    while (TRUE) {};
  }
  bp_debug_write_line(serial,"[BlastDebug:BlastInitFS] Successfully loaded SignSyst.",allow_debugging);
  bp_ui_erase_text(fb,info_mode->HorizontalResolution,info_mode->VerticalResolution,text_box);
  status=bp_ui_draw_text_ascii(fb,font_render,-1,(UINTN)info_mode->VerticalResolution*0.9,info_mode->HorizontalResolution,info_mode->VerticalResolution,"Parsing Filesystems...",&text_box);
  bp_initfs_INITFS *initfs=NULL;
  status=bp_initfs_create_initfs_structure(initfs_header,(UINT8 *)initfs_ptr,&initfs);
  if (EFI_ERROR(status)) {
    bp_debug_write_line(serial,"[BlastDebug:BlastInitFS] Error: can't parse InitFS structure.",allow_erroring);
    bp_ui_show_error_screen(serial,"BP_ERROR_INITFS_NO_STRUCTURE\0",fb,font_render,info_mode->HorizontalResolution,info_mode->VerticalResolution,error_frame,allow_erroring);
    while (TRUE) {};
  }
  bp_debug_write_line(serial,"[BlastDebug:BlastInitFS] Successfully parsed InitFS structure.",allow_debugging);
  bp_initfs_SIGNSYST *signsyst=NULL;
  status=bp_initfs_create_signsyst_structure(signsyst_header,(UINT8 *)signsyst_ptr,&signsyst);
  if (EFI_ERROR(status)) {
    bp_debug_write_line(serial,"[BlastDebug:BlastInitFS] Error: can't parse SignSyst structure.",allow_erroring);
    bp_ui_show_error_screen(serial,"BP_ERROR_SIGNSYST_NO_STRUCTURE\0",fb,font_render,info_mode->HorizontalResolution,info_mode->VerticalResolution,error_frame,allow_erroring);
    while (TRUE) {};
  }
  bp_ui_erase_text(fb,info_mode->HorizontalResolution,info_mode->VerticalResolution,text_box);
  status=bp_ui_draw_text_ascii(fb,font_render,-1,(UINTN)info_mode->VerticalResolution*0.9,info_mode->HorizontalResolution,info_mode->VerticalResolution,"Verifying InitFS integrity...",&text_box);
  bp_debug_write_line(serial,"[BlastDebug:BlastInitFS] Successfully parsed SignSyst structure.",allow_debugging);
  status=bp_initfs_check_initfs_integrity(initfs,signsyst);
  if (status==EFI_SECURITY_VIOLATION) {
    bp_debug_write_line(serial,"[BlastDebug:BlastInitFS] Error: critical security violation in boot process:",allow_erroring);
    bp_debug_write_line(serial,"[BlastDebug:BlastInitFS] InitFS integrity is compromised.",allow_erroring);
    bp_ui_show_error_screen(serial,"BP_ERROR_INITFS_COMPROMISED\0",fb,font_render,info_mode->HorizontalResolution,info_mode->VerticalResolution,error_frame,allow_erroring);
    while (TRUE) {};
  }
  bp_debug_write_line(serial,"[BlastDebug:BlastInitFS] Successfully verified InitFS integrity.",allow_debugging);
  bp_ui_erase_text(fb,info_mode->HorizontalResolution,info_mode->VerticalResolution,text_box);
  status=bp_ui_draw_text_ascii(fb,font_render,-1,(UINTN)info_mode->VerticalResolution*0.9,info_mode->HorizontalResolution,info_mode->VerticalResolution,"Loading kernel...",&text_box);
  bp_disk_FILE *kernel_file=NULL;
  status=bp_initfs_read_file(initfs,"shelter.vyx",&kernel_file);
  if (status==EFI_NOT_FOUND) {
    bp_debug_write_line(serial,"[BlastDebug:BlastInitFS] Error: couldn't found kernel.",allow_erroring);
    bp_ui_show_error_screen(serial,"BP_ERROR_KERNEL_NOT_FOUND\0",fb,font_render,info_mode->HorizontalResolution,info_mode->VerticalResolution,error_frame,allow_erroring);
    while (TRUE) {};
  } else if (EFI_ERROR(status)) {
    bp_debug_write_line(serial,"[BlastDebug:BlastInitFS] Error: couldn't read kernel.",allow_erroring);
    bp_ui_show_error_screen(serial,"BP_ERROR_KERNEL_NO_READ\0",fb,font_render,info_mode->HorizontalResolution,info_mode->VerticalResolution,error_frame,allow_erroring);
    while (TRUE) {};
  }
  bp_debug_write_line(serial,"[BlastDebug:BlastInitFS] Successfully readed kernel.",allow_debugging);
  bp_disk_FILE *keycard_file=NULL;
  status=bp_initfs_read_file(initfs,"keycard.bin",&keycard_file);
  if (status==EFI_NOT_FOUND) {
    bp_debug_write_line(serial,"[BlastDebug:BlastInitFS] Error: couldn't found keycard.",allow_erroring);
    bp_ui_show_error_screen(serial,"BP_ERROR_KEYCARD_NOT_FOUND\0",fb,font_render,info_mode->HorizontalResolution,info_mode->VerticalResolution,error_frame,allow_erroring);
    while (TRUE) {};
  } else if (EFI_ERROR(status)) {
    bp_debug_write_line(serial,"[BlastDebug:BlastInitFS] Error: couldn't read keycard.",allow_erroring);
    bp_ui_show_error_screen(serial,"BP_ERROR_KEYCARD_NO_READ\0",fb,font_render,info_mode->HorizontalResolution,info_mode->VerticalResolution,error_frame,allow_erroring);
    while (TRUE) {};
  }
  bp_debug_write_line(serial,"[BlastDebug:BlastVyx] Successfully readed keycard.",allow_debugging);
  bp_vyx_VYX_HEADER *kernel_header=NULL;
  status=bp_vyx_get_header(kernel_file,&kernel_header);
  if (EFI_ERROR(status)) {
    bp_debug_write_line(serial,"[BlastDebug:BlastVyx] Error: can't obtain kernel header.",allow_erroring);
    bp_ui_show_error_screen(serial,"BP_ERROR_KERNEL_NO_HEADER\0",fb,font_render,info_mode->HorizontalResolution,info_mode->VerticalResolution,error_frame,allow_erroring);
    while (TRUE) {};
  }
  bp_debug_write_line(serial,"[BlastDebug:BlastVyx] Successfully obtained kernel header.",allow_debugging);
  bp_vyx_SHELTER_BOOT_CONFIG *kernel_config=AllocatePool(sizeof(bp_vyx_SHELTER_BOOT_CONFIG));
  status=bp_vyx_create_shelter_boot_conf(boot_conf->kernel_log_level,
                                         boot_conf->kernel_test_benchmark,
                                         boot_conf->kernel_bench_iterations,
                                         boot_conf->kernel_log_disable_serial_port,
                                         boot_conf->kernel_disable_serial_port,
                                         boot_conf->kernel_log_ring_size,
                                         kernel_config);
  if (EFI_ERROR(status)) {
    bp_debug_write_line(serial,"[BlastDebug:BlastVyx] Error: can't create kernel config.",allow_erroring);
    bp_ui_show_error_screen(serial,"BP_ERROR_KERNEL_NO_CONFIG\0",fb,font_render,info_mode->HorizontalResolution,info_mode->VerticalResolution,error_frame,allow_erroring);
    while (TRUE) {};
  }
  bp_debug_write_line(serial,"[BlastDebug:BlastVyx] Successfully created kernel config.",allow_debugging);
  bp_vyx_LOADER_SETTING *loader_settings=NULL;
  status=bp_vyx_setup_physical_pages(kernel_header,kernel_file,keycard_file,kernel_config,&loader_settings);
  if (status==EFI_OUT_OF_RESOURCES) {
    bp_debug_write_line(serial,"[BlastDebug:BlastVyx] Error: can't obtain enough memory to load kernel.",allow_erroring);
    bp_ui_show_error_screen(serial,"BP_ERROR_KERNEL_NOT_ENOUGH_MEMORY\0",fb,font_render,info_mode->HorizontalResolution,info_mode->VerticalResolution,error_frame,allow_erroring);
    while (TRUE) {};
  } else if (EFI_ERROR(status)) {
    bp_debug_write_line(serial,"[BlastDebug:BlastVyx] Error: can't allocate memory for kernel.",allow_erroring);
    bp_ui_show_error_screen(serial,"BP_ERROR_KERNEL_NO_MEMORY\0",fb,font_render,info_mode->HorizontalResolution,info_mode->VerticalResolution,error_frame,allow_erroring);
    while (TRUE) {};
  }
  bp_debug_write_line(serial,"[BlastDebug:BlastVyx] Successfully allocated memory for kernel and keycard.",allow_debugging);
  EFI_PHYSICAL_ADDRESS page_table_ptr=0;
  EFI_VIRTUAL_ADDRESS stack_address=0;
  EFI_VIRTUAL_ADDRESS page_table_pool_va=0;
  status=bp_vyx_create_page_table(kernel_header,loader_settings,&page_table_ptr,&stack_address,&page_table_pool_va);
  if (EFI_ERROR(status)) {
    bp_debug_write_line(serial,"[BlastDebug:BlastVyx] Error: couldn't create kernel page table.",allow_erroring);
    bp_ui_show_error_screen(serial,"BP_ERROR_KERNEL_NO_PAGE_TABLE\0",fb,font_render,info_mode->HorizontalResolution,info_mode->VerticalResolution,error_frame,allow_erroring);
    while (TRUE) {};
  }
  kernel_config=(bp_vyx_SHELTER_BOOT_CONFIG*)loader_settings->shelter_boot_config_addr_phys;
  kernel_config->page_table_pool_pa=loader_settings->shelter_page_table_addr_phys;
  kernel_config->page_table_pool_va=page_table_pool_va;
  kernel_config->page_table_allocator_level=bp_vyx_get_pt_pool_allocator();
  bp_debug_write_line(serial,"[BlastDebug:BlastVyx] Successfully created kernel and keycard page table.",allow_debugging);
  EFI_VIRTUAL_ADDRESS stack_top=(stack_address+65*4096)-8;
  UINTN map_key;
  UINTN mmap_size=0;
  EFI_MEMORY_DESCRIPTOR *mmap=NULL;
  UINTN desc_size;
  UINT32 desc_version;
  status=gBS->GetMemoryMap(&mmap_size,mmap,&map_key,&desc_size,&desc_version);
  AsciiSPrint(temp,sizeof(temp),"[BlastDebug:BlastVyx] DescSize=%d, Mmap_size=%d",desc_size,mmap_size);
  bp_debug_write_line(serial,temp,allow_debugging);
  if (EFI_ERROR(status)) {
    bp_debug_write_line(serial,"[BlastDebug:BlastVyx] Received error for first call to GetMemoryMap. Allocating memory for memory map.",allow_debugging);
  }
  UINTN mmap_size_allocated=mmap_size+desc_size*20;
  mmap=AllocatePool(mmap_size_allocated);
  status=gBS->GetMemoryMap(&mmap_size_allocated,mmap,&map_key,&desc_size,&desc_version);
  if (EFI_ERROR(status)) {
    bp_debug_write_line(serial,"[BlastDebug:BlastVyx] Error: received error for second call to GetMemoryMap.",allow_debugging);
    while (TRUE) {};
  }
  UINTN entry_count=mmap_size_allocated/desc_size;
  bp_debug_write_line(serial,"[BlastDebug:BlastVyx] Obtained EFI memory map.",allow_debugging);
  bp_vyx_SHELTER_MEMORY_MAP_HEADER mmap_header={.sig_start={'S','h','e','M','m','a','p','B'},.entry_count=entry_count,.entry_size=sizeof(bp_vyx_SHELTER_MEMORY_MAP_ENTRY),.mmap_syntax_version=1};
  CopyMem((VOID*)(UINTN)loader_settings->shelter_memory_map_addr_phys,&mmap_header,sizeof(bp_vyx_SHELTER_MEMORY_MAP_HEADER));
  for (UINTN i=0;i<entry_count;++i) {
    EFI_MEMORY_DESCRIPTOR *d=(EFI_MEMORY_DESCRIPTOR *)((UINT8 *)mmap+i*desc_size);
    bp_vyx_SHELTER_MEMORY_MAP_ENTRY mmap_entry={.type=d->Type,.physical_start=d->PhysicalStart,.pages_count=d->NumberOfPages,.attributes=d->Attribute};
    VOID *target_entry_addr=(VOID*)((UINTN)loader_settings->shelter_memory_map_addr_phys+sizeof(bp_vyx_SHELTER_MEMORY_MAP_HEADER)+i*sizeof(bp_vyx_SHELTER_MEMORY_MAP_ENTRY));
    CopyMem(target_entry_addr,&mmap_entry,sizeof(bp_vyx_SHELTER_MEMORY_MAP_ENTRY));
  }
  bp_debug_write_line(serial,"[BlastDebug:BlastVyx] Parsed memory map for kernel.",allow_debugging);
  bp_debug_write_line(serial,"[BlastDebug:BlastVyx] Jumping to keycard...",allow_debugging);
  EFI_STATUS st=gBS->ExitBootServices(ImageHandle,map_key);
  if (EFI_ERROR(st)) {
    while (TRUE) {};
  }
  stack_top&=~0xFULL;
  __asm__ __volatile__ (
      "mov %0, %%rax\n"
      "mov %1, %%rbx\n"
      "mov %2, %%rcx\n"
      "jmp *%3\n"
      :
      : "r"(stack_top),
        "r"(page_table_ptr),
        "r"(kernel_header->text_offset),
        "r"(loader_settings->keycard_addr_phys)
      : "rax", "rbx", "rcx"
  );
  return EFI_SUCCESS;
}
