diff --git a/Makefile b/Makefile
index 22091c6bfd9ecb5e395e2616b94a778892009fed..c29155a11a5d065d5b3c9bcea3043f55e07816ff 100644
--- a/Makefile
+++ b/Makefile
@@ -5,7 +5,7 @@ bootloader-legacy:
 	$(MAKE) -C bootloader-legacy
 
 bootloader-uefi:
-	$(MAKE) -C bootloader-legacy
+	$(MAKE) -C bootloader-uefi
 
 kernel:
 	$(MAKE) -C kernel
diff --git a/NOTE b/NOTE
deleted file mode 100644
index 84640530fed2af626a620256065015e97d76fd3c..0000000000000000000000000000000000000000
--- a/NOTE
+++ /dev/null
@@ -1,2 +0,0 @@
-dd if=/dev/zero of=out.img bs=512K count=16
-VBoxManage convertfromraw out.img out.vdi --format vdi
diff --git a/README.md b/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..65d767473ab9d42adc0b18df7cabd03c93ec832e
--- /dev/null
+++ b/README.md
@@ -0,0 +1,41 @@
+# notes
+
+## register usage rule
+
+volatile (caller saved): rax, rcx, rdx
+
+non-volatile: others
+
+arguments and return value: rax, rcx, rdx, stack
+
+## bootloader(legacy) memory model
+
+- common
+
+0x7c00 - 0x7e00 : bootloader.img, executes from beginning 0x7c00  
+0x7e00 - 0x17c00 : kernel.img, called by bootloader, from beginning 0x7e00
+
+- bios age
+
+![](../res/1.png)
+
+- 32bit protected mode age
+
+Just used this mode to launch 64bit long mode. No paging enabled. 
+
+- 64bit long mode age
+
+0x1000 - 0x5000 : 64bit long mode paging table**s**
+0x00000000 - 0x00200000 : 512 * 4K pages, before the kernel initializing page table in C++.
+
+## bootloader(legacy) disk model
+
+0-511Byte : bootloader.img from boot.asm, MBR flag  
+512B - 64KiB : kernel.img. executes from 512Byte first instruction. 
+
+## works and TODO
+
+Currently, paging for 32bit bootloader not implemented. Not planned. 
+
+kernel currently working on both 32bit(without paging) and 64bit mode. But in the future, will work only in 64bit mode. 
+
diff --git a/bootloader-legacy/Makefile b/bootloader-legacy/Makefile
index ce6142a3fe43fb3407c00dc7d4e2c76796b12804..8fa0ceedd9f63dadef517e984786b05031cca5c4 100644
--- a/bootloader-legacy/Makefile
+++ b/bootloader-legacy/Makefile
@@ -1,6 +1,11 @@
 build:
 	nasm -f bin boot.asm -o boot.img
 
+build_x86:
+
+build_x86_64:
+
+
 run: build
 	qemu-system-x86_64 boot.img
 
diff --git a/bootloader-legacy/boot.asm b/bootloader-legacy/boot.asm
index 41043c6ae76886172467fcccf8a58bb74d36f625..58d580180a55f705942740cb05a38a8212d39eab 100644
--- a/bootloader-legacy/boot.asm
+++ b/bootloader-legacy/boot.asm
@@ -70,7 +70,7 @@ _load_kern:
 disk_io_error:
     mov bx, _motd_disk_error
     call println_bios
-    jmp _stall
+    jmp $
 
 
 
@@ -100,26 +100,56 @@ _prot_begin:
     mov ebx, _motd_32
     call println_vga
 
+    ; Test if 64bit available
+    call test_support_long_mode
+    cmp eax, 0
+    je _test_passed
+    mov ebx, _motd_no_long_mode
+    call println_vga
+    jmp _call_kern_32
+_test_passed:
+
+    jmp inline_enter_long_mode
+%include "./inline_x64lib.inc"
+    jmp _call_kern_64
+
+[bits 32]
+_call_kern_32:
     ; Enter the kernel. This should never return.
     call KERN_ADDR
 
     ; Kernel returns.
     mov ebx, _motd_endk
     call println_vga
+    jmp $
 
-_stall:
+[bits 64]
+_call_kern_64:
+    ; Enter the kernel. This should never return.
+    call KERN_ADDR
+
+    ; Kernel returns.
+    ;mov ebx, _motd_endk
+    ;call println_vga
+    ; TODO: add 64bit println_vga and error msg
     jmp $
 
+
 _motd_disk_error:
-    db 'DISK_IO_ERROR', 0x0
+    db 'MED', 0x0
 _motd_32:
-    db '[LOAD KERN SUCC] [ENTER X86 MODE SUCC]', 0x0
+    db 'M32', 0x0
 _motd_kern_ok:
-    db '[LOAD KERN SUCC]', 0x0
+    db 'MKN', 0x0
 _motd_endk:
-    db '[LOAD KERN SUCC] [ENTER X86 MODE SUCC] [KERN EXITED]', 0x0
+    db 'MEK', 0x0
+_motd_no_long_mode:
+    db 'MNL', 0x0
 _boot_drive_id:
     db 0x0
+
+_motd_debug_point:
+    db 'MDB', 0x0
     
 %include "./mbr_end.inc"    
 
diff --git a/bootloader-legacy/inline_x64lib.inc b/bootloader-legacy/inline_x64lib.inc
new file mode 100644
index 0000000000000000000000000000000000000000..463e4879745717bf8ccfb315b48d575bdde1d200
--- /dev/null
+++ b/bootloader-legacy/inline_x64lib.inc
@@ -0,0 +1,167 @@
+
+; requires: str.32.inc
+; runs in 32bit protection mode
+
+;test_cpuid_support:
+;    ; Check if CPUID is supported by attempting to flip the ID bit (bit 21) in
+;    ; the FLAGS register. If we can flip it, CPUID is available.
+; 
+;    ; Copy FLAGS in to EAX via stack
+;    pushfd
+;    pop eax
+; 
+;    ; Copy to ECX as well for comparing later on
+;    mov ecx, eax
+; 
+;    ; Flip the ID bit
+;    xor eax, 1 << 21
+; 
+;    ; Copy EAX to FLAGS via the stack
+;    push eax
+;    popfd
+; 
+;    ; Copy FLAGS back to EAX (with the flipped bit if CPUID is supported)
+;    pushfd
+;    pop eax
+; 
+;    ; Restore FLAGS from the old version stored in ECX (i.e. flipping the ID bit
+;    ; back if it was ever flipped).
+;    push ecx
+;    popfd
+; 
+;    ; Compare EAX and ECX. If they are equal then that means the bit wasn't
+;    ; flipped, and CPUID isn't supported.
+;    sub eax, ecx
+;    ; eax != 0 if CPUID supported, eax==0 if not supported. 
+;    ret
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+test_support_long_mode:
+    ; test if possible to enter x64 mode. 
+    ; return value in eax. 
+    ; return 0 = OK. 1 = CPUID_NOT_AVAIL, 2 = CPUID_EXT_NOT_AVAIL, 3 = LONGMODE_NOT_AVAIL
+;    call test_cpuid_support
+;    cmp eax, 0
+;    jne _cpuid_supported
+;    mov eax, 1
+;    ret
+;_cpuid_supported:
+    mov eax, 0x80000000     ; Set the A-register to 0x80000000.
+    cpuid                   ; CPU identification.
+    cmp eax, 0x80000001     ; Compare the A-register with 0x80000001.
+    jb _fail_no_long_mode_2 ; It is less, there is no long mode.
+    mov eax, 0x80000001     ; Set the A-register to 0x80000001.
+    cpuid                   ; CPU identification.
+    test edx, 1 << 29       ; Test if the LM-bit, which is bit 29, is set in the D-register.
+    jz _fail_no_long_mode_3 ; They aren't, there is no long mode.
+    mov eax, 0
+    ret
+_fail_no_long_mode_2:
+    mov eax, 2
+    ret
+_fail_no_long_mode_3:
+    mov eax, 3
+    ret
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+GDT64:                           ; Global Descriptor Table (64-bit).
+    .Null: equ $ - GDT64         ; The null descriptor.
+    dw 0xFFFF                    ; Limit (low).
+    dw 0                         ; Base (low).
+    db 0                         ; Base (middle)
+    db 0                         ; Access.
+    db 1                         ; Granularity.
+    db 0                         ; Base (high).
+    .Code: equ $ - GDT64         ; The code descriptor.
+    dw 0                         ; Limit (low).
+    dw 0                         ; Base (low).
+    db 0                         ; Base (middle)
+    db 10011010b                 ; Access (exec/read).
+    db 10101111b                 ; Granularity, 64 bits flag, limit19:16.
+    db 0                         ; Base (high).
+    .Data: equ $ - GDT64         ; The data descriptor.
+    dw 0                         ; Limit (low).
+    dw 0                         ; Base (low).
+    db 0                         ; Base (middle)
+    db 10010010b                 ; Access (read/write).
+    db 00000000b                 ; Granularity.
+    db 0                         ; Base (high).
+    .Pointer:                    ; The GDT-pointer.
+    dw $ - GDT64 - 1             ; Limit.
+    dq GDT64                     ; Base.
+
+inline_enter_long_mode:
+    ;;;;;;;;;;;;; section 1: paging
+    ; disable paging in 32bit protected mode (if any)
+    mov eax, cr0
+    and eax, 01111111111111111111111111111111b     ; Clear the PG-bit, which is bit 31. 
+    mov cr0, eax
+
+    ; prepare paging for long mode. Using memory 0x1000 - 0x5000, to put 4-level page tables.
+    mov edi, 0x1000    ; begin addr
+    xor eax, eax
+    mov ecx, 0x1000    ; size
+    rep stosd          ; memset, 0x1000 * 4Bytes to set this memory area to ZERO.
+
+    ; set PML4T
+    mov edi, 0x1000
+    mov cr3, edi
+
+    ; fill first entry of PML4T, PDPT, PDT. 
+    mov DWORD [edi], 0x2003 ; 0x2003 IS NOT the address. it contains many flags, and another DWORD is zero. Just a trick. 
+    mov edi, 0x2000
+    mov DWORD [edi], 0x3003
+    mov edi, 0x3000
+    mov DWORD [edi], 0x4003
+    mov edi, 0x4000
+
+    ; fill all entries of the PT. This is a trick, which not setting all bits in entry. 
+    ; This page table has 512 4K page, 0x00000000 - 0x00200000.
+    mov ebx, 0x00000003 ; BIT M--12 contains PageFrameNumber. 
+    mov ecx, 512 ; counter
+_set_one_entry:
+    mov DWORD [edi], ebx
+    add ebx, 0x1000 ; each page is 4K
+    add edi, 8 ; each entry is 64bit. 
+    loop _set_one_entry
+
+    ; Page table prepared. Enable PAE-paging. 
+    mov eax, cr4
+    or eax, 1<<5
+    mov cr4, eax
+
+    ;;;;;;;;;;;;;;;; Section 2: enter compatibility mode
+    mov ecx, 0xC0000080          ; Set the C-register to 0xC0000080, which is the EFER MSR.
+    rdmsr                        ; Read from the model-specific register.
+    or eax, 1 << 8               ; Set the LM-bit which is the 9th bit (bit 8).
+    wrmsr                        ; Write to the model-specific register.
+
+    mov eax, cr0                 ; Set the A-register to control register 0.
+    or eax, 1 << 31              ; Set the PG-bit, which is the 32nd bit (bit 31).
+    mov cr0, eax                 ; Set control register 0 to the A-register.
+
+
+    ;;;;;;;;;;;;;;;;; Section 3: enter 64bit long mode
+    lgdt [GDT64.Pointer]         ; Load the 64-bit global descriptor table.
+    jmp GDT64.Code:Realm64       ; Set the code segment and enter 64-bit long mode.
+
+[BITS 64]
+ 
+Realm64:
+    cli                           ; Clear the interrupt flag.
+    mov ax, GDT64.Data            ; Set the A-register to the data descriptor.
+    mov ds, ax                    ; Set the data segment to the A-register.
+    mov es, ax                    ; Set the extra segment to the A-register.
+    mov fs, ax                    ; Set the F-segment to the A-register.
+    mov gs, ax                    ; Set the G-segment to the A-register.
+    mov ss, ax                    ; Set the stack segment to the A-register.
+    ; done
+    ; 32bit print_vga not working in 64bit mode
+
+
+
+
+
+
diff --git a/kernel/Makefile b/kernel/Makefile
index a766e15dec5a6c6809bab16af49c686eba673e0a..91ca42462d6043efe5769cfce8ee8fc81fa35755 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -1,17 +1,26 @@
 
+# BITS could be 32 or 64.
+BITS ?= 64
+
+ifeq ($(BITS), 64)
+ARCH = x86_64
+else
+ARCH = i386
+endif
+
 assemble: kernel head
-	ld -o kernel.img -Ttext 0x7e00 --oformat binary image_head.o kernel.o -m elf_i386
+	ld -o kernel.img -Ttext 0x7e00 --oformat binary image_head.o kernel.o -m elf_$(ARCH)
 	# Sector 1 = bootloader, Sector 2 - (512B TO 64K) = kernel
 	# Extend kernel.img to correct size. 
 	test $$(stat -c %s kernel.img) -le 65024
 	truncate --size=65024 kernel.img
 
 head:
-	nasm -f elf image_head.asm -o image_head.o
+	nasm -f elf$(BITS) -DTARGET_BITS=$(BITS) image_head.asm -o image_head.o
 
 kernel:
-	g++ -ffreestanding -fno-pie -c kernel.cc -o kernel.o -m32 -std=c++17
+	g++ -ffreestanding -fno-pie -c kernel.cc -o kernel.o -m$(BITS) -std=c++17
 
 clean:
-	rm *.o *.img
+	rm -f *.o *.img
 
diff --git a/kernel/image_head.asm b/kernel/image_head.asm
index f6d9c3b5503f04e8d4de215858a80b32a78bc853..92c3af292ee64f06f6742a71ca49be3bb878cb91 100644
--- a/kernel/image_head.asm
+++ b/kernel/image_head.asm
@@ -1,4 +1,4 @@
-[bits 32]
+[bits TARGET_BITS]
 [extern main]
 call main
 ret
diff --git a/kernel/include/vga.hpp b/kernel/include/vga.hpp
index ffebbc37c2d50dad6e8cc22c4894a77c8c8efdc8..6eab67984e5dd914bd828cdf3f2a952de6b696f5 100644
--- a/kernel/include/vga.hpp
+++ b/kernel/include/vga.hpp
@@ -12,7 +12,6 @@ constexpr uint16_t VGA_MAKE_CHAR(char c, uint8_t color) {
 }
 constexpr uint8_t default_color = 0x0f;
 
-
 inline void trigger_scroll(uint16_t *pos) {
     for(uint16_t row = 1; row < VGA_HEIGHT; ++row) {
         memcpy(VGA_BEGIN_ADDR + (row-1)*VGA_WIDTH, VGA_BEGIN_ADDR + row*VGA_WIDTH, VGA_WIDTH);
diff --git a/res/1.png b/res/1.png
new file mode 100644
index 0000000000000000000000000000000000000000..732f6644a26bc32a4be02483e4dca48c9ce42e79
Binary files /dev/null and b/res/1.png differ