// platform.inc


// pjo, 18 oct 1999
// This file is merely a placeholder; soon to moved to hal/i386/generic.

#include <cyg/hal/i386.inc>


#define CYGPKG_HAL_I386_CPU_INIT_DEFINED
.macro hal_cpu_init

#ifdef CYG_HAL_STARTUP_FLOPPY
/* This code is loaded from a floppy disk when the PC powers up.  */
	.code16

	.extern _end

	sectorsPerTrack = 18
	bytesPerSector = 512
	bytesPerTrack = sectorsPerTrack * bytesPerSector
	dptLength = 3 /* words. */

	cld				/* always count up. */

/* Configure a stack that we can use. */
	movl $_start, %eax
	movw %ax, %sp
	shr $4, %eax
	andl $0xF000, %eax
	movw %ax, %ss

/* Ask the BIOS for info about the amount of RAM available.  We push these
	onto the stack for later use.
*/
	xorl %eax, %eax
	movb $0x88, %ah		/* Get the amount of extended memory. */
	int $0x15
	shl $10, %eax
	pushl %eax

	xorl %eax, %eax
	int $0x12			/* Get the amount of standard memory. */
	shl $10, %eax
	pushl %eax


/* Read the rest of the image to _start.  This code works by reading a track
	at a time...
*/
	movl $_end, %eax
	movl $_start, %ebx		/* Our destination address. */
	subl %ebx, %eax			/* Number of bytes in the image. */
	movl $1, %ecx			/* Track/sector to read from (starts at 1). */

0:
	cmpl $0, %eax
	jle 1f

	pushl %eax			/* Save the number of bytes we want. */
	pushl %ebx			/* Save our current address. */
	pushl %ecx			/* Save our disk location. */

/* Read in a track with head 0. */
	movl %ebx, %eax			/* Put our address into ES:BX. */
	shr $4, %eax
	movw %ax, %es
	andb $0xF, %ebx
	movw $0, %dx			/* Disk 0, head 0 */
	movb $0x02, %ah
	movb sectorsPerTrack, %al	/* Read the entire track. */
	movb $1, %cl
	int $0x13			/* CX points to our track/sector. */

/* So go ahead and resume execution at the real starting address.  This
	only serves to move us quickly to the real starting location; and has
	no effect after reading additional tracks.  If we didn't jump after
	reading the first track, then we limit ourselves to reading images of
	30k bytes max before overwriting us at 0x7C00.
*/
	ljmp $0, $2f
	hlt

	.align 4
2:

	popl %ecx
	popl %ebx
	popl %eax

/* Add our length to the address. */
	addl $bytesPerTrack, %ebx
	subl $bytesPerTrack, %eax

/* Maybe read in a track with head 1. */
	cmpl $0, %eax
	jle 1f

	pushl %eax			/* Save the number of bytes we want. */
	pushl %ebx			/* Save our current address. */
	pushl %ecx

	movl %ebx, %eax			/* Put our address into ES:BX. */
	shr $4, %eax
	movw %ax, %es
	andb $0xF, %ebx
	movw $0x0100, %dx		/* Disk 0, head 1 */
	movb $0x02, %ah
	movb sectorsPerTrack, %al	/* Read the entire track. */
	movb $1, %cl
	int $0x13			/* CX points to our track/sector. */

	popl %ecx
	popl %ebx
	popl %eax

/* Add our length to the address. */
	addl $bytesPerTrack, %ebx
	subl $bytesPerTrack, %eax

/* Move to the next track. */
	addb $0x1, %ch

	jmp 0b

/* Write the 0x55/0xAA signature at the end of the first block.  Without
	this signature the BIOS won't consider this block to be bootable.
*/
	. = _start + 510
	.byte 0x55
	.byte 0xAA


1:

/* Lets be nice and wait for the diskette drive motor to go off before continuing. */
	movw $0x40, %ax
	movw %ax, %es
	movl $0x40, %ebx
2:	es
	movb (%ebx), %al
	cmpb $0, %al
	jne 2b

/* Now we're all loaded up in memory. */

/* Disable interrupt handling. */
	cli

/* Configure GDT and IDT. */
	movl $gdt, %eax
	and $0xFFFF, %eax
	word
	cs
	lgdt (%eax)

	movl $idt, %eax
	and $0xFFFF, %eax
	word
	cs
	lidt (%eax)

/* Switch to protected mode. */
	smsw %eax
	orb $1, %al
	lmsw %eax
	ljmp $8, $3f

	hlt

	.align	4, 0xFF
gdt:
	.word	gdtEnd - gdtStart
	.long	gdtStart

	.align	4, 0xFF
idt:
	.word	0x07FF		/* Allow space for 256 interrupt vectors. */
	.long	0

gdtStart:
/* Selector 0x00 == invalid. */
	.word	0x0000
	.word	0x0000
	.byte	0x00
	.byte	0x00
	.byte	0x00
	.byte	0x00

/* Selector 0x08 == code. */
	.word	0xFFFF
	.word	0x0000
	.byte	0x00
	.byte	0x9B
	.byte	0xCF
	.byte	0x00

/* Selector 0x10 == data. */
	.word	0xFFFF
	.word	0x0000
	.byte	0x00
	.byte	0x93
	.byte	0xCF
	.byte	0x00

	.align	4, 0xFF
gdtEnd:

	.code32
3:

	movw $0x10, %ax
	movw %ax, %ds
	movw %ax, %es
	movw %ax, %fs
	movw %ax, %gs

/* Make our new stack point to the same place as the old one. */
	xorl %ebx, %ebx
	movw %ss, %bx
	shl $4, %ebx
	addl %esp, %ebx
	movw %ax, %ss
	movl %ebx, %esp
	movl $0, %ebp

/* Reset the flags register. */
	pushl $0
	popfl

/* _pc_entry() takes a pointer to our startup array (which only has standard
	and extended memory sizes in it, on the stack).
*/
	movl %esp, %ebx		/* They are the last parameters on the stack. */
	pushl %ebx

#endif /* CYG_HAL_STARTUP_FLOPPY */

.endm /* hal_cpu_init */



#define CYGPKG_HAL_I386_INTC_INIT_DEFINED
.macro hal_intc_init
## pjo: 27 Sep 1999: Initialize the interrupt controller.

# The interrupt controller is configured so that IRQ levels 0-7 trigger
#  interrupt vector 32-39; levels 8-15 trigger 40-47.
		movb $0x11, %al
		outb %al, $0x20
		movb $0x20, %al
		outb %al, $0x21
		movb $0x04, %al
		outb %al, $0x21
		movb $0x01, %al
		outb %al, $0x21
		movb $0xFF, %al			/* Mask off all interrupts. */
		outb %al, $0x21

		movb $0x11, %al
		outb %al, $0xA0
		movb $0x28, %al
		outb %al, $0xA1
		movb $0x02, %al
		outb %al, $0xA1
		movb $0x01, %al
		outb %al, $0xA1
		movb $0xFF, %al			/* Mask off all interrupts. */
		outb %al, $0xA1

.endm /* hal_intc_init */


#define CYGPKG_HAL_I386_FPU_DEFINED
.macro hal_fpu_init
# Tell the CPU to use the math hardware.
		movl %cr0, %eax
		orl $0x32, %eax
		movl %eax, %cr0

		finit

        ## Enable floating point exceptions. Bit mask:
        ##  1 - invalid operation
        ##  2 - denormalized operand
        ##  4 - zero divide
        ##  8 - overflow
        ## 16 - underflow
        ## 32 - precision
        fstcw  -4(%ebp)
        movl   -4(%ebp),%eax
        andb   $(~0x04),%al
        movl   %eax,-4(%ebp)
        fldcw  -4(%ebp)

# Tell the CPU to generate a interrupt 7 when the math device is used.
/* pjo... FIXME: may be a problem. */
#if 0
		movl %cr0, %eax
		orl $0x3A, %eax
		movl %eax, %cr0
#endif

.endm /* hal_fpu_init */


.macro	hal_fpu_save regs
.endm /* hal_fpu_save */

.macro	hal_fpu_save_caller regs
.endm /* hal_fpu_save_caller */

.macro	hal_fpu_save_callee regs
.endm /* hal_fpu_save_callee */

.macro	hal_fpu_load_caller regs
.endm /* hal_fpu_load_caller */

.macro	hal_fpu_load_callee regs
.endm /* hal_fpu_load_callee */

.macro	hal_fpu_load regs
.endm /* hal_fpu_load */



.macro hal_intc_ack vector
# Use any registers you like.
		movl \vector, %edx
		movb $0x20, %al
		cmpl $0x20, %edx
		jl 8f
		cmpl $0x30, %edx
		jge 9f
		outb %ax, $0x20
		jmp 8f
9:		outb %ax, $0xA0
8:		nop
.endm

