Minix1.5/kernel/start.x

| This file contains the assembler startup code for Minix.
| It cooperates with cstart.c to set up a good environment for main().
| It contains the following routines:

.define		_db		| trap to external debugger
.define		_get_chrome	| returns nonzero if display is color
.define		_get_ega	| returns nonzero if display is ega
.define		_get_ext_memsize  | returns amount of extended memory in K
.define		_get_low_memsize  | returns amount of low memory in K
.define		_get_processor	| returns processor type (86, 186, 286, 386)
.define		_get_word	| returns word at given segment:offset
.define		_put_word	| writes given word to given segment:offset

| All except db() only work in real mode, so must not be called by main() or
| later.

| Imported functions.

.extern		_cstart
.extern		_main

| Exported variables.

.define		kernel_ds

	.bss
.define		begbss
.define		begdata
.define		k_stktop
.define		_sizes

| Imported variables.

.extern		_gdt

#include <minix/config.h>
#include <minix/const.h>
#include <minix/com.h>
#include "const.h"
#include "protect.h"
#include "sconst.h"

/* BIOS software interrupts, subfunctions and return values. */
#define EQUIPMENT_CHECK		0x11
#	define EDISPLAY_MASK	0x30	/* mask for video display equipment */
#	define EMONO_DISPLAY	0x30	/* value for mono disply */
#define GET_EXTMEM_VEC		0x15	/* get extended memory size */
#	define GET_EXTMEM_FUNC	0x88
#define GET_MEM_VEC		0x12	/* get memory size */
#define SET_PROTECT_VEC		0x15	/* set protected mode */
#	define SET_PROTECT_FUNC 0x89
#define VIDEO			0x10
#	define ALTERNATE_SELECT	0x12
#	define A_S_INFO		0x10

	.text
|*===========================================================================*
|*				MINIX					     *
|*===========================================================================*
MINIX:				| this is the entry point for the MINIX kernel
	j	over_kernel_ds	| skip over the next few bytes
	.word	CLICK_SHIFT	| for build, later used by db for syms offset
kernel_ds:
	.word	0		| build puts kernel DS here at fixed address 4
over_kernel_ds:
	cli			| disable interrupts
	cld			| C compiler needs es = ds and direction = up

| Set up kernel segment registers and stack.
| The old fsck1.s sets up an invalid stack, so the above cli is beside the
| point, and a debugger trap here would crash.

	seg	cs
	mov	dx,kernel_ds	| dx is the only free register
	mov	ds,dx
	mov	es,dx
	mov	ss,dx
	mov	sp,#k_stktop	| set sp to point to the top of kernel stack

| Call C startup code to prepare for switching modes.

	push	ds
	push	cs
	push	di
	push	si
	push	dx
	push	cx
	push	bx
	push	ax
	call	_cstart
	add	sp,#8*2

| After switching to protected mode, the CPU may be in 32-bit mode, which has
| different instruction decoding, so "jmp _main" would fail.
| Fake a 32-bit return address to get around this ("ret" is the same in 32-bit
| mode apart from popping 32 bits).

	sub	ax,ax
	push	ax		| becomes harmless junk in 16-bit mode
	mov	ax,#_main
	push	ax

| Call the BIOS to switch to protected mode.
| This is just to do any cleanup necessary, typically to disable a hardware
| kludge which holds the A20 address line low.

| The call requires the gdt as set up by prot_init():
|	gdt pointer in gdt[1]
|	ldt pointer in gdt[2]
|	new ds in gdt[3]
|	new es in gdt[4]
|	new ss in gdt[5]
|	new cs in gdt[6]
|	nothing in gdt[7] (overwritten with BIOS cs)
|	ICW2 for master 8259 in bh
|	ICW2 for slave 8259 in bl
| The BIOS enables interrupts briefly - this is OK since the BIOS vectors
| are still valid.
| Most registers are destroyed.
| The 8259's are reinitialised.

	mov	si,#_gdt
	mov	bx,#IRQ0_VECTOR * 256 + IRQ8_VECTOR
	movb	ah,#SET_PROTECT_FUNC
	int	SET_PROTECT_VEC

| Now the processor is in protected mode.
| There is a little more protected mode initialization to do, but leave it
| to main(), to avoid using incompatible instructions here.

	ret			| "return" to _main


|*===========================================================================*
|*				db					     *
|*===========================================================================*

| PUBLIC void db();
| Trap to external debugger.
| This may be called from all modes (real or protected, 16 or 32-bit).

_db:
	int	3
	ret


|*===========================================================================*
|*				get_chrome				     *
|*===========================================================================*

| PUBLIC u16_t get_chrome();
| Call the BIOS to find out if the display is color.

_get_chrome:
	int	EQUIPMENT_CHECK		| get bit pattern for equipment
	and	ax,#EDISPLAY_MASK	| isolate color/mono field
	sub	ax,#EMONO_DISPLAY	| nonzero means it is color
	ret


|*===========================================================================*
|*				get_ega  				     *
|*===========================================================================*

| PUBLIC u16_t get_ega();
| Call the BIOS to find out if the display is EGA.
| (Actually this only tells if the BIOS supports EGA, not whether the
| screen is EGA. Doing it right is far more complicated.)

_get_ega:
	movb	bl,#A_S_INFO	| get info about
	movb	ah,#ALTERNATE_SELECT	| alternative display types
	int	VIDEO		| this will fail for non-EGA BIOS
	movb	al,bl		| success is determined by knowing
	movb	ah,#0		| a successful call will change bl
	sub	ax,#A_S_INFO	| nonzero means it is EGA
	ret


|*===========================================================================*
|*				get_ext_memsize				     *
|*===========================================================================*

| PUBLIC u16_t get_ext_memsize();
| Ask the BIOS how much extended memory there is.

_get_ext_memsize:
	pushf			| gak!, PC's set the interrupt enable flag
	movb	ah,#GET_EXTMEM_FUNC
	clc			| carry will stay clear if call exists
	int	GET_EXTMEM_VEC	| returns size (in K) in ax for AT's
	jnc	got_ext_memsize	| error, probably a PC
	sub	ax,ax
got_ext_memsize:
	popf
	ret


|*===========================================================================*
|*				get_low_memsize				     *
|*===========================================================================*

| PUBLIC u16_t get_low_memsize();
| Ask the BIOS how much normal memory there is.

_get_low_memsize:
	int	GET_MEM_VEC	| returns the size (in K) in ax
	ret


|*===========================================================================*
|*				get_processor				     *
|*===========================================================================*

| PUBLIC u16_t get_processor();
| Decide processor type among 8088=8086, 80188=80186, 80286, 80386.
| Return 86, 186, 286 or 386.
| Preserves all registers except the flags and the return register ax.

| Method:
| 8088=8086 and 80188=80186 push sp as new sp, 80286 and 80386 as old sp.
| All but 8088=8086 do shifts mod 32 or 16.
| 386 stores 0 for the upper 8 bits of the GDT pointer in 16 bit mode,
| while 286 stores 0xFF.

_get_processor:
	push	sp		| see if pushed sp == sp
	pop	ax
	cmp	ax,sp
	jz	new_processor
	push	cx		| see if shifts are mod 32
	mov	cx,#0x0120
	shlb	ch,cl		| zero tells if 86
	pop	cx
	mov	ax,#86
	jz	got_processor
	mov	ax,#186
	ret

new_processor:
	push	bp		| see if high bits are set in saved GDT
	mov	bp,sp
	sub	sp,#6		| space for GDT ptr
	defsgdt	(-6(bp))	| save 3 word GDT ptr
	add	sp,#4		| discard 2 words of GDT ptr
	pop	ax		| top word of GDT ptr
	pop	bp
	cmpb	ah,#0		| zero only for 386
	mov	ax,#286
	jnz	got_processor
	mov	ax,#386
got_processor:
	ret


|*===========================================================================*
|*				get_word				     *
|*===========================================================================*

| PUBLIC u16_t get_word(u16_t segment, u16_t *offset);
| Load and return the word at the far pointer  segment:offset.

_get_word:
	mov	cx,ds		| save ds
	pop	dx		| return adr
	pop	ds		| segment
	pop	bx		| offset
	sub	sp,#2+2		| adjust for parameters popped
	mov	ax,(bx)		| load the word to return
	mov	ds,cx		| restore ds
	jmp	(dx)		| return


|*===========================================================================*
|*				put_word				     *
|*===========================================================================*

| PUBLIC void put_word(u16_t segment, u16_t *offset, u16_t value);
| Store the word  value  at the far pointer  segment:offset.

_put_word:
	mov	cx,ds		| save ds
	pop	dx		| return adr
	pop	ds		| segment
	pop	bx		| offset
	pop	ax		| value
	sub	sp,#2+2+2	| adjust for parameters popped
	mov	(bx),ax		| store the word
	mov	ds,cx		| restore ds
	jmp	(dx)		| return


|*===========================================================================*
|*				data					     *
|*===========================================================================*

	.data
begdata:
_sizes:				| sizes of kernel, mm, fs filled in by build
	.word	0x526F		| this must be the first data entry (magic #)
	.word	CLICK_SHIFT	| consistency check for build
	.zerow	6		| build uses prevous 2 words and this space
	.space	K_STACK_BYTES	| kernel stack
k_stktop:			| top of kernel stack

	.bss
begbss: