mikanos 3章

## 3.2 レジスタ
レジスタ(CPUに内蔵された記憶領域)は2種類
- 汎用レジスタ: 一般の演算に使う
- 特殊レジスタ: CPUに内蔵された機能を制御する
    - RIP: retain the memory address which cpu will execute next
    - RFLAGS: flag which changes depending on the instruction result
        - e.g.) bit 6 is ZF. ZF becomes 1 when the result becomes 0.
    - CR0: the CPU important configuration

## 3.3 the first kernel
Bootloader is UEFI application, and then Bootloader will call kerbel as ELF binary.

```
extern "C" void KernelMain() {
    while(1) __asm__("hlt");
}
```
- extern "C"
This means this function is definened in C language.
in C++ language, the name of function is converted into another name.
So, when we call this function from BootLoader, which is created in C language, we should prevent name mangling(名前修飾).

- __asm__
inline assembly. embed assembly language into C language.

- hlt instruntion
`hlt` is an instruction to stop CPU.

- how to create kernel file?

`clang++ -O2 -Wall -g --target=x86_64-elf -ffreestanding -mno-red-zone -fno-exceptions -fno-rtti -std=c++17 -c main.cpp`

-O2: 最適化レベル2
-Wall: 警告たくさん出す
-g: デバッグ情報付きでコンパイルする
--target=x86_64-elf: X86_64向きの機械語生成。出力ファイルをELFとする。
-ffreestanding: フリースタンディング環境向きにコンパイルする
    ホスト環境: OSの上で動くプログラム
    フリースタンディング: OSがない環境で動くプログラム
-mno-red-zone: red Zone機能を無効にする

以下2つはOSからのサポートが必要なC++の言語機能を無効にする。
- fno-exceptions: C++の例外機能を使わない
- fno-rtti: C++の動的型情報を使わない
- std=C++17: C++のバージョンをC++17とする
- c:コンパイルのみ。リンクしない。

`ld.lld --entry KernelMain -z norelro --image-base 0x100000 --static -o kernel.elf main.o`
リンカによって実行ファイルを作る。

-  --entry KernelMain: エントリポイントの指定
-  -z norelro: リロケーション情報を読み込み専用にする機能を使わない??
- --image-base 0x100000: 出力されたバイナリのベースアドレスを0x100000とする
- -o kernel.elf : 出力ファイル名をkernel.elfとする
- --static: 静的リンクをする

- We have to allocate the memory to read the file
```
  // kernel fileのサイズをあらかじめ知る必要がある。
  // file infoのサイズはあらかじめ決まっている
  UINTN file_info_size = sizeof(EFI_FILE_INFO) + sizeof(CHAR16) * 12;
  UINT8 file_info_buffer[file_info_size];
  kernel_file->GetInfo(
      kernel_file, &gEfiFileInfoGuid,
      &file_info_size, file_info_buffer);

  EFI_FILE_INFO *file_info = (EFI_FILE_INFO *)file_info_buffer;
  UINTN kernel_file_size = file_info->FileSize;

  EFI_PHYSICAL_ADDRESS kernel_base_addr = 0x100000;
  gBS->AllocatePages(
      AllocateAddress, EfiLoaderData,
      (kernel_file_size + 0xfff) / 0x1000, &kernel_base_addr);
  kernel_file->Read(kernel_file, &kernel_file_size, (VOID *)kernel_base_addr);
  Print(L"Kernel: 0x%0lx (%lu bytes)\n", kernel_base_addr, kernel_file_size);
  // #@@range_end(read_kernel)
```

  - the reason why that we allocated the memory of `file_info` which is more than `EFI_FILE_INFO` by `sizeof(CHAR16) * 12`.

EFI_FILE_INFO is like this:
```
typedef struct {
    UINT64 Size, FileSize, PhysicalSize;
    EFI_TIME CreateTime, LastAccessTime, ModificationTime;
    ...
    CHAR16 FileName[];
} EFI_FILE_INFO
```

IF we do not specify the number of elements, FIleName's size is calculated as `0`. So, In order to include `\kernel.elf`, we should add `sizeof(CHAR16) * 12`.


- before starting kernel, we have to stop boot service.

```

  // #@@range_begin(exit_bs)
  EFI_STATUS status;
  status = gBS->ExitBootServices(image_handle, memmap.map_key);
  if (EFI_ERROR(status)) {
    status = GetMemoryMap(&memmap);
    if (EFI_ERROR(status)) {
      Print(L"failed to get memory map: %r\n", status);
      while (1);
    }
    status = gBS->ExitBootServices(image_handle, memmap.map_key);
    if (EFI_ERROR(status)) {
      Print(L"Could not exit boot service: %r\n", status);
      while (1);
    }
  }
  // #@@range_end(exit_bs)
  ```

- begin kernel
```

  // #@@range_begin(call_kernel)
  // UINT64 is 8byte.
  UINT64 entry_addr = *(UINT64 *)(kernel_base_addr + 24);

　// EntryPointType: Both of the argument and return type are void
  typedef void EntryPointType(void);
  EntryPointType *entry_point = (EntryPointType *)entry_addr;
  entry_point();
  // #@@range_end(call_kernel)
```

according to specification, entry point address is 8-byte integer from `kernel_base_addr+24byte` to `kernel_base_addr+24byte + 8byte`.
![S__7938233.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3680937/e8f2ca8e-2940-4e10-aa53-68e871365307.jpeg)


```
build

$HOME/osbook/devenv/run_qemu.sh Build/MikanLoaderX64/DEBUG_CLANG38/X64/Loader.efi /home/nonoka/workspace/mikanos/kernel/kernel.elf
```

## 3.4 display pixel

```
  // #@@range_begin(gop)
  EFI_GRAPHICS_OUTPUT_PROTOCOL* gop;
  OpenGOP(image_handle, &gop);
  Print(L"Resolution: %ux%u, Pixel Format: %s, %u pixels/line\n",
      gop->Mode->Info->HorizontalResolution,
      gop->Mode->Info->VerticalResolution,
      GetPixelFormatUnicode(gop->Mode->Info->PixelFormat),
      gop->Mode->Info->PixelsPerScanLine);
  Print(L"Frame Buffer: 0x%0lx - 0x%0lx, Size: %lu bytes\n",
      gop->Mode->FrameBufferBase,
      gop->Mode->FrameBufferBase + gop->Mode->FrameBufferSize,
      gop->Mode->FrameBufferSize);

  UINT8* frame_buffer = (UINT8*)gop->Mode->FrameBufferBase;
  for (UINTN i = 0; i < gop->Mode->FrameBufferSize; ++i) {
    frame_buffer[i] = 255;
  }
  // #@@range_end(gop)
  ```

  ```
  source $HOME/osbook/devenv/buildenv.sh
  clang++ $CPPFLAGS  -O2 --target=x86_64-elf -ffreestanding  -fno-exceptions -c main.cpp

ld.lld $LDFLAGS --entry KernelMain -z norelrp --image-base 0x100000 --static -o kernel.elf main.o
```

## 3.7 pointer & assembly language
```
#include <iostream>

void foo(){
   int i = 42;
   int*p = &i;
   int r1 = *p;
   *p = 1;
   int r2 = i;
   uintptr_t addr = reinterpret_cast<uintptr_t>(p);
   int*q = reinterpret_cast<int*>(addr);
}

int main(){
   foo();
}
```

assembly
```
// fooのアセンブリ言語の世界における名前。C++の名前修飾の機能による。
__Z3foov:
    push rbp //スタックにrbpの値をpushする。このときrspを-8してrspが指すところに値を書き込む。
    mov rbp, rsp // rbp = rsp
    mov dword ptr [rbp-4], 42 // [addr]はaddrへのメモリアクセス。dwordはメモリアクセスの大きさ。ptrは[]がメモリアクセスだと明示。rbp-4のメモリにdwordだけ42を書き込む。
```

後半
```
lea rax, [rbp-4] // メモリアクセスはしないで、計算結果だけレジスタに書き込む。raxにi(42)のアドレス。
mov qword ptr [rbp - 16], rax // [rbp-16]のアドレスの場所にraxを書き込む。

mov rax, qword ptr [rbp - 16]
mov ecx, dword ptr [rax]
mov dword ptr [rbp - 20], ecx

mov rax, qword ptr [rbp-16]
mov dword ptr [rax], 1

mov ecx, dword ptr [rbp - 4]
mov dword ptr [rbp - 24], ecx

mov rax, qword ptr [rbp - 16]
mov qword ptr [rbp - 32], rax

mov rax, qword ptr [rbp - 32]
mov qword ptr [rbp - 40], rax

pop rbp
ret
```

![S__2449411.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3680937/049da0fd-adaa-4899-e8a2-2c8de3970a0e.jpeg)