[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [MiNT] CPU detection broken



So here is my patch for the CPU detection.
Now the behaviour is correct for every CPU supported by the MiNTLib (including ColdFire, I hope).

I had to rewrite Getcookie() and get_sysvar() in assembly language, because they have to be compatible with every CPU. I know assembly language should be avoided as much as possible because of portability issues, but in this case there was no other solution. Fortunately, these assembly sources are small and simple, it will be easy to modify them. However, these functions are rarely modified.

I kept the "Backward compatibility kludge for MiNT 1.14.7", so if a cookie has a value of -42, Getcookie() will return 0 instead :-(

I wrote that code carefully, and I tested it as much as possible, I didn't found any problem. However, I cannot guarantee there is no hidden regression, so be careful. Code reviews will be highly appreciated.

I didn't include a copyright notice in the new files, because I don't want to own them. I didn't know what to put instead.

Please commit this patch with the following description:

----------------------------------------------------------------------
Fixed 68020+ detection.
Added ColdFire detection.
Rewritten getcookie.c in assembly language.
Split sysvar.c into getsysvar.S and setsysvar.c
Fixed MiNTLib Ident string for ColdFire.
Contributed by Vincent Riviere.
----------------------------------------------------------------------

--
Vincent Rivière
diff -aurN -x CVS mintlib.orig/mintlib/SRCFILES mintlib/mintlib/SRCFILES
--- mintlib.orig/mintlib/SRCFILES	2009-05-22 22:35:36.812500000 +0200
+++ mintlib/mintlib/SRCFILES	2009-05-31 23:20:46.317317500 +0200
@@ -17,6 +17,7 @@
 	assert.c \
 	buffindf.c \
 	calloc.c \
+	checkcpu.S \
 	console.c \
 	crtinit.c \
 	ctermid.c \
@@ -32,12 +33,13 @@
 	frexp.S \
 	ftime.c \
 	ftw.c \
-	getcookie.c \
+	getcookie.S \
 	getcwd.c \
 	getenv.c \
 	getloadavg.c \
 	getlogin.c \
 	getopt_old.c \
+	getsysvar.S \
 	getumask.c \
 	getwd.c \
 	globals.c \
@@ -89,12 +91,12 @@
 	setjmp.S \
 	setlocale.c \
 	setstack.S \
+	setsysvar.c \
 	spawn.c \
 	spawnve.c \
 	spawnvp.c \
 	stksiz.c \
 	syscall.c \
-	sysvar.c \
 	tell.c \
 	thread.c \
 	toxxx.c \
diff -aurN -x CVS mintlib.orig/mintlib/checkcpu.S mintlib/mintlib/checkcpu.S
--- mintlib.orig/mintlib/checkcpu.S	1970-01-01 01:00:00.000000000 +0100
+++ mintlib/mintlib/checkcpu.S	2009-06-01 17:10:49.515625000 +0200
@@ -0,0 +1,117 @@
+| checkcpu.S -- MiNTLib.
+|
+| This file is part of the MiNTLib project, and may only be used
+| modified and distributed under the terms of the MiNTLib project
+| license, COPYMINT.  By continuing to use, modify, or distribute
+| this file you indicate that you have read the license and
+| understand and accept it fully.
+
+| void _checkcpu(void);
+|
+| Check if the actual CPU is compatible with this binary.
+| If it is compatible, the function returns silently.
+| If it is not compatible, it displays an error message then exits with the
+| error code -1. In that case, this function never returns.
+|
+| WARNING: This function is called from the startup code before knowing the
+| actual CPU type. So it must be compatible with any processor (including
+| 680x0 and ColdFire models). So it must be written carefully by using only
+| instructions common to all of the supported processors. Especially, gas
+| pseudo-jump instructions must be avoided (jbsr, jbra...), because they may
+| be translated to unsupported jump instructions.
+
+	.extern	_Getcookie		| int Getcookie(long cookie, long *val);
+
+	.globl	__checkcpu
+__checkcpu:
+#ifdef __M68020__
+	subql	#4,sp			| Local variable for cookie value
+
+	pea	sp@
+	movl	#0x5f435055,sp@-	| "_CPU"
+	jsr	_Getcookie
+	addql	#8,sp
+
+	movel	sp@+,d1			| Cookie value
+
+	tstl	d0
+	bnes	.bad020			| _CPU cookie not found
+
+	cmpl	#20,d1
+	bhss	.ok020			| CPU >= 68020
+
+.bad020:
+	pea	.err020			| Error message
+	bra	.printexit
+
+.err020:
+	.ascii	"This program requires a 68020 or higher\r\n", \
+		"processor and cannot be run on this\r\n", \
+		"machine.\r\n\0"
+	.even
+.ok020:
+#endif
+
+#ifdef __mcoldfire__
+	subql	#4,sp			| Local variable for cookie value
+
+	pea	sp@
+	movl	#0x5f43465f,sp@-	| "_CF_"
+	jsr	_Getcookie
+	addql	#8,sp
+
+	movel	sp@+,d1			| Cookie value
+
+	tstl	d0
+	beqs	.okv4e			| _CF_ cookie found
+
+	pea	.errv4e			| Error message
+	bra	.printexit
+
+.errv4e:
+	.ascii	"This program requires a ColdFire V4e\r\n", \
+		"processor and cannot be run on this\r\n", \
+		"machine.\r\n\0"
+	.even
+.okv4e:
+#endif
+
+#ifdef __M68881__
+	subql	#4,sp			| Local variable for cookie value
+
+	pea	sp@
+	movl	#0x5f465055,sp@-	| "_FPU"
+	jsr	_Getcookie
+	addql	#8,sp
+
+	movel	sp@+,d1			| Cookie value
+
+	tstl	d0
+	bnes	.bad881			| _FPU cookie not found
+
+	tstl	d1
+	bnes	.ok881			| FPU present
+
+.bad881:
+	pea	.err881			| Error message
+	bra	.printexit
+
+.err881:
+	.ascii	"This program requires a 68881 or higher\r\n", \
+		"arithmetic coprocessor and cannot be run\r\n", \
+		"on this machine.\r\n\0"
+	.even
+.ok881:
+#endif
+	rts				| All requirements passed
+
+| Print a message then exit.
+| The message must have been pushed on the stack.
+.printexit:
+	movew	#9,sp@-			| Cconws()
+	trap	#1
+	addql	#6,sp
+
+	movew	#-1,sp@-		| Failure
+	movew	#0x4c,sp@-		| Pterm()
+	trap	#1
diff -aurN -x CVS mintlib.orig/mintlib/getcookie.S mintlib/mintlib/getcookie.S
--- mintlib.orig/mintlib/getcookie.S	1970-01-01 01:00:00.000000000 +0100
+++ mintlib/mintlib/getcookie.S	2009-06-01 14:48:04.406250000 +0200
@@ -0,0 +1,94 @@
+| getcookie.S -- MiNTLib.
+|
+| This file is part of the MiNTLib project, and may only be used
+| modified and distributed under the terms of the MiNTLib project
+| license, COPYMINT.  By continuing to use, modify, or distribute
+| this file you indicate that you have read the license and
+| understand and accept it fully.
+
+| int Getcookie(long cookie, long *p_value);
+|
+| Get the value of a system Cookie.
+|
+| WARNING: This function is called from the startup code before knowing the
+| actual CPU type. So it must be compatible with any processor (including
+| 680x0 and ColdFire models). So it must be written carefully by using only
+| instructions common to all of the supported processors. Especially, gas
+| pseudo-jump instructions must be avoided (jbsr, jbra...), because they may
+| be translated to unsupported jump instructions.
+
+	.extern	___has_no_ssystem	| int __has_no_ssystem;
+	.extern	_get_sysvar		| long get_sysvar(void *var);
+
+	.globl	_Getcookie
+_Getcookie:
+	lea	sp@(-16),sp
+	movml	d2/d3/a2/a3,sp@		| ColdFire compatibility
+
+	movel	sp@(16+4),d3		| cookie
+	movel	sp@(16+8),a3		| p_value
+
+	tstl	___has_no_ssystem
+	beqs	.get_with_ssystem
+
+	pea	0x5a0			| _p_cookies
+	jsr	_get_sysvar
+	addql	#4,sp
+
+	tstl	d0
+	beqs	.error			| No cookie jar
+
+	movl	d0,a0
+
+.nextcookie:
+	tstl	a0@
+	beqs	.error			| End of Cookie Jar
+
+	movel	a0@+,d0			| Cookie name
+	movel	a0@+,d1			| Cookie value
+
+	cmpl	d3,d0			| Right cookie ?
+	bnes	.nextcookie
+
+	moveq	#0,d0			| E_OK
+
+.return:
+	cmpl	#0,a3
+	beqs	.restore		| p_value == NULL
+
+	movl	d1,a3@			| *p_value = value;
+
+.restore:
+	movml	sp@,d2/d3/a2/a3		| ColdFire compatibility
+	lea	sp@(16),sp
+	rts
+
+.error:
+	moveq	#-1,d0			| EERROR
+	moveq	#0,d1			| Cookie value
+
+	bras	.return
+
+.get_with_ssystem:
+	pea	-42			| Local variable for cookie value
+
+	pea	sp@			| Pointer to the output variable
+	movl	d3,sp@-			| cookie
+	movew	#8,sp@-			| S_GETCOOKIE
+	movew	#0x154,sp@-		| Ssystem()
+	trap	#1
+	lea	sp@(12),sp
+
+	movel	sp@+,d1			| Cookie value
+
+	cmpl	#-1,d0
+	beqs	.error			| Fail
+
+	| Backward compatibility for MiNT 1.14.7:
+	| Ssystem() returns cookie value and ignores arg2!!
+	cmpl	#-42,d1
+	bnes	.return
+
+	movl	d0,d1			| Get value from return value
+
+	bras	.return
diff -aurN -x CVS mintlib.orig/mintlib/getcookie.c mintlib/mintlib/getcookie.c
--- mintlib.orig/mintlib/getcookie.c	2002-03-14 21:44:50.000000000 +0100
+++ mintlib/mintlib/getcookie.c	1970-01-01 01:00:00.000000000 +0100
@@ -1,86 +0,0 @@
-/*
- * Getcookie for MiNTlib
- * 
- * Author: jerry g geiger
- * 
- * - Ssystem extension Draco
- * - corrected by Frank Naumann, 1998-09-09
- * 
- * returns:
- * 
- * 	- 0 if cookie was found
- * 	- EERROR if cookie is missing
- * 	
- * 	if p_value is set, cookie value is copied to *p_value
- * 
- */
-
-#include <errno.h> 
-#include <mint/mintbind.h>
-#include <mint/ssystem.h>
-#include <mint/sysvars.h>
-
-#include "lib.h"
-
-int
-Getcookie (long cookie, long *p_value)
-{
-	if (__has_no_ssystem)
-	{
-		/* old method */
-		long *cookieptr = (long*) get_sysvar(_p_cookies);
-		
-		if (cookieptr)
-		{
-			while (*cookieptr)
-			{
-				if (*cookieptr == cookie)
-				{
-					if (p_value)
-						*p_value = cookieptr [1];
-					
-					return 0;
-				}
-				
-				cookieptr += 2;
-			}
-		}
-		if (p_value)
-			*p_value = 0;
-
-		return EERROR;
-	}
-	else
-	{
-		/* Ssystem supported, use it */
-		int	r;
-		long	v = -42;
-
-		/* Make sure that P_VALUE is zeroed if the cookie can't
-		   be found.  Reported by Tommy Andersen
-		   (tommya@post3.tele.dk).  */
-		if (p_value)
-			*p_value = 0;
-			
-		r = Ssystem(S_GETCOOKIE, cookie, &v);
-		/*
-		 * Backward compatibility for MiNT 1.14.7:
-		 * Ssystems() returns cookie value and ignores arg2!!
-		 */
-		if (r != -1 && v == -42)				
-			v = r;
- 
-		if (r == -1)							/* not found */
-		{
-			v = 0;
-			r = EERROR;
-		}
-		else
-			r = 0;
-
-		if (p_value)
-			*p_value = v;
-
-		return r;
-	}
-}
diff -aurN -x CVS mintlib.orig/mintlib/getsysvar.S mintlib/mintlib/getsysvar.S
--- mintlib.orig/mintlib/getsysvar.S	1970-01-01 01:00:00.000000000 +0100
+++ mintlib/mintlib/getsysvar.S	2009-06-01 17:41:03.625000000 +0200
@@ -0,0 +1,72 @@
+| getsysvar.S -- MiNTLib.
+|
+| This file is part of the MiNTLib project, and may only be used
+| modified and distributed under the terms of the MiNTLib project
+| license, COPYMINT.  By continuing to use, modify, or distribute
+| this file you indicate that you have read the license and
+| understand and accept it fully.
+
+| long get_sysvar(void *var);
+|
+| Read an OS variable.
+|
+| WARNING: This function is called from the startup code before knowing the
+| actual CPU type. So it must be compatible with any processor (including
+| 680x0 and ColdFire models). So it must be written carefully by using only
+| instructions common to all of the supported processors. Especially, gas
+| pseudo-jump instructions must be avoided (jbsr, jbra...), because they may
+| be translated to unsupported jump instructions.
+
+	.extern	___has_no_ssystem	| int __has_no_ssystem;
+
+	.globl	_get_sysvar
+_get_sysvar:
+	lea	sp@(-16),sp
+	movml	d2/d3/a2/a3,sp@		| ColdFire compatibility
+
+	movel	sp@(16+4),a3		| var
+
+	tstl	___has_no_ssystem
+	beqs	.get_with_ssystem
+
+	movel	#1,sp@-			| SUP_INQUIRE
+	movew	#0x20,sp@-		| Super()
+	trap	#1
+	addql	#6,sp
+
+	tstl	d0
+	beqs	.get_usermode		| We are in user mode
+
+	movel	a3@,d0			| Read the variable directly
+
+.return:
+	movml	sp@,d2/d3/a2/a3		| ColdFire compatibility
+	lea	sp@(16),sp
+	rts
+
+.get_with_ssystem:
+	clrl	sp@-
+	movl	a3,sp@-			| var
+	movew	#10,sp@-		| S_GETLVAL
+	movew	#0x154,sp@-		| Ssystem()
+	trap	#1
+	lea	sp@(12),sp
+
+	bras	.return
+
+.get_usermode:
+	clrl	sp@-			| SUP_SET
+	movew	#0x20,sp@-		| Super()
+	trap	#1			| Switch to supervisor mode
+	addql	#6,sp
+
+	movel	a3@,d3			| Get the variable value
+
+	movel	d0,sp@-			| Old SSP
+	movew	#0x20,sp@-		| Super()
+	trap	#1			| Restore user mode
+	addql	#6,sp
+
+	movel	d3,d0
+
+	bras	.return
diff -aurN -x CVS mintlib.orig/mintlib/ident.c mintlib/mintlib/ident.c
--- mintlib.orig/mintlib/ident.c	2001-09-27 18:31:39.000000000 +0200
+++ mintlib/mintlib/ident.c	2009-06-01 11:26:38.968750000 +0200
@@ -4,6 +4,9 @@
 #ifdef __M68020__
 "-m68020-60 "
 #endif
+#ifdef __mcoldfire__
+"-mcpu=5475 "
+#endif
 #ifdef __M68881__
 "-m68881 "
 #endif
diff -aurN -x CVS mintlib.orig/mintlib/setsysvar.c mintlib/mintlib/setsysvar.c
--- mintlib.orig/mintlib/setsysvar.c	1970-01-01 01:00:00.000000000 +0100
+++ mintlib/mintlib/setsysvar.c	2009-05-31 22:46:08.406250000 +0200
@@ -0,0 +1,20 @@
+
+#include <support.h>
+#include <mint/mintbind.h>
+#include <mint/ssystem.h>
+
+#include "lib.h"
+
+void
+set_sysvar_to_long (void *var, long val)
+{
+	if(__has_no_ssystem) {
+		long save_ssp;
+
+    		save_ssp = (long) Super((void *) 0L);
+    		*((volatile long *)var) = val;
+    		(void)Super((void *) save_ssp);
+	}
+	else
+		(void) Ssystem (S_SETLVAL, var, val); /* note: root only! */
+}
diff -aurN -x CVS mintlib.orig/mintlib/sysvar.c mintlib/mintlib/sysvar.c
--- mintlib.orig/mintlib/sysvar.c	2008-09-29 17:35:27.000000000 +0200
+++ mintlib/mintlib/sysvar.c	1970-01-01 01:00:00.000000000 +0100
@@ -1,45 +0,0 @@
-
-#include <support.h>
-#include <mint/mintbind.h>
-#include <mint/ssystem.h>
-
-#include "lib.h"
-
-
-long
-get_sysvar (void *var)
-{
-	if(__has_no_ssystem) {
-		long ret;
-		
-		if (Super(1L) == 0L) {
-			long save_ssp = (long) Super((void *) 0L);
-
-		/* note: dont remove volatile, otherwise gcc will reorder these
-		 * statements and we get bombs */
-    		ret = *((volatile long *)var);
-
-    		(void)Super((void *) save_ssp);
-    	} else {
-    		ret = *((volatile long *)var);
-    	}
-
-    	return ret;
-	}
-	else
-		return Ssystem (S_GETLVAL, var, NULL);
-}
-
-void
-set_sysvar_to_long (void *var, long val)
-{
-	if(__has_no_ssystem) {
-		long save_ssp;
-
-    		save_ssp = (long) Super((void *) 0L);
-    		*((volatile long *)var) = val;
-    		(void)Super((void *) save_ssp);
-	}
-	else
-		(void) Ssystem (S_SETLVAL, var, val); /* note: root only! */
-}
diff -aurN -x CVS mintlib.orig/startup/crt0.S mintlib/startup/crt0.S
--- mintlib.orig/startup/crt0.S	2009-05-30 00:31:46.187500000 +0200
+++ mintlib/startup/crt0.S	2009-06-01 14:52:42.171875000 +0200
@@ -6,11 +6,24 @@
 | Initialization code; this is common to both 16 and 32 bit libraries,
 | so be careful!
 |
-	.globl	__app		| short, declared in crtinit.c
-	.globl	__base		| BASEPAGE *, declared in globals.c
+| WARNING: All the instructions before the call to _checkcpu() must be
+| compatible with any processor (including 680x0 and ColdFire models).
+| So it must be written carefully by using only instructions common to all
+| of the supported processors. Especially, gas pseudo-jump instructions must
+| be avoided (jbsr, jbra...), because they may be translated to unsupported
+| jump instructions.
+
+|
+| The following external symbols are declared with .globl rather than
+| .extern in order to ensure they will be linked into the executable
+| even if they are not used in this file.
+
+	.globl	__app		| short, defined in crtinit.c
+	.globl	__base		| BASEPAGE *, defined in globals.c
 	.globl	__heapbase	| void *
-	.globl	__stksize	| long, declared by user or in stksiz.c
+	.globl	__stksize	| long, defined by user or in stksiz.c
 	.globl	_main		| for references
+	.globl	___has_no_ssystem	| int, defined in globals.c
 
 |
 | externs to pull ident strings of all used libraries into the
@@ -22,6 +35,13 @@
 	.globl	___Ident_gem
 
 |
+| Functions defined elsewhere.
+
+	.extern	__checkcpu	| void _checkcpu(void);
+	.extern	__acc_main	| void _acc_main(void);
+	.extern	__crtinit	| void _crtinit(void);
+
+|
 | Assumption: basepage is passed in a0 for accessories; for programs
 | a0 is always 0.
 
@@ -30,12 +50,14 @@
 	.globl	__start
 __start:
 	subl	a6, a6		| clear a6 for debuggers
-	cmpw	#0, a0		| test if acc or program
-	jeq	__startprg	| if a program, go elsewhere
+	cmpl	#0, a0		| test if acc or program
+	beqs	__startprg	| if a program, go elsewhere
 	tstl	a0@(36)		| also test parent basepage pointer
-	jne	__startprg	| for accs, it must be 0
+	bnes	__startprg	| for accs, it must be 0
 	movel	a0, __base	| acc basepage is in A0
 	lea	a0@(252), sp	| use the command line as a temporary stack
+	jsr	.early_init	| early initialization
+	jsr	__checkcpu	| check for correct CPU or exit
 	jmp	__acc_main	| function is in crtinit.c
 |
 | program startup code: doesn''t actually do much, other than push
@@ -47,9 +69,27 @@
 	movel	a0@(4), d0	| get _base->p_hitpa
 	bclr	#0, d0		| round off
 	movel	d0, sp		| set stack (temporarily)
+	jsr	.early_init	| early initialization
+	jsr	__checkcpu	| check for correct CPU or exit
 	jmp	__crtinit	| in crtinit.c
 
 |
+| Initialize global variables required by early initialization code.
+| Warning: The registers are not preserved
+|
+.early_init:
+	clrl	sp@-
+	clrl	sp@-
+	movew	#-1,sp@-	| Check Ssystem() availability
+	movew	#0x154,sp@-	| Ssystem()
+	trap	#1
+	lea	sp@(12),sp
+
+	movel	d0,___has_no_ssystem
+
+	rts
+
+|
 | interfaces for gprof: for crt0.o, does nothing, but for gcrt0.o branches
 | to the appropriate subroutines
 |
@@ -58,9 +98,9 @@
 	.globl 	___mcleanup
 
 #ifdef GCRT0
-	.globl	_monstartup
-	.globl	_moncontrol
-	.globl	__mcleanup
+	.extern	_monstartup
+	.extern	_moncontrol
+	.extern	__mcleanup
 
 __monstartup:
 	jmp	_monstartup