plan9fox/sys/src/9/pc/apmjump.s
cinap_lenrek 15c7d856bc apm: fix wrong segment load, zero segment registers
we loaded APMDSEG instead of APMDSEL into DS. (ouch!)

its not really clear why we loaded DS (wong) in the
first place as bios is supposed to do this. for the
machines where this worked it could have no effect
anyway because it was wrong so removing the DS load
and just zero all segment registers.
2013-09-16 16:23:51 +02:00

86 lines
1.4 KiB
ArmAsm

/*
* Far call, absolute indirect.
* The argument is the offset.
* We use a global structure for the jump params,
* so this is *not* reentrant or thread safe.
*/
#include "mem.h"
#define SSOVERRIDE BYTE $0x36
#define CSOVERRIDE BYTE $0x2E
GLOBL apmjumpstruct+0(SB), $8
TEXT apmfarcall(SB), $0
/*
* We call push and pop ourselves.
* As soon as we do the first push or pop,
* we can't use FP anymore.
*/
MOVL off+4(FP), BX
MOVL seg+0(FP), CX
MOVL BX, apmjumpstruct+0(SB)
MOVL CX, apmjumpstruct+4(SB)
/* load necessary registers from Ureg */
MOVL ureg+8(FP), DI
MOVL 28(DI), AX
MOVL 16(DI), BX
MOVL 24(DI), CX
MOVL 20(DI), DX
/* save registers, segments */
PUSHL DS
PUSHL ES
PUSHL FS
PUSHL GS
PUSHL BP
PUSHL DI
/*
* paranoia: zero the segments, since it's the
* BIOS's responsibility to initialize them.
* (trick picked up from Linux driver).
*/
PUSHL DX
XORL DX, DX
PUSHL DX
POPL DS
PUSHL DX
POPL ES
PUSHL DX
POPL FS
PUSHL DX
POPL GS
POPL DX
/*
* The actual call.
*/
CSOVERRIDE; BYTE $0xFF; BYTE $0x1D
LONG $apmjumpstruct+0(SB)
/* restore segments, registers */
POPL DI
POPL BP
POPL GS
POPL FS
POPL ES
POPL DS
PUSHFL
POPL 64(DI)
/* store interesting registers back in Ureg */
MOVL AX, 28(DI)
MOVL BX, 16(DI)
MOVL CX, 24(DI)
MOVL DX, 20(DI)
MOVL SI, 4(DI)
PUSHFL
POPL AX
ANDL $1, AX /* carry flag */
RET