⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 boothead.s

📁 MINIX2.0操作系统源码 MINIX2.0操作系统源码
💻 S
📖 第 1 页 / 共 2 页
字号:
!	Boothead.s - BIOS support for boot.c		Author: Kees J. Bot
!
!
! This file contains the startup and low level support for the secondary
! boot program.  It contains functions for disk, tty and keyboard I/O,
! copying memory to arbitrary locations, etc.
!
! The primary bootstrap code supplies the following parameters in registers:
!	dl	= Boot-device.
!	es:si	= Partition table entry if hard disk.
!

.define begtext, begdata, begbss
.data
begdata:
	.ascii	"(null)\0"
.bss
begbss:

	o32	    =	  0x66	! This assembler doesn't know 386 extensions
	BOOTOFF	    =	0x7C00	! 0x0000:BOOTOFF load a bootstrap here
	LOADSEG     =	0x1000	! Where this code is loaded.
	BUFFER	    =	0x0600	! First free memory
	PENTRYSIZE  =	    16	! Partition table entry size.
	DSKBASE     =	   120	! 120 = 4 * 0x1E = ptr to disk parameters
	DSKPARSIZE  =	    11	! 11 bytes of floppy parameters
	SECTORS	    =	     4	! Offset into parameters to sectors per track
	a_flags	    =	     2	! From a.out.h, struct exec
	a_text	    =	     8
	a_data	    =	    12
	a_bss	    =	    16
	a_total	    =	    24
	A_SEP	    =	  0x20	! Separate I&D flag
	K_I386	    =	0x0001	! Call Minix in 386 mode
	K_RET	    =	0x0020	! Returns to the monitor on reboot

	DS_SELECTOR =	   3*8	! Kernel data selector
	ES_SELECTOR =	   4*8	! Flat 4 Gb
	SS_SELECTOR =	   5*8	! Monitor stack
	CS_SELECTOR =	   6*8	! Kernel code
	MCS_SELECTOR=	   7*8	! Monitor code

! Imported variables and functions:
.extern _caddr, _daddr, _runsize, _edata, _end	! Runtime environment
.extern _device, _dskpars, _heads, _sectors	! Boot disk parameters
.extern _rem_part				! To pass partition info
.extern _k_flags				! Special kernel flags

.text
begtext:
.extern _boot, _printk				! Boot Minix, kernel printf

! Set segment registers and stack pointer using the programs own header!
! The header is either 32 bytes (short form) or 48 bytes (long form).  The
! bootblock will jump to address 0x10030 in both cases, calling one of the
! two jmpf instructions below.

	jmpf	boot, LOADSEG+3	! Set cs right (skipping long a.out header)
	.space	11		! jmpf + 11 = 16 bytes
	jmpf	boot, LOADSEG+2	! Set cs right (skipping short a.out header)
boot:
	mov	ax, #LOADSEG
	mov	ds, ax		! ds = header

	movb	al, a_flags
	testb	al, #A_SEP	! Separate I&D?
	jnz	sepID
comID:	xor	ax, ax
	xchg	ax, a_text	! No text
	add	a_data, ax	! Treat all text as data
sepID:
	mov	ax, a_total	! Total nontext memory usage
	and	ax, #0xFFFE	! Round down to even
	mov	a_total, ax	! total - text = data + bss + heap + stack
	cli			! Ignore interrupts while stack in limbo
	mov	sp, ax		! Set sp at the top of all that

	mov	ax, a_text	! Determine offset of ds above cs
	movb	cl, #4
	shr	ax, cl
	mov	cx, cs
	add	ax, cx
	mov	ds, ax		! ds = cs + text / 16
	mov	ss, ax
	sti			! Stack ok now
	push	es		! Save es, we need it for the partition table
	mov	es, ax
	cld			! C compiler wants UP

! Clear bss
	xor	ax, ax		! Zero
	mov	di, #_edata	! Start of bss is at end of data
	mov	cx, #_end	! End of bss (begin of heap)
	sub	cx, di		! Number of bss bytes
	shr	cx, #1		! Number of words
	rep
	stos			! Clear bss

! Copy primary boot parameters to variables.  (Can do this now that bss is
! cleared and may be written into).
	xorb	dh, dh
	mov	_device, dx	! Boot device (probably 0x00 or 0x80)
	mov	_rem_part+0, si	! Remote partition table offset
	pop	_rem_part+2	! and segment (saved es)

! Remember the current video mode for restoration on exit.
	movb	ah, #0x0F	! Get current video mode
	int	0x10
	andb	al, #0x7F	! Mask off bit 7 (no blanking)
	movb	old_vid_mode, al
	movb	cur_vid_mode, al

! Give C code access to the code segment, data segment and the size of this
! process.
	xor	ax, ax
	mov	dx, cs
	call	seg2abs
	mov	_caddr+0, ax
	mov	_caddr+2, dx
	xor	ax, ax
	mov	dx, ds
	call	seg2abs
	mov	_daddr+0, ax
	mov	_daddr+2, dx
	push	ds
	mov	ax, #LOADSEG
	mov	ds, ax		! Back to the header once more
	mov	ax, a_total+0
	mov	dx, a_total+2	! dx:ax = data + bss + heap + stack
	add	ax, a_text+0
	adc	dx, a_text+2	! dx:ax = text + data + bss + heap + stack
	pop	ds
	add	ax, #0x000F
	adc	dx, #0
	and	ax, #0xFFF0	! Round up to a segment
	mov	_runsize+0, ax
	mov	_runsize+2, dx	! 32 bit size of this process

! Time to switch to a higher level language (not much higher)
	call	_boot

.define	_exit, __exit, ___exit		! Make various compilers happy
_exit:
__exit:
___exit:
	mov	bx, sp
	cmp	2(bx), #0		! Good exit status?
	jz	reboot
quit:	mov	ax, #any_key
	push	ax
	call	_printk
	call	_getchar
reboot:	call	restore_video
	int	0x19			! Reboot the system
.data
any_key:
	.ascii	"\nHit any key to reboot\n\0"
.text

! Alas we need some low level support
!
! u32_t mon2abs(void *ptr)
!	Address in monitor data to absolute address.
.define _mon2abs
_mon2abs:
	mov	bx, sp
	mov	ax, 2(bx)	! ptr
	mov	dx, ds		! Monitor data segment
	jmp	seg2abs

! u32_t vec2abs(vector *vec)
!	8086 interrupt vector to absolute address.
.define _vec2abs
_vec2abs:
	mov	bx, sp
	mov	bx, 2(bx)
	mov	ax, (bx)
	mov	dx, 2(bx)	! dx:ax vector
	!jmp	seg2abs		! Translate

seg2abs:			! Translate dx:ax to the 32 bit address dx-ax
	push	cx
	movb	ch, dh
	movb	cl, #4
	shl	dx, cl
	shrb	ch, cl		! ch-dx = dx << 4
	add	ax, dx
	adcb	ch, #0		! ch-ax = ch-dx + ax
	movb	dl, ch
	xorb	dh, dh		! dx-ax = ch-ax
	pop	cx
	ret

abs2seg:			! Translate the 32 bit address dx-ax to dx:ax
	push	cx
	movb	ch, dl
	mov	dx, ax		! ch-dx = dx-ax
	and	ax, #0x000F	! Offset in ax
	movb	cl, #4
	shr	dx, cl
	shlb	ch, cl
	orb	dh, ch		! dx = ch-dx >> 4
	pop	cx
	ret

! void raw_copy(u32_t dstaddr, u32_t srcaddr, u32_t count)
!	Copy count bytes from srcaddr to dstaddr.  Don't do overlaps.
!	Also handles copying words to or from extended memory.
.define _raw_copy
_raw_copy:
	push	bp
	mov	bp, sp
	push	si
	push	di		! Save C variable registers
copy:
	cmp	14(bp), #0
	jnz	bigcopy
	mov	cx, 12(bp)
	jcxz	copydone	! Count is zero, end copy
	cmp	cx, #0xFFF0
	jb	smallcopy
bigcopy:mov	cx, #0xFFF0	! Don't copy more than about 64K at once
smallcopy:
	push	cx		! Save copying count
	mov	ax, 4(bp)
	mov	dx, 6(bp)
	cmp	dx, #0x0010	! Copy to extended memory?
	jae	ext_copy
	cmp	10(bp), #0x0010	! Copy from extended memory?
	jae	ext_copy
	call	abs2seg
	mov	di, ax
	mov	es, dx		! es:di = dstaddr
	mov	ax, 8(bp)
	mov	dx, 10(bp)
	call	abs2seg
	mov	si, ax
	mov	ds, dx		! ds:si = srcaddr
	shr	cx, #1		! Words to move
	rep
	movs			! Do the word copy
	adc	cx, cx		! One more byte?
	rep
	movsb			! Do the byte copy
	mov	ax, ss		! Restore ds and es from the remaining ss
	mov	ds, ax
	mov	es, ax
	jmp	copyadjust
ext_copy:
	mov	x_dst_desc+2, ax
	movb	x_dst_desc+4, dl ! Set base of destination segment
	mov	ax, 8(bp)
	mov	dx, 10(bp)
	mov	x_src_desc+2, ax
	movb	x_src_desc+4, dl ! Set base of source segment
	mov	si, #x_gdt	! es:si = global descriptor table
	shr	cx, #1		! Words to move
	movb	ah, #0x87	! Code for extended memory move
	int	0x15
copyadjust:
	pop	cx		! Restore count
	add	4(bp), cx
	adc	6(bp), #0	! srcaddr += copycount
	add	8(bp), cx
	adc	10(bp), #0	! dstaddr += copycount
	sub	12(bp), cx
	sbb	14(bp), #0	! count -= copycount
	jmp	copy		! and repeat
copydone:
	pop	di
	pop	si		! Restore C variable registers
	pop	bp
	ret

! u16_t get_word(u32_t addr);
! void put_word(u32_t addr, u16_t word);
!	Read or write a 16 bits word at an arbitrary location.
.define	_get_word, _put_word
_get_word:
	mov	bx, sp
	call	gp_getaddr
	mov	ax, (bx)	! Word to get from addr
	jmp	gp_ret
_put_word:
	mov	bx, sp
	push	6(bx)		! Word to store at addr
	call	gp_getaddr
	pop	(bx)		! Store the word
	jmp	gp_ret
gp_getaddr:
	mov	ax, 2(bx)
	mov	dx, 4(bx)
	call	abs2seg
	mov	bx, ax
	mov	ds, dx		! ds:bx = addr
	ret
gp_ret:
	push	es
	pop	ds		! Restore ds
	ret

! void relocate(void);
!	After the program has copied itself to a safer place, it needs to change
!	the segment registers.  Caddr has already been set to the new location.
.define _relocate
_relocate:
	pop	bx		! Return address
	mov	ax, _caddr+0
	mov	dx, _caddr+2
	call	abs2seg
	mov	cx, dx		! cx = new code segment
	mov	ax, cs		! Old code segment
	sub	ax, cx		! ax = -(new - old) = -Moving offset
	mov	dx, ds
	sub	dx, ax
	mov	ds, dx		! ds += (new - old)
	mov	es, dx
	mov	ss, dx
	xor	ax, ax
	call	seg2abs
	mov	_daddr+0, ax
	mov	_daddr+2, dx	! New data address
	push	cx		! New text segment
	push	bx		! Return offset of this function
	retf			! Relocate

! void *brk(void *addr)
! void *sbrk(size_t incr)
!	Cannot fail implementations of brk(2) and sbrk(3), so we can use
!	malloc(3).  They reboot on stack collision instead of returning -1.
.data
	.align	2
break:	.data2	_end		! A fake heap pointer
.text
.define _brk, __brk, _sbrk, __sbrk
_brk:
__brk:				! __brk is for the standard C compiler
	xor	ax, ax
	jmp	sbrk		! break= 0; return sbrk(addr);
_sbrk:
__sbrk:
	mov	ax, break	! ax= current break
sbrk:	push	ax		! save it as future return value
	mov	bx, sp		! Stack is now: (retval, retaddr, incr, ...)
	add	ax, 4(bx)	! ax= break + increment
	mov	break, ax	! Set new break
	lea	dx, -1024(bx)	! sp minus a bit of breathing space
	cmp	dx, ax		! Compare with the new break
	jb	heaperr		! Suffocating noises
	lea	dx, -4096(bx)	! A warning when heap+stack goes < 4K
	cmp	dx, ax
	jae	plenty		! No reason to complain
	mov	ax, #memwarn
	push	ax
	call	_printk		! Warn about memory running low
	pop	ax
	movb	memwarn, #0	! No more warnings
plenty:	pop	ax		! Return old break (0 for brk)
	ret
heaperr:mov	ax, #chmem
	push	ax
	mov	ax, #nomem
	push	ax
	call	_printk
	jmp	quit
.data
nomem:	.ascii	"\nOut of%s\0"
memwarn:.ascii	"\nLow on"
chmem:	.ascii	" memory, use chmem to increase the heap\n\0"
.text

! int dev_geometry(void);
!	Given the device "_device" and floppy disk parameters "_dskpars",
!	set the number of heads and sectors.  It returns true iff the device
!	exists.
.define	_dev_geometry
_dev_geometry:
	push	es
	push	di		! Save registers used by BIOS calls
	movb	dl, _device	! The default device
	cmpb	dl, #0x80	! Floppy < 0x80, winchester >= 0x80
	jae	winchester
floppy:
	int	0x11		! Get equipment configuration
	testb	al, #0x01	! Bit 0 set if floppies available
	jz	geoerr		! No floppy drives on this box
	shl	ax, #1		! Highest floppy drive # in bits 6-7
	shl	ax, #1		! Now in bits 0-1 of ah
	andb	ah, #0x03	! Extract bits
	cmpb	dl, ah		! Must be dl <= ah for drive to exist
	ja	geoerr		! Alas no drive dl.
	movb	dh, #2		! Floppies have two sides
	mov	bx, #_dskpars	! bx = disk parameters
	movb	cl, SECTORS(bx)
	xor	ax, ax
	mov	es, ax		! es = 0 = vector segment
	eseg
	mov	DSKBASE+0, bx
	eseg
	mov	DSKBASE+2, ds	! DSKBASE+2:DSKBASE+0 = ds:bx = floppy parms
	jmp	geoboth
winchester:
	movb	ah, #0x08	! Code for drive parameters
	int	0x13		! dl still contains drive
	jb	geoerr		! No such drive?
	andb	cl, #0x3F	! cl = max sector number (1-origin)
	incb	dh		! dh = 1 + max head number (0-origin)
geoboth:
	movb	_heads, dh	! Number of heads for this device
	movb	_sectors, cl	! Sectors per track
	movb	al, cl		! al = sectors per track
	mulb	dh		! ax = heads * sectors
	mov	secspcyl, ax	! Sectors per cylinder = heads * sectors
	mov	ax, #1		! Code for success
geodone:
	pop	di
	pop	es		! Restore di and es registers
	ret
geoerr:	xor	ax, ax		! Code for failure
	jmp	geodone
.bss
secspcyl:	.space 1*2
.text

! int readsectors(u32_t bufaddr, u32_t sector, u8_t count)
! int writesectors(u32_t bufaddr, u32_t sector, u8_t count)
!	Read/write several sectors from/to disk or floppy.  The buffer must
!	be between 64K boundaries!  Count must fit in a byte.  The external
!	variables _device, _sectors and _heads describe the disk and its
!	geometry.  Returns 0 for success, otherwise the BIOS error code.
!
.define _readsectors, _writesectors
_writesectors:
	push	bp
	mov	bp, sp
	movb	13(bp), #3	! Code for a disk write
	jmp	rwsec
_readsectors:
	push	bp
	mov	bp, sp
	movb	13(bp), #2	! Code for a disk read
rwsec:	push	di
	push	es
	mov	ax, 4(bp)
	mov	dx, 6(bp)
	call	abs2seg
	mov	bx, ax
	mov	es, dx		! es:bx = bufaddr
	mov	di, #3		! Execute 3 resets on floppy error
	cmpb	_device, #0x80
	jb	nohd
	mov	di, #1		! But only 1 reset on hard disk error
nohd:	cmpb	12(bp), #0	! count equals zero?
	jz	done
more:	mov	ax, 8(bp)
	mov	dx, 10(bp)	! dx:ax = abs sector.  Divide it by sectors/cyl
	div	secspcyl	! ax = cylinder, dx = sector within cylinder
	xchg	ax, dx		! ax = sector within cylinder, dx = cylinder
	movb	ch, dl		! ch = low 8 bits of cylinder
	divb	_sectors	! al = head, ah = sector (0-origin)
	xorb	dl, dl		! About to shift bits 8-9 of cylinder into dl
	shr	dx, #1
	shr	dx, #1		! dl[6..7] = high cylinder
	orb	dl, ah		! dl[0..5] = sector (0-origin)
	movb	cl, dl		! cl[0..5] = sector, cl[6..7] = high cyl
	incb	cl		! cl[0..5] = sector (1-origin)
	movb	dh, al		! dh = head
	movb	dl, _device	! dl = device to use
	movb	al, _sectors	! Sectors per track - Sector number (0-origin)
	subb	al, ah		! = Sectors left on this track
	cmpb	al, 12(bp)	! Compare with # sectors to transfer
	jbe	doit		! Can't go past the end of a cylinder?
	movb	al, 12(bp)	! 12(bp) < sectors left on this track
doit:	movb	ah, 13(bp)	! Code for disk read (2) or write (3)
	push	ax		! Save al = sectors to read
	int	0x13		! call the BIOS to do the transfer
	pop	cx		! Restore al in cl
	jb	ioerr		! I/O error
	movb	al, cl		! Restore al = sectors read
	addb	bh, al		! bx += 2 * al * 256 (add bytes transferred)
	addb	bh, al		! es:bx = where next sector is located
	add	8(bp), ax	! Update address by sectors transferred
	adc	10(bp), #0	! Don't forget high word
	subb	12(bp), al	! Decrement sector count by sectors transferred
	jnz	more		! Not all sectors have been transferred
done:	xorb	ah, ah		! No error here!
	jmp	finish
ioerr:	cmpb	ah, #0x80	! Disk timed out?  (Floppy drive empty)
	je	finish
	cmpb	ah, #0x03	! Disk write protected?
	je	finish
	dec	di		! Do we allow another reset?
	jl	finish		! No, report the error
	xorb	ah, ah		! Code for a reset (0)
	int	0x13
	jnb	more		! Succesful reset, try request again
finish:	movb	al, ah
	xorb	ah, ah		! ax = error number
	pop	es
	pop	di
	pop	bp
	ret

! int getchar(void), peekchar(void);
!	Read a character from the keyboard, or just look if there is one.
!	A carriage return is changed into a linefeed for UNIX compatibility.
.define _getchar, _peekchar

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -