shithub: riscv

ref: 38ea1ac105f4484f02bba3bfbc790ebe4f18f016
dir: /sys/src/9/pc64/apbootstrap.s/

View raw version
/*
 * Start an Application Processor. This must be placed on a 4KB boundary
 * somewhere in the 1st MB of conventional memory (APBOOTSTRAP). However,
 * due to some shortcuts below it's restricted further to within the 1st
 * 64KB. The AP starts in real-mode, with
 *   CS selector set to the startup memory address/16;
 *   CS base set to startup memory address;
 *   CS limit set to 64KB;
 *   CPL and IP set to 0.
 */
#include "mem.h"

#define NOP		BYTE $0x90		/* NOP */

#define pFARJMP32(s, o)	BYTE $0xea;		/* far jmp ptr32:16 */	\
			LONG $o; WORD $s
#define rFARJMP16(s, o)	BYTE $0xea;		/* far jump ptr16:16 */	\
			WORD $o; WORD $s;
#define rFARJMP32(s, o)	BYTE $0x66;		/* far jump ptr32:16 */	\
			pFARJMP32(s, o)

#define rLGDT(gdtptr)	BYTE $0x0f;		/* LGDT */		\
			BYTE $0x01; BYTE $0x16;				\
			WORD $gdtptr

#define rMOVAX(i)	BYTE $0xb8;		/* i -> AX */		\
			WORD $i;

#define	DELAY		BYTE $0xEB;		/* JMP .+2 */			\
			BYTE $0x00

MODE $16

TEXT apbootstrap(SB), 1, $-4 
	rFARJMP16(0, _apbootstrap-KZERO(SB))
	NOP; NOP; NOP;
TEXT _apvector(SB), 1, $-4 			/* address APBOOTSTRAP+0x08 */
	QUAD $0
TEXT _appml4(SB), 1, $-4 			/* address APBOOTSTRAP+0x10 */
	QUAD $0
TEXT _apapic(SB), 1, $-4 			/* address APBOOTSTRAP+0x18 */
	QUAD $0
TEXT _apmach(SB), 1, $-4 			/* address APBOOTSTRAP+0x20 */
	QUAD $0
TEXT _apefer(SB), 1, $-4
	QUAD $0x100				/* Long Mode Enable */

TEXT _apbootstrap(SB), 1, $-4 
	MOVW	CS, AX
	MOVW	AX, DS				/* initialise DS */

	rLGDT(_gdtptr32p<>-KZERO(SB))		/* load a basic gdt */

	MOVL	CR0, AX
	ORL	$1, AX
	MOVL	AX, CR0				/* turn on protected mode */
	DELAY					/* JMP .+2 */

	rFARJMP16(SELECTOR(3, SELGDT, 0), _ap32-KZERO(SB))

/*
 * Enable and activate Long Mode. From the manual:
 * 	make sure Page Size Extentions are off, and Page Global
 *	Extensions and Physical Address Extensions are on in CR4;
 *	set Long Mode Enable in the Extended Feature Enable MSR;
 *	set Paging Enable in CR0;
 *	make an inter-segment jump to the Long Mode code.
 * It's all in 32-bit mode until the jump is made.
 */
MODE $32

TEXT _ap32(SB), 1, $-4
	MOVW	$SELECTOR(2, SELGDT, 0), AX
	MOVW	AX, DS
	MOVW	AX, ES
	MOVW	AX, FS
	MOVW	AX, GS
	MOVW	AX, SS

	MOVL	_appml4-KZERO(SB), AX	/* physical address of PML4 */
	MOVL	AX, CR3			/* load the mmu */
	DELAY

	MOVL	CR4, AX
	ANDL	$~0x00000010, AX		/* Page Size */
	ORL	$0x000000A0, AX			/* Page Global, Phys. Address */
	MOVL	AX, CR4

	MOVL	$0xc0000080, CX			/* Extended Feature Enable */
	RDMSR
	ORL	_apefer-KZERO(SB), AX
	WRMSR

	MOVL	CR0, DX
	ANDL	$~0x6000000a, DX
	ORL	$0x80010000, DX			/* Paging Enable, Write Protect */
	MOVL	DX, CR0

	pFARJMP32(SELECTOR(KESEG, SELGDT, 0), _ap64-KZERO(SB))

/*
 * Long mode. Welcome to 2003.
 * Jump out of the identity map space;
 * load a proper long mode GDT;
 * initialise the stack and call the
 * C startup code in m->splpc.
 */
MODE $64

TEXT _ap64(SB), 1, $-4
	MOVQ	$_gdtptr64v<>(SB), AX
	MOVL	(AX), GDTR

	XORQ	AX, AX
	MOVW	AX, DS				/* not used in long mode */
	MOVW	AX, ES				/* not used in long mode */
	MOVW	AX, FS
	MOVW	AX, GS
	MOVW	AX, SS				/* not used in long mode */

	MOVW	AX, LDTR

	MOVQ	_apmach(SB), SP

	MOVQ	AX, RUSER			/* up = 0; */
	MOVQ	SP, RMACH			/* m = apmach */

	ADDQ	$MACHSIZE, SP

	PUSHQ	AX				/* clear flags */
	POPFQ

	MOVQ	_apvector(SB), AX
	MOVQ	_apapic(SB), RARG
	PUSHQ	RARG

	CALL	*AX

_halt:
	HLT
	JMP _halt
	
TEXT _gdt<>(SB), 1, $-4
	/* null descriptor */
	LONG	$0
	LONG	$0

	/* (KESEG) 64 bit long mode exec segment */
	LONG	$(0xFFFF)
	LONG	$(SEGL|SEGG|SEGP|(0xF<<16)|SEGPL(0)|SEGEXEC|SEGR)

	/* 32 bit data segment descriptor for 4 gigabytes (PL 0) */
	LONG	$(0xFFFF)
	LONG	$(SEGG|SEGB|(0xF<<16)|SEGP|SEGPL(0)|SEGDATA|SEGW)

	/* 32 bit exec segment descriptor for 4 gigabytes (PL 0) */
	LONG	$(0xFFFF)
	LONG	$(SEGG|SEGD|(0xF<<16)|SEGP|SEGPL(0)|SEGEXEC|SEGR)


TEXT _gdtptr32p<>(SB), 1, $-4
	WORD	$(4*8-1)
	LONG	$_gdt<>-KZERO(SB)

TEXT _gdtptr64p<>(SB), 1, $-4
	WORD	$(4*8-1)
	QUAD	$_gdt<>-KZERO(SB)

TEXT _gdtptr64v<>(SB), 1, $-4
	WORD	$(4*8-1)
	QUAD	$_gdt<>(SB)