/*	$OpenBSD: run_i386.S,v 1.2 2022/01/02 05:49:50 jsg Exp $	*/

/*
 * Copyright (c) 2015 YASUOKA Masahiko <yasuoka@yasuoka.net>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include <machine/asm.h>
#include <machine/specialreg.h>

#define	CODE_SEGMENT	0x10
#define	DATA_SEGMENT	0x18

	.globl _C_LABEL(run_i386_size)
_C_LABEL(run_i386_size):
	.long run_i386_end - _C_LABEL(run_i386_start)

	.align	4
	.text
	.globl	_C_LABEL(run_i386_start)
_C_LABEL(run_i386_start):
start:
	/*
	 * run_i386(_start) is to call the loaded kernel's start() with
	 * 32bit segment mode from x64 mode.
	 * %rdi == loaded start address, %rsi == kernel start address
	 */

	/* re-arrange the parameters for the x86 calling convention */
	mov	%edx, (run_i386_end - start - 0x20)(%rdi)
	mov	%ecx, (run_i386_end - start - 0x1c)(%rdi)
	mov	%r8d, (run_i386_end - start - 0x18)(%rdi)
	mov	%r9d, (run_i386_end - start - 0x14)(%rdi)
	mov	0x8(%rsp), %edx
	mov	%edx, (run_i386_end - start - 0x10)(%rdi)
	mov	0x10(%rsp), %edx
	mov	%edx, (run_i386_end - start - 0xc)(%rdi)
	mov	0x18(%rsp), %edx
	mov	%edx, (run_i386_end - start - 0x8)(%rdi)
	mov	0x20(%rsp), %edx
	mov	%edx, (run_i386_end - start - 0x4)(%rdi)

	/* Prepare jump address */
	lea	(start32a - start)(%rdi), %rax
	movl	%eax, (start32r - start)(%rdi)

	cli

	/* Setup GDT */
	lea	(gdt - start)(%rdi), %rax
	mov	%rax, (gdtrr - start)(%rdi)
	lgdt	(gdtr - start)(%rdi)

	/* Jump to set %cs */
	ljmp	*(start32r - start)(%rdi)

	.align	4
start32a:
	.code32
	movl	$DATA_SEGMENT, %eax
	movl	%eax, %ds
	movl	%eax, %es
	movl	%eax, %fs
	movl	%eax, %gs
	movl	%eax, %ss

	lea	(run_i386_end - start - 0x20)(%edi), %eax
	mov	%eax, %esp

	/* Disable Paging in CR0 */
	movl	%cr0, %eax
	andl	$(~CR0_PG), %eax
	movl	%eax, %cr0

	/* Disable PAE in CR4 */
	movl	%cr4, %eax
	andl	$(~CR4_PAE), %eax
	movl	%eax, %cr4

	jmp	start32b
start32b:
	.code32

	call	*%esi

	.align	4
start32r:
	.long	0
	.long	CODE_SEGMENT
	.align	4
gdt:
	.long	0, 0
	.long	0, 0
	.byte	0xff, 0xff, 0x00, 0x00, 0x00, 0x9f, 0xcf, 0x00
	.byte	0xff, 0xff, 0x00, 0x00, 0x00, 0x93, 0xcf, 0x00
gdtr:
	.word	gdtr - gdt
gdtrr:
	.quad
start32end:
	/* Space for the stack */
	.align	4
	.space	8192
run_i386_end:
