blob: 60be6a378d67ae79a5e75ce55530a00ecaaf54ce [file] [log] [blame]
/*
* 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
/*
* Note as we are running in 32-bit mode, all pointers are 32-bit.
* void multiboot_tramp(uint32_t magic, struct relocator *relocator,
* vm_offset_t entry)
*/
multiboot_tramp:
cli
pushl %ebp /* keep familiar stack frame */
movl %esp, %ebp /* current SP */
movl 0xc(%ebp),%eax /* relocator */
movl (%eax), %eax /* new SP */
movl %eax, %esp
/* now copy arguments to new stack */
movl 0x10(%ebp),%eax /* entry */
pushl %eax
movl 0xc(%ebp),%eax /* relocator */
pushl %eax
movl 0x8(%ebp),%eax /* magic */
pushl %eax
xorl %eax,%eax
pushl %eax /* fake IP, just to keep stack frame */
pushl %ebp
movl %esp, %ebp
subl $0x30, %esp /* local mbi, gdt and gdt desc */
movl 0xc(%ebp), %eax /* relocator */
pushl %eax
movl 0x4(%eax), %eax /* relocator->copy */
call *%eax
addl $0x4, %esp
movl %eax, -0x4(%ebp) /* save MBI */
/* set up GDT descriptor */
lea -0x1c(%ebp), %eax /* address of GDT */
movw $0x17, -0x22(%ebp) /* limit */
movl %eax, -0x20(%ebp) /* base */
/*
* set up following GDT:
* .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
*
* 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
*/
movw $0x0, -0x1c(%ebp)
movw $0x0, -0x1a(%ebp)
movb $0x0, -0x18(%ebp)
movb $0x0, -0x17(%ebp)
movb $0x0, -0x16(%ebp)
movb $0x0, -0x15(%ebp)
movw $0xffff, -0x14(%ebp)
movw $0x0, -0x12(%ebp)
movb $0x0, -0x10(%ebp)
movb $0x9a, -0xf(%ebp)
movb $0xcf, -0xe(%ebp)
movb $0x0, -0xd(%ebp)
movw $0xffff, -0xc(%ebp)
movw $0x0, -0xa(%ebp)
movb $0x0, -0x8(%ebp)
movb $0x92, -0x7(%ebp)
movb $0xcf, -0x6(%ebp)
movb $0x0, -0x5(%ebp)
lea -0x22(%ebp), %eax /* address of GDT */
lgdt (%eax)
movl 0x8(%ebp), %edx /* magic */
movl -0x4(%ebp), %ebx /* MBI */
movl 0x10(%ebp), %esi /* entry */
movl $SEL_SDATA, %eax
movw %ax, %ss
movw %ax, %ds
movw %ax, %es
movw %ax, %fs
movw %ax, %gs
/*
* We most likely don't need to push SEL_SDATA and esp
* because we do not expect to perform a privilege transition.
* However, it doesn't hurt us to push them as dboot will set
* up its own stack.
*/
movl %esp, %eax
pushl $SEL_SDATA
pushl %eax
pushf
pushl $SEL_SCODE
pushl %esi
movl %edx, %eax
iretl
multiboot_tramp_end: