Subject: port-i386/3336: dosboot.com doesn't work with Windows 95 default installation
To: None <gnats-bugs@gnats.netbsd.org>
From: None <martin@rumolt.teuto.de>
List: netbsd-bugs
Date: 03/16/1997 05:05:13
>Number:         3336
>Category:       port-i386
>Synopsis:       dosboot.com doesn't work with Windows 95 default installation
>Confidential:   no
>Severity:       serious
>Priority:       high
>Responsible:    gnats-admin (GNATS administrator)
>State:          open
>Class:          change-request
>Submitter-Id:   net
>Arrival-Date:   Sat Mar 15 20:20:02 1997
>Last-Modified:
>Originator:     Martin Husemann
>Organization:
private
>Release:        Mar 15
>Environment:
System: NetBSD rumolt.teuto.de 1.2C NetBSD 1.2C (RUMOLT) #2: Sat Mar 15 11:35:35 MET 1997 root@rumolt.teuto.de:/usr/src/sys-isdn/arch/i386/compile/RUMOLT i386


>Description:

The new (experimental) dosboot.com utilitiy from
src/sys/arch/i386/stand/dosboot doesn't work with any reasonable nowadays DOS
installation. If any memory manager is installed (himem.sys will do) it won't
see any extended memory and will crash DOS before having done all its
DOS-based IO.

>How-To-Repeat:

Walk to a Windows 95 system nearby, hit F8, 6, ENTER on boot and try
dosboot.com.

>Fix:

Apply the following fix (or something similar). This adds XMS support
and double-buffers the loaded kernel before crashing DOS. Works for me,
although it might fail if the stringtable in the kernel is bigger than
64k. Probably the right way to handle this is to allocate a second
temporary XMS buffer when the stringtable size is known, but it's too
late now for me. The assembler doesn't handle some constructs correct
when in 16/8 bit mode, so be carefull (and disassemble afterwards) if
changing the assembler code!

Small bug: this gets the extended memory size a few k to small (XMS
doesn't count the UMB as extended memory), but it's only a few k and
I didn't bother finding out how much exactly it is. Probably rounding up
to the next MB boundary would do...


diff -rc5 sys/arch/i386/stand.orig/lib/biosmem.S sys/arch/i386/stand/lib/biosmem.S
*** sys/arch/i386/stand.orig/lib/biosmem.S	Fri Mar 14 13:52:07 1997
--- sys/arch/i386/stand/lib/biosmem.S	Sun Mar 16 04:37:15 1997
***************
*** 37,47 ****
  
  #define	data32	.byte 0x66
  
  	.text
  
! /* get mem above 1M, in kByte */
  
  ENTRY(getbasemem)
  	pushl	%ebp
  	movl	%esp,%ebp
  	pushl	%ebx
--- 37,47 ----
  
  #define	data32	.byte 0x66
  
  	.text
  
! /* get mem below 1M, in kByte */
  
  ENTRY(getbasemem)
  	pushl	%ebp
  	movl	%esp,%ebp
  	pushl	%ebx
***************
*** 64,73 ****
--- 64,79 ----
  	pop	%esi
  	popl	%ebx
  	popl	%ebp
  	ret
  
+ /* global pointer to XMS driver, 0 if no XMS used */
+ 
+ .globl	_xmsdrv
+ _xmsdrv:
+ 	.long	0
+ 
  /* get mem above 1M, in kByte */
  
  ENTRY(getextmem)
  	pushl	%ebp
  	movl	%esp,%ebp
***************
*** 77,86 ****
--- 83,127 ----
  
  	call	_C_LABEL(prot_to_real)
  
  	movb	$0x88,%ah
  	int	$0x15
+ 
+ 	testw	%ax, %ax/* test for extended memory = 0, this may happen */
+ 	jnz	xdone	/* if himem.sys is installed and grabed all available */
+ 			/* memory. */
+ 			/* determine memory size by calling XMS then... */
+ 
+ 	.byte	0xb8	/* movw $0x4300,ax */
+ 	.word	0x4300
+ 	int	$0x2f	/* check if XMS installed */
+ 	cmpb	$0x80, %al
+ 	jnz	noxms
+ 
+ 	.byte	0xb8	/* movw $0x4310,ax */
+ 	.word	0x4310
+ 	int	$0x2f	/* get driver address */
+ 
+ 	.byte	0x89,0x1e	/* save es:bx to _xmsdrv */
+ 	.word	_xmsdrv
+ 	.byte	0x8c,0x06
+ 	.word	_xmsdrv+2
+ 
+ 	movb	$0x08, %ah	/* XMS: query free extended memory */
+ 	movb	$0x00, %bl
+ 	.byte	0xff, 0x1e
+ 	.word	_xmsdrv
+ 
+ 	data32
+ 	movw	%dx, %ax
+ 	jmp	xdone
+ 
+ noxms:		/* no XMS manager found */
+ 	data32	/* revert to former result (no extended memory) */
+ 	movl	$0, %eax
+ 
+ xdone:
  	data32
  	movl	$0, %ebx
  	mov	%ax,%bx
  
  	data32
***************
*** 89,96 ****
--- 130,208 ----
  	movl	%ebx, %eax
  
  	pop	%edi
  	pop	%esi
  	popl	%ebx
+ 	popl	%ebp
+ 	ret
+ 
+ /*
+ 	Allocate a block of XMS memory with the requested size
+ 		void * xmsalloc(long int kBytes);
+ 
+ 	Depends on _xmsdrv being set by getextmem() before first call
+ 	to this function.
+ 
+ 	Return value: a physical address.
+ */
+ ENTRY(xmsalloc)
+ 	pushl %ebp
+ 	movl  %esp, %ebp
+ 	pushl	%ebx
+ 	pushl	%esi
+ 	pushl	%edi
+ 
+ 	movl	0x8(%ebp), %edx # Kbytes needed
+ 
+ 	call	_C_LABEL(prot_to_real)	# enter real mode
+ 
+ 	movb	$0x09, %ah	# XMS allocate block
+ 	.byte 0xff,0x1e
+ 	.word _xmsdrv		# result: handle in %dx
+ 	movb	$0x0c, %ah	# XMS lock block
+ 	.byte 0xff,0x1e
+ 	.word _xmsdrv		# result: 32 bit physical address in DX:BX
+ 
+ 	data32
+ 	call	_C_LABEL(real_to_prot) # back to protected mode
+ 
+ 	movl	%edx, %eax
+ 	shl	$16, %eax
+ 	movw	%bx, %ax	# result in %eax
+ 
+ 	popl	%edi
+ 	popl	%esi
+ 	popl	%ebx
+ 	popl	%ebp
+ 	ret
+ 
+ /*
+  * ppbcopy(src, dst, cnt)
+  *	where src and dst are physical addresses
+  */
+ ENTRY(ppbcopy)
+ 	pushl	%ebp
+ 	movl	%esp, %ebp
+ 	pushl	%es
+ 	pushl	%esi
+ 	pushl	%edi
+ 
+ 	cld
+ 
+ 	# set %es to point at the flat segment
+ 	movl	$flatdataseg, %eax
+ 	movl	%ax, %es
+ 
+ 	movl	8(%ebp), %esi		# source
+ 	movl	12(%ebp), %edi		# destination
+ 	movl	16(%ebp), %ecx		# count
+ 
+ 	es
+ 	rep
+ 	movsb
+ 
+ 	popl	%edi
+ 	popl	%esi
+ 	popl	%es
  	popl	%ebp
  	ret
  
diff -rc5 sys/arch/i386/stand.orig/lib/exec.c sys/arch/i386/stand/lib/exec.c
*** sys/arch/i386/stand.orig/lib/exec.c	Fri Mar 14 13:52:13 1997
--- sys/arch/i386/stand/lib/exec.c	Sun Mar 16 04:36:06 1997
***************
*** 82,91 ****
--- 82,94 ----
  	struct exec x;
  	int cc, magic;
  	physaddr_t entry;
  	register physaddr_t cp;
  	u_long boot_argv[6];
+ 	long kernsize = 0;
+ 	physaddr_t tmpbuf = 0;
+ 	long origadr;
  
  #ifdef COMPAT_OLDBOOT
  	char *fsname, *devname;
  	int unit, part;
  	const char *filename;
***************
*** 120,129 ****
--- 123,141 ----
  
  	if(!loadaddr) loadaddr = (entry & 0x100000);
  
  	cp = loadaddr;
  
+ 	if (xmsdrv) {
+ 		/* Determine size of temporary buffer. Reserve some extra space for string table,
+ 		 * konvert to kB by rounding up. */
+ 		kernsize = (x.a_text + x.a_data + x.a_bss + sizeof(x.a_syms) + x.a_syms + 64*1024 + 1023) / 1024;
+ 		tmpbuf = xmsalloc(kernsize);
+ 		origadr = cp;
+ 		cp = tmpbuf;
+ 	}
+ 
  	/*
  	 * Leave a copy of the exec header before the text.
  	 * The kernel may use this to verify that the
  	 * symbols were loaded by this boot program.
  	 */
***************
*** 193,203 ****
  			goto shread;
  		cp += cc;
  	}
  	boot_argv[3] = (((u_int)cp + sizeof(int) - 1)) & (-sizeof(int));
  
! 	printf("=0x%lx\n", cp - loadaddr);
  
  	boot_argv[0] = boothowto;
  
  #ifdef COMPAT_OLDBOOT
  	/* prepare boot device information for kernel */
--- 205,218 ----
  			goto shread;
  		cp += cc;
  	}
  	boot_argv[3] = (((u_int)cp + sizeof(int) - 1)) & (-sizeof(int));
  
! 	if (tmpbuf)
! 		printf("=0x%lx\n", cp - tmpbuf);
! 	else
! 		printf("=0x%lx\n", cp - loadaddr);
  
  	boot_argv[0] = boothowto;
  
  #ifdef COMPAT_OLDBOOT
  	/* prepare boot device information for kernel */
***************
*** 240,249 ****
--- 255,273 ----
  	close(io);
  
  #ifdef DEBUG
  	printf("Start @ 0x%lx ...\n", entry);
  #endif
+ 
+ 	if (xmsdrv) {
+ 		/*
+ 		 * We know have done our last DOS IO, so we may
+ 		 * trash the OS. Copy the data from the temporary
+ 		 * buffer to its real adress.
+ 		 */
+ 		ppbcopy(tmpbuf, origadr, kernsize * 1024);
+ 	}
  
  	startprog(entry, 6, boot_argv, 0x90000);
  	panic("exec returned");
  
  shread:
diff -rc5 sys/arch/i386/stand.orig/lib/libi386.h sys/arch/i386/stand/lib/libi386.h
*** sys/arch/i386/stand.orig/lib/libi386.h	Fri Mar 14 13:52:15 1997
--- sys/arch/i386/stand/lib/libi386.h	Sun Mar 16 04:35:27 1997
***************
*** 38,47 ****
--- 38,51 ----
  void vpbcopy __P((void*, physaddr_t, int));
  void pvbcopy __P((physaddr_t, void*, int));
  void pbzero __P((physaddr_t, int));
  physaddr_t vtophys __P((void*));
  
+ extern int xmsdrv;
+ physaddr_t ppbcopy __P((physaddr_t, physaddr_t, int));
+ physaddr_t xmsalloc __P((int));
+ 
  int pread __P((int, physaddr_t, int));
  void startprog __P((physaddr_t, int, unsigned long*, physaddr_t));
  
  int exec_netbsd __P((const char*, physaddr_t, int, char*, char*));
  int netbsd_opt __P((char));
>Audit-Trail:
>Unformatted: