0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

mikanOS 3章を整理 [前編]

Last updated at Posted at 2022-03-26

はじめに

今回はカーネルを call してみます
基本的には、mikanOS の sample コードを読み解き、
コードから具体的なフローを学んでいくスタンスでまとめていきます。

⇦前|mikanOS 2章を整理 || mikanOS 3章を整理[後編]|⇨

Kernel を呼び出すフロー

まずは Kernel.elf を取り込んで、
ソフト的に色々できるようにします。

色々と言っても複雑なことではなく、
ファイルサイズを確認したり、kernel を WorkMemory に配置して
アプリケーションとして Call 出来る準備をしたりします。

flow_chart.png

Kernel の取り込み

冒頭にあるように Kernel.elf を一旦取り込む必要があります。
取り込むために必要な Open() について確認してみましょう。

Open() の概要:
以下 "*This" を基準に "FileName" の "file" もしくは "directory" を検索して開く

open_specification.png

Main.c
/*take in kernel.elf*/
  EFI_FILE_PROTOCOL* kernel_file;
  status = root_dir->Open(
      root_dir,           //*This 
      &kernel_file,       //**NewHandle
      L"\\kernel.elf",    //*FileName
      EFI_FILE_MODE_READ, //OpenMode
      0);                 //Attributes

/*
"*This" を基準に "FileName" の "file" もしくは "directory" を開く
                     || <=イコール 
  "root_dir" から "kernel.elf" を read mode で開く
*/

Kernel のサイズ確認

application として kernel を call するのであれば、
横やりが入らないように workmemory の一部を kernel 用に確保してあげる必要があります。

そのためにもファイルサイズ情報が必須です。
アプローチとしては GetInfo() を使うのですが、
まずは仕様確認。
Getinfo.png

欲しいのは Kernel ファイルの情報なので、
EFI_FILE_INFO かな。。って事で仕様をチラ見する。
efi_file_info.png

GetInfo で output するデータは Void * なので
データの中身自体は Void 型となります。
しかし、想定しているデータは EFI_FILE_INFO :構造体です。

よってデータ取得後、
Void* を EFI_FILE_INFO* とするようなキャストが必要になります。

check_kernel_size.c
EFI_STATUS EFIAPI UefiMain(
    EFI_HANDLE image_handle,
    EFI_SYSTEM_TABLE* system_table) 
  {
    UINTN BufferSize = sizeof(EFI_FILE_INFO) + sizeof(CHAR16)*12;
    UINT8 void_kernel_info[BufferSize];
    status = kernel_file->GetInfo(
             kernel_file, &gEfiFileInfoGuid,
             &BufferSize,void_kernel_info);
    if (EFI_ERROR(status)) {Print(L"Fail to get kernel info\n");}
    EFI_FILE_INFO* kernel_info = (EFI_FILE_INFO*)void_kernel_info;

    Print(L"All done\n");
    while (1);
    return EFI_SUCCESS;
}

メモリ領域の確保

カーネルサイズを確認したら、
work memory に配置する領域を確保します。
pagealocate.png
EFI_ALLOCATE_TYPE の説明についてはOS自作入門を買って確認しましょう。
*UEFI specification に説明ありますけど。。。

keep_workmemory.c
EFI_STATUS EFIAPI UefiMain(
    EFI_HANDLE image_handle,
    EFI_SYSTEM_TABLE* system_table) 
  {

    //alocate kernel on work memory
    EFI_PHYSICAL_ADDRESS kernel_base_addr = 0x100000;
    gBS->AllocatePages(
        AllocateAddress, EfiLoaderData,
        (kernel_info.FileSize + 0xfff) / 0x1000, &kernel_base_addr);

    //↓ 以下の記述が無くても動作はする。
    //kernel_file->Read(kernel_file, &(kernel_info.FileSize), (VOID*)kernel_base_addr);

    Print(L"All done\n");
    while (1);
    return EFI_SUCCESS;
}

UEFI Boot service 終了

kernel を呼び出す前に Boot Service を終了させる必要があります。
ココ に参考情報があります。boot service から runtime srvice の
移行するためのお約束として Exit boot service するようです。
editboot.png
当初に get memory map を call したときに map key は取得しているのですが、
その後の操作で map key は変わっている場合がありますので、exit する際には
再度 get memory map を call して map key の更新が必要です。

exit_boot_service.c
EFI_STATUS EFIAPI UefiMain(
    EFI_HANDLE image_handle,
    EFI_SYSTEM_TABLE* system_table) 
  {    
    //Exit boot services
    MemMap_Make(&MemMap,4096*4);
    status = gBS->ExitBootServices(image_handle, MemMap.map_key);
    if (EFI_ERROR(status)) {
      Print(L"Fail to ExitBootServices\n");}
    }

Kernel の起動

Point 1 : entry point 明確化
base address から 24バイトのオフセットに
Entry point のアドレスが格納されています(らしい)。
そのため (base address + 24)をポインタキャストして * とすれば
Entry point のアドレスになると思います。

Point 2: kernel を call するために関数のプロトタイプ宣言が必要
呼び出す kernel は結局、関数なので
引数と戻り値を定義するプロトタイプ宣言が
必要という意義は納得です。

その他: 作法としてストックしておけば、とりあえず今は良いかも

boot_kernel.c
    //set entry point and call kernel
    UINT64 entry_addr = *(UINT64*)(kernel_base_addr + 24);    /* <= Point 1*/
    typedef void EntryPointType(void);                        /* <= Point 2*/
    EntryPointType* entry_point = (EntryPointType*)entry_addr;
    entry_point();
0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?