xref: /plan9-contrib/sys/src/9/pcboot/realmode.c (revision 0792d947be768a877eb2f61da0eec05e1238d60b)
1 #include	"u.h"
2 #include	"../port/lib.h"
3 #include	"mem.h"
4 #include	"dat.h"
5 #include	"fns.h"
6 #include	"io.h"
7 #include	"ureg.h"
8 #include	"../port/error.h"
9 
10 /*
11  * Back the processor into real mode to run a BIOS call,
12  * then return.  This must be used carefully, since it
13  * completely disables hardware interrupts (e.g., the i8259)
14  * while running.  It is *not* using VM86 mode.
15  * Maybe that's really the right answer, but real mode
16  * is fine for now.  We don't expect to use this very much --
17  * just for BIOS INT 13 disk i/o.
18  */
19 
20 void realmode0(void);		/* in realmode0.s */
21 void realmodeintrinst(void);	/* in realmode0.s */
22 void realmodeend(void);		/* in realmode0.s */
23 
24 extern ushort rmseg;		/* in realmode0.s */
25 
26 static Ureg rmu;
27 static QLock rmlock;
28 static int beenhere;
29 
30 void
realmode(Ureg * ureg)31 realmode(Ureg *ureg)
32 {
33 	int s, sz;
34 	ulong cr3;
35 	uchar *ip;
36 
37 	qlock(&rmlock);
38 	if (!beenhere)
39 		iprint("into bios in real mode...");
40 	*(Ureg *)RMUADDR = *ureg;
41 
42 	/*
43 	 * in pxe-loaded bootstraps, the l.s real-mode code is already
44 	 * below 64K, but for pbs-loaded bootstraps, we need to copy it there.
45 	 */
46 	ip = (void *)realmodeintrinst;		/* the INT instruction */
47 	ip[1] = ureg->trap;			/* insert INT number */
48 	coherence();
49 	if ((uintptr)KTZERO == KZERO+PXEBASE)	/* pxe-loaded? */
50 		rmseg = 0;			/* into JMPFAR instr. */
51 	else {
52 		/* copy l.s so that it can be run from 16-bit mode */
53 		sz = (char *)realmodeend - (char *)KTZERO;
54 		if (sz > RMSIZE)
55 			panic("real mode code %d bytes > %d", sz, RMSIZE);
56 		rmseg = (RMCODE - KZERO) >> 4;	/* into JMPFAR instr. */
57 		memmove((void*)RMCODE, (void*)KTZERO, sz);
58 	}
59 	coherence();
60 
61 	s = splhi();
62 	m->pdb[PDX(0)] = m->pdb[PDX(KZERO)];	/* identity map low */
63 	cr3 = getcr3();
64 	putcr3(PADDR(m->pdb));
65 	if (arch)
66 		arch->introff();
67 	else
68 		i8259off();
69 
70 	realmode0();
71 	splhi();				/* who knows what the bios did */
72 
73 	if(m->tss){
74 		/*
75 		 * Called from memory.c before initialization of mmu.
76 		 * Don't turn interrupts on before the kernel is ready!
77 		 */
78 		if (arch)
79 			arch->intron();
80 		else
81 			i8259on();
82 	}
83 	m->pdb[PDX(0)] = 0;	/* remove low mapping */
84 	putcr3(cr3);
85 	splx(s);
86 
87 	*ureg = *(Ureg *)RMUADDR;
88 	if (!beenhere) {
89 		beenhere = 1;
90 		iprint("and back\n");
91 	}
92 	qunlock(&rmlock);
93 }
94