diff --git a/Makefile b/Makefile
index 0ca1e7bf777d275ad240668770d019fa746d0dbc..aaef11cce026a1233240c3befe9a61c621a33e81 100644
--- a/Makefile
+++ b/Makefile
@@ -56,6 +56,7 @@ KERNEL_DEPS   := ${BOOT_OBJ} ${KERNEL_LIB}
 LD_M_x86_64   := elf_x86_64
 LD_M_x86      := elf_i386
 LD_FLAGS      ?=
+#LD_FLAGS      += --whole-archive
 LD_FLAGS      += ${KERNEL_DEPS}
 LD_FLAGS      += -o ${KERNEL_ELF}
 LD_FLAGS      += --gc-sections
@@ -82,6 +83,13 @@ QEMU_FLAGS    += -kernel ${KERNEL_ELF}
 qemu : ${KERNEL_ELF}
 	${QEMU_${ARCH}} ${QEMU_FLAGS}
 
-.PHONY : build qemu
+# objdump
+objdump : ${KERNEL_ELF}
+	objdump -D ${KERNEL_ELF}
+
+readelf : ${KERNEL_ELF}
+	readelf --all ${KERNEL_ELF}
+
+.PHONY : build qemu objdump readelf
 
 # end
diff --git a/src/arch/x86_64/link.ld b/src/arch/x86_64/link.ld
index ae313ee218f5225a7688de46aa7efbee9c872eb4..874eb9bed9f802b5e4d5e33e116831be639ed98d 100644
--- a/src/arch/x86_64/link.ld
+++ b/src/arch/x86_64/link.ld
@@ -3,8 +3,12 @@ ENTRY(start)
 SECTIONS {
     . = 1M;
 
+    .multiboot : ALIGN(4k) {
+        KEEP(*(.multiboot))
+        KEEP(*(.multiboot_rust))
+    }
+
     .boot : ALIGN(4k) {
-        KEEP(*(.multiboot1))
         *(.boot)
     }
 
diff --git a/src/arch/x86_64/mod.rs b/src/arch/x86_64/mod.rs
new file mode 100644
index 0000000000000000000000000000000000000000..f3dcc9932f43b006432368a4ca24923103ec4405
--- /dev/null
+++ b/src/arch/x86_64/mod.rs
@@ -0,0 +1,12 @@
+// both cannot coexist (AFAIK.) and QEMU
+// cannot boot multiboot2 kernels directly
+//
+// so multiboot1 it is .. temporarily
+
+// multiboot1 header and glue code
+#[cfg(all())]
+mod multiboot1;
+
+// multiboot2 header and glue code
+#[cfg(any())]
+mod multiboot2;
diff --git a/src/arch/x86_64/multiboot1.rs b/src/arch/x86_64/multiboot1.rs
new file mode 100644
index 0000000000000000000000000000000000000000..3a61044346ae6ccf6ea4a6270223d9bfbeb605c3
--- /dev/null
+++ b/src/arch/x86_64/multiboot1.rs
@@ -0,0 +1,82 @@
+use core::ffi::CStr;
+
+#[allow(unused)]
+#[repr(C)]
+struct Multiboot1Header {
+    magic: u32,
+    flags: u32,
+    checksum: u32,
+
+    _unused: [u32; 5], // header_addr, load_addr, load_end_addr, bss_end_addr, entry_addr
+
+    mode_type: u32,
+    width: u32,
+    height: u32,
+    depth: u32,
+}
+
+const MAGIC: u32 = 0x1BADB002;
+const ALIGN: u32 = 1 << 0;
+const MEMINFO: u32 = 1 << 1;
+const VIDEO: u32 = 1 << 2;
+const FLAGS: u32 = ALIGN | MEMINFO | VIDEO;
+
+#[used]
+#[no_mangle]
+#[link_section = ".multiboot"]
+static MULTIBOOT1_HEADER: Multiboot1Header = Multiboot1Header {
+    magic: MAGIC,
+    flags: FLAGS,
+    checksum: (0x100000000 - (MAGIC + FLAGS) as u64) as u32,
+
+    _unused: [0; 5],
+
+    mode_type: 0, // 0 = linear graphics
+    width: 0,     // 0 = no preference
+    height: 0,    // 0 = no preference
+    depth: 0,     // 0 = no preference
+};
+
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+struct Multiboot1Information {
+    flags: u32,
+    optional: [u8; 112],
+}
+
+impl Multiboot1Information {
+    fn bootloader_name(&self) -> Option<&str> {
+        if (self.flags & 1 << 9) != 0 {
+            let ptr = u32::from_le_bytes((self.optional[60..=64]).try_into().ok()?) as _;
+            let s = unsafe { CStr::from_ptr(ptr) };
+            let s = s.to_str().ok()?;
+
+            Some(s)
+        } else {
+            None
+        }
+    }
+
+    fn framebuffer(&self) -> Option<&[u8]> {
+        if (self.flags & 1 << 12) != 0 {
+            Some(&self.optional[84..])
+        } else {
+            None
+        }
+    }
+}
+
+#[no_mangle]
+extern "C" fn kernel_main(magic_num: u64) {
+    let mb1_info_pointer = magic_num & u32::MAX as u64;
+    let mb1_info = unsafe { *(mb1_info_pointer as *const Multiboot1Information) };
+
+    crate::println!(
+        "\0{:?}\n{:#b}\n{:?}",
+        mb1_info.bootloader_name(),
+        mb1_info.flags,
+        mb1_info.framebuffer(),
+    );
+
+    crate::kernel_main();
+}
diff --git a/src/arch/x86_64/multiboot2.rs b/src/arch/x86_64/multiboot2.rs
new file mode 100644
index 0000000000000000000000000000000000000000..892aac2015781eb8740eab28c1353312f3cfa986
--- /dev/null
+++ b/src/arch/x86_64/multiboot2.rs
@@ -0,0 +1,32 @@
+#[allow(unused)]
+#[repr(C)]
+pub struct Multiboot2Header {
+    magic: u32,
+    architecture: u32,
+    header_length: u32,
+    checksum: u32,
+    end_tag_0: u32,
+    end_tag_1: u32,
+}
+
+const MAGIC: u32 = 0xE85250D6;
+const ARCH: u32 = 0; // 32 bit (protected mode)
+const LEN: u32 = core::mem::size_of::<Multiboot2Header>() as u32;
+const CHECKSUM: u32 = (0x100000000 - (MAGIC + ARCH + LEN) as u64) as u32;
+
+#[used]
+#[no_mangle]
+#[link_section = ".multiboot"]
+pub static MULTIBOOT2_HEADER: Multiboot2Header = Multiboot2Header {
+    magic: MAGIC,
+    architecture: ARCH,
+    header_length: LEN,
+    checksum: CHECKSUM,
+    end_tag_0: 0,
+    end_tag_1: 8,
+};
+
+#[no_mangle]
+pub extern "C" fn kernel_main(_magic_num: u64) {
+    crate::kernel_main();
+}
diff --git a/src/arch/x86_64/start.asm b/src/arch/x86_64/start.asm
index 6bfa8215fa2cb6f414678d6be8b3e4d2e88ddce1..4bcb16a1cf4400c5567236c7066abe21b6555037 100644
--- a/src/arch/x86_64/start.asm
+++ b/src/arch/x86_64/start.asm
@@ -2,38 +2,13 @@
     extern kernel_main
 
     ;; ----------
-    ;; Multiboot2
-    ;; ----------
-
-    section .multiboot2
-
-header_start:
-    dd 0xE85250D6                                             ;; multiboot2 magic
-    dd 0                                                      ;; arch: 32 bit (protected mode)
-    dd header_end - header_start                              ;; header length
-    dd 0x100000000 - (0xE85250D6 + header_end - header_start) ;; checksum
-
-    dd 0 ;; end tag
-    dd 8
-header_end:
-
-    ;; ----------
-    ;; Multiboot1
+    ;; Boot entry
     ;; ----------
 
-    section .multiboot1
-    dd 0x1BADB002                     ;; multiboot1 magic
-    dd 3                              ;; flags
-    dd 0x100000000 - (0x1BADB002 + 3) ;; checksum
-
     section .boot
     global start
     bits 32
 
-    ;; ----------
-    ;; Boot entry
-    ;; ----------
-
 start:
     cli
     cld
@@ -43,6 +18,8 @@ start:
 
     ;; support checks
     call check_multiboot1
+    push ebx
+    push ebx
     call check_cpuid
     call check_long_mode
 
@@ -201,7 +178,8 @@ long_mode_start:
 	; print 'OK'
 	mov dword [0xb8000], 0x2F4B2F4F
 
-    mov rdi, 42
+    ;; take the multiboot info struct pointer
+    pop rdi
 	call kernel_main
 .halt:
 	hlt
diff --git a/src/lib.rs b/src/lib.rs
index ed0fe1bb3178cc4a8f8e215234b3cd6816c67dc7..82848fbdcbeb0a92a347c671f894b03a3db9f0e1 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,6 +1,9 @@
 #![no_std]
 #![no_main]
 
+#[path = "arch/x86_64/mod.rs"]
+pub mod arch;
+
 pub mod vga;
 
 #[panic_handler]
@@ -8,12 +11,11 @@ fn panic_handler(_: &core::panic::PanicInfo) -> ! {
     loop {}
 }
 
-#[no_mangle]
-#[link_section = ".boot"]
-pub extern "C" fn kernel_main(magic_num: u64) -> ! {
+fn kernel_main() -> ! {
     // null byte clears the VGA buffer
-    print!("\0");
-    println!("Hello from Hyperion, magic_num = {magic_num}");
+    // print!("\0");
+
+    // println!("Hello from Hyperion, pointer = {pointer:#x}, fb = {fb:#x}");
 
     loop {
         unsafe {