root/usr/src/boot/efi/loader/arch/amd64/multiboot_tramp.S
/*
 * This file and its contents are supplied under the terms of the
 * Common Development and Distribution License ("CDDL"), version 1.0.
 * You may only use this file in accordance with the terms of version
 * 1.0 of the CDDL.
 *
 * A full copy of the text of the CDDL should have accompanied this
 * source.  A copy of the CDDL is also available via the Internet at
 * http://www.illumos.org/license/CDDL.
 */

/*
 * Copyright 2016 Toomas Soome <tsoome@me.com>
 */

#include <x86/specialreg.h>

        .file   "multiboot_tramp.s"

/*
 * dboot expects a 32-bit multiboot environment and to execute in 32-bit mode.
 *
 * EAX: MB magic
 * EBX: 32-bit physical address of MBI
 * CS: 32-bit read/execute code segment with offset 0 and limit 0xFFFFFFFF
 * DS: 32-bit read/write data segment with offset 0 and limit 0xFFFFFFFF
 * ES: 32-bit read/write data segment with offset 0 and limit 0xFFFFFFFF
 * FS: 32-bit read/write data segment with offset 0 and limit 0xFFFFFFFF
 * GS: 32-bit read/write data segment with offset 0 and limit 0xFFFFFFFF
 * SS: 32-bit read/write data segment with offset 0 and limit 0xFFFFFFFF
 * A20 enabled
 * CR0: PG cleared, PE set
 * EFLAGS: VM cleared, IF cleared
 * interrupts disabled
 */

                .set    SEL_SCODE,0x8
                .set    SEL_SDATA,0x10

                .text
                .p2align 4
                .globl  multiboot_tramp
                .type   multiboot_tramp, STT_FUNC

/*
 * void multiboot_tramp(uint32_t magic, struct relocator *relocator,
 *    vm_offset_t entry)
 */
multiboot_tramp:
                cli
                movq    (%rsi), %rax
                movq    %rax, %rsp              /* Switch to temporary stack. */
                movq    0x8(%rsi), %rax         /* relocator->copy */
                pushq   %rdi                    /* save magic */
                pushq   %rdx                    /* save entry */
                movq    %rsi, %rdi
                callq   *%rax
                movq    %rax, %rbx              /* MBI */
                popq    %rsi                    /* entry to rsi */
                popq    %rdi                    /* restore magic */
                lea     gdt(%rip), %rax
                lea     gdtaddr(%rip), %rdx
                movq    %rax, (%rdx)
                lea     gdtdesc(%rip), %rax
                lgdt    (%rax)

                /* record the address */
                lea     multiboot_tramp_2(%rip), %rcx
                movq    %rsp, %rax
                pushq   $SEL_SDATA
                pushq   %rax
                pushf
                pushq   $SEL_SCODE
                lea     multiboot_tramp_1(%rip), %rax
                pushq   %rax
                iretq

                .code32
multiboot_tramp_1:
                movl    $SEL_SDATA, %eax
                movw    %ax, %ss
                movw    %ax, %ds
                movw    %ax, %es
                movw    %ax, %fs
                movw    %ax, %gs

                movl    %cr0, %eax              /* disable paging */
                btrl    $31, %eax
                movl    %eax, %cr0
                jmp     *%ecx
multiboot_tramp_2:
                movl    %cr4, %eax              /* disable PAE, PGE, PSE */
                andl    $~(CR4_PGE | CR4_PAE | CR4_PSE), %eax
                movl    %eax, %cr4
                movl    $MSR_EFER, %ecx
                rdmsr                           /* updates %edx:%eax */
                btcl    $8, %eax                /* clear long mode */
                wrmsr
                movl    %edi, %eax              /* magic */
                jmp     *%esi                   /* jump to kernel */

/* GDT record */
                .p2align 4
gdt:
/*
 * This will create access for 4GB flat memory with
 * base = 0x00000000, segment limit = 0xffffffff
 * page granulariy 4k
 * 32-bit protected mode
 * ring 0
 * code segment is executable RW
 * data segment is not-executable RW
 */
                .word   0x0, 0x0                /* NULL entry */
                .byte   0x0, 0x0, 0x0, 0x0
                .word   0xffff, 0x0             /* code segment */
                .byte   0x0, 0x9a, 0xcf, 0x0
                .word   0xffff, 0x0             /* data segment */
                .byte   0x0, 0x92, 0xcf, 0x0
gdt_end:

                .p2align 4
gdtdesc:        .word   gdt_end - gdt - 1       /* limit */
gdtaddr:        .long   0                       /* base */
                .long   0

multiboot_tramp_end: