xref: /plan9-contrib/sys/src/9/pcboot/realmode.c (revision 0792d947be768a877eb2f61da0eec05e1238d60b)
125210b06SDavid du Colombier #include	"u.h"
225210b06SDavid du Colombier #include	"../port/lib.h"
325210b06SDavid du Colombier #include	"mem.h"
425210b06SDavid du Colombier #include	"dat.h"
525210b06SDavid du Colombier #include	"fns.h"
625210b06SDavid du Colombier #include	"io.h"
725210b06SDavid du Colombier #include	"ureg.h"
825210b06SDavid du Colombier #include	"../port/error.h"
925210b06SDavid du Colombier 
1025210b06SDavid du Colombier /*
1125210b06SDavid du Colombier  * Back the processor into real mode to run a BIOS call,
1225210b06SDavid du Colombier  * then return.  This must be used carefully, since it
1325210b06SDavid du Colombier  * completely disables hardware interrupts (e.g., the i8259)
1425210b06SDavid du Colombier  * while running.  It is *not* using VM86 mode.
1525210b06SDavid du Colombier  * Maybe that's really the right answer, but real mode
1625210b06SDavid du Colombier  * is fine for now.  We don't expect to use this very much --
1725210b06SDavid du Colombier  * just for BIOS INT 13 disk i/o.
1825210b06SDavid du Colombier  */
1925210b06SDavid du Colombier 
2025210b06SDavid du Colombier void realmode0(void);		/* in realmode0.s */
2125210b06SDavid du Colombier void realmodeintrinst(void);	/* in realmode0.s */
2225210b06SDavid du Colombier void realmodeend(void);		/* in realmode0.s */
2325210b06SDavid du Colombier 
2425210b06SDavid du Colombier extern ushort rmseg;		/* in realmode0.s */
2525210b06SDavid du Colombier 
2625210b06SDavid du Colombier static Ureg rmu;
2725210b06SDavid du Colombier static QLock rmlock;
2825210b06SDavid du Colombier static int beenhere;
2925210b06SDavid du Colombier 
3025210b06SDavid du Colombier void
realmode(Ureg * ureg)3125210b06SDavid du Colombier realmode(Ureg *ureg)
3225210b06SDavid du Colombier {
3325210b06SDavid du Colombier 	int s, sz;
3425210b06SDavid du Colombier 	ulong cr3;
3525210b06SDavid du Colombier 	uchar *ip;
3625210b06SDavid du Colombier 
3725210b06SDavid du Colombier 	qlock(&rmlock);
3825210b06SDavid du Colombier 	if (!beenhere)
3925210b06SDavid du Colombier 		iprint("into bios in real mode...");
4025210b06SDavid du Colombier 	*(Ureg *)RMUADDR = *ureg;
4125210b06SDavid du Colombier 
4225210b06SDavid du Colombier 	/*
4325210b06SDavid du Colombier 	 * in pxe-loaded bootstraps, the l.s real-mode code is already
4425210b06SDavid du Colombier 	 * below 64K, but for pbs-loaded bootstraps, we need to copy it there.
4525210b06SDavid du Colombier 	 */
4625210b06SDavid du Colombier 	ip = (void *)realmodeintrinst;		/* the INT instruction */
4725210b06SDavid du Colombier 	ip[1] = ureg->trap;			/* insert INT number */
4825210b06SDavid du Colombier 	coherence();
4925210b06SDavid du Colombier 	if ((uintptr)KTZERO == KZERO+PXEBASE)	/* pxe-loaded? */
5025210b06SDavid du Colombier 		rmseg = 0;			/* into JMPFAR instr. */
5125210b06SDavid du Colombier 	else {
5225210b06SDavid du Colombier 		/* copy l.s so that it can be run from 16-bit mode */
5325210b06SDavid du Colombier 		sz = (char *)realmodeend - (char *)KTZERO;
5425210b06SDavid du Colombier 		if (sz > RMSIZE)
55*0792d947SDavid du Colombier 			panic("real mode code %d bytes > %d", sz, RMSIZE);
5625210b06SDavid du Colombier 		rmseg = (RMCODE - KZERO) >> 4;	/* into JMPFAR instr. */
5725210b06SDavid du Colombier 		memmove((void*)RMCODE, (void*)KTZERO, sz);
5825210b06SDavid du Colombier 	}
5925210b06SDavid du Colombier 	coherence();
6025210b06SDavid du Colombier 
6125210b06SDavid du Colombier 	s = splhi();
6225210b06SDavid du Colombier 	m->pdb[PDX(0)] = m->pdb[PDX(KZERO)];	/* identity map low */
6325210b06SDavid du Colombier 	cr3 = getcr3();
6425210b06SDavid du Colombier 	putcr3(PADDR(m->pdb));
6525210b06SDavid du Colombier 	if (arch)
6625210b06SDavid du Colombier 		arch->introff();
6725210b06SDavid du Colombier 	else
6825210b06SDavid du Colombier 		i8259off();
6925210b06SDavid du Colombier 
7025210b06SDavid du Colombier 	realmode0();
7125210b06SDavid du Colombier 	splhi();				/* who knows what the bios did */
7225210b06SDavid du Colombier 
7325210b06SDavid du Colombier 	if(m->tss){
7425210b06SDavid du Colombier 		/*
7525210b06SDavid du Colombier 		 * Called from memory.c before initialization of mmu.
7625210b06SDavid du Colombier 		 * Don't turn interrupts on before the kernel is ready!
7725210b06SDavid du Colombier 		 */
7825210b06SDavid du Colombier 		if (arch)
7925210b06SDavid du Colombier 			arch->intron();
8025210b06SDavid du Colombier 		else
8125210b06SDavid du Colombier 			i8259on();
8225210b06SDavid du Colombier 	}
8325210b06SDavid du Colombier 	m->pdb[PDX(0)] = 0;	/* remove low mapping */
8425210b06SDavid du Colombier 	putcr3(cr3);
8525210b06SDavid du Colombier 	splx(s);
8625210b06SDavid du Colombier 
8725210b06SDavid du Colombier 	*ureg = *(Ureg *)RMUADDR;
8825210b06SDavid du Colombier 	if (!beenhere) {
8925210b06SDavid du Colombier 		beenhere = 1;
9025210b06SDavid du Colombier 		iprint("and back\n");
9125210b06SDavid du Colombier 	}
9225210b06SDavid du Colombier 	qunlock(&rmlock);
9325210b06SDavid du Colombier }
94