[comp.os.minix] Fix to 1.2 to support weird EGA boards

ast@cs.vu.nl (Andy Tanenbaum) (09/14/87)

We have tested a number of EGA boards here.  Almost none of them are compatible
with the IBM board.  MINIX 1.2 works with the monochrome, CGA, and IBM EGA 
board, but the screen goes blank every 25 lines with noncompatible EGA boards.
The enclosed fix provides fix-listings for kernel/tty.c and kernel/klib88.s
that have #ifdef SOFTSCROLL in strategic places.  If you recompile tty.c
with -DSOFTSCROLL, the resulting kernel works on noncompatible EGA cards.
The price you pay is in performance.  On our Zenith Z-248 AT clones, the
scrolling rate drops from 160 lines/sec to about 45 lines/sec when you use
the SOFTSCROLL option, so only use it if you have to.

Both files are fix-listings relative to 1.2.  The changes that I made to 
klib88.s to support loading the root file system from hard disk and using
extended memory on ATs are also present, although to use these features you
also need to install fixes to fs/main.c and mm/main.c, as posted earlier and
available from the archive.

These fixes (and all fixes that I post), will be part of the "official" 1.3
version, which won't happen until mid 1988.  I have other fish to fry in the
meanwhile.

I just noticed that the comment on line 4 of fix.c is wrong.  After the fix,
files 'new' and 'old.fix' are the same, of course.

Andy Tanenbaum (ast@cs.vu.nl)

: This is a shar archive.  Extract with sh, not csh.
: This archive ends with exit, so do not worry about trailing junk.
: --------------------------- cut here --------------------------
PATH=/bin:/usr/bin
echo Extracting \t\t\y\.\d\i\f\f
sed 's/^X//' > \t\t\y\.\d\i\f\f << '+ END-OF-FILE '\t\t\y\.\d\i\f\f
X155c155
X< PUBLIC  int color;		/* 1 if console is color, 0 if it is mono */
X---
X> PUBLIC int color;		/* 1 if console is color, 0 if it is mono */
X1036d1035
X< 
X1044,1045c1043,1057
X<   int amount, offset;
X< 
X---
X>   int amount, offset, bytes;
X> 
X>   bytes = 2 * (SCR_LINES - 1) * LINE_WIDTH;	/* 2 * 24 * 80 bytes */
X> #ifdef SOFTSCROLL
X>   /* Software scrolling for non-IBM compatible EGA cards. */
X>   if (dir == GO_FORWARD) {
X> 	scr_up(vid_base);
X> 	vid_copy(NIL_PTR, vid_base,
X> 		tp->tty_org+bytes, LINE_WIDTH);
X>   } else {
X> 	scr_down(vid_base);
X> 	vid_copy(NIL_PTR, vid_base, tp->tty_org, LINE_WIDTH);
X>   }
X> #else
X>   /* Normal scrolling using the 6845 registers. */
X1049c1061
X< 	offset = (tp->tty_org + 2 * (SCR_LINES - 1) * LINE_WIDTH) & vid_mask;
X---
X> 	offset = (tp->tty_org + bytes) & vid_mask;
X1055a1068
X> #endif
+ END-OF-FILE tty.diff
chmod 'u=rw,g=r,o=r' \t\t\y\.\d\i\f\f
set `sum \t\t\y\.\d\i\f\f`
sum=$1
case $sum in
25618)	:;;
*)	echo 'Bad sum in '\t\t\y\.\d\i\f\f >&2
esac
echo Extracting \k\l\i\b\8\8\.\d\i\f\f
sed 's/^X//' > \k\l\i\b\8\8\.\d\i\f\f << '+ END-OF-FILE '\k\l\i\b\8\8\.\d\i\f\f
X15a16,17
X> |   scr_up:	scroll screen a line up (in software, by copying)
X> |   scr_donw:	scroll screen a line down (in software, by copying)
X20a23
X> |   em_xfer:	read or write AT extended memory using the BIOS
X25c28
X< .globl _wreboot, _dma_read, _dma_write
X---
X> .globl _wreboot, _dma_read, _dma_write, _em_xfer, _scr_up, _scr_down
X474,491c477,512
X< |*				get_byte				     *
X< |*===========================================================================*
X< | This routine is used to fetch a byte from anywhere in memory.
X< | The call is:
X< |     c = get_byte(seg, off)
X< | where
X< |     'seg' is the value to put in es
X< |     'off' is the offset from the es value
X< _get_byte:
X< 	push bp			| save bp
X< 	mov bp,sp		| we need to access parameters
X< 	push es			| save es
X< 	mov es,4(bp)		| load es with segment value
X< 	mov bx,6(bp)		| load bx with offset from segment
X< 	seg es			| go get the byte
X< 	movb al,(bx)		| al = byte
X< 	xorb ah,ah		| ax = byte
X< 	pop es			| restore es
X---
X> |*				scr_up  				     *
X> |*===========================================================================*
X> | This routine scrolls the screen up one line on an EGA display 
X> | 
X> | The call is:
X> |     scr_up(org)
X> | where
X> |     'org'       is the video segment origin of the desired page
X> 
X> _scr_up:
X> 	push bp			| we need bp to access the parameters
X> 	mov bp,sp		| set bp to sp for indexing
X> 	push si			| save the registers
X> 	push di			| save di
X> 	push cx			| save cx
X> 	push es			| save es
X> 	push ds			| save ds
X> 	mov si,#160		| si = pointer to data to be copied
X> 	mov di,#0		| di = offset within video ram
X> 	mov cx,#1920		| cx = word count for copy loop
X> 
X> 	pushf			| copying may now start; save flags
X> 	cli			| interrupts just get in the way: disable them
X> 	mov ax,4(bp)
X> 	mov es,ax		| load es now: int routines may ruin it
X> 	mov ds,ax
X> 
X> 	rep			| this is the copy loop
X> 	movw			| ditto
X> 
X> 	popf			| restore flags
X> 	pop ds			| restore ds
X> 	pop es			| restore es
X> 	pop cx			| restore cx
X> 	pop di			| restore di
X> 	pop si			| restore si
X495,561c516,775
X< 
X< 
X< 
X< |*===========================================================================*
X< |*				reboot & wreboot			     *
X< |*===========================================================================*
X< | This code reboots the PC
X< 
X< _reboot:
X< 	cli			| disable interrupts
X< 	mov ax,#0x20		| re-enable interrupt controller
X< 	out 0x20
X< 	call resvec		| restore the vectors in low core
X< 	mov ax,#0x40
X< 	mov ds,ax
X< 	mov ax,#0x1234
X< 	mov 0x72,ax
X< 	mov ax,#0xFFFF
X< 	mov ds,ax
X< 	mov ax,3
X< 	push ax
X< 	mov ax,1
X< 	push ax
X< 	reti
X< 
X< _wreboot:
X< 	cli			| disable interrupts
X< 	mov ax,#0x20		| re-enable interrupt controller
X< 	out 0x20
X< 	call resvec		| restore the vectors in low core
X< 	xor ax,ax		| wait for character before continuing
X< 	int 0x16		| get char
X< 	mov ax,#0x40
X< 	mov ds,ax
X< 	mov ax,#0x1234
X< 	mov 0x72,ax
X< 	mov ax,#0xFFFF
X< 	mov ds,ax
X< 	mov ax,3
X< 	push ax
X< 	mov ax,1
X< 	push ax
X< 	reti
X< 
X< | Restore the interrupt vectors in low core.
X< resvec:	cld
X< 	mov cx,#2*71
X< 	mov si,#_vec_table
X< 	xor di,di
X< 	mov es,di
X< 	rep
X< 	movw
X< 	ret
X< 
X< | Some library routines use exit, so this label is needed.
X< | Actual calls to exit cannot occur in the kernel.
X< .globl _exit
X< _exit:	sti
X< 	jmp _exit
X< 
X< .data
X< lockvar:	.word 0		| place to store flags for lock()/restore()
X< vidlock:	.word 0		| dummy variable for use with lock prefix
X< splimit:	.word 0		| stack limit for current task (kernel only)
X< tmp:		.word 0		| count of bytes already copied
X< stkoverrun:	.asciz "Kernel stack overrun, task = "
X< _vec_table:	.zerow 142	| storage for interrupt vectors
X---
X> |*===========================================================================*
X> |*				  scr_down				     *
X> |*===========================================================================*
X> | This routine scrolls the screen down one line on an EGA display 
X> | 
X> | The call is:
X> |     scr_down(org)
X> | where
X> |     'org'       is the video segment origin of the desired page
X> 
X> _scr_down:
X> 	push bp			| we need bp to access the parameters
X> 	mov bp,sp		| set bp to sp for indexing
X> 	push si			| save the registers
X> 	push di			| save di
X> 	push cx			| save cx
X> 	push es			| save es
X> 	push ds			| save ds
X> 	mov si,#3838		| si = pointer to data to be copied
X> 	mov di,#3998		| di = offset within video ram
X> 	mov cx,#1920		| cx = word count for copy loop
X> 
X> 	pushf			| copying may now start; save flags
X> 	cli			| interrupts just get in the way: disable them
X> 	mov ax,4(bp)
X> 	mov es,ax		| load es now: int routines may ruin it
X> 	mov ds,ax
X> 
X> 	std
X> 	rep			| this is the copy loop
X> 	movw			| ditto
X> 
X> 	popf			| restore flags
X> 	pop ds			| restore ds
X> 	pop es			| restore es
X> 	pop cx			| restore cx
X> 	pop di			| restore di
X> 	pop si			| restore si
X> 	pop bp			| restore bp
X> 	ret			| return to caller
X> 
X> |*===========================================================================*
X> |*				get_byte				     *
X> |*===========================================================================*
X> | This routine is used to fetch a byte from anywhere in memory.
X> | The call is:
X> |     c = get_byte(seg, off)
X> | where
X> |     'seg' is the value to put in es
X> |     'off' is the offset from the es value
X> _get_byte:
X> 	push bp			| save bp
X> 	mov bp,sp		| we need to access parameters
X> 	push es			| save es
X> 	mov es,4(bp)		| load es with segment value
X> 	mov bx,6(bp)		| load bx with offset from segment
X> 	seg es			| go get the byte
X> 	movb al,(bx)		| al = byte
X> 	xorb ah,ah		| ax = byte
X> 	pop es			| restore es
X> 	pop bp			| restore bp
X> 	ret			| return to caller
X> 
X> |===========================================================================
X> |                		em_xfer
X> |===========================================================================
X> |
X> |  This file contains one routine which transfers words between user memory
X> |  and extended memory on an AT or clone.  A BIOS call (INT 15h, Func 87h)
X> |  is used to accomplish the transfer.  The BIOS call is "faked" by pushing
X> |  the processor flags on the stack and then doing a far call to the actual
X> |  BIOS location.  An actual INT 15h would get a MINIX complaint from an
X> |  unexpected trap.
X> |
X> |  NOTE:  WARNING:  CAUTION: ...
X> |  Before using this routine, you must find your BIOS address for INT 15h.
X> |  The debug command "d 0:54 57" will give you the segment and address of
X> |  the BIOS call.  On my machine this generates:
X> |      0000:0050      59 F8 00 F0                          Y...
X> |  These values are then plugged into the two strange ".word xxxx" lines
X> |  near the end of this routine.  They correspond to offset=0xf859 and
X> |  seg=0xf000.  The offset is the first two bytes and the segment is the
X> |  last two bytes (Note the byte swap).
X> |
X> |  This particular BIOS routine runs with interrupts off since the 80286
X> |  must be placed in protected mode to access the memory above 1 Mbyte.
X> |  So there should be no problems using the BIOS call.
X> |
X> 	.text
X> gdt:				| Begin global descriptor table
X> 					| Dummy descriptor
X> 	.word 0		| segment length (limit)
X> 	.word 0		| bits 15-0 of physical address
X> 	.byte 0		| bits 23-16 of physical address
X> 	.byte 0		| access rights byte
X> 	.word 0		| reserved
X> 					| descriptor for GDT itself
X> 	.word 0		| segment length (limit)
X> 	.word 0		| bits 15-0 of physical address
X> 	.byte 0		| bits 23-16 of physical address
X> 	.byte 0		| access rights byte
X> 	.word 0		| reserved
X> src:					| source descriptor
X> srcsz:	.word 0		| segment length (limit)
X> srcl:	.word 0		| bits 15-0 of physical address
X> srch:	.byte 0		| bits 23-16 of physical address
X> 	.byte 0x93	| access rights byte
X> 	.word 0		| reserved
X> tgt:					| target descriptor
X> tgtsz:	.word 0		| segment length (limit)
X> tgtl:	.word 0		| bits 15-0 of physical address
X> tgth:	.byte 0		| bits 23-16 of physical address
X> 	.byte 0x93	| access rights byte
X> 	.word 0		| reserved
X> 					| BIOS CS descriptor
X> 	.word 0		| segment length (limit)
X> 	.word 0		| bits 15-0 of physical address
X> 	.byte 0		| bits 23-16 of physical address
X> 	.byte 0		| access rights byte
X> 	.word 0		| reserved
X> 					| stack segment descriptor
X> 	.word 0		| segment length (limit)
X> 	.word 0		| bits 15-0 of physical address
X> 	.byte 0		| bits 23-16 of physical address
X> 	.byte 0		| access rights byte
X> 	.word 0		| reserved
X> 
X> |
X> |
X> |  Execute a transfer between user memory and extended memory.
X> |
X> |  status = em_xfer(source, dest, count);
X> |
X> |    Where:
X> |       status => return code (0 => OK)
X> |       source => Physical source address (32-bit)
X> |       dest   => Physical destination address (32-bit)
X> |       count  => Number of words to transfer
X> |
X> |
X> |
X> _em_xfer:
X> 
X> 	push	bp		| Save registers
X> 	mov	bp,sp
X> 	push	si
X> 	push	es
X> 	push	cx
X> |
X> |  Pick up source and destination addresses and update descriptor tables
X> |
X> 	mov ax,4(bp)
X> 	seg cs
X> 	mov srcl,ax
X> 	mov ax,6(bp)
X> 	seg cs
X> 	movb srch,al
X> 	mov ax,8(bp)
X> 	seg cs
X> 	mov tgtl,ax
X> 	mov ax,10(bp)
X> 	seg cs
X> 	movb tgth,al
X> |
X> |  Update descriptor table segment limits
X> |
X> 	mov cx,12(bp)
X> 	mov ax,cx
X> 	add ax,ax
X> 	seg cs
X> 	mov tgtsz,ax
X> 	seg cs
X> 	mov srcsz,ax
X> |
X> |  Now do actual DOS call
X> |
X> 	push cs
X> 	pop es
X> 	seg cs
X> 	mov si,#gdt
X> 	movb ah,#0x87
X> 	pushf
X> 	int 0x15		| Do a far call to BIOS routine
X> |
X> |  All done, return to caller.
X> |
X> 
X> 	pop	cx		| restore registers
X> 	pop	es
X> 	pop	si
X> 	mov	sp,bp
X> 	pop	bp
X> 	ret
X> 
X> 
X> 
X> |*===========================================================================*
X> |*				reboot & wreboot			     *
X> |*===========================================================================*
X> | This code reboots the PC
X> 
X> _reboot:
X> 	cli			| disable interrupts
X> 	mov ax,#0x20		| re-enable interrupt controller
X> 	out 0x20
X> 	call resvec		| restore the vectors in low core
X> 	mov ax,#0x40
X> 	mov ds,ax
X> 	mov ax,#0x1234
X> 	mov 0x72,ax
X> 	mov ax,#0xFFFF
X> 	mov ds,ax
X> 	mov ax,3
X> 	push ax
X> 	mov ax,1
X> 	push ax
X> 	reti
X> 
X> _wreboot:
X> 	cli			| disable interrupts
X> 	mov ax,#0x20		| re-enable interrupt controller
X> 	out 0x20
X> 	call resvec		| restore the vectors in low core
X> 	xor ax,ax		| wait for character before continuing
X> 	int 0x16		| get char
X> 	mov ax,#0x40
X> 	mov ds,ax
X> 	mov ax,#0x1234
X> 	mov 0x72,ax
X> 	mov ax,#0xFFFF
X> 	mov ds,ax
X> 	mov ax,3
X> 	push ax
X> 	mov ax,1
X> 	push ax
X> 	reti
X> 
X> | Restore the interrupt vectors in low core.
X> resvec:	cld
X> 	mov cx,#2*71
X> 	mov si,#_vec_table
X> 	xor di,di
X> 	mov es,di
X> 	rep
X> 	movw
X> 	ret
X> 
X> | Some library routines use exit, so this label is needed.
X> | Actual calls to exit cannot occur in the kernel.
X> .globl _exit
X> _exit:	sti
X> 	jmp _exit
X> 
X> .data
X> lockvar:	.word 0		| place to store flags for lock()/restore()
X> vidlock:	.word 0		| dummy variable for use with lock prefix
X> splimit:	.word 0		| stack limit for current task (kernel only)
X> tmp:		.word 0		| count of bytes already copied
X> stkoverrun:	.asciz "Kernel stack overrun, task = "
X> _vec_table:	.zerow 142	| storage for interrupt vectors
+ END-OF-FILE klib88.diff
chmod 'u=rw,g=r,o=r' \k\l\i\b\8\8\.\d\i\f\f
set `sum \k\l\i\b\8\8\.\d\i\f\f`
sum=$1
case $sum in
22890)	:;;
*)	echo 'Bad sum in '\k\l\i\b\8\8\.\d\i\f\f >&2
esac
exit 0