Ha3sm going 100% Squeal Mode
/Ha3sm/code/8086/ABOUT


When you make a 386 switch modeoids like switching hands with your
silverware eating a steak it squeals like a stuck pig. Squeal Mode is
fully scizophrenic operation of the 386+. It's a delicate surgical
operation to re-join two pigs that were born Siamese twins joined at the
snout, and one is a runt. Both are severely deformed. The good news is we
got plenty of pigs to try this on, and I LOVE porkchops.

Neologisms used...

	dismiss  IRET. Return with address, code segment and flags passed.
	dual	 16 bit datum, INTeLese "word"
	event	 user/invoker of IDT or legvecs
	legvec	 8086 interrupt vector
	reflex	 device handler bottom end, event service
	pull	 pop value keeping value
	submit	 INT N, synchronous trap
	core	 as in pullcore, A C D B SP BP SI and DI

This 8086 dir is for XT/AT stuff like BIOS calls. This is much of what a
PC is and I don't want to throw that info out. Proximity is the best
documentation. The ROMs are on your bus. I also don't want to write a lot
of 8086 code. Like floppy drivers. Although I don't even like the BIOS
keyboard driver. Options are good though, particularly when trying to get
a system going at all. I looked deep into the shiny yellow eyes of...

	o spot-reassembling the BIOS to USE16 pmode

	o VM86

	o switching to real mode

Switching to real mode is what the BIOS will like best. And is the
simplest of the three, and I've done it before. And is least dependant on
the more inscrutable INTeLnesses. This way we worry about the PE flag and
not much other pmode bletchery. This minimizes the Wintendo game of trying
to find out how things work that don't work. Molesting a gargoyle like the
PC isn't half bad if you leave the flag draped over it's faces.

Here's the plan ...

    init ...
		trivial & done
		Copy the legvecs to $legvec.

		fleshed out but untested
		Write IRQup, which catches an 8086 event, goes to ring0 
		and submits an event into a pmode reflex, and returns to
		rmode.

		trivial&done
		replicate IRQup for each event number that will use it 

		trivial
		self-mod each replica of IRQup with the event number 
		in question at init time so you don't have to pass
		that value into one instance of it while doing
		twisted state stunts at runtime

		Trivial
		Hook each legacy event vector in k0 to the pertinent replica
		of IRQup. Probably the IRQs (at 0x20->0x2f) and exception 2,
		single-step exception.

		trivial
		Hook the hot events like NMI with a pure rmode reflex. In 
			addition to the pmode reflex.

		fleshed out but untested
		Write a FINT that switches to real mode, calls the 
			BIOS from real mode, switches back to pmode.

		trivial &done
		Replicate the above for the 16 or so interesting BIOS INTs.

		trivial and done
		init-self-mod each copy of FINT for the entry point of each
		BIOS INT FINTed.

		trivial and done
		name the entry points of the FINTs in assembly state ala
		FINT10 FINT11 FINT12 to be used ala   call FINT13


from ring0 ...  
		Use legacy BIOS calls at will via call FINTxn. Set up
		the call as per BIOS register conventions, ignoring the 
		high duals of the core registers. Recieve BIOS return info
		as per BIOS legacy usual.


. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
              
Squeal Mode bimodal events
				   _________straight 8086 reflex---dismiss
               8086 legvecs @ 0   /				     /
                    ______	 /				<---/
		   |8086\	/
		  /|8086 ------/              
		 / |8086 /   
living 	     r	/  |IRQup  --=------->     IRQupN
well in        /   |8086    /                 |
rmode	 *POW*/    |IRQup--/                  |
or --->>>EVENT     |IRQup /                   |
pmode         \    |___     		      |
               \                              |
              p \                        switch to pmode ring 0 
                 |           r                |
                 |       /---------  submit the event number N
		 |	 |		      |
                 |       |             pmode event handler returns here
  A		 V 	 V	 /->      consuming submit frame
  |              |              /              |
  |    r         |             /        switch to rmode
  \ -----	 |   <-------  |   <-\	      |
		 |	       |      \	   dismiss
                 \      ____   |r      \_____/
                  \    |       | 
                   \   | I  \  |
                    \  |     \ |dismiss
                     \ | D    \|
                      \|    __/\
                       | T   /  \
                       |    /    \ 
      /\               |   /      \
       |               |____       \p
       \    p			   /
	\_________________________/

 
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .


ring 0 wants to call a BIOS INT

There will be routines ala FINT10, FINT11, FINT12... based on this, FINT.



get your (386+) regs as per the particular
BIOS INT spec, but bigger
        |
        |
  call FINT10    	(pmode interface to BIOS INT 0x10)
        |
    switch to rmode
          |
  push an 8086 dismiss frame
      by hand
     	  |				
get the regs like they were when FINT was called	  
	  |	
    jump far BIOS 0x10 entry point**  -----> BIOS ------> dismiss
          |					         /
    BIOS dismisses to here ***	    <-------------------/
          |
     switch to pmode
          |
  get regs like they were at BIOS dismiss
	  |	  
          return

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

** the far jump 16:16 pointers are selfmodded for each FINTxn to the
appropriate RAM ROM image at init time, based on the original bootup
legvecs+RAMROM shifts. Or just leave 'em in ROM. But still it's a self-mod
for more than one box.

You need about 16 instances of IRQup init-modded to the pertinent event
number. NMI will have a straight-8086 reflex in addition to the pmode
reflex, so you need IRQup for the IRQs. The 8086 exceptions can have
8086 ignore reflexes.

*** part of the aforementioned 8086 IRET stack frame push. 


........................................................................


SUMMARY

In order to flip back and forth from rmode to pmode and not kill
event-handling, i.e. to still run an OS, you have to leave events on. That
means you have to handle events in either mode roughly equivalently. I
want the option of calling the legacy BIOS INTs. Some of them probably
kill IRQ-handling, but that's the breaks. So do interrupt gates, BTW. I
want the option of using the BIOS only in the kernel though. That means
I'm going from pmode to rmode, BIOS, then back to pmode. That's in the
FINTs. I'm going to leave events on in the FINTs, off in the default
IRQups. The BIOS probably varies from INT to INT on that. Worst case, I
doubt the BIOS turns off NMI except when asked to. Hope.

Given an rmode BIOS INT in what is otherwise a pmode OS, events occur in
rmode. Asynchronous events that may occur in such a scenario are NMI, 8086
exceptions, and IRQs. No protection exceptions, no synchronous traps, i.e.
INTs. That gives about 25 events that one has to prepare for in rmode.
IRQs get spliced back to pmode, dismiss, and return to rmode. They use the
pmode handlers. They need a splice. NMI will have an explicit rmode reflex
in addition to the pmode reflex, or the one NMI reflex will be coded
mode-indifferently. 8086 exceptions can be ignored in a kernel.

Thus to not throw out the BIOS and still have an OS one has to have a BIOS
INT wrapper (FINT in Ha3sm), and an IRQ modesplice (IRQup in Ha3sm). Both
are instantiated for each IRQ or INT in question to reduce problems with
the severe state restrictions on code handling events on a scizophrenic
machine.

FINT is the top of this. IRQup only happens when an async event occurs
during a FINT. FINTs are the only time I foresee proactively switching to
rmode.

..............................

One FINTxn is about 27 bytes. One IRQup is about 37. This means the
overhead for this is about the magnitude of the overhead for a pmode trap,
so shunted rmode events and FINTs have about the lag of regular pmode
events. Async pmode events aren't effected.

Sow is 149 bytes. The replicas of FINT and IRQup are sty and wallow in the
low 64k. sow+sty+wallow+FINT+IRQup is 1203 bytes. That's at runtime. That
may grow if other events get added, like the single-step trace event 2.

The boot image cost of sow+IRQup+FINT is 213 bytes. That won't grow by
much. Heh. Make a nice bootsector, eh?


..................................

The first Squeal Mode will assume a tiny ring0 stack in 64k0. That is
wrappable, later.

--------------------------------

If you don't turn IRQs off in an IRQup they may occur in rmode or pmode.  
To emulate interrupt gates you'll want to turn off IRQs for most IRQups.
The recursive nature of the which-mode-are-we-in problem is offset by the
nesting involved, and each nesting layer loses some possible event
scenarios, and gets orders of magnitude less frequent, and yes, harder to
debug.

................................

Development and Testing procedures

	Stare at the code for weeks.
	Pore over the listing. Before trying to run the two-headed pig.
	Don't do anything extraneous at first, like RAMing the ROMs.
	Check the sty and wallow visually on the screen. 

	Set up just the IRQup side and run in rmode for long stretches, 
		and expect pmode twitches to still work as such.

	DO FINTs with IRQs off and no IRQups.

	Siamese the pig.	

in roughly that order. Repeat as necessary.

..............................................................................

Pure Squeal Mode Code,  PSMC

Memory refs with modr/m (and SIB) aren't the same in use16 and use32. Here are some
instructions that are, as far as the assembled bytes...
(as checked against osimplay)

	push <reg>
	pull <reg>
	pullcore
	pushcore
	copy 
	copies 
	copy byte
	copies bytes
	call <reg>		# bogus osimplay? jump <reg> isn't squealable.
	when bla short   target
	swap <reg> with <reg>

Ultimately, you need an address literal at some point. That routine or level or
whatever will probably have to be in two versions. 


The init for all this is in global/init/sow.
