/*
 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
 *
 * @APPLE_LICENSE_HEADER_START@
 * 
 * Portions Copyright (c) 1999 Apple Computer, Inc.  All Rights
 * Reserved.  This file contains Original Code and/or Modifications of
 * Original Code as defined in and that are subject to the Apple Public
 * Source License Version 1.1 (the "License").  You may not use this file
 * except in compliance with the License.  Please obtain a copy of the
 * License at http://www.apple.com/publicsource and read it before using
 * this file.
 * 
 * The Original Code and all software distributed under the License are
 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT.  Please see the
 * License for the specific language governing rights and limitations
 * under the License.
 * 
 * @APPLE_LICENSE_HEADER_END@
 */
/*
 * Copyright 1993 NeXT Computer, Inc.
 * All rights reserved.
 *
 * Harness for calling real-mode BIOS functions.
 */

#include "legacy/asm.h"

#define data32	.byte 0x66
#define addr32	.byte 0x67

#define O_INT	0
#define O_EAX	4
#define O_EBX	8
#define O_ECX	12
#define O_EDX	16
#define O_EDI	20
#define O_ESI	24
#define O_EBP	28
#define O_CS	32
#define O_DS	34
#define O_ES	36
#define O_FLG	38

.data
	.lcomm save_eax,  4,2
	.lcomm save_edx,  4,2
	.lcomm save_es,   2,1
	.lcomm save_flag, 2,1
	.lcomm new_eax,   4,2
	.lcomm new_edx,   4,2
	.lcomm new_es,    2,1

.text

/*============================================================================
 * Call real-mode BIOS INT functions.
 *
 */
ENTRY(bios)
	enter	$0,$0
	pushal
	
	movl	8(%ebp), %edx		// address of save area
	movb	O_INT(%edx), %al	// save int number
	movb	%al, do_int+1
	
	movl	O_EBX(%edx), %ebx
	movl	O_ECX(%edx), %ecx
	movl	O_EDI(%edx), %edi
	movl	O_ESI(%edx), %esi
	movl	O_EBP(%edx), %ebp
	movl	%edx, save_edx
	movl	O_EAX(%edx), %eax
	movl	%eax, new_eax
	movl	O_EDX(%edx), %eax
	movl	%eax, new_edx
	movw	O_ES(%edx),  %ax
	movl	%ax, new_es

	call	EXT(_prot_to_real)
	
	data32
	addr32
	mov	new_eax, %eax
	data32
	addr32
	mov	new_edx, %edx
	data32
	addr32
	mov	new_es, %es

do_int:
	int	$0x00
	pushf
	data32
	addr32
	movl	%eax, save_eax
	popl	%eax			    // actually pop %ax
	addr32
	movl	%eax, save_flag		// actually movw
	mov	%es, %ax
	addr32
	movl	%eax, save_es		// actually movw
	data32
	call	EXT(_real_to_prot)
	
	movl	%edx, new_edx		// save new edx before clobbering
	movl	save_edx, %edx
	movl	new_edx, %eax		// now move it into buffer
	movl	%eax, O_EDX(%edx)
	movl	save_eax, %eax
	movl	%eax, O_EAX(%edx)
	movw	save_es, %ax
	movw	%ax, O_ES(%edx)
	movw	save_flag, %ax
	movw	%ax, O_FLG(%edx)
	movl	%ebx, O_EBX(%edx)
	movl	%ecx, O_ECX(%edx)
	movl	%edi, O_EDI(%edx)
	movl	%esi, O_ESI(%edx)
	movl	%ebp, O_EBP(%edx)
	
	popal
	leave
	
	ret
	
/*============================================================================
 * Determines the total system memory size using various BIOS Int 15 calls.
 *
 */
ENTRY(get_memsize)
	enter	$0, $0				# create frame pointer (32 bit operand/stack)
	pushal						# save all registers

	movl	8(%ebp), %ebx		# push input structure pointer to stack
	pushl	%ebx

	call	EXT(_prot_to_real)	# switch to real mode

	##################################################################
	# In real mode.
	# Do not forget the opcode overrides, since the assembler
	# does not know we have made a transition to 16-bit operation.
	##################################################################

	data32
	movl	$0xE801, %eax		# Get memory size
	clc
	int		$0x15
	data32
	jnc		getmsz_e801

	data32
	movl	$0xDA88, %eax 		# Get memory size
	clc
	int		$0x15
	data32
	jnc		getmsz_da88

	movb	$0x8A, %ah			# Get memory size
	clc
	int		$0x15
	data32
	jnc		getmsz_8a

	movb	$0x88, %ah			# Get memory size
	clc
	int		$0x15
	data32
	jnc		getmsz_88

	xorl	%edx, %edx			# Error, cannot get memory size
	xorl	%eax, %eax

getmsz_done:
	data32
	addr32
	pushl	%eax				# Push EAX to 32-bit stack

	data32
	call	EXT(_real_to_prot)  # Back to protected mode. EAX is modified.

	##################################################################
	# Back to protected mode.
	##################################################################

	popl	%eax				# Pop EAX from stack
	popl	%ebx				# Pop pointer to register structure

	# Copy the result to the input structure pointed to by a pointer
	# which is on top of the stack. Write register EAX and EDX to the
	# structure.

	movl	%eax, O_EAX(%ebx)
	movl	%edx, O_EDX(%ebx)

	popal						# restore all registers
	leave						# undo enter operator
	ret

getmsz_88:
	orl		%eax, %eax
	data32
	jz		getmsz_64m
	xorl	%edx, %edx

getmsz_8a:
	data32
	movl	$1024, %ebx			# Add in 1M
	addl	%ebx, %eax
	adcl	$0, %edx
	data32
	jmp		getmsz_done

getmsz_64m:
	data32
	movl	$1, %edx
	xorl	%eax, %eax
	data32
	jmp		getmsz_done

getmsz_da88:
	xor		%dh, %dh
	movb	%cl, %dl
	movl	%ebx, %eax
	data32
	jmp		getmsz_8a

getmsz_e801:
	xorl	%edx, %edx
	orl		%ebx, %ebx
	data32
	jz		getmsz_88

	data32
	movl	$64, %eax
	mul		%ebx

	data32
	movl	$16384, %ebx
	addl	%ebx, %eax
	adcl	$0, %edx

	data32
	jmp		getmsz_done
