Porting OpenBSD to the Solbourne S4000

[ Index ] [ Prev: A Few Words on Serial ] [ Next: Every PMAP Goes to Heaven ]

Introducing The CPU

Since the Solbourne is still, somewhat, a sparc-based machine, I can reuse a lot of code written for the OpenBSD/sparc port, or alter it a little to the S4000 needs. This allows me to progress pretty quickly (oh, and the fact that I am currently unemployed helps a lot, too).

On the other hand, the sparc port sometimes have layers or interfaces that are necessary for code that can run on three different processor families (sun4, sun4c and sun4m), which are overkill or simply unnecessary for the KAP processor.

Nevertheless, to benefit from the existing code, it is often better to conform to a particular interface, rather than replace it with a simpler routine.

This particular ``Unknown CPU type'' panic is a very good example of this. Since there are a lot of variation in processors, the processor-agnostic parts of the port refer to a per-cpu structure, which provides information such as the cache size and type (write-back or write-through?), and dedicated callbacks to perform several operation, which can turn to be empty functions on processors where the function does not makes sense (such as flushing a write-through cache) or is not available (any cache operation on a processor which does not have any).

This is why sys/arch/sparc/sparc/cpu.c contains the CPU-specific routines, as well as a table to find which CPU we are using, based upon the decoding of the %psr (Processor Status Register) fields:

#define	ANY	-1	/* match any version */

struct cpu_conf {
	int	arch;
	int	cpu_impl;
	int	cpu_vers;
	int	mmu_impl;
	int	mmu_vers;
	char	*name;
	struct	module_info *minfo;
} cpu_conf[] = {
#if defined(SUN4)
	{ CPU_SUN4, 0, 0, ANY, ANY, "MB86900/1A or L64801", &module_sun4 },
	{ CPU_SUN4, 1, 0, ANY, ANY, "L64811", &module_sun4 },
	{ CPU_SUN4, 1, 1, ANY, ANY, "CY7C601", &module_sun4 },

#if defined(SUN4C)
	{ CPU_SUN4C, 0, 0, ANY, ANY, "MB86900/1A or L64801", &module_sun4c },
	{ CPU_SUN4C, 1, 0, ANY, ANY, "L64811", &module_sun4c },
	{ CPU_SUN4C, 1, 1, ANY, ANY, "CY7C601", &module_sun4c },
	{ CPU_SUN4C, 9, 0, ANY, ANY, "W8601/8701 or MB86903", &module_sun4c },

#if defined(SUN4M)
	{ CPU_SUN4M, 0, 4, 0, 4, "MB86904", &module_swift },
	{ CPU_SUN4M, 0, 5, 0, 5, "MB86907", &module_turbosparc },
	{ CPU_SUN4M, 1, 1, 1, 0, "CY7C601/604", &module_cypress },
	{ CPU_SUN4M, 1, 1, 1, 0xb, "CY7C601/605 (v.b)", &module_cypress },
	{ CPU_SUN4M, 1, 1, 1, 0xc, "CY7C601/605 (v.c)", &module_cypress },
	{ CPU_SUN4M, 1, 1, 1, 0xf, "CY7C601/605 (v.f)", &module_cypress },
	{ CPU_SUN4M, 1, 3, 1, ANY, "CY7C611", &module_cypress },
	{ CPU_SUN4M, 1, 0xe, 1, 7, "RT620/625", &module_hypersparc },
	{ CPU_SUN4M, 1, 0xf, 1, 7, "RT620/625", &module_hypersparc },
	{ CPU_SUN4M, 4, 0, 0, ANY, "TMS390Z50 v0 or TMS390Z55", &module_viking
	{ CPU_SUN4M, 4, 1, 0, ANY, "TMS390Z50 v1", &module_viking },
	{ CPU_SUN4M, 4, 1, 4, ANY, "TMS390S10", &module_ms1 },
	{ CPU_SUN4M, 4, 2, 0, ANY, "TI_MS2", &module_ms2 },
	{ CPU_SUN4M, 4, 3, ANY, ANY, "TI_4_3", &module_viking },
	{ CPU_SUN4M, 4, 4, ANY, ANY, "TI_4_4", &module_viking },

	{ ANY, ANY, ANY, ANY, ANY, "Unknown", &module_unknown }
We have two problems here. First, since I compile without any of the SUN4, SUN4C and SUN4M defines, the only matched processor is the last one. Second, module_unknown causes cpumatch_unknown to be invoked early, and as you can see, it does not do much:
struct module_info module_unknown = {

cpumatch_unknown(sc, mp, node)
	struct cpu_softc *sc;
	struct module_info *mp;
	int	node;
	panic("Unknown CPU type: "
	      "cpu: impl %d, vers %d; mmu: impl %d, vers %d",
		sc->cpu_impl, sc->cpu_vers,
		sc->mmu_impl, sc->mmu_vers);

The panic itself was still a good thing. Not only did it gave me the values I needed to add a line for the KAP processor, but it also proved the serial code was indeed working well. So I quickly created a matching line for it:

#if defined(S4000)
	{ ANY, 5, 0, ANY, ANY, "KAP_M2", &module_kap },
	{ ANY, ANY, ANY, ANY, ANY, "unrecognized KAP variant", &module_kap },
and a module_info structure mostly cloning the module_sun4c one (as I supposed back then that the KAP, like the sun4c, had a write-through cache - it has a write-back cache instead).

With this code in place, the kernel would boot further, and reach the pmap_bootstrap routine. It was time to write a real pmap module...

[ Index ] [ Prev: A Few Words on Serial ] [ Next: Every PMAP Goes to Heaven ]