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