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: