File:  [Early Linux] / linux / boot / setup.sg
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Tue Apr 24 18:01:30 2018 UTC (8 years, 2 months ago) by root
Branches: linus, MAIN
CVS tags: linux010, HEAD
linux 0.10

/* 
 *
 *	setup.s		(C) 1991 Linus Torvalds
 *
 * setup.s is responsible for getting the system data from the BIOS,
 * and putting them into the appropriate places in system memory.
 * both setup.s and system has been loaded by the bootblock.
 *
 * This code asks the bios for memory/disk/other parameters, and
 * puts them in a "safe" place: 0x90000-0x901FF, ie where the
 * boot-block used to be. It is then up to the protected mode
 * system to read them from there before the area is overwritten
 * for buffer-blocks.
 *
 */

/* 
 * NOTE! These had better be the same as in bootsect.s!
 */

INITSEG  = 0x9000	# we move boot here - out of the way
SYSSEG   = 0x1000	# system loaded at 0x10000 (65536).
SETUPSEG = 0x9020	# this is the current segment

.globl begtext, begdata, begbss, endtext, enddata, endbss
.text
begtext:
.data
begdata:
.bss
begbss:
.text

entry start
start:

/* 
 * ok, the read went well so we get current cursor position and save it for
 * posterity.
 */

	mov	$INITSEG,%ax	# this is done in bootsect already, but...
	mov	%ax,%ds
	mov	$0x03,%ah	# read cursor pos
	xor	%bh,%bh
	int	0x10		# save it in known place, con_init fetches
	mov	[0],%dx		# it from 0x90000.

/* 
 * Get memory size (extended mem, kB)
 */

	mov	$0x88,%ah
	int	0x15
	mov	[2],%ax

/* 
 * Get hd0 data
 */

	mov	$0x0000,%ax
	mov	%ax,%ds
	lds	%si,[4*0x41]
	mov	$INITSEG,%ax
	mov	%ax,%es
	mov	$0x0080,%di
	mov	$0x10,%cx
	rep
	movsb

/* 
 * Get hd1 data
 */

	mov	$0x0000,%ax
	mov	%ax,%ds
	lds	%si,[4*0x46]
	mov	$INITSEG,%ax
	mov	%ax,%es
	mov	$0x0090,%di
	mov	$0x10,%cx
	rep
	movsb

/* 
 * Check that there IS a hd1 :-)
 */

	mov	$0x01500,%ax
	mov	$0x81,%dl
	int	0x13
	jc	no_disk1
	cmp	%ah,$3
	je	is_disk1
no_disk1:
	mov	$INITSEG,%ax
	mov	%ax,%es
	mov	$0x0090,%di
	mov	$0x10,%cx
	mov	$0x00,%ax
	rep
	stosb
is_disk1:

/* 
 * now we want to move to protected mode ...
 */

	cli			# no interrupts allowed !

/* 
 * first we move the system to it's rightful place
 */

	mov	$0x0000,%ax
	cld			# 'direction'=0, movs moves forward
do_move:
	mov	%ax,%es		# destination segment
	add	$0x1000,%ax
	cmp	%ax,$0x9000
	jz	end_move
	mov	%ax,%ds		# source segment
	sub	%di,%di
	sub	%si,%si
	mov 	$0x8000,%cx
	rep
	movsw
	jmp	do_move

/* 
 * then we load the segment descriptors
 */

end_move:
	mov	$SETUPSEG,%ax	# right, forgot this at first. didn't work :-)
	mov	%ax,%ds
	lidt	idt_48		# load idt with 0,0
	lgdt	gdt_48		# load gdt with whatever appropriate

/* 
 * that was painless, now we enable A20
 */

	call	empty_8042
	mov	$0xD1,%al		# command write
	out	%al,$0x64
	call	empty_8042
	mov	$0xDF,%al		# A20 on
	out	%al,$0x60
	call	empty_8042

/* 
 * well, that went ok, I hope. Now we have to reprogram the interrupts :-(
 * we put them right after the intel-reserved hardware interrupts, at
 * int 0x20-0x2F. There they won't mess up anything. Sadly IBM really
 * messed this up with the original PC, and they haven't been able to
 * rectify it afterwards. Thus the bios puts interrupts at 0x08-0x0f,
 * which is used for the internal hardware interrupts as well. We just
 * have to reprogram the 8259's, and it isn't fun.
 */

	mov	$0x11,%al		# initialization sequence
	out	%al,$0x20		# send it to 8259A-1
	.word	0x00eb,0x00eb		# jmp $+2, jmp $+2
	out	%al,$0xA0		# and to 8259A-2
	.word	0x00eb,0x00eb
	mov	$0x20,%al		# start of hardware int's (0x20)
	out	%al,$0x21
	.word	0x00eb,0x00eb
	mov	$0x28,%al		# start of hardware int's 2 (0x28)
	out	%al,$0xA1
	.word	0x00eb,0x00eb
	mov	$0x04,%al		# 8259-1 is master
	out	%al,$0x21
	.word	0x00eb,0x00eb
	mov	$0x02,%al		# 8259-2 is slave
	out	%al,$0xA1
	.word	0x00eb,0x00eb
	mov	$0x01,%al		# 8086 mode for both
	out	%al,$0x21
	.word	0x00eb,0x00eb
	out	%al,$0xA1
	.word	0x00eb,0x00eb
	mov	$0xFF,%al		# mask off all interrupts for now
	out	%al,$0x21
	.word	0x00eb,0x00eb
	out	%al,$0xA1

/* 
 * well, that certainly wasn't fun :-(. Hopefully it works, and we don't
 * need no steenking BIOS anyway (except for the initial loading :-).
 * The BIOS-routine wants lots of unnecessary data, and it's less
 * "interesting" anyway. This is how REAL programmers do it.
 *
 * Well, now's the time to actually move into protected mode. To make
 * things as simple as possible, we do no register set-up or anything,
 * we let the gnu-compiled 32-bit programs do that. We just jump to
 * absolute address 0x00000, in 32-bit protected mode.
 */

	mov	$0x0001,%ax	# protected mode (PE) bit
	lmsw	%ax		# This is it!
	jmpi	0,8		# jmp offset 0 of segment 8 (%cs)

/* 
 * This routine checks that the keyboard command queue is empty
 * No timeout is used - if this hangs there is something wrong with
 * the machine, and we probably couldn't proceed anyway.
 */
empty_8042:
	.word	0x00eb,0x00eb
	in	$0x64,%al	# 8042 status port
	test	%al,$2		# is input buffer full?
	jnz	empty_8042	# yes - loop
	ret

gdt:
	.word	0,0,0,0		# dummy

	.word	0x07FF		# 8Mb - limit=2047 (2048*4096=8Mb)
	.word	0x0000		# base address=0
	.word	0x9A00		# code read/exec
	.word	0x00C0		# granularity=4096, 386

	.word	0x07FF		# 8Mb - limit=2047 (2048*4096=8Mb)
	.word	0x0000		# base address=0
	.word	0x9200		# data read/write
	.word	0x00C0		# granularity=4096, 386

idt_48:
	.word	0			# idt limit=0
	.word	0,0			# idt base=0L

gdt_48:
	.word	0x800		# gdt limit=2048, 256 GDT entries
	.word	512+gdt,0x9	# gdt base = 0X9xxxx
	
.text
endtext:
.data
enddata:
.bss
endbss:

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.