Repository: tailix/libkernaux (language: python)

Issue:
Finish Multiboot 2
~~Including memory map export.~~


Discussion / hints:

Fix patch:
diff --git a/.gitignore b/.gitignore
index deb9a0e0..2c4d0ded 100644
--- a/.gitignore
+++ b/.gitignore
@@ -57,6 +57,15 @@
 /libtool
 /stamp-h1
 
+# Temporary
+/confcache
+/confdefs.h
+/confinc.mk
+/confmf.BSD
+/confmf.GNU
+/conftest.c
+/conftest.err
+
 /examples/test-suite.log
 /examples/*.log
 /examples/*.trs
@@ -97,8 +106,10 @@
 /examples/printf_str_va
 /examples/units_human
 
+/tests/multiboot2_header_print0
 /tests/multiboot2_header_print1
 /tests/multiboot2_header_print2
+/tests/multiboot2_info_print0
 /tests/multiboot2_info_print1
 /tests/multiboot2_info_print2
 /tests/test_arch_i386
diff --git a/ChangeLog b/ChangeLog
index 50013cf5..ef58b7b7 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2022-12-16  Alex Kotov  <kotovalexarian@gmail.com>
+
+	* configure.ac: Feature "--with[out]-multiboot2" has been added
+	* include/kernaux/multiboot2.h: Has been made stable
+
 2022-12-14  Alex Kotov  <kotovalexarian@gmail.com>
 
 	* configure.ac: Enable shared library
diff --git a/Makefile.am b/Makefile.am
index 3822d088..15886e37 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -93,7 +93,6 @@ libkernaux_la_SOURCES += \
 	src/multiboot2/header_helpers.c \
 	src/multiboot2/header_is_valid.c \
 	src/multiboot2/header_print.c \
-	src/multiboot2/info_convert.c \
 	src/multiboot2/info_helpers.c \
 	src/multiboot2/info_is_valid.c \
 	src/multiboot2/info_print.c
diff --git a/README.md b/README.md
index 030ceba8..79f7fa7c 100644
--- a/README.md
+++ b/README.md
@@ -66,7 +66,7 @@ zero). Work-in-progress APIs can change at any time.
 * Data formats
   * [ELF](/include/kernaux/elf.h) (*work in progress*)
   * [MBR](/include/kernaux/mbr.h) (*work in progress*)
-  * [Multiboot 2 (GRUB 2)](/include/kernaux/multiboot2.h.in) (*work in progress*)
+  * [Multiboot 2 (GRUB 2)](/include/kernaux/multiboot2.h.in) (*non-breaking since* **?.?.?**)
     * [Example: header macros](/examples/multiboot2_header_macro.c)
 * Utilities
   * [Measurement units utils](/include/kernaux/units.h) (*work in progress*)
@@ -169,6 +169,7 @@ explicitly included, use `--without-all`.
 * `--with[out]-cmdline` - command line parser
 * `--with[out]-free-list` - free list memory allocator
 * `--with[out]-memmap` - memory map
+* `--with[out]-multiboot2` - Multiboot 2 utils
 * `--with[out]-ntoa` - itoa/ftoa
 * `--with[out]-printf` - printf
 
diff --git a/configure.ac b/configure.ac
index 7e71f46c..efb63a9d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -69,7 +69,7 @@ AC_ARG_WITH(  [elf],             AS_HELP_STRING([--without-elf],            [wit
 AC_ARG_WITH(  [free-list],       AS_HELP_STRING([--without-free-list],      [without free list memory allocator]))
 AC_ARG_WITH(  [mbr],             AS_HELP_STRING([--without-mbr],            [without MBR utils]))
 AC_ARG_WITH(  [memmap],          AS_HELP_STRING([--without-memmap],         [without memory map]))
-AC_ARG_WITH(  [multiboot2],      AS_HELP_STRING([--without-multiboot2],     [without Multiboot 2 information parser]))
+AC_ARG_WITH(  [multiboot2],      AS_HELP_STRING([--without-multiboot2],     [without Multiboot 2 utils]))
 AC_ARG_WITH(  [ntoa],            AS_HELP_STRING([--without-ntoa],           [without itoa/ftoa]))
 AC_ARG_WITH(  [pfa],             AS_HELP_STRING([--without-pfa],            [without Page Frame Allocator]))
 AC_ARG_WITH(  [printf],          AS_HELP_STRING([--without-printf],         [without printf]))
@@ -265,7 +265,7 @@ AS_IF([test "$with_elf"               = yes], [AC_DEFINE([WITH_ELF],
 AS_IF([test "$with_free_list"         = yes], [AC_DEFINE([WITH_FREE_LIST],         [1], [with free list memory allocator])])
 AS_IF([test "$with_mbr"               = yes], [AC_DEFINE([WITH_MBR],               [1], [with MBR utils])])
 AS_IF([test "$with_memmap"            = yes], [AC_DEFINE([WITH_MEMMAP],            [1], [with memory map])])
-AS_IF([test "$with_multiboot2"        = yes], [AC_DEFINE([WITH_MULTIBOOT2],        [1], [with Multiboot 2 information parser])])
+AS_IF([test "$with_multiboot2"        = yes], [AC_DEFINE([WITH_MULTIBOOT2],        [1], [with Multiboot 2 utils])])
 AS_IF([test "$with_ntoa"              = yes], [AC_DEFINE([WITH_NTOA],              [1], [with ntoa])])
 AS_IF([test "$with_pfa"               = yes], [AC_DEFINE([WITH_PFA],               [1], [with Page Frame Allocator])])
 AS_IF([test "$with_printf"            = yes], [AC_DEFINE([WITH_PRINTF],            [1], [with printf])])
diff --git a/examples/multiboot2_header_macro.c b/examples/multiboot2_header_macro.c
index 779c4fdc..41426aab 100644
--- a/examples/multiboot2_header_macro.c
+++ b/examples/multiboot2_header_macro.c
@@ -54,6 +54,7 @@ multiboot2_header = {
         .magic = KERNAUX_MULTIBOOT2_HEADER_MAGIC,
         .arch = KERNAUX_MULTIBOOT2_HEADER_ARCH_I386,
         .total_size = sizeof(multiboot2_header),
+        // This macro helps to calculate the checksum.
         .checksum = KERNAUX_MULTIBOOT2_HEADER_CHECKSUM(
             KERNAUX_MULTIBOOT2_HEADER_ARCH_I386,
             sizeof(multiboot2_header)
diff --git a/include/Makefile.am b/include/Makefile.am
index 7388080a..5c55567c 100644
--- a/include/Makefile.am
+++ b/include/Makefile.am
@@ -1,31 +1,37 @@
 nobase_include_HEADERS = \
-	kernaux.h                         \
-	kernaux/arch/i386.h               \
-	kernaux/arch/i386-idt.h           \
-	kernaux/arch/riscv64.h            \
-	kernaux/arch/x86_64.h             \
-	kernaux/arch/x86.h                \
-	kernaux/asm/i386.h                \
-	kernaux/asm/riscv64.h             \
-	kernaux/asm/x86_64.h              \
-	kernaux/asm/x86.h                 \
-	kernaux/assert.h                  \
-	kernaux/cmdline.h                 \
-	kernaux/elf.h                     \
-	kernaux/free_list.h               \
-	kernaux/generic/display.h         \
-	kernaux/generic/malloc.h          \
-	kernaux/generic/mutex.h           \
-	kernaux/macro.h                   \
-	kernaux/macro/packing_end.run     \
-	kernaux/macro/packing_start.run   \
-	kernaux/mbr.h                     \
-	kernaux/memmap.h                  \
-	kernaux/multiboot2.h              \
-	kernaux/multiboot2/header_macro.h \
-	kernaux/ntoa.h                    \
-	kernaux/pfa.h                     \
-	kernaux/printf.h                  \
-	kernaux/printf_fmt.h              \
-	kernaux/units.h                   \
+	kernaux.h                            \
+	kernaux/arch/i386.h                  \
+	kernaux/arch/i386-idt.h              \
+	kernaux/arch/riscv64.h               \
+	kernaux/arch/x86_64.h                \
+	kernaux/arch/x86.h                   \
+	kernaux/asm/i386.h                   \
+	kernaux/asm/riscv64.h                \
+	kernaux/asm/x86_64.h                 \
+	kernaux/asm/x86.h                    \
+	kernaux/assert.h                     \
+	kernaux/cmdline.h                    \
+	kernaux/elf.h                        \
+	kernaux/free_list.h                  \
+	kernaux/generic/display.h            \
+	kernaux/generic/malloc.h             \
+	kernaux/generic/mutex.h              \
+	kernaux/macro.h                      \
+	kernaux/macro/packing_end.run        \
+	kernaux/macro/packing_start.run      \
+	kernaux/mbr.h                        \
+	kernaux/memmap.h                     \
+	kernaux/multiboot2.h                 \
+	kernaux/multiboot2/header_helpers.h  \
+	kernaux/multiboot2/header_is_valid.h \
+	kernaux/multiboot2/header_macro.h    \
+	kernaux/multiboot2/header_print.h    \
+	kernaux/multiboot2/info_helpers.h    \
+	kernaux/multiboot2/info_is_valid.h   \
+	kernaux/multiboot2/info_print.h      \
+	kernaux/ntoa.h                       \
+	kernaux/pfa.h                        \
+	kernaux/printf.h                     \
+	kernaux/printf_fmt.h                 \
+	kernaux/units.h                      \
 	kernaux/version.h
diff --git a/include/kernaux.h b/include/kernaux.h
index 8d66bb75..38ae77a0 100644
--- a/include/kernaux.h
+++ b/include/kernaux.h
@@ -17,7 +17,6 @@
 #include <kernaux/mbr.h>
 #include <kernaux/memmap.h>
 #include <kernaux/multiboot2.h>
-#include <kernaux/multiboot2/header_macro.h>
 #include <kernaux/ntoa.h>
 #include <kernaux/pfa.h>
 #include <kernaux/printf.h>
diff --git a/include/kernaux/multiboot2.h b/include/kernaux/multiboot2.h
index b689c3aa..8120ac48 100644
--- a/include/kernaux/multiboot2.h
+++ b/include/kernaux/multiboot2.h
@@ -7,7 +7,6 @@ extern "C" {
 
 #include <kernaux/macro.h>
 #include <kernaux/generic/display.h>
-#include <kernaux/memmap.h>
 #include <kernaux/multiboot2/header_macro.h>
 
 #include <stdint.h>
@@ -24,13 +23,6 @@ extern "C" {
 // @see https://www.gnu.org/software/grub/manual/multiboot2/multiboot.html#Basic-tags-structure
 #define KERNAUX_MULTIBOOT2_TAG_ALIGN    8
 
-#define KERNAUX_MULTIBOOT2_HEADER_CHECKSUM(arch, total_size) \
-    ((uint32_t)(-(                                           \
-        ((uint32_t)KERNAUX_MULTIBOOT2_HEADER_MAGIC) +        \
-        ((uint32_t)(arch)) +                                 \
-        ((uint32_t)(total_size))                             \
-    )))
-
 #define KERNAUX_MULTIBOOT2_DATA(ptr) (((uint8_t*)(ptr)) + sizeof(*(ptr)))
 
 #define KERNAUX_MULTIBOOT2_HTAG_NEXT(tag_base) \
@@ -97,7 +89,7 @@ KERNAUX_STATIC_TEST_STRUCT_SIZE(KernAux_Multiboot2_HTagBase, 8);
 
 struct KernAux_Multiboot2_Info {
     uint32_t total_size;
-    uint32_t reserved1;
+    uint32_t reserved;
 }
 KERNAUX_PACKED;
 
@@ -154,7 +146,7 @@ struct KernAux_Multiboot2_ITag_MemoryMap_EntryBase {
     uint64_t base_addr;
     uint64_t length;
     uint32_t type;
-    uint32_t reserved1;
+    uint32_t reserved;
 }
 KERNAUX_PACKED;
 
@@ -177,6 +169,8 @@ struct KernAux_Multiboot2_HTag_InfoReq {
     // type = 1
     // size > 8
     struct KernAux_Multiboot2_HTagBase base;
+
+    // DATA: uint32_t mbi_tag_types[]
 }
 KERNAUX_PACKED;
 
@@ -302,6 +296,8 @@ struct KernAux_Multiboot2_ITag_BootCmdLine {
     // type = 1
     // size > 8
     struct KernAux_Multiboot2_ITagBase base;
+
+    // DATA: char cmdline[]
 }
 KERNAUX_PACKED;
 
@@ -311,6 +307,8 @@ struct KernAux_Multiboot2_ITag_BootLoaderName {
     // type = 2
     // size > 8
     struct KernAux_Multiboot2_ITagBase base;
+
+    // DATA: char name[]
 }
 KERNAUX_PACKED;
 
@@ -323,6 +321,8 @@ struct KernAux_Multiboot2_ITag_Module {
 
     uint32_t mod_start;
     uint32_t mod_end;
+
+    // DATA: char cmdline[]
 }
 KERNAUX_PACKED;
 
@@ -345,7 +345,7 @@ struct KernAux_Multiboot2_ITag_BIOSBootDevice {
     // size = 20
     struct KernAux_Multiboot2_ITagBase base;
 
-    uint32_t bios_dev;
+    uint32_t biosdev;
     uint32_t partition;
     uint32_t sub_partition;
 }
@@ -360,6 +360,8 @@ struct KernAux_Multiboot2_ITag_MemoryMap {
 
     uint32_t entry_size;
     uint32_t entry_version;
+
+    // DATA: varies(entry_size) KernAux_Multiboot2_ITag_MemoryMap_EntryBase entries[]
 }
 KERNAUX_PACKED;
 
@@ -383,7 +385,7 @@ KERNAUX_STATIC_TEST_STRUCT_SIZE(KernAux_Multiboot2_ITag_VBEInfo, 784);
 
 struct KernAux_Multiboot2_ITag_FramebufferInfo {
     // type = 8
-    // size > 31
+    // size > 32
     struct KernAux_Multiboot2_ITagBase base;
 
     uint64_t framebuffer_addr;
@@ -392,25 +394,37 @@ struct KernAux_Multiboot2_ITag_FramebufferInfo {
     uint32_t framebuffer_height;
     uint8_t framebuffer_bpp;
     uint8_t framebuffer_type;
-    uint8_t reserved1;
+
+    // WARNING: GRUB 2 and Limine don't follow the spec, so we do not too!
+    // Multiboot 2: https://www.gnu.org/software/grub/manual/multiboot2/multiboot.html#Framebuffer-info
+    // GRUB 2:      https://github.com/rhboot/grub2/blob/7259d55ffcf124e32eafb61aa381f9856e98a708/include/multiboot2.h#L288
+    // Limine:      https://github.com/limine-bootloader/limine/blob/1aba6b3aeb72ac55b177132ca75ea8adfbcb78aa/common/protos/multiboot2.h#L292
+    uint16_t reserved;
+
+    // DATA: varies color_info[]
 }
 KERNAUX_PACKED;
 
-KERNAUX_STATIC_TEST_STRUCT_SIZE(KernAux_Multiboot2_ITag_FramebufferInfo, 31);
+KERNAUX_STATIC_TEST_STRUCT_SIZE(KernAux_Multiboot2_ITag_FramebufferInfo, 32);
 
+// WARNING: GRUB 2 and Limine don't follow the spec, so we do not too!
+// Multiboot 2: https://www.gnu.org/software/grub/manual/multiboot2/multiboot.html#ELF_002dSymbols
+// GRUB 2:      https://github.com/rhboot/grub2/blob/7259d55ffcf124e32eafb61aa381f9856e98a708/include/multiboot2.h#L314-L322
+// Limine:      https://github.com/limine-bootloader/limine/blob/1aba6b3aeb72ac55b177132ca75ea8adfbcb78aa/common/protos/multiboot2.h#L318-L326
 struct KernAux_Multiboot2_ITag_ELFSymbols {
     // type = 9
-    // size > 16
+    // size > 20
     struct KernAux_Multiboot2_ITagBase base;
 
-    uint16_t num;
-    uint16_t ent_size;
-    uint16_t shndx;
-    uint16_t reserved1;
+    uint32_t num;
+    uint32_t entsize;
+    uint32_t shndx;
+
+    // DATA: varies section_headers[]
 }
 KERNAUX_PACKED;
 
-KERNAUX_STATIC_TEST_STRUCT_SIZE(KernAux_Multiboot2_ITag_ELFSymbols, 16);
+KERNAUX_STATIC_TEST_STRUCT_SIZE(KernAux_Multiboot2_ITag_ELFSymbols, 20);
 
 struct KernAux_Multiboot2_ITag_APMTable {
     // type = 10
@@ -460,7 +474,9 @@ struct KernAux_Multiboot2_ITag_SMBIOSTables {
 
     uint8_t major;
     uint8_t minor;
-    uint8_t reserved1[6];
+    uint8_t reserved[6];
+
+    // TODO: DATA?
 }
 KERNAUX_PACKED;
 
@@ -470,6 +486,8 @@ struct KernAux_Multiboot2_ITag_ACPIOldRSDP {
     // type = 14
     // size > 8
     struct KernAux_Multiboot2_ITagBase base;
+
+    // TODO: DATA?
 }
 KERNAUX_PACKED;
 
@@ -479,6 +497,8 @@ struct KernAux_Multiboot2_ITag_ACPINewRSDP {
     // type = 15
     // size > 8
     struct KernAux_Multiboot2_ITagBase base;
+
+    // TODO: DATA?
 }
 KERNAUX_PACKED;
 
@@ -488,6 +508,8 @@ struct KernAux_Multiboot2_ITag_NetworkingInfo {
     // type = 16
     // size > 8
     struct KernAux_Multiboot2_ITagBase base;
+
+    // TODO: DATA?
 }
 KERNAUX_PACKED;
 
@@ -500,6 +522,8 @@ struct KernAux_Multiboot2_ITag_EFIMemoryMap {
 
     uint32_t descriptor_size;
     uint32_t descriptor_version;
+
+    // TODO: DATA?
 }
 KERNAUX_PACKED;
 
@@ -581,256 +605,26 @@ const char *KernAux_Multiboot2_HTag_RelocatableHeader_Preference_to_str(
     enum KernAux_Multiboot2_HTag_RelocatableHeader_Preference pref
 );
 
-/************************************
- * Information conversion functions *
- ************************************/
-
-bool KernAux_Multiboot2_Info_to_memmap(
-    const struct KernAux_Multiboot2_Info *multiboot2_info,
-    KernAux_MemMap memmap
-);
-
-/***************************
- * Header helper functions *
- ***************************/
-
-const struct KernAux_Multiboot2_HTagBase
-*KernAux_Multiboot2_Header_first_tag_with_type(
-    const struct KernAux_Multiboot2_Header *multiboot2_header,
-    enum KernAux_Multiboot2_HTag tag_type
-);
-
-const struct KernAux_Multiboot2_HTagBase
-*KernAux_Multiboot2_Header_tag_with_type_after(
-    const struct KernAux_Multiboot2_Header *multiboot2_header,
-    enum KernAux_Multiboot2_HTag tag_type,
-    const struct KernAux_Multiboot2_HTagBase *after_tag
-);
-
-/********************************
- * Information helper functions *
- ********************************/
-
-const struct KernAux_Multiboot2_ITagBase
-*KernAux_Multiboot2_Info_first_tag_with_type(
-    const struct KernAux_Multiboot2_Info *multiboot2_info,
-    enum KernAux_Multiboot2_ITag tag_type
-);
-
-const struct KernAux_Multiboot2_ITagBase
-*KernAux_Multiboot2_Info_tag_with_type_after(
-    const struct KernAux_Multiboot2_Info *multiboot2_info,
-    enum KernAux_Multiboot2_ITag tag_type,
-    const struct KernAux_Multiboot2_ITagBase *after_tag
-);
-
-const char *KernAux_Multiboot2_Info_boot_cmd_line(
-    const struct KernAux_Multiboot2_Info *multiboot2_info
-);
-
-/*******************************
- * Header validation functions *
- *******************************/
-
-bool KernAux_Multiboot2_Header_is_valid(
-    const struct KernAux_Multiboot2_Header *multiboot2_header
-);
-
-bool KernAux_Multiboot2_HTagBase_is_valid(
-    const struct KernAux_Multiboot2_HTagBase *tag_base
-);
-
-bool KernAux_Multiboot2_HTag_None_is_valid(
-    const struct KernAux_Multiboot2_HTag_None *tag
-);
-
-bool KernAux_Multiboot2_HTag_InfoReq_is_valid(
-    const struct KernAux_Multiboot2_HTag_InfoReq *tag
-);
-
-bool KernAux_Multiboot2_HTag_Addr_is_valid(
-    const struct KernAux_Multiboot2_HTag_Addr *tag
-);
-
-bool KernAux_Multiboot2_HTag_EntryAddr_is_valid(
-    const struct KernAux_Multiboot2_HTag_EntryAddr *tag
-);
-
-bool KernAux_Multiboot2_HTag_Flags_is_valid(
-    const struct KernAux_Multiboot2_HTag_Flags *tag
-);
-
-bool KernAux_Multiboot2_HTag_Framebuffer_is_valid(
-    const struct KernAux_Multiboot2_HTag_Framebuffer *tag
-);
-
-bool KernAux_Multiboot2_HTag_ModuleAlign_is_valid(
-    const struct KernAux_Multiboot2_HTag_ModuleAlign *tag
-);
-
-bool KernAux_Multiboot2_HTag_EFIBootServices_is_valid(
-    const struct KernAux_Multiboot2_HTag_EFIBootServices *tag
-);
-
-bool KernAux_Multiboot2_HTag_EFII386EntryAddr_is_valid(
-    const struct KernAux_Multiboot2_HTag_EFII386EntryAddr *tag
-);
-
-bool KernAux_Multiboot2_HTag_EFIAmd64EntryAddr_is_valid(
-    const struct KernAux_Multiboot2_HTag_EFIAmd64EntryAddr *tag
-);
-
-bool KernAux_Multiboot2_HTag_RelocatableHeader_is_valid(
-    const struct KernAux_Multiboot2_HTag_RelocatableHeader *tag
-);
-
-/************************************
- * Information validation functions *
- ************************************/
-
-bool KernAux_Multiboot2_Info_is_valid(
-    const struct KernAux_Multiboot2_Info *multiboot2_info
-);
-
-bool KernAux_Multiboot2_ITagBase_is_valid(
-    const struct KernAux_Multiboot2_ITagBase *tag_base
-);
-
-bool KernAux_Multiboot2_ITag_None_is_valid(
-    const struct KernAux_Multiboot2_ITag_None *tag
-);
-
-bool KernAux_Multiboot2_ITag_BootCmdLine_is_valid(
-    const struct KernAux_Multiboot2_ITag_BootCmdLine *tag
-);
-
-bool KernAux_Multiboot2_ITag_BootLoaderName_is_valid(
-    const struct KernAux_Multiboot2_ITag_BootLoaderName *tag
-);
-
-bool KernAux_Multiboot2_ITag_Module_is_valid(
-    const struct KernAux_Multiboot2_ITag_Module *tag
-);
-
-bool KernAux_Multiboot2_ITag_BasicMemoryInfo_is_valid(
-    const struct KernAux_Multiboot2_ITag_BasicMemoryInfo *tag
-);
-
-bool KernAux_Multiboot2_ITag_BIOSBootDevice_is_valid(
-    const struct KernAux_Multiboot2_ITag_BIOSBootDevice *tag
-);
-
-bool KernAux_Multiboot2_ITag_MemoryMap_is_valid(
-    const struct KernAux_Multiboot2_ITag_MemoryMap *tag
-);
-
-bool KernAux_Multiboot2_ITag_VBEInfo_is_valid(
-    const struct KernAux_Multiboot2_ITag_VBEInfo *tag
-);
-
-bool KernAux_Multiboot2_ITag_FramebufferInfo_is_valid(
-    const struct KernAux_Multiboot2_ITag_FramebufferInfo *tag
-);
-
-bool KernAux_Multiboot2_ITag_ELFSymbols_is_valid(
-    const struct KernAux_Multiboot2_ITag_ELFSymbols *tag
-);
-
-bool KernAux_Multiboot2_ITag_APMTable_is_valid(
-    const struct KernAux_Multiboot2_ITag_APMTable *tag
-);
-
-bool KernAux_Multiboot2_ITag_EFI32bitSystemTablePtr_is_valid(
-    const struct KernAux_Multiboot2_ITag_EFI32bitSystemTablePtr *tag
-);
-
-bool KernAux_Multiboot2_ITag_EFI64bitSystemTablePtr_is_valid(
-    const struct KernAux_Multiboot2_ITag_EFI64bitSystemTablePtr *tag
-);
-
-bool KernAux_Multiboot2_ITag_SMBIOSTables_is_valid(
-    const struct KernAux_Multiboot2_ITag_SMBIOSTables *tag
-);
-
-bool KernAux_Multiboot2_ITag_ACPIOldRSDP_is_valid(
-    const struct KernAux_Multiboot2_ITag_ACPIOldRSDP *tag
-);
-
-bool KernAux_Multiboot2_ITag_ACPINewRSDP_is_valid(
-    const struct KernAux_Multiboot2_ITag_ACPINewRSDP *tag
-);
-
-bool KernAux_Multiboot2_ITag_NetworkingInfo_is_valid(
-    const struct KernAux_Multiboot2_ITag_NetworkingInfo *tag
-);
-
-bool KernAux_Multiboot2_ITag_EFIMemoryMap_is_valid(
-    const struct KernAux_Multiboot2_ITag_EFIMemoryMap *tag
-);
-
-bool KernAux_Multiboot2_ITag_EFIBootServicesNotTerminated_is_valid(
-    const struct KernAux_Multiboot2_ITag_EFIBootServicesNotTerminated *tag
-);
-
-bool KernAux_Multiboot2_ITag_EFI32bitImageHandlePtr_is_valid(
-    const struct KernAux_Multiboot2_ITag_EFI32bitImageHandlePtr *tag
-);
-
-bool KernAux_Multiboot2_ITag_EFI64bitImageHandlePtr_is_valid(
-    const struct KernAux_Multiboot2_ITag_EFI64bitImageHandlePtr *tag
-);
-
-bool KernAux_Multiboot2_ITag_ImageLoadBasePhysAddr_is_valid(
-    const struct KernAux_Multiboot2_ITag_ImageLoadBasePhysAddr *tag
-);
-
-/**************************
- * Header print functions *
- **************************/
-
-void KernAux_Multiboot2_Header_print(
-    const struct KernAux_Multiboot2_Header *multiboot2_header,
-    KernAux_Display display
-);
-
-void KernAux_Multiboot2_HTagBase_print(
-    const struct KernAux_Multiboot2_HTagBase *tag_base,
-    KernAux_Display display
-);
-
-/*******************************
- * Information print functions *
- *******************************/
-
-void KernAux_Multiboot2_Info_print(
-    const struct KernAux_Multiboot2_Info *multiboot2_info,
-    KernAux_Display display
-);
+/********************
+ * Helper functions *
+ ********************/
 
-void KernAux_Multiboot2_ITagBase_print(
-    const struct KernAux_Multiboot2_ITagBase *tag_base,
-    KernAux_Display display
-);
+#include <kernaux/multiboot2/header_helpers.h>
+#include <kernaux/multiboot2/info_helpers.h>
 
-void KernAux_Multiboot2_ITag_BootCmdLine_print(
-    const struct KernAux_Multiboot2_ITag_BootCmdLine *tag,
-    KernAux_Display display
-);
+/************************
+ * Validation functions *
+ ************************/
 
-void KernAux_Multiboot2_ITag_BootLoaderName_print(
-    const struct KernAux_Multiboot2_ITag_BootLoaderName *tag,
-    KernAux_Display display
-);
+#include <kernaux/multiboot2/header_is_valid.h>
+#include <kernaux/multiboot2/info_is_valid.h>
 
-void KernAux_Multiboot2_ITag_MemoryMap_print(
-    const struct KernAux_Multiboot2_ITag_MemoryMap *tag,
-    KernAux_Display display
-);
+/*******************
+ * Print functions *
+ *******************/
 
-void KernAux_Multiboot2_ITag_ELFSymbols_print(
-    const struct KernAux_Multiboot2_ITag_ELFSymbols *tag,
-    KernAux_Display display
-);
+#include <kernaux/multiboot2/header_print.h>
+#include <kernaux/multiboot2/info_print.h>
 
 #ifdef __cplusplus
 }
diff --git a/include/kernaux/multiboot2/header_helpers.h b/include/kernaux/multiboot2/header_helpers.h
new file mode 100644
index 00000000..a9d3be6c
--- /dev/null
+++ b/include/kernaux/multiboot2/header_helpers.h
@@ -0,0 +1,27 @@
+#ifndef KERNAUX_INCLUDED_MULTIBOOT2_HEADER_HELPERS
+#define KERNAUX_INCLUDED_MULTIBOOT2_HEADER_HELPERS
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <kernaux/multiboot2.h>
+
+const struct KernAux_Multiboot2_HTagBase
+*KernAux_Multiboot2_Header_first_tag_with_type(
+    const struct KernAux_Multiboot2_Header *multiboot2_header,
+    enum KernAux_Multiboot2_HTag tag_type
+);
+
+const struct KernAux_Multiboot2_HTagBase
+*KernAux_Multiboot2_Header_tag_with_type_after(
+    const struct KernAux_Multiboot2_Header *multiboot2_header,
+    enum KernAux_Multiboot2_HTag tag_type,
+    const struct KernAux_Multiboot2_HTagBase *after_tag
+);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/kernaux/multiboot2/header_is_valid.h b/include/kernaux/multiboot2/header_is_valid.h
new file mode 100644
index 00000000..cd9b4d76
--- /dev/null
+++ b/include/kernaux/multiboot2/header_is_valid.h
@@ -0,0 +1,66 @@
+#ifndef KERNAUX_INCLUDED_MULTIBOOT2_HEADER_IS_VALID
+#define KERNAUX_INCLUDED_MULTIBOOT2_HEADER_IS_VALID
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <kernaux/multiboot2.h>
+
+bool KernAux_Multiboot2_Header_is_valid(
+    const struct KernAux_Multiboot2_Header *multiboot2_header
+);
+
+bool KernAux_Multiboot2_HTagBase_is_valid(
+    const struct KernAux_Multiboot2_HTagBase *tag_base
+);
+
+bool KernAux_Multiboot2_HTag_None_is_valid(
+    const struct KernAux_Multiboot2_HTag_None *tag
+);
+
+bool KernAux_Multiboot2_HTag_InfoReq_is_valid(
+    const struct KernAux_Multiboot2_HTag_InfoReq *tag
+);
+
+bool KernAux_Multiboot2_HTag_Addr_is_valid(
+    const struct KernAux_Multiboot2_HTag_Addr *tag
+);
+
+bool KernAux_Multiboot2_HTag_EntryAddr_is_valid(
+    const struct KernAux_Multiboot2_HTag_EntryAddr *tag
+);
+
+bool KernAux_Multiboot2_HTag_Flags_is_valid(
+    const struct KernAux_Multiboot2_HTag_Flags *tag
+);
+
+bool KernAux_Multiboot2_HTag_Framebuffer_is_valid(
+    const struct KernAux_Multiboot2_HTag_Framebuffer *tag
+);
+
+bool KernAux_Multiboot2_HTag_ModuleAlign_is_valid(
+    const struct KernAux_Multiboot2_HTag_ModuleAlign *tag
+);
+
+bool KernAux_Multiboot2_HTag_EFIBootServices_is_valid(
+    const struct KernAux_Multiboot2_HTag_EFIBootServices *tag
+);
+
+bool KernAux_Multiboot2_HTag_EFII386EntryAddr_is_valid(
+    const struct KernAux_Multiboot2_HTag_EFII386EntryAddr *tag
+);
+
+bool KernAux_Multiboot2_HTag_EFIAmd64EntryAddr_is_valid(
+    const struct KernAux_Multiboot2_HTag_EFIAmd64EntryAddr *tag
+);
+
+bool KernAux_Multiboot2_HTag_RelocatableHeader_is_valid(
+    const struct KernAux_Multiboot2_HTag_RelocatableHeader *tag
+);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/kernaux/multiboot2/header_macro.h b/include/kernaux/multiboot2/header_macro.h
index 83bd1b60..dc9ee80d 100644
--- a/include/kernaux/multiboot2/header_macro.h
+++ b/include/kernaux/multiboot2/header_macro.h
@@ -10,6 +10,13 @@ extern "C" {
 
 #include <stdint.h>
 
+#define KERNAUX_MULTIBOOT2_HEADER_CHECKSUM(arch, total_size) \
+    ((uint32_t)(-(                                           \
+        ((uint32_t)KERNAUX_MULTIBOOT2_HEADER_MAGIC) +        \
+        ((uint32_t)(arch)) +                                 \
+        ((uint32_t)(total_size))                             \
+    )))
+
 #define KERNAUX_MULTIBOOT2_HFIELDS_COMMON(name, type) \
     struct {                                          \
         struct KernAux_Multiboot2_HTag_##type tag;    \
diff --git a/include/kernaux/multiboot2/header_print.h b/include/kernaux/multiboot2/header_print.h
new file mode 100644
index 00000000..a2027163
--- /dev/null
+++ b/include/kernaux/multiboot2/header_print.h
@@ -0,0 +1,79 @@
+#ifndef KERNAUX_INCLUDED_MULTIBOOT2_HEADER_PRINT
+#define KERNAUX_INCLUDED_MULTIBOOT2_HEADER_PRINT
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <kernaux/multiboot2.h>
+
+void KernAux_Multiboot2_Header_print(
+    const struct KernAux_Multiboot2_Header *multiboot2_header,
+    KernAux_Display display
+);
+
+void KernAux_Multiboot2_HTagBase_print(
+    const struct KernAux_Multiboot2_HTagBase *tag_base,
+    KernAux_Display display
+);
+
+void KernAux_Multiboot2_HTag_None_print(
+    const struct KernAux_Multiboot2_HTag_None *tag,
+    KernAux_Display display
+);
+
+void KernAux_Multiboot2_HTag_InfoReq_print(
+    const struct KernAux_Multiboot2_HTag_InfoReq *tag,
+    KernAux_Display display
+);
+
+void KernAux_Multiboot2_HTag_Addr_print(
+    const struct KernAux_Multiboot2_HTag_Addr *tag,
+    KernAux_Display display
+);
+
+void KernAux_Multiboot2_HTag_EntryAddr_print(
+    const struct KernAux_Multiboot2_HTag_EntryAddr *tag,
+    KernAux_Display display
+);
+
+void KernAux_Multiboot2_HTag_Flags_print(
+    const struct KernAux_Multiboot2_HTag_Flags *tag,
+    KernAux_Display display
+);
+
+void KernAux_Multiboot2_HTag_Framebuffer_print(
+    const struct KernAux_Multiboot2_HTag_Framebuffer *tag,
+    KernAux_Display display
+);
+
+void KernAux_Multiboot2_HTag_ModuleAlign_print(
+    const struct KernAux_Multiboot2_HTag_ModuleAlign *tag,
+    KernAux_Display display
+);
+
+void KernAux_Multiboot2_HTag_EFIBootServices_print(
+    const struct KernAux_Multiboot2_HTag_EFIBootServices *tag,
+    KernAux_Display display
+);
+
+void KernAux_Multiboot2_HTag_EFII386EntryAddr_print(
+    const struct KernAux_Multiboot2_HTag_EFII386EntryAddr *tag,
+    KernAux_Display display
+);
+
+void KernAux_Multiboot2_HTag_EFIAmd64EntryAddr_print(
+    const struct KernAux_Multiboot2_HTag_EFIAmd64EntryAddr *tag,
+    KernAux_Display display
+);
+
+void KernAux_Multiboot2_HTag_RelocatableHeader_print(
+    const struct KernAux_Multiboot2_HTag_RelocatableHeader *tag,
+    KernAux_Display display
+);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/kernaux/multiboot2/info_helpers.h b/include/kernaux/multiboot2/info_helpers.h
new file mode 100644
index 00000000..315c025a
--- /dev/null
+++ b/include/kernaux/multiboot2/info_helpers.h
@@ -0,0 +1,31 @@
+#ifndef KERNAUX_INCLUDED_MULTIBOOT2_INFO_HELPERS
+#define KERNAUX_INCLUDED_MULTIBOOT2_INFO_HELPERS
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <kernaux/multiboot2.h>
+
+const struct KernAux_Multiboot2_ITagBase
+*KernAux_Multiboot2_Info_first_tag_with_type(
+    const struct KernAux_Multiboot2_Info *multiboot2_info,
+    enum KernAux_Multiboot2_ITag tag_type
+);
+
+const struct KernAux_Multiboot2_ITagBase
+*KernAux_Multiboot2_Info_tag_with_type_after(
+    const struct KernAux_Multiboot2_Info *multiboot2_info,
+    enum KernAux_Multiboot2_ITag tag_type,
+    const struct KernAux_Multiboot2_ITagBase *after_tag
+);
+
+const char *KernAux_Multiboot2_Info_boot_cmd_line(
+    const struct KernAux_Multiboot2_Info *multiboot2_info
+);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/kernaux/multiboot2/info_is_valid.h b/include/kernaux/multiboot2/info_is_valid.h
new file mode 100644
index 00000000..d8bf8158
--- /dev/null
+++ b/include/kernaux/multiboot2/info_is_valid.h
@@ -0,0 +1,110 @@
+#ifndef KERNAUX_INCLUDED_MULTIBOOT2_INFO_IS_VALID
+#define KERNAUX_INCLUDED_MULTIBOOT2_INFO_IS_VALID
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <kernaux/multiboot2.h>
+
+bool KernAux_Multiboot2_Info_is_valid(
+    const struct KernAux_Multiboot2_Info *multiboot2_info
+);
+
+bool KernAux_Multiboot2_ITagBase_is_valid(
+    const struct KernAux_Multiboot2_ITagBase *tag_base
+);
+
+bool KernAux_Multiboot2_ITag_None_is_valid(
+    const struct KernAux_Multiboot2_ITag_None *tag
+);
+
+bool KernAux_Multiboot2_ITag_BootCmdLine_is_valid(
+    const struct KernAux_Multiboot2_ITag_BootCmdLine *tag
+);
+
+bool KernAux_Multiboot2_ITag_BootLoaderName_is_valid(
+    const struct KernAux_Multiboot2_ITag_BootLoaderName *tag
+);
+
+bool KernAux_Multiboot2_ITag_Module_is_valid(
+    const struct KernAux_Multiboot2_ITag_Module *tag
+);
+
+bool KernAux_Multiboot2_ITag_BasicMemoryInfo_is_valid(
+    const struct KernAux_Multiboot2_ITag_BasicMemoryInfo *tag
+);
+
+bool KernAux_Multiboot2_ITag_BIOSBootDevice_is_valid(
+    const struct KernAux_Multiboot2_ITag_BIOSBootDevice *tag
+);
+
+bool KernAux_Multiboot2_ITag_MemoryMap_is_valid(
+    const struct KernAux_Multiboot2_ITag_MemoryMap *tag
+);
+
+bool KernAux_Multiboot2_ITag_VBEInfo_is_valid(
+    const struct KernAux_Multiboot2_ITag_VBEInfo *tag
+);
+
+bool KernAux_Multiboot2_ITag_FramebufferInfo_is_valid(
+    const struct KernAux_Multiboot2_ITag_FramebufferInfo *tag
+);
+
+bool KernAux_Multiboot2_ITag_ELFSymbols_is_valid(
+    const struct KernAux_Multiboot2_ITag_ELFSymbols *tag
+);
+
+bool KernAux_Multiboot2_ITag_APMTable_is_valid(
+    const struct KernAux_Multiboot2_ITag_APMTable *tag
+);
+
+bool KernAux_Multiboot2_ITag_EFI32bitSystemTablePtr_is_valid(
+    const struct KernAux_Multiboot2_ITag_EFI32bitSystemTablePtr *tag
+);
+
+bool KernAux_Multiboot2_ITag_EFI64bitSystemTablePtr_is_valid(
+    const struct KernAux_Multiboot2_ITag_EFI64bitSystemTablePtr *tag
+);
+
+bool KernAux_Multiboot2_ITag_SMBIOSTables_is_valid(
+    const struct KernAux_Multiboot2_ITag_SMBIOSTables *tag
+);
+
+bool KernAux_Multiboot2_ITag_ACPIOldRSDP_is_valid(
+    const struct KernAux_Multiboot2_ITag_ACPIOldRSDP *tag
+);
+
+bool KernAux_Multiboot2_ITag_ACPINewRSDP_is_valid(
+    const struct KernAux_Multiboot2_ITag_ACPINewRSDP *tag
+);
+
+bool KernAux_Multiboot2_ITag_NetworkingInfo_is_valid(
+    const struct KernAux_Multiboot2_ITag_NetworkingInfo *tag
+);
+
+bool KernAux_Multiboot2_ITag_EFIMemoryMap_is_valid(
+    const struct KernAux_Multiboot2_ITag_EFIMemoryMap *tag
+);
+
+bool KernAux_Multiboot2_ITag_EFIBootServicesNotTerminated_is_valid(
+    const struct KernAux_Multiboot2_ITag_EFIBootServicesNotTerminated *tag
+);
+
+bool KernAux_Multiboot2_ITag_EFI32bitImageHandlePtr_is_valid(
+    const struct KernAux_Multiboot2_ITag_EFI32bitImageHandlePtr *tag
+);
+
+bool KernAux_Multiboot2_ITag_EFI64bitImageHandlePtr_is_valid(
+    const struct KernAux_Multiboot2_ITag_EFI64bitImageHandlePtr *tag
+);
+
+bool KernAux_Multiboot2_ITag_ImageLoadBasePhysAddr_is_valid(
+    const struct KernAux_Multiboot2_ITag_ImageLoadBasePhysAddr *tag
+);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/kernaux/multiboot2/info_print.h b/include/kernaux/multiboot2/info_print.h
new file mode 100644
index 00000000..c8422c33
--- /dev/null
+++ b/include/kernaux/multiboot2/info_print.h
@@ -0,0 +1,134 @@
+#ifndef KERNAUX_INCLUDED_MULTIBOOT2_INFO_PRINT
+#define KERNAUX_INCLUDED_MULTIBOOT2_INFO_PRINT
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <kernaux/multiboot2.h>
+
+void KernAux_Multiboot2_Info_print(
+    const struct KernAux_Multiboot2_Info *multiboot2_info,
+    KernAux_Display display
+);
+
+void KernAux_Multiboot2_ITagBase_print(
+    const struct KernAux_Multiboot2_ITagBase *tag_base,
+    KernAux_Display display
+);
+
+void KernAux_Multiboot2_ITag_None_print(
+    const struct KernAux_Multiboot2_ITag_None *tag,
+    KernAux_Display display
+);
+
+void KernAux_Multiboot2_ITag_BootCmdLine_print(
+    const struct KernAux_Multiboot2_ITag_BootCmdLine *tag,
+    KernAux_Display display
+);
+
+void KernAux_Multiboot2_ITag_BootLoaderName_print(
+    const struct KernAux_Multiboot2_ITag_BootLoaderName *tag,
+    KernAux_Display display
+);
+
+void KernAux_Multiboot2_ITag_Module_print(
+    const struct KernAux_Multiboot2_ITag_Module *tag,
+    KernAux_Display display
+);
+
+void KernAux_Multiboot2_ITag_BasicMemoryInfo_print(
+    const struct KernAux_Multiboot2_ITag_BasicMemoryInfo *tag,
+    KernAux_Display display
+);
+
+void KernAux_Multiboot2_ITag_BIOSBootDevice_print(
+    const struct KernAux_Multiboot2_ITag_BIOSBootDevice *tag,
+    KernAux_Display display
+);
+
+void KernAux_Multiboot2_ITag_MemoryMap_print(
+    const struct KernAux_Multiboot2_ITag_MemoryMap *tag,
+    KernAux_Display display
+);
+
+void KernAux_Multiboot2_ITag_VBEInfo_print(
+    const struct KernAux_Multiboot2_ITag_VBEInfo *tag,
+    KernAux_Display display
+);
+
+void KernAux_Multiboot2_ITag_FramebufferInfo_print(
+    const struct KernAux_Multiboot2_ITag_FramebufferInfo *tag,
+    KernAux_Display display
+);
+
+void KernAux_Multiboot2_ITag_ELFSymbols_print(
+    const struct KernAux_Multiboot2_ITag_ELFSymbols *tag,
+    KernAux_Display display
+);
+
+void KernAux_Multiboot2_ITag_APMTable_print(
+    const struct KernAux_Multiboot2_ITag_APMTable *tag,
+    KernAux_Display display
+);
+
+void KernAux_Multiboot2_ITag_EFI32bitSystemTablePtr_print(
+    const struct KernAux_Multiboot2_ITag_EFI32bitSystemTablePtr *tag,
+    KernAux_Display display
+);
+
+void KernAux_Multiboot2_ITag_EFI64bitSystemTablePtr_print(
+    const struct KernAux_Multiboot2_ITag_EFI64bitSystemTablePtr *tag,
+    KernAux_Display display
+);
+
+void KernAux_Multiboot2_ITag_SMBIOSTables_print(
+    const struct KernAux_Multiboot2_ITag_SMBIOSTables *tag,
+    KernAux_Display display
+);
+
+void KernAux_Multiboot2_ITag_ACPIOldRSDP_print(
+    const struct KernAux_Multiboot2_ITag_ACPIOldRSDP *tag,
+    KernAux_Display display
+);
+
+void KernAux_Multiboot2_ITag_ACPINewRSDP_print(
+    const struct KernAux_Multiboot2_ITag_ACPINewRSDP *tag,
+    KernAux_Display display
+);
+
+void KernAux_Multiboot2_ITag_NetworkingInfo_print(
+    const struct KernAux_Multiboot2_ITag_NetworkingInfo *tag,
+    KernAux_Display display
+);
+
+void KernAux_Multiboot2_ITag_EFIMemoryMap_print(
+    const struct KernAux_Multiboot2_ITag_EFIMemoryMap *tag,
+    KernAux_Display display
+);
+
+void KernAux_Multiboot2_ITag_EFIBootServicesNotTerminated_print(
+    const struct KernAux_Multiboot2_ITag_EFIBootServicesNotTerminated *tag,
+    KernAux_Display display
+);
+
+void KernAux_Multiboot2_ITag_EFI32bitImageHandlePtr_print(
+    const struct KernAux_Multiboot2_ITag_EFI32bitImageHandlePtr *tag,
+    KernAux_Display display
+);
+
+void KernAux_Multiboot2_ITag_EFI64bitImageHandlePtr_print(
+    const struct KernAux_Multiboot2_ITag_EFI64bitImageHandlePtr *tag,
+    KernAux_Display display
+);
+
+void KernAux_Multiboot2_ITag_ImageLoadBasePhysAddr_print(
+    const struct KernAux_Multiboot2_ITag_ImageLoadBasePhysAddr *tag,
+    KernAux_Display display
+);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/multiboot2/enums_to_str.c b/src/multiboot2/enums_to_str.c
index dcb8b14e..67dc4a47 100644
--- a/src/multiboot2/enums_to_str.c
+++ b/src/multiboot2/enums_to_str.c
@@ -13,7 +13,7 @@ const char *KernAux_Multiboot2_Header_Arch_to_str(
     case KERNAUX_MULTIBOOT2_HEADER_ARCH_I386:
         return "i386";
     case KERNAUX_MULTIBOOT2_HEADER_ARCH_MIPS32:
-        return "MIPS32"; // TODO: specify this architecture in README
+        return "MIPS32";
     default:
         return NULL;
     }
diff --git a/src/multiboot2/header_is_valid.c b/src/multiboot2/header_is_valid.c
index f192c164..f01f85f9 100644
--- a/src/multiboot2/header_is_valid.c
+++ b/src/multiboot2/header_is_valid.c
@@ -248,7 +248,6 @@ bool KernAux_Multiboot2_HTag_RelocatableHeader_is_valid(
         tag->base.type == KERNAUX_MULTIBOOT2_HTAG_RELOCATABLE_HEADER &&
         tag->base.size == 24 &&
         tag->min_addr <= tag->max_addr
-        // TODO: additional requirements?
     )) {
         return false;
     }
diff --git a/src/multiboot2/header_print.c b/src/multiboot2/header_print.c
index bfe76c85..b514a2e6 100644
--- a/src/multiboot2/header_print.c
+++ b/src/multiboot2/header_print.c
@@ -10,9 +10,34 @@
 #include <stddef.h>
 #include <stdint.h>
 
-#define PRINTLN(s) KernAux_Display_println(display, s)
+#define PRINTLN(s) do { KernAux_Display_println(display, s); } while (0)
+
+#define PRINTF(format, ...) \
+    do { KernAux_Display_printf(display, format, __VA_ARGS__); } while (0)
 #define PRINTLNF(format, ...) \
-    KernAux_Display_printlnf(display, format, __VA_ARGS__)
+    do { KernAux_Display_printlnf(display, format, __VA_ARGS__); } while (0)
+
+#define HEADER(Type) do { \
+    KERNAUX_ASSERT(tag);                                       \
+    KERNAUX_ASSERT(display);                                   \
+                                                               \
+    if (!KernAux_Multiboot2_HTag_##Type##_is_valid(tag)) {     \
+        PRINTLN("Multiboot 2 header tag // invalid!");         \
+    }                                                          \
+                                                               \
+    KERNAUX_CAST_CONST(unsigned long, flags, tag->base.flags); \
+    KERNAUX_CAST_CONST(unsigned long, size,  tag->base.size);  \
+                                                               \
+    PRINTLN("Multiboot 2 header tag {");                       \
+    PRINTLNF("  u16 type: %u (%s)",                            \
+        tag->base.type,                                        \
+        KernAux_Multiboot2_HTag_to_str(tag->base.type)         \
+    );                                                         \
+    PRINTLNF("  u16 flags: %lu", flags);                       \
+    PRINTLNF("  u32 size: %lu", size);                         \
+} while (0)
+
+#define FOOTER do { PRINTLN("}"); } while (0)
 
 void KernAux_Multiboot2_Header_print(
     const struct KernAux_Multiboot2_Header *const multiboot2_header,
@@ -25,14 +50,15 @@ void KernAux_Multiboot2_Header_print(
     KERNAUX_CAST_CONST(unsigned long, total_size, multiboot2_header->total_size);
     KERNAUX_CAST_CONST(unsigned long, checksum,   multiboot2_header->checksum);
 
-    PRINTLN("Multiboot 2 header");
-    PRINTLNF("  magic: %lu", magic);
-    PRINTLNF("  arch: %u (%s)",
+    PRINTLN("Multiboot 2 header {");
+    PRINTLNF("  u32 magic: %lu", magic);
+    PRINTLNF("  u32 arch: %u (%s)",
         multiboot2_header->arch,
         KernAux_Multiboot2_Header_Arch_to_str(multiboot2_header->arch)
     );
-    PRINTLNF("  size: %lu", total_size);
-    PRINTLNF("  checksum: %lu", checksum);
+    PRINTLNF("  u32 size: %lu", total_size);
+    PRINTLNF("  u32 checksum: %lu", checksum);
+    PRINTLN("}");
 
     const struct KernAux_Multiboot2_HTagBase *tag_base =
         (struct KernAux_Multiboot2_HTagBase*)
@@ -43,9 +69,7 @@ void KernAux_Multiboot2_Header_print(
            ((uint8_t*)multiboot2_header + multiboot2_header->total_size))
     {
         if (!KernAux_Multiboot2_HTagBase_is_valid(tag_base)) return;
-
         KernAux_Multiboot2_HTagBase_print(tag_base, display);
-
         tag_base = KERNAUX_MULTIBOOT2_HTAG_NEXT(tag_base);
     }
 }
@@ -57,71 +81,267 @@ void KernAux_Multiboot2_HTagBase_print(
     KERNAUX_ASSERT(tag_base);
     KERNAUX_ASSERT(display);
 
-    if (!KernAux_Multiboot2_HTagBase_is_valid(tag_base)) return;
-
-    KERNAUX_CAST_CONST(unsigned long, flags, tag_base->flags);
-    KERNAUX_CAST_CONST(unsigned long, size,  tag_base->size);
-
-    PRINTLN("Multiboot 2 header tag");
-    PRINTLNF("  type: %u (%s)",
-        tag_base->type,
-        KernAux_Multiboot2_HTag_to_str(tag_base->type)
-    );
-    PRINTLNF("  flags: %lu", flags);
-    PRINTLNF("  size: %lu", size);
-
     switch (tag_base->type) {
     case KERNAUX_MULTIBOOT2_HTAG_NONE:
+        KernAux_Multiboot2_HTag_None_print(
+            (struct KernAux_Multiboot2_HTag_None*)tag_base,
+            display
+        );
         break;
     case KERNAUX_MULTIBOOT2_HTAG_INFO_REQ:
-        {
-            // TODO: print
-        }
+        KernAux_Multiboot2_HTag_InfoReq_print(
+            (struct KernAux_Multiboot2_HTag_InfoReq*)tag_base,
+            display
+        );
         break;
     case KERNAUX_MULTIBOOT2_HTAG_ADDR:
-        {
-            // TODO: print
-        }
+        KernAux_Multiboot2_HTag_Addr_print(
+            (struct KernAux_Multiboot2_HTag_Addr*)tag_base,
+            display
+        );
         break;
     case KERNAUX_MULTIBOOT2_HTAG_ENTRY_ADDR:
-        {
-            // TODO: print
-        }
+        KernAux_Multiboot2_HTag_EntryAddr_print(
+            (struct KernAux_Multiboot2_HTag_EntryAddr*)tag_base,
+            display
+        );
         break;
     case KERNAUX_MULTIBOOT2_HTAG_FLAGS:
-        {
-            // TODO: print
-        }
+        KernAux_Multiboot2_HTag_Flags_print(
+            (struct KernAux_Multiboot2_HTag_Flags*)tag_base,
+            display
+        );
         break;
     case KERNAUX_MULTIBOOT2_HTAG_FRAMEBUFFER:
-        {
-            // TODO: print
-        }
+        KernAux_Multiboot2_HTag_Framebuffer_print(
+            (struct KernAux_Multiboot2_HTag_Framebuffer*)tag_base,
+            display
+        );
         break;
     case KERNAUX_MULTIBOOT2_HTAG_MODULE_ALIGN:
-        {
-            // TODO: print
-        }
+        KernAux_Multiboot2_HTag_ModuleAlign_print(
+            (struct KernAux_Multiboot2_HTag_ModuleAlign*)tag_base,
+            display
+        );
         break;
     case KERNAUX_MULTIBOOT2_HTAG_EFI_BOOT_SERVICES:
-        {
-            // TODO: print
-        }
+        KernAux_Multiboot2_HTag_EFIBootServices_print(
+            (struct KernAux_Multiboot2_HTag_EFIBootServices*)tag_base,
+            display
+        );
         break;
     case KERNAUX_MULTIBOOT2_HTAG_EFI_I386_ENTRY_ADDR:
-        {
-            // TODO: print
-        }
+        KernAux_Multiboot2_HTag_EFII386EntryAddr_print(
+            (struct KernAux_Multiboot2_HTag_EFII386EntryAddr*)tag_base,
+            display
+        );
         break;
     case KERNAUX_MULTIBOOT2_HTAG_EFI_AMD64_ENTRY_ADDR:
-        {
-            // TODO: print
-        }
+        KernAux_Multiboot2_HTag_EFIAmd64EntryAddr_print(
+            (struct KernAux_Multiboot2_HTag_EFIAmd64EntryAddr*)tag_base,
+            display
+        );
         break;
     case KERNAUX_MULTIBOOT2_HTAG_RELOCATABLE_HEADER:
+        KernAux_Multiboot2_HTag_RelocatableHeader_print(
+            (struct KernAux_Multiboot2_HTag_RelocatableHeader*)tag_base,
+            display
+        );
+        break;
+    }
+}
+
+void KernAux_Multiboot2_HTag_None_print(
+    const struct KernAux_Multiboot2_HTag_None *const tag,
+    const KernAux_Display display
+) {
+    HEADER(None);
+    FOOTER;
+}
+
+void KernAux_Multiboot2_HTag_InfoReq_print(
+    const struct KernAux_Multiboot2_HTag_InfoReq *const tag,
+    const KernAux_Display display
+) {
+    HEADER(InfoReq);
+
+    // Print data:
+
+    PRINTLN("  u32 mbi_tag_types[]: [");
+
+    const uint32_t *const mbi_tag_types =
+        (const uint32_t*)KERNAUX_MULTIBOOT2_DATA(tag);
+
+    for (
+        size_t index = 0;
+        index < (tag->base.size - sizeof(*tag)) / sizeof(uint32_t);
+        ++index
+    ) {
+        KERNAUX_CAST_CONST(unsigned long, type, mbi_tag_types[index]);
+
+        PRINTLNF("    %lu (%s)",
+            type,
+            KernAux_Multiboot2_ITag_to_str(type)
+        );
+    }
+
+    PRINTLN("  ]");
+
+    FOOTER;
+}
+
+void KernAux_Multiboot2_HTag_Addr_print(
+    const struct KernAux_Multiboot2_HTag_Addr *const tag,
+    const KernAux_Display display
+) {
+    HEADER(Addr);
+
+    KERNAUX_CAST_CONST(unsigned long, header_addr,   tag->header_addr);
+    KERNAUX_CAST_CONST(unsigned long, load_addr,     tag->load_addr);
+    KERNAUX_CAST_CONST(unsigned long, load_end_addr, tag->load_end_addr);
+    KERNAUX_CAST_CONST(unsigned long, bss_end_addr,  tag->bss_end_addr);
+
+    PRINTLNF("  u32 header_addr: %lu",   header_addr);
+    PRINTLNF("  u32 load_addr: %lu",     load_addr);
+    PRINTLNF("  u32 load_end_addr: %lu", load_end_addr);
+    PRINTLNF("  u32 bss_end_addr: %lu",  bss_end_addr);
+
+    FOOTER;
+}
+
+void KernAux_Multiboot2_HTag_EntryAddr_print(
+    const struct KernAux_Multiboot2_HTag_EntryAddr *const tag,
+    const KernAux_Display display
+) {
+    HEADER(EntryAddr);
+
+    KERNAUX_CAST_CONST(unsigned long, entry_addr, tag->entry_addr);
+
+    PRINTLNF("  u32 entry_addr: %lu", entry_addr);
+
+    FOOTER;
+}
+
+void KernAux_Multiboot2_HTag_Flags_print(
+    const struct KernAux_Multiboot2_HTag_Flags *const tag,
+    const KernAux_Display display
+) {
+    HEADER(Flags);
+
+    KERNAUX_CAST_CONST(unsigned long, console_flags, tag->console_flags);
+
+    PRINTF("  u32 console_flags: %lu (", console_flags);
+
+    static const struct {
+        uint32_t number;
+        const char *name;
+    } flags[] = {
         {
-            // TODO: print
+            .number = KERNAUX_MULTIBOOT2_HTAG_FLAGS_REQUIRE_CONSOLE,
+            .name = "REQUIRE_CONSOLE",
+        },
+        {
+            .number = KERNAUX_MULTIBOOT2_HTAG_FLAGS_EGA_SUPPORT,
+            .name = "EGA_SUPPORT",
         }
-        break;
+    };
+
+    bool is_first = true;
+    for (size_t index = 0; index < sizeof(flags) / sizeof(flags[0]); ++index) {
+        if (tag->console_flags & flags[index].number) {
+            if (is_first) {
+                PRINTLN("");
+            } else {
+                PRINTLN(" |");
+            }
+            PRINTF("    %s", flags[index].name);
+            is_first = false;
+        }
+    }
+    if (is_first) {
+        PRINTLN(")");
+    } else {
+        PRINTLN("");
+        PRINTLN("  )");
     }
+
+    FOOTER;
+}
+
+void KernAux_Multiboot2_HTag_Framebuffer_print(
+    const struct KernAux_Multiboot2_HTag_Framebuffer *const tag,
+    const KernAux_Display display
+) {
+    HEADER(Framebuffer);
+
+    KERNAUX_CAST_CONST(unsigned long, width,  tag->width);
+    KERNAUX_CAST_CONST(unsigned long, height, tag->height);
+    KERNAUX_CAST_CONST(unsigned long, depth,  tag->depth);
+
+    PRINTLNF("  u32 width: %lu",  width);
+    PRINTLNF("  u32 height: %lu", height);
+    PRINTLNF("  u32 depth: %lu",  depth);
+
+    FOOTER;
+}
+
+void KernAux_Multiboot2_HTag_ModuleAlign_print(
+    const struct KernAux_Multiboot2_HTag_ModuleAlign *const tag,
+    const KernAux_Display display
+) {
+    HEADER(ModuleAlign);
+
+    FOOTER;
+}
+
+void KernAux_Multiboot2_HTag_EFIBootServices_print(
+    const struct KernAux_Multiboot2_HTag_EFIBootServices *const tag,
+    const KernAux_Display display
+) {
+    HEADER(EFIBootServices);
+
+    FOOTER;
+}
+
+void KernAux_Multiboot2_HTag_EFII386EntryAddr_print(
+    const struct KernAux_Multiboot2_HTag_EFII386EntryAddr *const tag,
+    const KernAux_Display display
+) {
+    HEADER(EFII386EntryAddr);
+
+    KERNAUX_CAST_CONST(unsigned long, entry_addr, tag->entry_addr);
+
+    PRINTLNF("  u32 entry_addr: %lu", entry_addr);
+
+    FOOTER;
+}
+
+void KernAux_Multiboot2_HTag_EFIAmd64EntryAddr_print(
+    const struct KernAux_Multiboot2_HTag_EFIAmd64EntryAddr *const tag,
+    const KernAux_Display display
+) {
+    HEADER(EFIAmd64EntryAddr);
+
+    KERNAUX_CAST_CONST(unsigned long, entry_addr, tag->entry_addr);
+
+    PRINTLNF("  u32 entry_addr: %lu", entry_addr);
+
+    FOOTER;
+}
+
+void KernAux_Multiboot2_HTag_RelocatableHeader_print(
+    const struct KernAux_Multiboot2_HTag_RelocatableHeader *const tag,
+    const KernAux_Display display
+) {
+    HEADER(RelocatableHeader);
+
+    KERNAUX_CAST_CONST(unsigned long, min_addr, tag->min_addr);
+    KERNAUX_CAST_CONST(unsigned long, max_addr, tag->max_addr);
+    KERNAUX_CAST_CONST(unsigned long, align,    tag->align);
+
+    PRINTLNF("  u32 min_addr: %lu", min_addr);
+    PRINTLNF("  u32 max_addr: %lu", max_addr);
+    PRINTLNF("  u32 align: %lu",    align);
+
+    FOOTER;
 }
diff --git a/src/multiboot2/info_convert.c b/src/multiboot2/info_convert.c
deleted file mode 100644
index b195494d..00000000
--- a/src/multiboot2/info_convert.c
+++ /dev/null
@@ -1,63 +0,0 @@
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <kernaux/assert.h>
-#include <kernaux/multiboot2.h>
-
-#ifdef WITH_MEMMAP
-#include <kernaux/memmap.h>
-#endif
-
-#include <stdbool.h>
-
-#ifdef WITH_MEMMAP
-// TODO: implement this
-bool KernAux_Multiboot2_Info_to_memmap(
-    const struct KernAux_Multiboot2_Info *multiboot2_info,
-    KernAux_MemMap memmap
-) {
-    KERNAUX_ASSERT(multiboot2_info);
-
-    KernAux_MemMap_init(memmap, 0);
-    if (!KernAux_Multiboot2_Info_is_valid(multiboot2_info)) return false;
-
-    const struct KernAux_Multiboot2_ITagBase *const basic_memory_info_tag_base =
-        KernAux_Multiboot2_Info_first_tag_with_type(
-            multiboot2_info,
-            KERNAUX_MULTIBOOT2_ITAG_BASIC_MEMORY_INFO
-        );
-    const struct KernAux_Multiboot2_ITagBase *const memory_map_tag_base =
-        KernAux_Multiboot2_Info_first_tag_with_type(
-            multiboot2_info,
-            KERNAUX_MULTIBOOT2_ITAG_MEMORY_MAP
-        );
-
-    // FIXME: Basic memory info tag may not be provided by some boot loaders on
-    // EFI platforms if EFI boot services are enabled and available for the
-    // loaded image (EFI boot services not terminated tag exists in Multiboot2
-    // information structure).
-    if (basic_memory_info_tag_base == NULL || memory_map_tag_base == NULL) {
-        return false;
-    }
-
-    const struct KernAux_Multiboot2_ITag_BasicMemoryInfo *const
-        basic_memory_info_tag =
-        (const struct KernAux_Multiboot2_ITag_BasicMemoryInfo*)
-        basic_memory_info_tag_base;
-    const struct KernAux_Multiboot2_ITag_MemoryMap *const
-        memory_map_tag =
-        (const struct KernAux_Multiboot2_ITag_MemoryMap*)
-        memory_map_tag_base;
-
-    // FIXME: The value returned for upper memory is maximally the address of
-    // the first upper memory hole minus 1 megabyte. It is not guaranteed to be
-    // this value.
-    const size_t memory_size = (size_t)basic_memory_info_tag->mem_upper * 1024;
-    KernAux_MemMap_init(memmap, memory_size);
-
-    (void)memory_map_tag;
-
-    return false;
-}
-#endif
diff --git a/src/multiboot2/info_is_valid.c b/src/multiboot2/info_is_valid.c
index a748140b..aed43223 100644
--- a/src/multiboot2/info_is_valid.c
+++ b/src/multiboot2/info_is_valid.c
@@ -287,7 +287,7 @@ bool KernAux_Multiboot2_ITag_FramebufferInfo_is_valid(
     KERNAUX_ASSERT(tag);
     return (
         tag->base.type == KERNAUX_MULTIBOOT2_ITAG_FRAMEBUFFER_INFO &&
-        tag->base.size >= 31
+        tag->base.size >= 32
     );
 }
 
@@ -297,10 +297,10 @@ bool KernAux_Multiboot2_ITag_ELFSymbols_is_valid(
     KERNAUX_ASSERT(tag);
     return (
         tag->base.type == KERNAUX_MULTIBOOT2_ITAG_ELF_SYMBOLS &&
-        tag->base.size >= 16 &&
+        tag->base.size >= 20 &&
         (
-            tag->ent_size == 0 ||
-            (tag->base.size - 16) % tag->ent_size == 0
+            tag->entsize == 0 ||
+            (tag->base.size - 20) % tag->entsize == 0
         )
     );
 }
diff --git a/src/multiboot2/info_print.c b/src/multiboot2/info_print.c
index 7e9c4734..0d000d48 100644
--- a/src/multiboot2/info_print.c
+++ b/src/multiboot2/info_print.c
@@ -3,18 +3,40 @@
 #endif
 
 #include <kernaux/assert.h>
+#include <kernaux/generic/display.h>
 #include <kernaux/macro.h>
 #include <kernaux/multiboot2.h>
 
 #include <stddef.h>
 #include <stdint.h>
 
-// TODO: create macro for this
-#define INT_IF(a, b) (sizeof(int) == sizeof(long) ? (a) : (b))
+#define PRINT(s)   do { KernAux_Display_print  (display, s); } while (0)
+#define PRINTLN(s) do { KernAux_Display_println(display, s); } while (0)
 
-#define PRINTLN(s) KernAux_Display_println(display, s)
+#define PRINTF(format, ...) \
+    do { KernAux_Display_printf  (display, format, __VA_ARGS__); } while (0)
 #define PRINTLNF(format, ...) \
-    KernAux_Display_printlnf(display, format, __VA_ARGS__)
+    do { KernAux_Display_printlnf(display, format, __VA_ARGS__); } while (0)
+
+#define HEADER(Type) do { \
+    KERNAUX_ASSERT(tag);                                     \
+    KERNAUX_ASSERT(display);                                 \
+                                                             \
+    if (!KernAux_Multiboot2_ITag_##Type##_is_valid(tag)) {   \
+        PRINTLN("Multiboot 2 info tag // invalid!");         \
+    }                                                        \
+                                                             \
+    KERNAUX_CAST_CONST(unsigned long, size, tag->base.size); \
+                                                             \
+    PRINTLN("Multiboot 2 info tag {");                       \
+    PRINTLNF("  u32 type: %u (%s)",                          \
+        tag->base.type,                                      \
+        KernAux_Multiboot2_ITag_to_str(tag->base.type)       \
+    );                                                       \
+    PRINTLNF("  u32 size: %lu", size);                       \
+} while (0)
+
+#define FOOTER do { PRINTLN("}"); } while (0)
 
 void KernAux_Multiboot2_Info_print(
     const struct KernAux_Multiboot2_Info *const multiboot2_info,
@@ -24,11 +46,12 @@ void KernAux_Multiboot2_Info_print(
     KERNAUX_ASSERT(display);
 
     KERNAUX_CAST_CONST(unsigned long, total_size, multiboot2_info->total_size);
-    KERNAUX_CAST_CONST(unsigned long, reserved1,  multiboot2_info->reserved1);
+    KERNAUX_CAST_CONST(unsigned long, reserved,   multiboot2_info->reserved);
 
-    PRINTLN("Multiboot 2 info");
-    PRINTLNF("  size: %lu", total_size);
-    PRINTLNF("  reserved1: %lu", reserved1);
+    PRINTLN("Multiboot 2 info {");
+    PRINTLNF("  u32 size: %lu",     total_size);
+    PRINTLNF("  u32 reserved: %lu", reserved);
+    PRINTLN("}");
 
     const struct KernAux_Multiboot2_ITagBase *tag_base =
         (struct KernAux_Multiboot2_ITagBase*)
@@ -39,9 +62,7 @@ void KernAux_Multiboot2_Info_print(
            ((uint8_t*)multiboot2_info + multiboot2_info->total_size))
     {
         if (!KernAux_Multiboot2_ITagBase_is_valid(tag_base)) return;
-
         KernAux_Multiboot2_ITagBase_print(tag_base, display);
-
         tag_base = KERNAUX_MULTIBOOT2_ITAG_NEXT(tag_base);
     }
 }
@@ -53,20 +74,12 @@ void KernAux_Multiboot2_ITagBase_print(
     KERNAUX_ASSERT(tag_base);
     KERNAUX_ASSERT(display);
 
-    if (!KernAux_Multiboot2_ITagBase_is_valid(tag_base)) return;
-
-    PRINTLN("Multiboot 2 info tag");
-
-    PRINTLNF("  type: %u (%s)",
-        tag_base->type,
-        KernAux_Multiboot2_ITag_to_str(tag_base->type)
-    );
-
-    KERNAUX_CAST_CONST(unsigned long, size, tag_base->size);
-    PRINTLNF("  size: %lu", size);
-
     switch (tag_base->type) {
     case KERNAUX_MULTIBOOT2_ITAG_NONE:
+        KernAux_Multiboot2_ITag_None_print(
+            (struct KernAux_Multiboot2_ITag_None*)tag_base,
+            display
+        );
         break;
     case KERNAUX_MULTIBOOT2_ITAG_BOOT_CMD_LINE:
         KernAux_Multiboot2_ITag_BootCmdLine_print(
@@ -81,43 +94,22 @@ void KernAux_Multiboot2_ITagBase_print(
         );
         break;
     case KERNAUX_MULTIBOOT2_ITAG_MODULE:
-        {
-            const struct KernAux_Multiboot2_ITag_Module *const tag_module =
-                (struct KernAux_Multiboot2_ITag_Module*)tag_base;
-
-            KERNAUX_CAST_CONST(unsigned long, mod_start, tag_module->mod_start);
-            KERNAUX_CAST_CONST(unsigned long, mod_end,   tag_module->mod_end);
-
-            PRINTLNF("  start: %lu", mod_start);
-            PRINTLNF("  end: %lu", mod_end);
-            PRINTLNF("  cmdline: %s", KERNAUX_MULTIBOOT2_DATA(tag_module));
-        }
+        KernAux_Multiboot2_ITag_Module_print(
+            (struct KernAux_Multiboot2_ITag_Module*)tag_base,
+            display
+        );
         break;
     case KERNAUX_MULTIBOOT2_ITAG_BASIC_MEMORY_INFO:
-        {
-            const struct KernAux_Multiboot2_ITag_BasicMemoryInfo *const tag_bmi =
-                (struct KernAux_Multiboot2_ITag_BasicMemoryInfo*)tag_base;
-
-            KERNAUX_CAST_CONST(unsigned long, mem_lower, tag_bmi->mem_lower);
-            KERNAUX_CAST_CONST(unsigned long, mem_upper, tag_bmi->mem_upper);
-
-            PRINTLNF("  mem lower: %lu", mem_lower);
-            PRINTLNF("  mem upper: %lu", mem_upper);
-        }
+        KernAux_Multiboot2_ITag_BasicMemoryInfo_print(
+            (struct KernAux_Multiboot2_ITag_BasicMemoryInfo*)tag_base,
+            display
+        );
         break;
     case KERNAUX_MULTIBOOT2_ITAG_BIOS_BOOT_DEVICE:
-        {
-            const struct KernAux_Multiboot2_ITag_BIOSBootDevice *const tag_bbd =
-                (struct KernAux_Multiboot2_ITag_BIOSBootDevice*)tag_base;
-
-            KERNAUX_CAST_CONST(unsigned long, bios_dev,      tag_bbd->bios_dev);
-            KERNAUX_CAST_CONST(unsigned long, partition,     tag_bbd->partition);
-            KERNAUX_CAST_CONST(unsigned long, sub_partition, tag_bbd->sub_partition);
-
-            PRINTLNF("  bios dev: %lu", bios_dev);
-            PRINTLNF("  partition: %lu", partition);
-            PRINTLNF("  sub_partition: %lu", sub_partition);
-        }
+        KernAux_Multiboot2_ITag_BIOSBootDevice_print(
+            (struct KernAux_Multiboot2_ITag_BIOSBootDevice*)tag_base,
+            display
+        );
         break;
     case KERNAUX_MULTIBOOT2_ITAG_MEMORY_MAP:
         KernAux_Multiboot2_ITag_MemoryMap_print(
@@ -126,42 +118,16 @@ void KernAux_Multiboot2_ITagBase_print(
         );
         break;
     case KERNAUX_MULTIBOOT2_ITAG_VBE_INFO:
-        {
-            const struct KernAux_Multiboot2_ITag_VBEInfo *const tag_vbe =
-                (struct KernAux_Multiboot2_ITag_VBEInfo*)tag_base;
-
-            KERNAUX_CAST_CONST(unsigned long, vbe_mode,          tag_vbe->vbe_mode);
-            KERNAUX_CAST_CONST(unsigned long, vbe_interface_seg, tag_vbe->vbe_interface_seg);
-            KERNAUX_CAST_CONST(unsigned long, vbe_interface_off, tag_vbe->vbe_interface_off);
-            KERNAUX_CAST_CONST(unsigned long, vbe_interface_len, tag_vbe->vbe_interface_len);
-
-            PRINTLNF("  VBE mode: %lu",          vbe_mode);
-            PRINTLNF("  VBE interface seg: %lu", vbe_interface_seg);
-            PRINTLNF("  VBE interface off: %lu", vbe_interface_off);
-            PRINTLNF("  VBE interface len: %lu", vbe_interface_len);
-        }
+        KernAux_Multiboot2_ITag_VBEInfo_print(
+            (struct KernAux_Multiboot2_ITag_VBEInfo*)tag_base,
+            display
+        );
         break;
     case KERNAUX_MULTIBOOT2_ITAG_FRAMEBUFFER_INFO:
-        {
-            const struct KernAux_Multiboot2_ITag_FramebufferInfo *const tag_fb =
-                (struct KernAux_Multiboot2_ITag_FramebufferInfo*)tag_base;
-
-            KERNAUX_CAST_CONST(unsigned long long, framebuffer_addr,   tag_fb->framebuffer_addr);
-            KERNAUX_CAST_CONST(unsigned long,      framebuffer_pitch,  tag_fb->framebuffer_pitch);
-            KERNAUX_CAST_CONST(unsigned long,      framebuffer_width,  tag_fb->framebuffer_width);
-            KERNAUX_CAST_CONST(unsigned long,      framebuffer_height, tag_fb->framebuffer_height);
-            KERNAUX_CAST_CONST(unsigned long,      framebuffer_bpp,    tag_fb->framebuffer_bpp);
-            KERNAUX_CAST_CONST(unsigned long,      framebuffer_type,   tag_fb->framebuffer_type);
-            KERNAUX_CAST_CONST(unsigned long,      reserved1,          tag_fb->reserved1);
-
-            PRINTLNF("  framebuffer addr: %llu",  framebuffer_addr);
-            PRINTLNF("  framebuffer pitch: %lu",  framebuffer_pitch);
-            PRINTLNF("  framebuffer width: %lu",  framebuffer_width);
-            PRINTLNF("  framebuffer height: %lu", framebuffer_height);
-            PRINTLNF("  framebuffer bpp: %lu",    framebuffer_bpp);
-            PRINTLNF("  framebuffer type: %lu",   framebuffer_type);
-            PRINTLNF("  reserved1: %lu",          reserved1);
-        }
+        KernAux_Multiboot2_ITag_FramebufferInfo_print(
+            (struct KernAux_Multiboot2_ITag_FramebufferInfo*)tag_base,
+            display
+        );
         break;
     case KERNAUX_MULTIBOOT2_ITAG_ELF_SYMBOLS:
         KernAux_Multiboot2_ITag_ELFSymbols_print(
@@ -170,159 +136,178 @@ void KernAux_Multiboot2_ITagBase_print(
         );
         break;
     case KERNAUX_MULTIBOOT2_ITAG_APM_TABLE:
-        {
-            const struct KernAux_Multiboot2_ITag_APMTable *const tag_apm =
-                (struct KernAux_Multiboot2_ITag_APMTable*)tag_base;
-
-            KERNAUX_CAST_CONST(unsigned long, version,     tag_apm->version);
-            KERNAUX_CAST_CONST(unsigned long, cseg,        tag_apm->cseg);
-            KERNAUX_CAST_CONST(unsigned long, offset,      tag_apm->offset);
-            KERNAUX_CAST_CONST(unsigned long, cseg_16,     tag_apm->cseg_16);
-            KERNAUX_CAST_CONST(unsigned long, dseg,        tag_apm->dseg);
-            KERNAUX_CAST_CONST(unsigned long, flags,       tag_apm->flags);
-            KERNAUX_CAST_CONST(unsigned long, cseg_len,    tag_apm->cseg_len);
-            KERNAUX_CAST_CONST(unsigned long, cseg_16_len, tag_apm->cseg_16_len);
-            KERNAUX_CAST_CONST(unsigned long, dseg_len,    tag_apm->dseg_len);
-
-            PRINTLNF("  version: %lu",     version);
-            PRINTLNF("  cseg: %lu",        cseg);
-            PRINTLNF("  offset: %lu",      offset);
-            PRINTLNF("  cseg 16: %lu",     cseg_16);
-            PRINTLNF("  dseg: %lu",        dseg);
-            PRINTLNF("  flags: %lu",       flags);
-            PRINTLNF("  cseg len: %lu",    cseg_len);
-            PRINTLNF("  cseg 16 len: %lu", cseg_16_len);
-            PRINTLNF("  dseg len: %lu",    dseg_len);
-        }
+        KernAux_Multiboot2_ITag_APMTable_print(
+            (struct KernAux_Multiboot2_ITag_APMTable*)tag_base,
+            display
+        );
         break;
     case KERNAUX_MULTIBOOT2_ITAG_EFI_32BIT_SYSTEM_TABLE_PTR:
-        {
-            // TODO: print
-        }
+        KernAux_Multiboot2_ITag_EFI32bitSystemTablePtr_print(
+            (struct KernAux_Multiboot2_ITag_EFI32bitSystemTablePtr*)tag_base,
+            display
+        );
         break;
     case KERNAUX_MULTIBOOT2_ITAG_EFI_64BIT_SYSTEM_TABLE_PTR:
-        {
-            // TODO: print
-        }
+        KernAux_Multiboot2_ITag_EFI64bitSystemTablePtr_print(
+            (struct KernAux_Multiboot2_ITag_EFI64bitSystemTablePtr*)tag_base,
+            display
+        );
         break;
     case KERNAUX_MULTIBOOT2_ITAG_SMBIOS_TABLES:
-        {
-            const struct KernAux_Multiboot2_ITag_SMBIOSTables *const tag_smbios =
-                (struct KernAux_Multiboot2_ITag_SMBIOSTables*)tag_base;
-
-            KERNAUX_CAST_CONST(unsigned long, major,     tag_smbios->major);
-            KERNAUX_CAST_CONST(unsigned long, minor,     tag_smbios->minor);
-            KERNAUX_CAST_CONST(unsigned long, reserved0, tag_smbios->reserved1[0]);
-            KERNAUX_CAST_CONST(unsigned long, reserved1, tag_smbios->reserved1[1]);
-            KERNAUX_CAST_CONST(unsigned long, reserved2, tag_smbios->reserved1[2]);
-            KERNAUX_CAST_CONST(unsigned long, reserved3, tag_smbios->reserved1[3]);
-            KERNAUX_CAST_CONST(unsigned long, reserved4, tag_smbios->reserved1[4]);
-            KERNAUX_CAST_CONST(unsigned long, reserved5, tag_smbios->reserved1[5]);
-
-            PRINTLNF("  major: %lu", major);
-            PRINTLNF("  minor: %lu", minor);
-
-            PRINTLNF(
-                "  reserved1: {%lu, %lu, %lu, %lu, %lu, %lu}",
-                reserved0, reserved1, reserved2,
-                reserved3, reserved4, reserved5
-            );
-        }
+        KernAux_Multiboot2_ITag_SMBIOSTables_print(
+            (struct KernAux_Multiboot2_ITag_SMBIOSTables*)tag_base,
+            display
+        );
         break;
     case KERNAUX_MULTIBOOT2_ITAG_ACPI_OLD_RSDP:
-        {
-            // TODO: print
-        }
+        KernAux_Multiboot2_ITag_ACPIOldRSDP_print(
+            (struct KernAux_Multiboot2_ITag_ACPIOldRSDP*)tag_base,
+            display
+        );
         break;
     case KERNAUX_MULTIBOOT2_ITAG_ACPI_NEW_RSDP:
-        {
-            // TODO: print
-        }
+        KernAux_Multiboot2_ITag_ACPINewRSDP_print(
+            (struct KernAux_Multiboot2_ITag_ACPINewRSDP*)tag_base,
+            display
+        );
         break;
     case KERNAUX_MULTIBOOT2_ITAG_NETWORKING_INFO:
-        {
-            // TODO: print
-        }
+        KernAux_Multiboot2_ITag_NetworkingInfo_print(
+            (struct KernAux_Multiboot2_ITag_NetworkingInfo*)tag_base,
+            display
+        );
         break;
     case KERNAUX_MULTIBOOT2_ITAG_EFI_MEMORY_MAP:
-        {
-            // TODO: print
-        }
+        KernAux_Multiboot2_ITag_EFIMemoryMap_print(
+            (struct KernAux_Multiboot2_ITag_EFIMemoryMap*)tag_base,
+            display
+        );
         break;
     case KERNAUX_MULTIBOOT2_ITAG_EFI_BOOT_SERVICES_NOT_TERMINATED:
+        KernAux_Multiboot2_ITag_EFIBootServicesNotTerminated_print(
+            (struct KernAux_Multiboot2_ITag_EFIBootServicesNotTerminated*)
+            tag_base,
+            display
+        );
         break;
     case KERNAUX_MULTIBOOT2_ITAG_EFI_32BIT_IMAGE_HANDLE_PTR:
-        {
-            // TODO: print
-        }
+        KernAux_Multiboot2_ITag_EFI32bitImageHandlePtr_print(
+            (struct KernAux_Multiboot2_ITag_EFI32bitImageHandlePtr*)tag_base,
+            display
+        );
         break;
     case KERNAUX_MULTIBOOT2_ITAG_EFI_64BIT_IMAGE_HANDLE_PTR:
-        {
-            // TODO: print
-        }
+        KernAux_Multiboot2_ITag_EFI64bitImageHandlePtr_print(
+            (struct KernAux_Multiboot2_ITag_EFI64bitImageHandlePtr*)tag_base,
+            display
+        );
         break;
     case KERNAUX_MULTIBOOT2_ITAG_IMAGE_LOAD_BASE_PHYS_ADDR:
-        {
-            KERNAUX_CAST_CONST(
-                unsigned long,
-                load_base_addr,
-                ((struct KernAux_Multiboot2_ITag_ImageLoadBasePhysAddr*)
-                    tag_base)->load_base_addr
-            );
-            PRINTLNF("  load base addr: %lu", load_base_addr);
-        }
+        KernAux_Multiboot2_ITag_ImageLoadBasePhysAddr_print(
+            (struct KernAux_Multiboot2_ITag_ImageLoadBasePhysAddr*)tag_base,
+            display
+        );
         break;
     }
 }
 
+void KernAux_Multiboot2_ITag_None_print(
+    const struct KernAux_Multiboot2_ITag_None *const tag,
+    const KernAux_Display display
+) {
+    HEADER(None);
+    FOOTER;
+}
+
 void KernAux_Multiboot2_ITag_BootCmdLine_print(
     const struct KernAux_Multiboot2_ITag_BootCmdLine *const tag,
     const KernAux_Display display
 ) {
-    KERNAUX_ASSERT(tag);
-    KERNAUX_ASSERT(display);
+    HEADER(BootCmdLine);
 
-    if (!KernAux_Multiboot2_ITag_BootCmdLine_is_valid(tag)) {
-        PRINTLN("  invalid!");
-        return;
-    }
+    // Print data:
+    PRINTLNF("  char cmdline[]: \"%s\"", KERNAUX_MULTIBOOT2_DATA(tag));
 
-    PRINTLNF("  cmdline: %s", KERNAUX_MULTIBOOT2_DATA(tag));
+    FOOTER;
 }
 
 void KernAux_Multiboot2_ITag_BootLoaderName_print(
     const struct KernAux_Multiboot2_ITag_BootLoaderName *const tag,
     const KernAux_Display display
 ) {
-    KERNAUX_ASSERT(tag);
-    KERNAUX_ASSERT(display);
+    HEADER(BootLoaderName);
 
-    if (!KernAux_Multiboot2_ITag_BootLoaderName_is_valid(tag)) {
-        PRINTLN("  invalid!");
-        return;
-    }
+    // Print data:
+    PRINTLNF("  char name[]: \"%s\"", KERNAUX_MULTIBOOT2_DATA(tag));
 
-    PRINTLNF("  name: %s", KERNAUX_MULTIBOOT2_DATA(tag));
+    FOOTER;
+}
+
+void KernAux_Multiboot2_ITag_Module_print(
+    const struct KernAux_Multiboot2_ITag_Module *const tag,
+    const KernAux_Display display
+) {
+    HEADER(Module);
+
+    KERNAUX_CAST_CONST(unsigned long, mod_start, tag->mod_start);
+    KERNAUX_CAST_CONST(unsigned long, mod_end,   tag->mod_end);
+
+    PRINTLNF("  u32 mod_start: %lu", mod_start);
+    PRINTLNF("  u32 mod_end: %lu", mod_end);
+
+    // Print data:
+    PRINTLNF("  char cmdline[]: \"%s\"", KERNAUX_MULTIBOOT2_DATA(tag));
+
+    FOOTER;
+}
+
+void KernAux_Multiboot2_ITag_BasicMemoryInfo_print(
+    const struct KernAux_Multiboot2_ITag_BasicMemoryInfo *const tag,
+    const KernAux_Display display
+) {
+    HEADER(BasicMemoryInfo);
+
+    KERNAUX_CAST_CONST(unsigned long, mem_lower, tag->mem_lower);
+    KERNAUX_CAST_CONST(unsigned long, mem_upper, tag->mem_upper);
+
+    PRINTLNF("  u32 mem_lower: %lu", mem_lower);
+    PRINTLNF("  u32 mem_upper: %lu", mem_upper);
+
+    FOOTER;
+}
+
+void KernAux_Multiboot2_ITag_BIOSBootDevice_print(
+    const struct KernAux_Multiboot2_ITag_BIOSBootDevice *const tag,
+    const KernAux_Display display
+) {
+    HEADER(BIOSBootDevice);
+
+    KERNAUX_CAST_CONST(unsigned long, biosdev,       tag->biosdev);
+    KERNAUX_CAST_CONST(unsigned long, partition,     tag->partition);
+    KERNAUX_CAST_CONST(unsigned long, sub_partition, tag->sub_partition);
+
+    PRINTLNF("  u32 biosdev: %lu",       biosdev);
+    PRINTLNF("  u32 partition: %lu",     partition);
+    PRINTLNF("  u32 sub_partition: %lu", sub_partition);
+
+    FOOTER;
 }
 
 void KernAux_Multiboot2_ITag_MemoryMap_print(
     const struct KernAux_Multiboot2_ITag_MemoryMap *const tag,
     const KernAux_Display display
 ) {
-    KERNAUX_ASSERT(tag);
-    KERNAUX_ASSERT(display);
-
-    if (!KernAux_Multiboot2_ITag_MemoryMap_is_valid(tag)) {
-        PRINTLN("  invalid!");
-        return;
-    }
+    HEADER(MemoryMap);
 
     KERNAUX_CAST_CONST(unsigned long, entry_size,    tag->entry_size);
     KERNAUX_CAST_CONST(unsigned long, entry_version, tag->entry_version);
 
-    PRINTLNF("  entry size: %lu",    entry_size);
-    PRINTLNF("  entry version: %lu", entry_version);
-    PRINTLN("  entries:");
+    PRINTLNF("  u32 entry_size: %lu",    entry_size);
+    PRINTLNF("  u32 entry_version: %lu", entry_version);
+
+    // Print data:
+
+    PRINTLN ("  varies(entry_size) entries[]: [");
 
     const struct KernAux_Multiboot2_ITag_MemoryMap_EntryBase *const entries =
         (struct KernAux_Multiboot2_ITag_MemoryMap_EntryBase*)
@@ -336,37 +321,291 @@ void KernAux_Multiboot2_ITag_MemoryMap_print(
         KERNAUX_CAST_CONST(unsigned long long, base_addr, entries[index].base_addr);
         KERNAUX_CAST_CONST(unsigned long long, length,    entries[index].length);
         KERNAUX_CAST_CONST(unsigned long,      type,      entries[index].type);
-        KERNAUX_CAST_CONST(unsigned long,      reserved1, entries[index].reserved1);
+        KERNAUX_CAST_CONST(unsigned long,      reserved,  entries[index].reserved);
+
+        PRINTLNF("    [%zu] entry: {", index);
+        PRINTLNF("      u64 base_addr: %llu", base_addr);
+        PRINTLNF("      u64 length: %llu",    length);
+        PRINTLNF("      u32 type: %lu",       type);
+        PRINTLNF("      u32 reserved: %lu",   reserved);
+        PRINTLN ("    }");
+    }
 
-        PRINTLNF("    entry %zu", index);
-        PRINTLNF("      base addr: %llu", base_addr);
-        PRINTLNF("      length: %llu",    length);
-        PRINTLNF("      type: %lu",       type);
-        PRINTLNF("      reserved1: %lu",  reserved1);
+    PRINTLN("  ]");
+    FOOTER;
+}
+
+void KernAux_Multiboot2_ITag_VBEInfo_print(
+    const struct KernAux_Multiboot2_ITag_VBEInfo *const tag,
+    const KernAux_Display display
+) {
+    HEADER(VBEInfo);
+
+    KERNAUX_CAST_CONST(unsigned long, mode,          tag->vbe_mode);
+    KERNAUX_CAST_CONST(unsigned long, interface_seg, tag->vbe_interface_seg);
+    KERNAUX_CAST_CONST(unsigned long, interface_off, tag->vbe_interface_off);
+    KERNAUX_CAST_CONST(unsigned long, interface_len, tag->vbe_interface_len);
+
+    PRINTLNF("  u16 vbe_mode: %lu",          mode);
+    PRINTLNF("  u16 vbe_interface_seg: %lu", interface_seg);
+    PRINTLNF("  u16 vbe_interface_off: %lu", interface_off);
+    PRINTLNF("  u16 vbe_interface_len: %lu", interface_len);
+
+    const size_t cols = 16;
+
+    PRINTLN ("  u8 vbe_control_info[]: [");
+    for (
+        size_t index = 0;
+        index < sizeof(tag->vbe_control_info) / sizeof(tag->vbe_control_info[0]);
+        index += cols
+    ) {
+        PRINTF("    %-3u", tag->vbe_control_info[index]);
+        for (size_t col = 1; col < cols; ++col) {
+            PRINTF(" %-3u", tag->vbe_control_info[index + col]);
+        }
+        PRINTLN("");
+    }
+    PRINTLN ("  ]");
+
+    PRINTLN ("  u8 vbe_mode_info[]: [");
+    for (
+        size_t index = 0;
+        index < sizeof(tag->vbe_mode_info) / sizeof(tag->vbe_mode_info[0]);
+        index += cols
+    ) {
+        PRINTF("    %-3u", tag->vbe_mode_info[index]);
+        for (size_t col = 1; col < cols; ++col) {
+            PRINTF(" %-3u", tag->vbe_mode_info[index + col]);
+        }
+        PRINTLN("");
     }
+    PRINTLN ("  ]");
+
+    FOOTER;
+}
+
+void KernAux_Multiboot2_ITag_FramebufferInfo_print(
+    const struct KernAux_Multiboot2_ITag_FramebufferInfo *const tag,
+    const KernAux_Display display
+) {
+    HEADER(FramebufferInfo);
+
+    KERNAUX_CAST_CONST(unsigned long long, addr,     tag->framebuffer_addr);
+    KERNAUX_CAST_CONST(unsigned long,      pitch,    tag->framebuffer_pitch);
+    KERNAUX_CAST_CONST(unsigned long,      width,    tag->framebuffer_width);
+    KERNAUX_CAST_CONST(unsigned long,      height,   tag->framebuffer_height);
+    KERNAUX_CAST_CONST(unsigned long,      bpp,      tag->framebuffer_bpp);
+    KERNAUX_CAST_CONST(unsigned long,      type,     tag->framebuffer_type);
+    KERNAUX_CAST_CONST(unsigned long,      reserved, tag->reserved);
+
+    PRINTLNF("  u64 framebuffer_addr: %llu",  addr);
+    PRINTLNF("  u32 framebuffer_pitch: %lu",  pitch);
+    PRINTLNF("  u32 framebuffer_width: %lu",  width);
+    PRINTLNF("  u32 framebuffer_height: %lu", height);
+    PRINTLNF("  u8 framebuffer_bpp: %lu",     bpp);
+    PRINTLNF("  u8 framebuffer_type: %lu",    type);
+    PRINTLNF("  u16 reserved: %lu",           reserved);
+
+    // TODO: Print data?
+
+    FOOTER;
 }
 
 void KernAux_Multiboot2_ITag_ELFSymbols_print(
     const struct KernAux_Multiboot2_ITag_ELFSymbols *const tag,
     const KernAux_Display display
 ) {
-    KERNAUX_ASSERT(tag);
-    KERNAUX_ASSERT(display);
+    HEADER(ELFSymbols);
 
-    if (!KernAux_Multiboot2_ITag_ELFSymbols_is_valid(tag)) {
-        PRINTLN("  invalid!");
-        return;
-    }
+    KERNAUX_CAST_CONST(unsigned long, num,     tag->num);
+    KERNAUX_CAST_CONST(unsigned long, entsize, tag->entsize);
+    KERNAUX_CAST_CONST(unsigned long, shndx,   tag->shndx);
+
+    PRINTLNF("  u32 num: %lu",      num);
+    PRINTLNF("  u32 entsize: %lu",  entsize);
+    PRINTLNF("  u32 shndx: %lu",    shndx);
+
+    // TODO: Print data?
+
+    FOOTER;
+}
+
+void KernAux_Multiboot2_ITag_APMTable_print(
+    const struct KernAux_Multiboot2_ITag_APMTable *const tag,
+    const KernAux_Display display
+) {
+    HEADER(APMTable);
+
+    KERNAUX_CAST_CONST(unsigned long, version,     tag->version);
+    KERNAUX_CAST_CONST(unsigned long, cseg,        tag->cseg);
+    KERNAUX_CAST_CONST(unsigned long, offset,      tag->offset);
+    KERNAUX_CAST_CONST(unsigned long, cseg_16,     tag->cseg_16);
+    KERNAUX_CAST_CONST(unsigned long, dseg,        tag->dseg);
+    KERNAUX_CAST_CONST(unsigned long, flags,       tag->flags);
+    KERNAUX_CAST_CONST(unsigned long, cseg_len,    tag->cseg_len);
+    KERNAUX_CAST_CONST(unsigned long, cseg_16_len, tag->cseg_16_len);
+    KERNAUX_CAST_CONST(unsigned long, dseg_len,    tag->dseg_len);
+
+    PRINTLNF("  u16 version: %lu",     version);
+    PRINTLNF("  u16 cseg: %lu",        cseg);
+    PRINTLNF("  u32 offset: %lu",      offset);
+    PRINTLNF("  u16 cseg_16: %lu",     cseg_16);
+    PRINTLNF("  u16 dseg: %lu",        dseg);
+    PRINTLNF("  u16 flags: %lu",       flags);
+    PRINTLNF("  u16 cseg_len: %lu",    cseg_len);
+    PRINTLNF("  u16 cseg_16_len: %lu", cseg_16_len);
+    PRINTLNF("  u16 dseg_len: %lu",    dseg_len);
+
+    FOOTER;
+}
+
+void KernAux_Multiboot2_ITag_EFI32bitSystemTablePtr_print(
+    const struct KernAux_Multiboot2_ITag_EFI32bitSystemTablePtr *const tag,
+    const KernAux_Display display
+) {
+    HEADER(EFI32bitSystemTablePtr);
+
+    KERNAUX_CAST_CONST(unsigned long, pointer, tag->pointer);
+
+    PRINTLNF("  u32 pointer: %lu", pointer);
+
+    FOOTER;
+}
+
+void KernAux_Multiboot2_ITag_EFI64bitSystemTablePtr_print(
+    const struct KernAux_Multiboot2_ITag_EFI64bitSystemTablePtr *const tag,
+    const KernAux_Display display
+) {
+    HEADER(EFI64bitSystemTablePtr);
+
+    KERNAUX_CAST_CONST(unsigned long long, pointer, tag->pointer);
+
+    PRINTLNF("  u64 pointer: %llu", pointer);
+
+    FOOTER;
+}
+
+void KernAux_Multiboot2_ITag_SMBIOSTables_print(
+    const struct KernAux_Multiboot2_ITag_SMBIOSTables *const tag,
+    const KernAux_Display display
+) {
+    HEADER(SMBIOSTables);
+
+    KERNAUX_CAST_CONST(unsigned long, major,     tag->major);
+    KERNAUX_CAST_CONST(unsigned long, minor,     tag->minor);
+    KERNAUX_CAST_CONST(unsigned long, reserved0, tag->reserved[0]);
+    KERNAUX_CAST_CONST(unsigned long, reserved1, tag->reserved[1]);
+    KERNAUX_CAST_CONST(unsigned long, reserved2, tag->reserved[2]);
+    KERNAUX_CAST_CONST(unsigned long, reserved3, tag->reserved[3]);
+    KERNAUX_CAST_CONST(unsigned long, reserved4, tag->reserved[4]);
+    KERNAUX_CAST_CONST(unsigned long, reserved5, tag->reserved[5]);
+
+    PRINTLNF("  u8 major: %lu", major);
+    PRINTLNF("  u8 minor: %lu", minor);
+    PRINTLNF("  u8 reserved[6]: [%lu, %lu, %lu, %lu, %lu, %lu]",
+        reserved0, reserved1, reserved2,
+        reserved3, reserved4, reserved5
+    );
+
+    // TODO: Print data?
+
+    FOOTER;
+}
+
+void KernAux_Multiboot2_ITag_ACPIOldRSDP_print(
+    const struct KernAux_Multiboot2_ITag_ACPIOldRSDP *const tag,
+    const KernAux_Display display
+) {
+    HEADER(ACPIOldRSDP);
+
+    // TODO: Print data?
+
+    FOOTER;
+}
+
+void KernAux_Multiboot2_ITag_ACPINewRSDP_print(
+    const struct KernAux_Multiboot2_ITag_ACPINewRSDP *const tag,
+    const KernAux_Display display
+) {
+    HEADER(ACPINewRSDP);
+
+    // TODO: Print data?
+
+    FOOTER;
+}
+
+void KernAux_Multiboot2_ITag_NetworkingInfo_print(
+    const struct KernAux_Multiboot2_ITag_NetworkingInfo *const tag,
+    const KernAux_Display display
+) {
+    HEADER(NetworkingInfo);
+
+    // TODO: Print data?
+
+    FOOTER;
+}
+
+void KernAux_Multiboot2_ITag_EFIMemoryMap_print(
+    const struct KernAux_Multiboot2_ITag_EFIMemoryMap *const tag,
+    const KernAux_Display display
+) {
+    HEADER(EFIMemoryMap);
+
+    KERNAUX_CAST_CONST(unsigned long, descr_size,    tag->descriptor_size);
+    KERNAUX_CAST_CONST(unsigned long, descr_version, tag->descriptor_version);
+
+    PRINTLNF("  u32 descriptor_size: %lu",    descr_size);
+    PRINTLNF("  u32 descriptor_version: %lu", descr_version);
+
+    // TODO: Print data?
+
+    FOOTER;
+}
+
+void KernAux_Multiboot2_ITag_EFIBootServicesNotTerminated_print(
+    const struct KernAux_Multiboot2_ITag_EFIBootServicesNotTerminated *const tag,
+    const KernAux_Display display
+) {
+    HEADER(EFIBootServicesNotTerminated);
+
+    FOOTER;
+}
+
+void KernAux_Multiboot2_ITag_EFI32bitImageHandlePtr_print(
+    const struct KernAux_Multiboot2_ITag_EFI32bitImageHandlePtr *const tag,
+    const KernAux_Display display
+) {
+    HEADER(EFI32bitImageHandlePtr);
+
+    KERNAUX_CAST_CONST(unsigned long, pointer, tag->pointer);
+
+    PRINTLNF("  u32 pointer: %lu", pointer);
+
+    FOOTER;
+}
+
+void KernAux_Multiboot2_ITag_EFI64bitImageHandlePtr_print(
+    const struct KernAux_Multiboot2_ITag_EFI64bitImageHandlePtr *const tag,
+    const KernAux_Display display
+) {
+    HEADER(EFI64bitImageHandlePtr);
+
+    KERNAUX_CAST_CONST(unsigned long long, pointer, tag->pointer);
+
+    PRINTLNF("  u64 pointer: %llu", pointer);
+
+    FOOTER;
+}
+
+void KernAux_Multiboot2_ITag_ImageLoadBasePhysAddr_print(
+    const struct KernAux_Multiboot2_ITag_ImageLoadBasePhysAddr *const tag,
+    const KernAux_Display display
+) {
+    HEADER(ImageLoadBasePhysAddr);
 
-    KERNAUX_CAST_CONST(unsigned long, num,       tag->num);
-    KERNAUX_CAST_CONST(unsigned long, ent_size,  tag->ent_size);
-    KERNAUX_CAST_CONST(unsigned long, shndx,     tag->shndx);
-    KERNAUX_CAST_CONST(unsigned long, reserved1, tag->reserved1);
+    KERNAUX_CAST_CONST(unsigned long, load_base_addr, tag->load_base_addr);
 
-    PRINTLNF("  num: %lu",       num);
-    PRINTLNF("  entsize: %lu",   ent_size);
-    PRINTLNF("  shndx: %lu",     shndx);
-    PRINTLNF("  reserved1: %lu", reserved1);
+    PRINTLNF("  u32 load_base_addr: %lu", load_base_addr);
 
-    // TODO: implement this
+    FOOTER;
 }


Test patch:
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 841ab08a..7db522c0 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -4,6 +4,19 @@ CLEANFILES =
 TESTS =
 noinst_PROGRAMS = $(TESTS)
 
+############################
+# multiboot2_header_print0 #
+############################
+
+if WITH_MULTIBOOT2
+noinst_PROGRAMS += multiboot2_header_print0
+multiboot2_header_print0_LDADD = $(top_builddir)/libkernaux.la
+multiboot2_header_print0_SOURCES = \
+	main.c \
+	multiboot2_header_print0.c \
+	multiboot2_header_example0.h
+endif
+
 ############################
 # multiboot2_header_print1 #
 ############################
@@ -30,6 +43,19 @@ multiboot2_header_print2_SOURCES = \
 	multiboot2_header_example2.h
 endif
 
+##########################
+# multiboot2_info_print0 #
+##########################
+
+if WITH_MULTIBOOT2
+noinst_PROGRAMS += multiboot2_info_print0
+multiboot2_info_print0_LDADD = $(top_builddir)/libkernaux.la
+multiboot2_info_print0_SOURCES = \
+	main.c \
+	multiboot2_info_print0.c \
+	multiboot2_info_example0.h
+endif
+
 ##########################
 # multiboot2_info_print1 #
 ##########################
@@ -189,6 +215,7 @@ endif
 if WITH_MULTIBOOT2
 TESTS += test_multiboot2_header_print
 test_multiboot2_header_print_DEPENDENCIES = \
+	multiboot2_header_print0 \
 	multiboot2_header_print1 \
 	multiboot2_header_print2
 test_multiboot2_header_print_LDADD = $(top_builddir)/libkernaux.la
@@ -232,6 +259,7 @@ endif
 if WITH_MULTIBOOT2
 TESTS += test_multiboot2_info_print
 test_multiboot2_info_print_DEPENDENCIES = \
+	multiboot2_info_print0 \
 	multiboot2_info_print1 \
 	multiboot2_info_print2
 test_multiboot2_info_print_LDADD = $(top_builddir)/libkernaux.la
diff --git a/tests/multiboot2_header_example0.h b/tests/multiboot2_header_example0.h
new file mode 100644
index 00000000..f0b0f578
--- /dev/null
+++ b/tests/multiboot2_header_example0.h
@@ -0,0 +1,32 @@
+#include <kernaux/macro.h>
+#include <kernaux/multiboot2.h>
+
+#include <kernaux/macro/packing_start.run>
+
+// Minimal example
+KERNAUX_ALIGNED(KERNAUX_MULTIBOOT2_HEADER_ALIGN)
+static const struct {
+    struct KernAux_Multiboot2_Header multiboot2_header;
+    struct KernAux_Multiboot2_HTag_None tag_none;
+}
+KERNAUX_PACKED
+multiboot2_header_example0 = {
+    .multiboot2_header = {
+        .magic = KERNAUX_MULTIBOOT2_HEADER_MAGIC,
+        .arch = KERNAUX_MULTIBOOT2_HEADER_ARCH_I386,
+        .total_size = sizeof(multiboot2_header_example0),
+        .checksum = KERNAUX_MULTIBOOT2_HEADER_CHECKSUM(
+            KERNAUX_MULTIBOOT2_HEADER_ARCH_I386,
+            sizeof(multiboot2_header_example0)
+        ),
+    },
+    .tag_none = {
+        .base = {
+            .type = KERNAUX_MULTIBOOT2_HTAG_NONE,
+            .flags = 0,
+            .size = sizeof(multiboot2_header_example0.tag_none),
+        },
+    },
+};
+
+#include <kernaux/macro/packing_end.run>
diff --git a/tests/multiboot2_header_example1.h b/tests/multiboot2_header_example1.h
index 5d743db5..8c1ad62a 100644
--- a/tests/multiboot2_header_example1.h
+++ b/tests/multiboot2_header_example1.h
@@ -1,7 +1,30 @@
+#include <kernaux/macro.h>
+#include <kernaux/multiboot2.h>
+
 #include <kernaux/macro/packing_start.run>
 
+KERNAUX_ALIGNED(KERNAUX_MULTIBOOT2_HEADER_ALIGN)
 static const struct {
     struct KernAux_Multiboot2_Header multiboot2_header;
+
+    struct KernAux_Multiboot2_HTag_Flags tag_flags1;
+    uint8_t _align1[4];
+
+    struct KernAux_Multiboot2_HTag_Flags tag_flags2;
+    uint8_t _align2[4];
+
+    struct KernAux_Multiboot2_HTag_Flags tag_flags3;
+    uint8_t _align3[4];
+
+    struct KernAux_Multiboot2_HTag_Flags tag_flags4;
+    uint8_t _align4[4];
+
+    struct {
+        struct KernAux_Multiboot2_HTag_InfoReq tag;
+        uint32_t mbi_tag_types[1];
+    } tag_info_req;
+    uint8_t _align5[4];
+
     struct KernAux_Multiboot2_HTag_None tag_none;
 }
 KERNAUX_PACKED
@@ -15,6 +38,52 @@ multiboot2_header_example1 = {
             sizeof(multiboot2_header_example1)
         ),
     },
+    .tag_flags1 = {
+        .base = {
+            .type = KERNAUX_MULTIBOOT2_HTAG_FLAGS,
+            .flags = 0,
+            .size = sizeof(multiboot2_header_example1.tag_flags1),
+        },
+        .console_flags = 0,
+    },
+    .tag_flags2 = {
+        .base = {
+            .type = KERNAUX_MULTIBOOT2_HTAG_FLAGS,
+            .flags = 0,
+            .size = sizeof(multiboot2_header_example1.tag_flags2),
+        },
+        .console_flags = KERNAUX_MULTIBOOT2_HTAG_FLAGS_REQUIRE_CONSOLE,
+    },
+    .tag_flags3 = {
+        .base = {
+            .type = KERNAUX_MULTIBOOT2_HTAG_FLAGS,
+            .flags = 0,
+            .size = sizeof(multiboot2_header_example1.tag_flags3),
+        },
+        .console_flags = KERNAUX_MULTIBOOT2_HTAG_FLAGS_EGA_SUPPORT,
+    },
+    .tag_flags4 = {
+        .base = {
+            .type = KERNAUX_MULTIBOOT2_HTAG_FLAGS,
+            .flags = 0,
+            .size = sizeof(multiboot2_header_example1.tag_flags4),
+        },
+        .console_flags =
+            KERNAUX_MULTIBOOT2_HTAG_FLAGS_REQUIRE_CONSOLE |
+            KERNAUX_MULTIBOOT2_HTAG_FLAGS_EGA_SUPPORT,
+    },
+    .tag_info_req = {
+        .tag = {
+            .base = {
+                .type = KERNAUX_MULTIBOOT2_HTAG_INFO_REQ,
+                .flags = 0,
+                .size = sizeof(multiboot2_header_example1.tag_info_req),
+            },
+        },
+        .mbi_tag_types = {
+            KERNAUX_MULTIBOOT2_ITAG_NONE,
+        },
+    },
     .tag_none = {
         .base = {
             .type = KERNAUX_MULTIBOOT2_HTAG_NONE,
diff --git a/tests/multiboot2_header_example2.h b/tests/multiboot2_header_example2.h
index 26d3e59c..a37e00ac 100644
--- a/tests/multiboot2_header_example2.h
+++ b/tests/multiboot2_header_example2.h
@@ -1,7 +1,9 @@
 #include <kernaux/macro.h>
+#include <kernaux/multiboot2.h>
 
 #include <kernaux/macro/packing_start.run>
 
+KERNAUX_ALIGNED(KERNAUX_MULTIBOOT2_HEADER_ALIGN)
 static const struct {
     struct KernAux_Multiboot2_Header multiboot2_header;
 
@@ -85,10 +87,10 @@ multiboot2_header_example2 = {
             .flags = 0,
             .size = sizeof(multiboot2_header_example2.tag_addr),
         },
-        .header_addr = 0,
-        .load_addr = 0,
-        .load_end_addr = 0,
-        .bss_end_addr = 0,
+        .header_addr = 0xcafebabe,
+        .load_addr = 0xdeadbeaf,
+        .load_end_addr = 0xdeadbabe,
+        .bss_end_addr = 0xcafebeaf,
     },
     .tag_entry_addr = {
         .base = {
@@ -96,7 +98,7 @@ multiboot2_header_example2 = {
             .flags = 0,
             .size = sizeof(multiboot2_header_example2.tag_entry_addr),
         },
-        .entry_addr = 0,
+        .entry_addr = 0xcafebabe,
     },
     .tag_flags = {
         .base = {
@@ -104,10 +106,7 @@ multiboot2_header_example2 = {
             .flags = 0,
             .size = sizeof(multiboot2_header_example2.tag_flags),
         },
-        .console_flags = (
-            KERNAUX_MULTIBOOT2_HTAG_FLAGS_REQUIRE_CONSOLE |
-            KERNAUX_MULTIBOOT2_HTAG_FLAGS_EGA_SUPPORT
-        ),
+        .console_flags = 0,
     },
     .tag_framebuffer = {
         .base = {
@@ -115,9 +114,9 @@ multiboot2_header_example2 = {
             .flags = 0,
             .size = sizeof(multiboot2_header_example2.tag_framebuffer),
         },
-        .width = 0,
-        .height = 0,
-        .depth = 0,
+        .width = 80,
+        .height = 25,
+        .depth = 8,
     },
     .tag_module_align = {
         .base = {
@@ -139,7 +138,7 @@ multiboot2_header_example2 = {
             .flags = 0,
             .size = sizeof(multiboot2_header_example2.tag_efi_i386_entry_addr),
         },
-        .entry_addr = 0,
+        .entry_addr = 0xcafebabe,
     },
     .tag_efi_amd64_entry_addr = {
         .base = {
@@ -147,7 +146,7 @@ multiboot2_header_example2 = {
             .flags = 0,
             .size = sizeof(multiboot2_header_example2.tag_efi_amd64_entry_addr),
         },
-        .entry_addr = 0,
+        .entry_addr = 0xdeadbeaf,
     },
     .tag_relocatable_header = {
         .base = {
@@ -155,9 +154,9 @@ multiboot2_header_example2 = {
             .flags = 0,
             .size = sizeof(multiboot2_header_example2.tag_relocatable_header),
         },
-        .min_addr = 0,
-        .max_addr = 0,
-        .align = 0,
+        .min_addr = 0xcafebabe,
+        .max_addr = 0xdeadbeaf,
+        .align = 8,
         .preferences =
             KERNAUX_MULTIBOOT2_HTAG_RELOCATABLE_HEADER_PREFERENCE_LOWEST,
     },
diff --git a/tests/multiboot2_header_print0.c b/tests/multiboot2_header_print0.c
new file mode 100644
index 00000000..89836d3f
--- /dev/null
+++ b/tests/multiboot2_header_print0.c
@@ -0,0 +1,43 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#define KERNAUX_ACCESS_PROTECTED
+
+#include <kernaux/generic/display.h>
+#include <kernaux/macro.h>
+#include <kernaux/multiboot2.h>
+
+#include <assert.h>
+#include <stdarg.h>
+#include <stdio.h>
+
+#include "multiboot2_header_example0.h"
+
+static void my_putc(void *display KERNAUX_UNUSED, char c)
+{
+    putchar(c);
+}
+
+static
+void my_vprintf(void *display KERNAUX_UNUSED, const char *format, va_list va)
+{
+    vprintf(format, va);
+}
+
+static const struct KernAux_Display display = {
+    .putc = my_putc,
+    .vprintf = my_vprintf,
+};
+
+void test_main()
+{
+    assert(KernAux_Multiboot2_Header_is_valid(
+        (struct KernAux_Multiboot2_Header*)&multiboot2_header_example0
+    ));
+
+    KernAux_Multiboot2_Header_print(
+        (struct KernAux_Multiboot2_Header*)&multiboot2_header_example0,
+        &display
+    );
+}
diff --git a/tests/multiboot2_info_example0.h b/tests/multiboot2_info_example0.h
new file mode 100644
index 00000000..ec33ee0a
--- /dev/null
+++ b/tests/multiboot2_info_example0.h
@@ -0,0 +1,26 @@
+#include <kernaux/macro.h>
+#include <kernaux/multiboot2.h>
+
+#include <kernaux/macro/packing_start.run>
+
+// Minimal example
+KERNAUX_ALIGNED(KERNAUX_MULTIBOOT2_INFO_ALIGN)
+static const struct {
+    struct KernAux_Multiboot2_Info multiboot2_info;
+    struct KernAux_Multiboot2_ITag_None tag_none;
+}
+KERNAUX_PACKED
+multiboot2_info_example0 = {
+    .multiboot2_info = {
+        .total_size = sizeof(multiboot2_info_example0),
+        .reserved = 0,
+    },
+    .tag_none = {
+        .base = {
+            .type = KERNAUX_MULTIBOOT2_ITAG_NONE,
+            .size = sizeof(multiboot2_info_example0.tag_none),
+        },
+    },
+};
+
+#include <kernaux/macro/packing_end.run>
diff --git a/tests/multiboot2_info_example1.h b/tests/multiboot2_info_example1.h
index 62c4b66f..66e09434 100644
--- a/tests/multiboot2_info_example1.h
+++ b/tests/multiboot2_info_example1.h
@@ -1,3 +1,7 @@
+#include <kernaux/macro.h>
+#include <kernaux/multiboot2.h>
+
+KERNAUX_ALIGNED(KERNAUX_MULTIBOOT2_INFO_ALIGN)
 static const uint8_t multiboot2_info_example1[864] = {
     96, 3, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 12, 0, 0, 0,
     0, 0, 64, 0, 0, 0, 232, 133, 1, 0, 0, 0, 21, 0, 0, 0,
diff --git a/tests/multiboot2_info_example2.h b/tests/multiboot2_info_example2.h
index f807a345..9b204c96 100644
--- a/tests/multiboot2_info_example2.h
+++ b/tests/multiboot2_info_example2.h
@@ -1,7 +1,9 @@
 #include <kernaux/macro.h>
+#include <kernaux/multiboot2.h>
 
 #include <kernaux/macro/packing_start.run>
 
+KERNAUX_ALIGNED(KERNAUX_MULTIBOOT2_INFO_ALIGN)
 static const struct {
     struct KernAux_Multiboot2_Info multiboot2_info;
 
@@ -46,7 +48,6 @@ static const struct {
         struct KernAux_Multiboot2_ITag_FramebufferInfo tag;
         uint8_t data[8];
     } tag_framebuffer_info;
-    uint8_t _align6[1];
 
     struct {
         struct KernAux_Multiboot2_ITag_ELFSymbols tag;
@@ -110,7 +111,7 @@ KERNAUX_PACKED
 multiboot2_info_example2 = {
     .multiboot2_info = {
         .total_size = sizeof(multiboot2_info_example2),
-        .reserved1 = 0,
+        .reserved = 0,
     },
     .tag_boot_cmd_line = {
         .tag = {
@@ -165,7 +166,7 @@ multiboot2_info_example2 = {
             .type = KERNAUX_MULTIBOOT2_ITAG_BIOS_BOOT_DEVICE,
             .size = sizeof(multiboot2_info_example2.tag_bios_boot_device),
         },
-        .bios_dev = 0,
+        .biosdev = 0,
         .partition = 1,
         .sub_partition = 2,
     },
@@ -200,6 +201,24 @@ multiboot2_info_example2 = {
         .vbe_interface_seg = 123,
         .vbe_interface_off = 456,
         .vbe_interface_len = 789,
+        .vbe_control_info = {
+            [0]   = 0,
+            [16]  = 1,
+            [32]  = 12,
+            [48]  = 123,
+            [79]  = 1,
+            [95]  = 12,
+            [111] = 123,
+        },
+        .vbe_mode_info = {
+            [0]   = 0,
+            [16]  = 3,
+            [32]  = 32,
+            [48]  = 255,
+            [79]  = 3,
+            [95]  = 32,
+            [111] = 255,
+        },
     },
     .tag_framebuffer_info = {
         .tag = {
@@ -223,12 +242,11 @@ multiboot2_info_example2 = {
                 .size = sizeof(multiboot2_info_example2.tag_elf_symbols),
             },
             .num = 10,
-            .ent_size = 0,
-            .shndx = 40,
-            .reserved1 = 0,
+            .entsize = 40,
+            .shndx = 9,
         },
         .data = {
-            9, 0, 0, 0, 0, 0, 0, 0,
+            0, 0, 0, 0,
             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
             0, 0, 0, 0, 27, 0, 0, 0, 1, 0, 0, 0, 6, 0, 0, 0,
@@ -293,7 +311,7 @@ multiboot2_info_example2 = {
             },
             .major = 1,
             .minor = 2,
-            .reserved1 = {0, 0, 0, 0, 0, 0},
+            .reserved = {0, 0, 0, 0, 0, 0},
         },
         .data = {0, 0, 0, 0, 0, 0, 0, 0},
     },
diff --git a/tests/multiboot2_info_print0.c b/tests/multiboot2_info_print0.c
new file mode 100644
index 00000000..642a7aa1
--- /dev/null
+++ b/tests/multiboot2_info_print0.c
@@ -0,0 +1,43 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#define KERNAUX_ACCESS_PROTECTED
+
+#include <kernaux/generic/display.h>
+#include <kernaux/macro.h>
+#include <kernaux/multiboot2.h>
+
+#include <assert.h>
+#include <stdarg.h>
+#include <stdio.h>
+
+#include "multiboot2_info_example0.h"
+
+static void my_putc(void *display KERNAUX_UNUSED, char c)
+{
+    putchar(c);
+}
+
+static
+void my_vprintf(void *display KERNAUX_UNUSED, const char *format, va_list va)
+{
+    vprintf(format, va);
+}
+
+static const struct KernAux_Display display = {
+    .putc = my_putc,
+    .vprintf = my_vprintf,
+};
+
+void test_main()
+{
+    assert(KernAux_Multiboot2_Info_is_valid(
+        &multiboot2_info_example0.multiboot2_info
+    ));
+
+    KernAux_Multiboot2_Info_print(
+        &multiboot2_info_example0.multiboot2_info,
+        &display
+    );
+}
diff --git a/tests/test_multiboot2_common_packing.c b/tests/test_multiboot2_common_packing.c
index facf4222..b54653f4 100644
--- a/tests/test_multiboot2_common_packing.c
+++ b/tests/test_multiboot2_common_packing.c
@@ -106,8 +106,8 @@ void test_main()
     INFO_SIZEOF1(BIOSBootDevice,               bios_boot_device,                 20          );
     INFO_SIZEOF2(MemoryMap,                    memory_map,                       16, 160 - 16);
     INFO_SIZEOF1(VBEInfo,                      vbe_info,                         784         );
-    INFO_SIZEOF2(FramebufferInfo,              framebuffer_info,                 31, 8       );
-    INFO_SIZEOF2(ELFSymbols,                   elf_symbols,                      16, 420 - 16);
+    INFO_SIZEOF2(FramebufferInfo,              framebuffer_info,                 32, 8       );
+    INFO_SIZEOF2(ELFSymbols,                   elf_symbols,                      20, 420 - 20);
     INFO_SIZEOF1(APMTable,                     apm_table,                        28          );
     INFO_SIZEOF1(EFI32bitSystemTablePtr,       efi_32bit_system_table_ptr,       12          );
     INFO_SIZEOF1(EFI64bitSystemTablePtr,       efi_64bit_system_table_ptr,       16          );
diff --git a/tests/test_multiboot2_header_print.c b/tests/test_multiboot2_header_print.c
index d43b3e52..4b173a16 100644
--- a/tests/test_multiboot2_header_print.c
+++ b/tests/test_multiboot2_header_print.c
@@ -9,70 +9,186 @@
 #endif
 #include <stdio.h>
 
+static const char output0[] =
+    "Multiboot 2 header {\n"
+    "  u32 magic: 3897708758\n"
+    "  u32 arch: 0 (i386)\n"
+    "  u32 size: 24\n"
+    "  u32 checksum: 397258514\n"
+    "}\n"
+    "Multiboot 2 header tag {\n"
+    "  u16 type: 0 (none)\n"
+    "  u16 flags: 0\n"
+    "  u32 size: 8\n"
+    "}\n";
+
 static const char output1[] =
-    "Multiboot 2 header\n"
-    "  magic: 3897708758\n"
-    "  arch: 4 (MIPS32)\n"
-    "  size: 24\n"
-    "  checksum: 397258510\n"
-    "Multiboot 2 header tag\n"
-    "  type: 0 (none)\n"
-    "  flags: 0\n"
-    "  size: 8\n";
+    "Multiboot 2 header {\n"
+    "  u32 magic: 3897708758\n"
+    "  u32 arch: 4 (MIPS32)\n"
+    "  u32 size: 104\n"
+    "  u32 checksum: 397258430\n"
+    "}\n"
+    "Multiboot 2 header tag {\n"
+    "  u16 type: 4 (flags)\n"
+    "  u16 flags: 0\n"
+    "  u32 size: 12\n"
+    "  u32 console_flags: 0 ()\n"
+    "}\n"
+    "Multiboot 2 header tag {\n"
+    "  u16 type: 4 (flags)\n"
+    "  u16 flags: 0\n"
+    "  u32 size: 12\n"
+    "  u32 console_flags: 1 (\n"
+    "    REQUIRE_CONSOLE\n"
+    "  )\n"
+    "}\n"
+    "Multiboot 2 header tag {\n"
+    "  u16 type: 4 (flags)\n"
+    "  u16 flags: 0\n"
+    "  u32 size: 12\n"
+    "  u32 console_flags: 2 (\n"
+    "    EGA_SUPPORT\n"
+    "  )\n"
+    "}\n"
+    "Multiboot 2 header tag {\n"
+    "  u16 type: 4 (flags)\n"
+    "  u16 flags: 0\n"
+    "  u32 size: 12\n"
+    "  u32 console_flags: 3 (\n"
+    "    REQUIRE_CONSOLE |\n"
+    "    EGA_SUPPORT\n"
+    "  )\n"
+    "}\n"
+    "Multiboot 2 header tag {\n"
+    "  u16 type: 1 (information request)\n"
+    "  u16 flags: 0\n"
+    "  u32 size: 12\n"
+    "  u32 mbi_tag_types[]: [\n"
+    "    0 (none)\n"
+    "  ]\n"
+    "}\n"
+    "Multiboot 2 header tag {\n"
+    "  u16 type: 0 (none)\n"
+    "  u16 flags: 0\n"
+    "  u32 size: 8\n"
+    "}\n";
 
 static const char output2[] =
-    "Multiboot 2 header\n"
-    "  magic: 3897708758\n"
-    "  arch: 0 (i386)\n"
-    "  size: 272\n"
-    "  checksum: 397258266\n"
-    "Multiboot 2 header tag\n"
-    "  type: 1 (information request)\n"
-    "  flags: 0\n"
-    "  size: 96\n"
-    "Multiboot 2 header tag\n"
-    "  type: 2 (address)\n"
-    "  flags: 0\n"
-    "  size: 24\n"
-    "Multiboot 2 header tag\n"
-    "  type: 3 (entry address)\n"
-    "  flags: 0\n"
-    "  size: 12\n"
-    "Multiboot 2 header tag\n"
-    "  type: 4 (flags)\n"
-    "  flags: 0\n"
-    "  size: 12\n"
-    "Multiboot 2 header tag\n"
-    "  type: 5 (framebuffer)\n"
-    "  flags: 0\n"
-    "  size: 20\n"
-    "Multiboot 2 header tag\n"
-    "  type: 6 (module alignment)\n"
-    "  flags: 0\n"
-    "  size: 8\n"
-    "Multiboot 2 header tag\n"
-    "  type: 7 (EFI boot services)\n"
-    "  flags: 0\n"
-    "  size: 8\n"
-    "Multiboot 2 header tag\n"
-    "  type: 8 (EFI i386 entry address)\n"
-    "  flags: 0\n"
-    "  size: 12\n"
-    "Multiboot 2 header tag\n"
-    "  type: 9 (EFI amd64 entry address)\n"
-    "  flags: 0\n"
-    "  size: 12\n"
-    "Multiboot 2 header tag\n"
-    "  type: 10 (relocatable header)\n"
-    "  flags: 0\n"
-    "  size: 24\n"
-    "Multiboot 2 header tag\n"
-    "  type: 0 (none)\n"
-    "  flags: 0\n"
-    "  size: 8\n";
+    "Multiboot 2 header {\n"
+    "  u32 magic: 3897708758\n"
+    "  u32 arch: 0 (i386)\n"
+    "  u32 size: 272\n"
+    "  u32 checksum: 397258266\n"
+    "}\n"
+    "Multiboot 2 header tag {\n"
+    "  u16 type: 1 (information request)\n"
+    "  u16 flags: 0\n"
+    "  u32 size: 96\n"
+    "  u32 mbi_tag_types[]: [\n"
+    "    0 (none)\n"
+    "    1 (boot cmd line)\n"
+    "    2 (boot loader name)\n"
+    "    3 (module)\n"
+    "    4 (basic memory info)\n"
+    "    5 (BIOS boot device)\n"
+    "    6 (memory map)\n"
+    "    7 (VBE info)\n"
+    "    8 (framebuffer info)\n"
+    "    9 (ELF symbols)\n"
+    "    10 (APM table)\n"
+    "    11 (EFI 32bit system table ptr)\n"
+    "    12 (EFI 64bit system table ptr)\n"
+    "    13 (SMBIOS tables)\n"
+    "    14 (ACPI old RSDP)\n"
+    "    15 (ACPI new RSDP)\n"
+    "    16 (networking info)\n"
+    "    17 (EFI memory map)\n"
+    "    18 (EFI boot services not terminated)\n"
+    "    19 (EFI 32bit image handle ptr)\n"
+    "    20 (EFI 64bit image handle ptr)\n"
+    "    21 (image load base phys addr)\n"
+    "  ]\n"
+    "}\n"
+    "Multiboot 2 header tag {\n"
+    "  u16 type: 2 (address)\n"
+    "  u16 flags: 0\n"
+    "  u32 size: 24\n"
+    "  u32 header_addr: 3405691582\n"
+    "  u32 load_addr: 3735928495\n"
+    "  u32 load_end_addr: 3735927486\n"
+    "  u32 bss_end_addr: 3405692591\n"
+    "}\n"
+    "Multiboot 2 header tag {\n"
+    "  u16 type: 3 (entry address)\n"
+    "  u16 flags: 0\n"
+    "  u32 size: 12\n"
+    "  u32 entry_addr: 3405691582\n"
+    "}\n"
+    "Multiboot 2 header tag {\n"
+    "  u16 type: 4 (flags)\n"
+    "  u16 flags: 0\n"
+    "  u32 size: 12\n"
+    "  u32 console_flags: 0 ()\n"
+    "}\n"
+    "Multiboot 2 header tag {\n"
+    "  u16 type: 5 (framebuffer)\n"
+    "  u16 flags: 0\n"
+    "  u32 size: 20\n"
+    "  u32 width: 80\n"
+    "  u32 height: 25\n"
+    "  u32 depth: 8\n"
+    "}\n"
+    "Multiboot 2 header tag {\n"
+    "  u16 type: 6 (module alignment)\n"
+    "  u16 flags: 0\n"
+    "  u32 size: 8\n"
+    "}\n"
+    "Multiboot 2 header tag {\n"
+    "  u16 type: 7 (EFI boot services)\n"
+    "  u16 flags: 0\n"
+    "  u32 size: 8\n"
+    "}\n"
+    "Multiboot 2 header tag {\n"
+    "  u16 type: 8 (EFI i386 entry address)\n"
+    "  u16 flags: 0\n"
+    "  u32 size: 12\n"
+    "  u32 entry_addr: 3405691582\n"
+    "}\n"
+    "Multiboot 2 header tag {\n"
+    "  u16 type: 9 (EFI amd64 entry address)\n"
+    "  u16 flags: 0\n"
+    "  u32 size: 12\n"
+    "  u32 entry_addr: 3735928495\n"
+    "}\n"
+    "Multiboot 2 header tag {\n"
+    "  u16 type: 10 (relocatable header)\n"
+    "  u16 flags: 0\n"
+    "  u32 size: 24\n"
+    "  u32 min_addr: 3405691582\n"
+    "  u32 max_addr: 3735928495\n"
+    "  u32 align: 8\n"
+    "}\n"
+    "Multiboot 2 header tag {\n"
+    "  u16 type: 0 (none)\n"
+    "  u16 flags: 0\n"
+    "  u32 size: 8\n"
+    "}\n";
 
 void test_main()
 {
+    {
+        FILE *const fd = popen("./multiboot2_header_print0", "r");
+        assert(fd != NULL);
+
+        for (const char *ch = output0; *ch; ++ch) {
+            assert(fgetc(fd) == *ch);
+        }
+
+        const int status = pclose(fd);
+        assert(status == 0);
+    }
+
     {
         FILE *const fd = popen("./multiboot2_header_print1", "r");
         assert(fd != NULL);
diff --git a/tests/test_multiboot2_info_helpers.c b/tests/test_multiboot2_info_helpers.c
index 536aefd4..7a6c34eb 100644
--- a/tests/test_multiboot2_info_helpers.c
+++ b/tests/test_multiboot2_info_helpers.c
@@ -18,7 +18,7 @@ static const struct {
 } KERNAUX_PACKED multiboot2_without_boot_cmd_line = {
     .multiboot2_info = {
         .total_size = sizeof(multiboot2_without_boot_cmd_line),
-        .reserved1 = 0,
+        .reserved = 0,
     },
     .tag_none = {
         .base = {
@@ -42,7 +42,7 @@ static const struct {
 } KERNAUX_PACKED multiboot2_with_some_boot_cmd_line = {
     .multiboot2_info = {
         .total_size = sizeof(multiboot2_with_some_boot_cmd_line),
-        .reserved1 = 0,
+        .reserved = 0,
     },
     .tag_boot_cmd_line = {
         .tag = {
@@ -84,7 +84,7 @@ static const struct {
 } KERNAUX_PACKED multiboot2_with_two_boot_cmd_lines = {
     .multiboot2_info = {
         .total_size = sizeof(multiboot2_with_two_boot_cmd_lines),
-        .reserved1 = 0,
+        .reserved = 0,
     },
     .tag_boot_cmd_line1 = {
         .tag = {
diff --git a/tests/test_multiboot2_info_print.c b/tests/test_multiboot2_info_print.c
index 0310f5f8..1ecc1fa4 100644
--- a/tests/test_multiboot2_info_print.c
+++ b/tests/test_multiboot2_info_print.c
@@ -3,273 +3,409 @@
 #endif
 
 #include <assert.h>
+#include <stdlib.h>
+#include <string.h>
 
 #ifndef __USE_POSIX2
 #define __USE_POSIX2
 #endif
 #include <stdio.h>
 
+static const char output0[] =
+    "Multiboot 2 info {\n"
+    "  u32 size: 16\n"
+    "  u32 reserved: 0\n"
+    "}\n"
+    "Multiboot 2 info tag {\n"
+    "  u32 type: 0 (none)\n"
+    "  u32 size: 8\n"
+    "}\n";
+
 static const char output1[] =
-    "Multiboot 2 info\n"
-    "  size: 864\n"
-    "  reserved1: 0\n"
-    "Multiboot 2 info tag\n"
-    "  type: 21 (image load base phys addr)\n"
-    "  size: 12\n"
-    "  load base addr: 4194304\n"
-    "Multiboot 2 info tag\n"
-    "  type: 1 (boot cmd line)\n"
-    "  size: 21\n"
-    "  cmdline: hello kernel\n"
-    "Multiboot 2 info tag\n"
-    "  type: 2 (boot loader name)\n"
-    "  size: 30\n"
-    "  name: GRUB 2.02-2ubuntu8.20\n"
-    "Multiboot 2 info tag\n"
-    "  type: 10 (APM table)\n"
-    "  size: 28\n"
-    "  version: 258\n"
-    "  cseg: 61440\n"
-    "  offset: 54479\n"
-    "  cseg 16: 61440\n"
-    "  dseg: 61440\n"
-    "  flags: 3\n"
-    "  cseg len: 65520\n"
-    "  cseg 16 len: 65520\n"
-    "  dseg len: 65520\n"
-    "Multiboot 2 info tag\n"
-    "  type: 3 (module)\n"
-    "  size: 29\n"
-    "  start: 1056768\n"
-    "  end: 1061532\n"
-    "  cmdline: hello module\n"
-    "Multiboot 2 info tag\n"
-    "  type: 3 (module)\n"
-    "  size: 17\n"
-    "  start: 1064960\n"
-    "  end: 1069652\n"
-    "  cmdline: \n"
-    "Multiboot 2 info tag\n"
-    "  type: 6 (memory map)\n"
-    "  size: 160\n"
-    "  entry size: 24\n"
-    "  entry version: 0\n"
-    "  entries:\n"
-    "    entry 0\n"
-    "      base addr: 0\n"
-    "      length: 654336\n"
-    "      type: 1\n"
-    "      reserved1: 0\n"
-    "    entry 1\n"
-    "      base addr: 654336\n"
-    "      length: 1024\n"
-    "      type: 2\n"
-    "      reserved1: 0\n"
-    "    entry 2\n"
-    "      base addr: 983040\n"
-    "      length: 65536\n"
-    "      type: 2\n"
-    "      reserved1: 0\n"
-    "    entry 3\n"
-    "      base addr: 1048576\n"
-    "      length: 133038080\n"
-    "      type: 1\n"
-    "      reserved1: 0\n"
-    "    entry 4\n"
-    "      base addr: 134086656\n"
-    "      length: 131072\n"
-    "      type: 2\n"
-    "      reserved1: 0\n"
-    "    entry 5\n"
-    "      base addr: 4294705152\n"
-    "      length: 262144\n"
-    "      type: 2\n"
-    "      reserved1: 0\n"
-    "Multiboot 2 info tag\n"
-    "  type: 9 (ELF symbols)\n"
-    "  size: 420\n"
-    "  num: 10\n"
-    "  entsize: 0\n"
-    "  shndx: 40\n"
-    "  reserved1: 0\n"
-    "Multiboot 2 info tag\n"
-    "  type: 4 (basic memory info)\n"
-    "  size: 16\n"
-    "  mem lower: 639\n"
-    "  mem upper: 129920\n"
-    "Multiboot 2 info tag\n"
-    "  type: 5 (BIOS boot device)\n"
-    "  size: 20\n"
-    "  bios dev: 224\n"
-    "  partition: 4294967295\n"
-    "  sub_partition: 4294967295\n"
-    "Multiboot 2 info tag\n"
-    "  type: 8 (framebuffer info)\n"
-    "  size: 32\n"
-    "  framebuffer addr: 753664\n"
-    "  framebuffer pitch: 160\n"
-    "  framebuffer width: 80\n"
-    "  framebuffer height: 25\n"
-    "  framebuffer bpp: 16\n"
-    "  framebuffer type: 2\n"
-    "  reserved1: 0\n"
-    "Multiboot 2 info tag\n"
-    "  type: 14 (ACPI old RSDP)\n"
-    "  size: 28\n"
-    "Multiboot 2 info tag\n"
-    "  type: 0 (none)\n"
-    "  size: 8\n";
+    "Multiboot 2 info {\n"
+    "  u32 size: 864\n"
+    "  u32 reserved: 0\n"
+    "}\n"
+    "Multiboot 2 info tag {\n"
+    "  u32 type: 21 (image load base phys addr)\n"
+    "  u32 size: 12\n"
+    "  u32 load_base_addr: 4194304\n"
+    "}\n"
+    "Multiboot 2 info tag {\n"
+    "  u32 type: 1 (boot cmd line)\n"
+    "  u32 size: 21\n"
+    "  char cmdline[]: \"hello kernel\"\n"
+    "}\n"
+    "Multiboot 2 info tag {\n"
+    "  u32 type: 2 (boot loader name)\n"
+    "  u32 size: 30\n"
+    "  char name[]: \"GRUB 2.02-2ubuntu8.20\"\n"
+    "}\n"
+    "Multiboot 2 info tag {\n"
+    "  u32 type: 10 (APM table)\n"
+    "  u32 size: 28\n"
+    "  u16 version: 258\n"
+    "  u16 cseg: 61440\n"
+    "  u32 offset: 54479\n"
+    "  u16 cseg_16: 61440\n"
+    "  u16 dseg: 61440\n"
+    "  u16 flags: 3\n"
+    "  u16 cseg_len: 65520\n"
+    "  u16 cseg_16_len: 65520\n"
+    "  u16 dseg_len: 65520\n"
+    "}\n"
+    "Multiboot 2 info tag {\n"
+    "  u32 type: 3 (module)\n"
+    "  u32 size: 29\n"
+    "  u32 mod_start: 1056768\n"
+    "  u32 mod_end: 1061532\n"
+    "  char cmdline[]: \"hello module\"\n"
+    "}\n"
+    "Multiboot 2 info tag {\n"
+    "  u32 type: 3 (module)\n"
+    "  u32 size: 17\n"
+    "  u32 mod_start: 1064960\n"
+    "  u32 mod_end: 1069652\n"
+    "  char cmdline[]: \"\"\n"
+    "}\n"
+    "Multiboot 2 info tag {\n"
+    "  u32 type: 6 (memory map)\n"
+    "  u32 size: 160\n"
+    "  u32 entry_size: 24\n"
+    "  u32 entry_version: 0\n"
+    "  varies(entry_size) entries[]: [\n"
+    "    [0] entry: {\n"
+    "      u64 base_addr: 0\n"
+    "      u64 length: 654336\n"
+    "      u32 type: 1\n"
+    "      u32 reserved: 0\n"
+    "    }\n"
+    "    [1] entry: {\n"
+    "      u64 base_addr: 654336\n"
+    "      u64 length: 1024\n"
+    "      u32 type: 2\n"
+    "      u32 reserved: 0\n"
+    "    }\n"
+    "    [2] entry: {\n"
+    "      u64 base_addr: 983040\n"
+    "      u64 length: 65536\n"
+    "      u32 type: 2\n"
+    "      u32 reserved: 0\n"
+    "    }\n"
+    "    [3] entry: {\n"
+    "      u64 base_addr: 1048576\n"
+    "      u64 length: 133038080\n"
+    "      u32 type: 1\n"
+    "      u32 reserved: 0\n"
+    "    }\n"
+    "    [4] entry: {\n"
+    "      u64 base_addr: 134086656\n"
+    "      u64 length: 131072\n"
+    "      u32 type: 2\n"
+    "      u32 reserved: 0\n"
+    "    }\n"
+    "    [5] entry: {\n"
+    "      u64 base_addr: 4294705152\n"
+    "      u64 length: 262144\n"
+    "      u32 type: 2\n"
+    "      u32 reserved: 0\n"
+    "    }\n"
+    "  ]\n"
+    "}\n"
+    "Multiboot 2 info tag {\n"
+    "  u32 type: 9 (ELF symbols)\n"
+    "  u32 size: 420\n"
+    "  u32 num: 10\n"
+    "  u32 entsize: 40\n"
+    "  u32 shndx: 9\n"
+    "}\n"
+    "Multiboot 2 info tag {\n"
+    "  u32 type: 4 (basic memory info)\n"
+    "  u32 size: 16\n"
+    "  u32 mem_lower: 639\n"
+    "  u32 mem_upper: 129920\n"
+    "}\n"
+    "Multiboot 2 info tag {\n"
+    "  u32 type: 5 (BIOS boot device)\n"
+    "  u32 size: 20\n"
+    "  u32 biosdev: 224\n"
+    "  u32 partition: 4294967295\n"
+    "  u32 sub_partition: 4294967295\n"
+    "}\n"
+    "Multiboot 2 info tag {\n"
+    "  u32 type: 8 (framebuffer info)\n"
+    "  u32 size: 32\n"
+    "  u64 framebuffer_addr: 753664\n"
+    "  u32 framebuffer_pitch: 160\n"
+    "  u32 framebuffer_width: 80\n"
+    "  u32 framebuffer_height: 25\n"
+    "  u8 framebuffer_bpp: 16\n"
+    "  u8 framebuffer_type: 2\n"
+    "  u16 reserved: 0\n"
+    "}\n"
+    "Multiboot 2 info tag {\n"
+    "  u32 type: 14 (ACPI old RSDP)\n"
+    "  u32 size: 28\n"
+    "}\n"
+    "Multiboot 2 info tag {\n"
+    "  u32 type: 0 (none)\n"
+    "  u32 size: 8\n"
+    "}\n";
+
+static const char output2_part1[] =
+    "Multiboot 2 info {\n"
+    "  u32 size: 1816\n"
+    "  u32 reserved: 0\n"
+    "}\n"
+    "Multiboot 2 info tag {\n"
+    "  u32 type: 1 (boot cmd line)\n"
+    "  u32 size: 23\n"
+    "  char cmdline[]: \"Hello, Kernel!\"\n"
+    "}\n"
+    "Multiboot 2 info tag {\n"
+    "  u32 type: 2 (boot loader name)\n"
+    "  u32 size: 30\n"
+    "  char name[]: \"GRUB 2.02-2ubuntu8.20\"\n"
+    "}\n"
+    "Multiboot 2 info tag {\n"
+    "  u32 type: 3 (module)\n"
+    "  u32 size: 33\n"
+    "  u32 mod_start: 123\n"
+    "  u32 mod_end: 456\n"
+    "  char cmdline[]: \"Hello, Module 1!\"\n"
+    "}\n"
+    "Multiboot 2 info tag {\n"
+    "  u32 type: 3 (module)\n"
+    "  u32 size: 33\n"
+    "  u32 mod_start: 123\n"
+    "  u32 mod_end: 456\n"
+    "  char cmdline[]: \"Hello, Module 2!\"\n"
+    "}\n"
+    "Multiboot 2 info tag {\n"
+    "  u32 type: 4 (basic memory info)\n"
+    "  u32 size: 16\n"
+    "  u32 mem_lower: 123\n"
+    "  u32 mem_upper: 456\n"
+    "}\n"
+    "Multiboot 2 info tag {\n"
+    "  u32 type: 5 (BIOS boot device)\n"
+    "  u32 size: 20\n"
+    "  u32 biosdev: 0\n"
+    "  u32 partition: 1\n"
+    "  u32 sub_partition: 2\n"
+    "}\n"
+    "Multiboot 2 info tag {\n"
+    "  u32 type: 6 (memory map)\n"
+    "  u32 size: 160\n"
+    "  u32 entry_size: 24\n"
+    "  u32 entry_version: 0\n"
+    "  varies(entry_size) entries[]: [\n"
+    "    [0] entry: {\n"
+    "      u64 base_addr: 0\n"
+    "      u64 length: 654336\n"
+    "      u32 type: 1\n"
+    "      u32 reserved: 0\n"
+    "    }\n"
+    "    [1] entry: {\n"
+    "      u64 base_addr: 654336\n"
+    "      u64 length: 1024\n"
+    "      u32 type: 2\n"
+    "      u32 reserved: 0\n"
+    "    }\n"
+    "    [2] entry: {\n"
+    "      u64 base_addr: 983040\n"
+    "      u64 length: 65536\n"
+    "      u32 type: 2\n"
+    "      u32 reserved: 0\n"
+    "    }\n"
+    "    [3] entry: {\n"
+    "      u64 base_addr: 1048576\n"
+    "      u64 length: 133038080\n"
+    "      u32 type: 1\n"
+    "      u32 reserved: 0\n"
+    "    }\n"
+    "    [4] entry: {\n"
+    "      u64 base_addr: 134086656\n"
+    "      u64 length: 131072\n"
+    "      u32 type: 2\n"
+    "      u32 reserved: 0\n"
+    "    }\n"
+    "    [5] entry: {\n"
+    "      u64 base_addr: 4294705152\n"
+    "      u64 length: 262144\n"
+    "      u32 type: 2\n"
+    "      u32 reserved: 0\n"
+    "    }\n"
+    "  ]\n"
+    "}\n";
 
-static const char output2[] =
-    "Multiboot 2 info\n"
-    "  size: 1816\n"
-    "  reserved1: 0\n"
-    "Multiboot 2 info tag\n"
-    "  type: 1 (boot cmd line)\n"
-    "  size: 23\n"
-    "  cmdline: Hello, Kernel!\n"
-    "Multiboot 2 info tag\n"
-    "  type: 2 (boot loader name)\n"
-    "  size: 30\n"
-    "  name: GRUB 2.02-2ubuntu8.20\n"
-    "Multiboot 2 info tag\n"
-    "  type: 3 (module)\n"
-    "  size: 33\n"
-    "  start: 123\n"
-    "  end: 456\n"
-    "  cmdline: Hello, Module 1!\n"
-    "Multiboot 2 info tag\n"
-    "  type: 3 (module)\n"
-    "  size: 33\n"
-    "  start: 123\n"
-    "  end: 456\n"
-    "  cmdline: Hello, Module 2!\n"
-    "Multiboot 2 info tag\n"
-    "  type: 4 (basic memory info)\n"
-    "  size: 16\n"
-    "  mem lower: 123\n"
-    "  mem upper: 456\n"
-    "Multiboot 2 info tag\n"
-    "  type: 5 (BIOS boot device)\n"
-    "  size: 20\n"
-    "  bios dev: 0\n"
-    "  partition: 1\n"
-    "  sub_partition: 2\n"
-    "Multiboot 2 info tag\n"
-    "  type: 6 (memory map)\n"
-    "  size: 160\n"
-    "  entry size: 24\n"
-    "  entry version: 0\n"
-    "  entries:\n"
-    "    entry 0\n"
-    "      base addr: 0\n"
-    "      length: 654336\n"
-    "      type: 1\n"
-    "      reserved1: 0\n"
-    "    entry 1\n"
-    "      base addr: 654336\n"
-    "      length: 1024\n"
-    "      type: 2\n"
-    "      reserved1: 0\n"
-    "    entry 2\n"
-    "      base addr: 983040\n"
-    "      length: 65536\n"
-    "      type: 2\n"
-    "      reserved1: 0\n"
-    "    entry 3\n"
-    "      base addr: 1048576\n"
-    "      length: 133038080\n"
-    "      type: 1\n"
-    "      reserved1: 0\n"
-    "    entry 4\n"
-    "      base addr: 134086656\n"
-    "      length: 131072\n"
-    "      type: 2\n"
-    "      reserved1: 0\n"
-    "    entry 5\n"
-    "      base addr: 4294705152\n"
-    "      length: 262144\n"
-    "      type: 2\n"
-    "      reserved1: 0\n"
-    "Multiboot 2 info tag\n"
-    "  type: 7 (VBE info)\n"
-    "  size: 784\n"
-    "  VBE mode: 0\n"
-    "  VBE interface seg: 123\n"
-    "  VBE interface off: 456\n"
-    "  VBE interface len: 789\n"
-    "Multiboot 2 info tag\n"
-    "  type: 8 (framebuffer info)\n"
-    "  size: 39\n"
-    "  framebuffer addr: 123\n"
-    "  framebuffer pitch: 456\n"
-    "  framebuffer width: 123\n"
-    "  framebuffer height: 456\n"
-    "  framebuffer bpp: 8\n"
-    "  framebuffer type: 1\n"
-    "  reserved1: 0\n"
-    "Multiboot 2 info tag\n"
-    "  type: 9 (ELF symbols)\n"
-    "  size: 420\n"
-    "  num: 10\n"
-    "  entsize: 0\n"
-    "  shndx: 40\n"
-    "  reserved1: 0\n"
-    "Multiboot 2 info tag\n"
-    "  type: 10 (APM table)\n"
-    "  size: 28\n"
-    "  version: 0\n"
-    "  cseg: 123\n"
-    "  offset: 456\n"
-    "  cseg 16: 789\n"
-    "  dseg: 123\n"
-    "  flags: 1\n"
-    "  cseg len: 456\n"
-    "  cseg 16 len: 789\n"
-    "  dseg len: 123\n"
-    "Multiboot 2 info tag\n"
-    "  type: 11 (EFI 32bit system table ptr)\n"
-    "  size: 12\n"
-    "Multiboot 2 info tag\n"
-    "  type: 12 (EFI 64bit system table ptr)\n"
-    "  size: 16\n"
-    "Multiboot 2 info tag\n"
-    "  type: 13 (SMBIOS tables)\n"
-    "  size: 24\n"
-    "  major: 1\n"
-    "  minor: 2\n"
-    "  reserved1: {0, 0, 0, 0, 0, 0}\n"
-    "Multiboot 2 info tag\n"
-    "  type: 14 (ACPI old RSDP)\n"
-    "  size: 16\n"
-    "Multiboot 2 info tag\n"
-    "  type: 15 (ACPI new RSDP)\n"
-    "  size: 16\n"
-    "Multiboot 2 info tag\n"
-    "  type: 16 (networking info)\n"
-    "  size: 16\n"
-    "Multiboot 2 info tag\n"
-    "  type: 17 (EFI memory map)\n"
-    "  size: 24\n"
-    "Multiboot 2 info tag\n"
-    "  type: 18 (EFI boot services not terminated)\n"
-    "  size: 8\n"
-    "Multiboot 2 info tag\n"
-    "  type: 19 (EFI 32bit image handle ptr)\n"
-    "  size: 12\n"
-    "Multiboot 2 info tag\n"
-    "  type: 20 (EFI 64bit image handle ptr)\n"
-    "  size: 16\n"
-    "Multiboot 2 info tag\n"
-    "  type: 21 (image load base phys addr)\n"
-    "  size: 12\n"
-    "  load base addr: 123\n"
-    "Multiboot 2 info tag\n"
-    "  type: 0 (none)\n"
-    "  size: 8\n";
+static const char output2_part2[] =
+    "Multiboot 2 info tag {\n"
+    "  u32 type: 7 (VBE info)\n"
+    "  u32 size: 784\n"
+    "  u16 vbe_mode: 0\n"
+    "  u16 vbe_interface_seg: 123\n"
+    "  u16 vbe_interface_off: 456\n"
+    "  u16 vbe_interface_len: 789\n"
+    "  u8 vbe_control_info[]: [\n"
+    "    0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0  \n"
+    "    1   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0  \n"
+    "    12  0   0   0   0   0   0   0   0   0   0   0   0   0   0   0  \n"
+    "    123 0   0   0   0   0   0   0   0   0   0   0   0   0   0   0  \n"
+    "    0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   1  \n"
+    "    0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   12 \n"
+    "    0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   123\n"
+    "    0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0  \n"
+    "    0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0  \n"
+    "    0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0  \n"
+    "    0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0  \n"
+    "    0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0  \n"
+    "    0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0  \n"
+    "    0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0  \n"
+    "    0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0  \n"
+    "    0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0  \n"
+    "    0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0  \n"
+    "    0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0  \n"
+    "    0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0  \n"
+    "    0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0  \n"
+    "    0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0  \n"
+    "    0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0  \n"
+    "    0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0  \n"
+    "    0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0  \n"
+    "    0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0  \n"
+    "    0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0  \n"
+    "    0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0  \n"
+    "    0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0  \n"
+    "    0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0  \n"
+    "    0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0  \n"
+    "    0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0  \n"
+    "    0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0  \n"
+    "  ]\n"
+    "  u8 vbe_mode_info[]: [\n"
+    "    0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0  \n"
+    "    3   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0  \n"
+    "    32  0   0   0   0   0   0   0   0   0   0   0   0   0   0   0  \n"
+    "    255 0   0   0   0   0   0   0   0   0   0   0   0   0   0   0  \n"
+    "    0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   3  \n"
+    "    0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   32 \n"
+    "    0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   255\n"
+    "    0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0  \n"
+    "    0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0  \n"
+    "    0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0  \n"
+    "    0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0  \n"
+    "    0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0  \n"
+    "    0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0  \n"
+    "    0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0  \n"
+    "    0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0  \n"
+    "    0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0  \n"
+    "  ]\n"
+    "}\n";
+
+static const char output2_part3[] =
+    "Multiboot 2 info tag {\n"
+    "  u32 type: 8 (framebuffer info)\n"
+    "  u32 size: 40\n"
+    "  u64 framebuffer_addr: 123\n"
+    "  u32 framebuffer_pitch: 456\n"
+    "  u32 framebuffer_width: 123\n"
+    "  u32 framebuffer_height: 456\n"
+    "  u8 framebuffer_bpp: 8\n"
+    "  u8 framebuffer_type: 1\n"
+    "  u16 reserved: 0\n"
+    "}\n"
+    "Multiboot 2 info tag {\n"
+    "  u32 type: 9 (ELF symbols)\n"
+    "  u32 size: 420\n"
+    "  u32 num: 10\n"
+    "  u32 entsize: 40\n"
+    "  u32 shndx: 9\n"
+    "}\n"
+    "Multiboot 2 info tag {\n"
+    "  u32 type: 10 (APM table)\n"
+    "  u32 size: 28\n"
+    "  u16 version: 0\n"
+    "  u16 cseg: 123\n"
+    "  u32 offset: 456\n"
+    "  u16 cseg_16: 789\n"
+    "  u16 dseg: 123\n"
+    "  u16 flags: 1\n"
+    "  u16 cseg_len: 456\n"
+    "  u16 cseg_16_len: 789\n"
+    "  u16 dseg_len: 123\n"
+    "}\n"
+    "Multiboot 2 info tag {\n"
+    "  u32 type: 11 (EFI 32bit system table ptr)\n"
+    "  u32 size: 12\n"
+    "  u32 pointer: 0\n"
+    "}\n"
+    "Multiboot 2 info tag {\n"
+    "  u32 type: 12 (EFI 64bit system table ptr)\n"
+    "  u32 size: 16\n"
+    "  u64 pointer: 0\n"
+    "}\n"
+    "Multiboot 2 info tag {\n"
+    "  u32 type: 13 (SMBIOS tables)\n"
+    "  u32 size: 24\n"
+    "  u8 major: 1\n"
+    "  u8 minor: 2\n"
+    "  u8 reserved[6]: [0, 0, 0, 0, 0, 0]\n"
+    "}\n"
+    "Multiboot 2 info tag {\n"
+    "  u32 type: 14 (ACPI old RSDP)\n"
+    "  u32 size: 16\n"
+    "}\n"
+    "Multiboot 2 info tag {\n"
+    "  u32 type: 15 (ACPI new RSDP)\n"
+    "  u32 size: 16\n"
+    "}\n"
+    "Multiboot 2 info tag {\n"
+    "  u32 type: 16 (networking info)\n"
+    "  u32 size: 16\n"
+    "}\n"
+    "Multiboot 2 info tag {\n"
+    "  u32 type: 17 (EFI memory map)\n"
+    "  u32 size: 24\n"
+    "  u32 descriptor_size: 123\n"
+    "  u32 descriptor_version: 1\n"
+    "}\n"
+    "Multiboot 2 info tag {\n"
+    "  u32 type: 18 (EFI boot services not terminated)\n"
+    "  u32 size: 8\n"
+    "}\n"
+    "Multiboot 2 info tag {\n"
+    "  u32 type: 19 (EFI 32bit image handle ptr)\n"
+    "  u32 size: 12\n"
+    "  u32 pointer: 0\n"
+    "}\n"
+    "Multiboot 2 info tag {\n"
+    "  u32 type: 20 (EFI 64bit image handle ptr)\n"
+    "  u32 size: 16\n"
+    "  u64 pointer: 0\n"
+    "}\n"
+    "Multiboot 2 info tag {\n"
+    "  u32 type: 21 (image load base phys addr)\n"
+    "  u32 size: 12\n"
+    "  u32 load_base_addr: 123\n"
+    "}\n"
+    "Multiboot 2 info tag {\n"
+    "  u32 type: 0 (none)\n"
+    "  u32 size: 8\n"
+    "}\n";
 
 void test_main()
 {
+    {
+        FILE *const fd = popen("./multiboot2_info_print0", "r");
+        assert(fd != NULL);
+
+        for (const char *ch = output0; *ch; ++ch) {
+            assert(fgetc(fd) == *ch);
+        }
+
+        const int status = pclose(fd);
+        assert(status == 0);
+    }
+
     {
         FILE *const fd = popen("./multiboot2_info_print1", "r");
         assert(fd != NULL);
@@ -283,6 +419,15 @@ void test_main()
     }
 
     {
+        const size_t part1_len = strlen(output2_part1);
+        const size_t part2_len = strlen(output2_part2);
+        const size_t part3_len = strlen(output2_part3);
+        char *const output2 = malloc(1 + part1_len + part2_len + part3_len);
+        assert(output2);
+        strcpy(output2, output2_part1);
+        strcat(output2, output2_part2);
+        strcat(output2, output2_part3);
+
         FILE *const fd = popen("./multiboot2_info_print2", "r");
         assert(fd != NULL);
 
diff --git a/tests/test_multiboot2_info_validation.c b/tests/test_multiboot2_info_validation.c
index 8ccd9ebd..45017566 100644
--- a/tests/test_multiboot2_info_validation.c
+++ b/tests/test_multiboot2_info_validation.c
@@ -328,7 +328,7 @@ tag_bios_boot_device_valid = {
         .type = KERNAUX_MULTIBOOT2_ITAG_BIOS_BOOT_DEVICE,
         .size = 20,
     },
-    .bios_dev = 123,
+    .biosdev = 123,
     .partition = 456,
     .sub_partition = 789,
 };
@@ -339,7 +339,7 @@ tag_bios_boot_device_invalid_type = {
         .type = KERNAUX_MULTIBOOT2_ITAG_NONE,
         .size = 20,
     },
-    .bios_dev = 123,
+    .biosdev = 123,
     .partition = 456,
     .sub_partition = 789,
 };
@@ -350,7 +350,7 @@ tag_bios_boot_device_invalid_size = {
         .type = KERNAUX_MULTIBOOT2_ITAG_BIOS_BOOT_DEVICE,
         .size = 21,
     },
-    .bios_dev = 123,
+    .biosdev = 123,
     .partition = 456,
     .sub_partition = 789,
 };
@@ -530,15 +530,14 @@ tag_vbe_info_invalid_size = {
  ******************/
 
 static const struct KernAux_Multiboot2_ITag_ELFSymbols
-tag_elf_symbols_with_zero_ent_size_valid = {
+tag_elf_symbols_with_zero_entsize_valid = {
     .base = {
         .type = KERNAUX_MULTIBOOT2_ITAG_ELF_SYMBOLS,
-        .size = 16,
+        .size = 20,
     },
     .num = 0,
-    .ent_size = 0,
+    .entsize = 0,
     .shndx = 0,
-    .reserved1 = 0,
 };
 
 /**************
@@ -551,7 +550,7 @@ static const struct {
 } KERNAUX_PACKED multiboot2_empty_valid = {
     .multiboot2_info = {
         .total_size = 8 + 8,
-        .reserved1 = 0,
+        .reserved = 0,
     },
     .tag_none = {
         .base = {
@@ -568,7 +567,7 @@ static const struct {
 } KERNAUX_PACKED multiboot2_with_some_additional_tag_valid = {
     .multiboot2_info = {
         .total_size = 8 + 16 + 8,
-        .reserved1 = 0,
+        .reserved = 0,
     },
     .tag_basic_memory_info = {
         .base = {
@@ -595,7 +594,7 @@ static const struct {
 } KERNAUX_PACKED multiboot2_with_more_additional_tags_valid = {
     .multiboot2_info = {
         .total_size = 8 + 16 + (20 + 4) + 8,
-        .reserved1 = 0,
+        .reserved = 0,
     },
     .tag_basic_memory_info = {
         .base = {
@@ -610,7 +609,7 @@ static const struct {
             .type = KERNAUX_MULTIBOOT2_ITAG_BIOS_BOOT_DEVICE,
             .size = 20,
         },
-        .bios_dev = 123,
+        .biosdev = 123,
         .partition = 456,
         .sub_partition = 789,
     },
@@ -628,7 +627,7 @@ static const struct {
 } KERNAUX_PACKED multiboot2_empty_invalid_size = {
     .multiboot2_info = {
         .total_size = 8,
-        .reserved1 = 0,
+        .reserved = 0,
     },
     .tag_none = {
         .base = {
@@ -641,7 +640,7 @@ static const struct {
 static const struct KernAux_Multiboot2_Info
 multiboot2_without_none_tag_invalid = {
     .total_size = 8,
-    .reserved1 = 0,
+    .reserved = 0,
 };
 
 static const struct {
@@ -650,7 +649,7 @@ static const struct {
 } KERNAUX_PACKED multiboot2_with_invalid_last_tag_invalid = {
     .multiboot2_info = {
         .total_size = 8 + 16,
-        .reserved1 = 0,
+        .reserved = 0,
     },
     .tag_basic_memory_info = {
         .base = {
@@ -672,7 +671,7 @@ static const struct {
 } KERNAUX_PACKED multiboot2_with_early_none_tag_invalid = {
     .multiboot2_info = {
         .total_size = 8 + 16 + 8 + (20 + 4) + 8,
-        .reserved1 = 0,
+        .reserved = 0,
     },
     .tag_basic_memory_info = {
         .base = {
@@ -693,7 +692,7 @@ static const struct {
             .type = KERNAUX_MULTIBOOT2_ITAG_BIOS_BOOT_DEVICE,
             .size = 20,
         },
-        .bios_dev = 123,
+        .biosdev = 123,
         .partition = 456,
         .sub_partition = 789,
     },
@@ -714,7 +713,7 @@ static const struct {
 } KERNAUX_PACKED multiboot2_with_more_additional_tags_invalid_size_too_big = {
     .multiboot2_info = {
         .total_size = 8 + 16 + (20 + 4) + 8 + 1,
-        .reserved1 = 0,
+        .reserved = 0,
     },
     .tag_basic_memory_info = {
         .base = {
@@ -729,7 +728,7 @@ static const struct {
             .type = KERNAUX_MULTIBOOT2_ITAG_BIOS_BOOT_DEVICE,
             .size = 20,
         },
-        .bios_dev = 123,
+        .biosdev = 123,
         .partition = 456,
         .sub_partition = 789,
     },
@@ -750,7 +749,7 @@ static const struct {
 } KERNAUX_PACKED multiboot2_with_more_additional_tags_invalid_size_too_small = {
     .multiboot2_info = {
         .total_size = 8 + 16 + (20 + 4) + 8 - 1,
-        .reserved1 = 0,
+        .reserved = 0,
     },
     .tag_basic_memory_info = {
         .base = {
@@ -765,7 +764,7 @@ static const struct {
             .type = KERNAUX_MULTIBOOT2_ITAG_BIOS_BOOT_DEVICE,
             .size = 20,
         },
-        .bios_dev = 123,
+        .biosdev = 123,
         .partition = 456,
         .sub_partition = 789,
     },
@@ -955,7 +954,7 @@ void test_main()
     ));
 
     assert(KernAux_Multiboot2_ITagBase_is_valid(
-        &tag_elf_symbols_with_zero_ent_size_valid.base
+        &tag_elf_symbols_with_zero_entsize_valid.base
     ));
 
     // Tag_None
@@ -1124,6 +1123,6 @@ void test_main()
 
 
     assert(KernAux_Multiboot2_ITag_ELFSymbols_is_valid(
-        &tag_elf_symbols_with_zero_ent_size_valid
+        &tag_elf_symbols_with_zero_entsize_valid
     ));
 }