
#define KERNBASE 0xc0000000
#define KERNBASE_PDE	0xc00
#define RECURS_PDE	(KERNBASE_PDE-4)
#define PAGETABLE	(RECURS_PDE<<20)	/* va of page tables accesessed
						   through recursive PDE */
#define PAGEDIR		(PAGETABLE+(RECURS_PDE<<10)) /* va of page directory */
#define PAGEDIRADDR 	(PAGEDIR+RECURS_PDE)	/* va containing the address
						     of the page dir */

#define CPUID_PGE       0x2000

#define PADDR(addr)	(addr-KERNBASE)
#define R(foo) ((foo)-KERNBASE)

#define ALIGN 4
#define EXT(x) x
#define LEXT(x) x ## :

#define addr32	.byte 0x67
#define data32	.byte 0x66
#define ENTRY(x)	.globl EXT(x); .align ALIGN; LEXT(x)

#define	SEL_KPL			0
#define	GSEL(s,r)		(((s)<<3) | r)

#define GNULL_SEL		0
#define GCODE_SEL		1
#define GDATA_SEL		2

#define CS16_SEL		3
#define DS16_SEL		4


#define CS16_ATTRIB		0x009e
#define DS16_ATTRIB		0x0092

#define REAL_SEG		0x0080
#define REAL_OFS		0x0000
#define REAL_ADDR		0x0800

#define PHY16(addr) (addr-code_start+REAL_ADDR)

#define ADDR16_OFS(addr) ((addr-code_start)+REAL_OFS)
#define ADDR16_SEG(addr) REAL_SEG

#define STACK_SEG		0x0100
#define STACK_OFS		0x0FF0
#define STACK			((STACK_SEG<<4) + STACK_OFF)

#define	PG_RW			0x002
#define PG_V			0x001

#define CR0_WP_OFF		0xFFFEFFFF
#define CR0_AM_OFF		0xFFFBFFFF

#define CR0_PE			0x00000001
#define CR0_PE_OFF		0xfffffffe

#define CR0_PG			0x80000000
#define CR0_PG_OFF		0x7fffffff

	.file "stuff.S"

	.text



	.align 4

code_start:	/* Code to be copied to low memory starts here */

gdtstore:	.word	100
		.long	PHY16(newgdt)

		.align 4

newgdt:		.long	0x00000000	/* null descriptor */
		.long	0x00000000	

		.long	0x0000FFFF	/* kernel code */
		.long	0x00CF9F00
	
		.long	0x0000FFFF	/* kernel data */
		.long	0x00CF9300

		.long	0x0000FFFF	/* 16 bit code */
		.long	0x00009F00

		.long	0x8000FFFF	/* 16 bit data */
		.long	0x0000930B


boot1:	/* Now executing in identity mapped address space in the low 4k */

	/* Switch off paging */
	movl	%cr0,%eax
	andl	$CR0_PG_OFF,%eax
	movl	%eax,%cr0

	xorl	%eax,%eax
	movl	%eax,%cr3	/* flush paging cache */

	/* Switch to new gdt */
	mov	$PHY16(gdtstore),%eax
	lgdt	(%eax)

	ljmp	$GSEL(GCODE_SEL,SEL_KPL),$PHY16(boot2)
boot2:
	movw	$GSEL(DS16_SEL,SEL_KPL), %ax /* load segment registers with
						64k segments */
	mov	%ax, %ds
	mov	%ax, %ss
	mov	%ax, %es
	mov	%ax, %fs
	mov	%ax, %gs


	ljmp	$GSEL(CS16_SEL,SEL_KPL),$PHY16(boot3)


boot3:	/* in use16 code segment, at PHY16(boot3) */
	
	/* Switch off protection bits */
	data32
	mov	%cr0, %eax
	data32
	andl	$CR0_PE_OFF&CR0_WP_OFF&CR0_AM_OFF, %eax
	data32
	mov	%eax, %cr0

	data32
	ljmp	$ADDR16_SEG(1f),$ADDR16_OFS(1f)

1:	 /* Finally in real mode */

	
	/* Set up the stack */
	data32
	movl	$STACK_SEG,%ebx
	mov	%bx,%ss
	data32
	movl	$STACK_OFS,%esp

	/* Interrupt table */
	xor	%eax,%eax
	mov	%ax,%ds
	data32
	movl	$PHY16(newidt),%ebx
	addr32
	data32
	lidt	(%ebx)

	/* Set interrupt masks */
	movb	$0x8F,%al /* IRQs 12,13,14 */
	outb	%al,$0xa1
	movb	$0xB8,%al /* IRQs 0,1,2,6 */
	outb	%al,$0x21
	sti

	/* Clear pending interrupts */
	movb	$0x20,%al
	outb	%al,$0xa0
	outb	%al,$0x20

	/* Enable PIT Counter */
	movb	$0x36,%al
	outb	%al,$0x43	/* Counter 0 set bits 0-7 then 8-15 */
	movb	$0x00,%al
	outb	%al,$0x40
	movb	$0x00,%al
	outb	%al,$0x40

	/* Set video mode */
	data32
	movl	$0x00000083,%eax
	int	$0x10

	data32
	movl	$0x00000701,%eax
	data32
	movl	$0x00000700,%ebx
	xor	%ecx,%ecx
	data32
	movl	$0x0000184F,%edx
	int	$0x10
	dec	%ah
	inc	%al
	int	$0x10

	data32
	movl	$0x00000200,%eax
	xor	%ebx,%ebx
	data32
	movl	$0x00001800,%edx
	int	$0x10



	/* If the system used a boot rom, then put back the old
	   int $0x19 boot vector. The boot rom leaves "MR" at
	   address 0:0x304 */
	xor	%eax,%eax
	mov	%ax,%ds
	.byte	0xA1,0x04,0x03	/* mov (0x304),%ax */
	.byte	0x3D,0x52,0x4d	/* cmp $0x4d52,%ax */
	jnz	1f

	addr32
	data32
	movl	(0x00000300),%eax
	addr32
	data32
	movl	%eax,(0x00000064)

1:
	/* Reset the disk system */
	data32
	movl	$0x00000000,%eax
	movl	$0x00000080,%edx
	int $0x13

	/* Try to boot... */
	int $0x19

		.align 4
newidt:		.word	0x03ff
		.long	0x00000000

code_end:

ENTRY(do_diskboot)
	cli

	/* Put PICs back into bios compatible mode */
	movb	$0x11,%al
	outb	%al,$0xa0
	outb	%al,$0x20

	movb	$0x70,%al /* IRQ 8 vector */
	outb	%al,$0xa1
	movb	$0x08,%al /* IRQ 0 vector */
	outb	%al,$0x21

	movb	$0x02,%al
	outb	%al,$0xa1
	movb	$0x04,%al
	outb	%al,$0x21

	movb	$0x01,%al
	outb	%al,$0xa1
	outb	%al,$0x21

	movb	$0xFF,%al /* mask */
	outb	%al,$0xa1
	movb	$0xFF,%al /* mask */
	outb	%al,$0x21

	/* Now deal with the PIT */
	movb	$0x54,%al
	outb	%al,$0x43	/* Counter 1 set bits 8-15 */
	movb	$0x12,%al
	outb	%al,$0x41

	movb	$0x36,%al
	outb	%al,$0x43	/* Counter 2 set bits 0-7 then 8-15 */
	movb	$0x33,%al
	outb	%al,$0x42
	movb	$0x05,%al
	outb	%al,$0x42

	/* Wait until later to initialize counter 0 */





	/* Make a page directory entry which maps low addresses to physical */

	movl	(KERNBASE_PDE+PAGEDIR),%eax /* get pde for KERNBASE*/
	movl	%eax,(PAGEDIR) 		/* copy to pde for low 4mb of memory */	

	movl	%cr3,%eax
	movl	%eax,%cr3		/* flush TLB cache */
	
	movl	(PAGETABLE), %eax	/* get the PTE for 0 or KERNBASE */
	orl	$PG_RW,	%eax		/* make it writable - otherwise kernel
					   does a copy-on-write!	*/
	movl	%eax,(PAGETABLE)

	movl	%cr3,%eax
	movl	%eax,%cr3		/* flush TLB cache */

	/* Copy code to low 4kb of memory */
	cld
	movl	$code_start,%esi
	movl	$PHY16(code_start),%edi
	movl	$(code_end-code_start),%ecx
	rep
	movsb

	pushl	$PHY16(boot1)
	ret
