Page 2 of 2

Re: Can't get a working bootloader in my old 8086

Posted: Wed Apr 07, 2010 4:06 am
by jal
Love4Boobies wrote:It's not an implementation choice - the wrong SP value is being pushed.
Intel clearly meant the push operation to always be countered by a pop, not reading the value from the stack. And since the pop does the reverse of push, a push sp followed by a pop sp works as it should.
The way around this is to replace all occurences of "push sp" with:
There's no need for a way around: as long as you pop sp when you have pushed sp, there's no problem. The fact that your expectation is different from what happens does not matter.
It is a bug as many people on this forum will tell you - the BIOS Boot Specification specifically defines the address 0000:7C00h to make sure that code will always work
The BIOS boot specification was drawn up by Compaq, Phoenix and Intel in the mid nineties. Why people think this is authorative and has anything to say on BIOSes that predate this specification, and are not of those companies, I don't know.
the same physical address will not be enough as a simple relative jump will screw everything over
A relative jump works perfectly, methinks. It's absolute jumps within the segment that would screw things up.
I meant officially. And to go through unofficial material is more often than not unreliable. I'm also missing the link in your post to such a list
It is called the "Intel 80286 Programmer's Reference Manual".
The Intel 80286 Programmer's Reference Manual wrote:Software Compatibility Considerations

In general, the real address mode 80286 will correctly execute ROM-based
8086/8088 software. The following is a list of the minor differences between
8086 and 80286 (Real mode).

1. Add Six Interrupt Vectors. The 80286 adds six interrupts which arise
only if the 8086 program has a hidden bug. These interrupts occur only
for instructions which were undefined on the 8086/8088 or if a segment
wraparound is attempted. It is recommended that you add an interrupt
handler to the 8086 software that is to be run on the 80286, which
will treat these interrupts as invalid operations. This additional
software does not significantly effect the existing 8086 software
because the interrupts do not normally occur and should not already
have been used since they are in the interrupt group reserved by
Intel. Table C-1 describes the new 80286 interrupts.

2. Do not Rely on 8086/8088 Instruction Clock Counts. The 80286 takes
fewer clocks for most instructions than the 8086/8088. The areas to
look into are delays between I/O operations, and assumed delays in
8086/8088 operating in parallel with an 8087.

3. Divide Exceptions Point at the DIV Instruction. Any interrupt on the
80286 will always leave the saved CS:IP value pointing at the
beginning of the instruction that failed (including prefixes). On the
8086, the CS:IP value saved for a divide exception points at the next
instruction.

4. Use Interrupt 16 for Numeric Exceptions. Any 80287 system must use
interrupt vector 16 for the numeric error interrupt. If an 8086/8087
or 8088/8087 system uses another vector for the 8087 interrupt, both
vectors should point at the numeric error interrupt handler.

5. Numeric Exception Handlers Should allow Prefixes. The saved CS:IP
value in the NPX environment save area will point at any leading
prefixes before an ESC instruction. On 8086/8088 systems, this value
points only at the ESC instruction.

6. Do Not Attempt Undefined 8086/8088 Operations. Instructions like
POP CS or MOV CS,op will either cause exception 6 (undefined opcode)
or perform a protection setup operation like LIDT on the 80286.
Undefined bit encodings for bits 5-3 of the second byte of POP MEM or
PUSH MEM will cause exception 13 on the 80286.

7. Place a Far JMP Instruction at FFFF0H. After reset, CS:IP = F000:FFF0
on the 80286 (versus FFFF:0000 on the 8086/8088). This change was made
to allow sufficient code space to enter protected mode without
reloading CS. Placing a far JMP instruction at FFFF0H will avoid this
difference. Note that the BOOTSTRAP option of LOC86 will automatically
generate this jump instruction.

8. Do not Rely on the Value Written by PUSH SP. The 80286 will push a
different value on the stack for PUSH SP than the 8086/8088. If the
value pushed is important, replace PUSH SP instructions with the
following three instructions:
PUSH BP
MOV BP,SP
XCHG BP,[BP]
This code functions as the 8086/8088 PUSH SP instruction on the 80286.

9. Do not Shift or Rotate by More than 31 Bits. The 80286 masks all
shift/rotate counts to the low 5 bits. This MOD 32 operation limits
the count to a maximum of 31 bits. With this change, the longest
shift/rotate instruction is 39 clocks. Without this change, the
longest shift/rotate instruction would be 264 clocks, which delays
interrupt response until the instruction completes execution.

10. Do not Duplicate Prefixes. The 80286 sets an instruction length limit
of 10 bytes. The only way to violate this limit is by duplicating a
prefix two or more times before an instruction. Exception 6 occurs if
the instruction length limit is violated. The 8086/8088 has no
instruction length limit.

11. Do not Rely on Odd 8086/8088 LOCK Characteristics. The LOCK prefix and
its corresponding output signal should only be used to prevent other
bus masters from interrupting a data movement operation. The 80286
will always assert LOCK during an XCHG instruction with memory (even
if the LOCK prefix was not used). LOCK should only be used with the
XCHG, MOV, MOVS, INS, and OUTS instructions. The 80286 LOCK signal
will not go active during an instruction prefetch.

12. Do not Single Step External Interrupt Handlers. The priority of the
80286 single step interrupt is different from that of the 8086/8088.
This change was made to prevent an external interrupt from being
single-stepped if it occurs while single stepping through a program.
The 80286 single step interrupt has higher priority than any external
interrupt. The 80286 will still single step through an interrupt
handler invoked by INT instructions or an instruction exception.

13. Do not Rely on IDIV Exceptions for Quotients of 80H or 8000H. The
80286 can generate the largest negative number as a quotient for IDIV
instructions. The 8086 will instead cause exception 0.

14. Do not Rely on NMI Interrupting NMI Handlers. After an NMI is
recognized, the NMI input and processor extension limit error
interrupt is masked until the first IRET instruction is executed.

15. The NPX error signal does not pass through an interrupt controller
(an 8087 INT signal does). Any interrupt controller-oriented
instructions for the 8087 may have to be deleted.

16. If any real-mode program relies on address space wrap-around (e.g.,
FFF0:0400=0000:0300), then external hardware should be used to force
the upper 4 addresses to zero during real mode.

17. Do not use I/O ports 00F8-00FFH. These are reserved for controlling
80287 and future processor extensions.
In case you need glasses, my post came before Gigasoft's post.
Gigasoft wrote:One of the very first instructions of BOOTPROG is shl ax, 6, which obviously won't work.
l4b wrote:80386+ CPUs support extended registers, which is the most likely cause of your problems. (Don't worry about fancy instructions, I've never seen them in boot sectors.)
Here, Gs already nailed the problem down, you giving uninformative and in this case wrong answers. It's funny, you do it again:
Divide exceptions in the 8086 will leave CS:IP pointing to the following instruction.
Gigasoft already wrote:After a divide error, the saved IP points to the next instruction
Do not rely on IDIV exceptions for quotients of 80H or 8000H. The 8086 will cause exception 0.
Gigasoft already wrote:IDIV with result equal to 80h (byte) or 8000h (word) causes divide error
Look, I've nothing against you, and have no intention of trolling, it's just that you misinform and duplicate.


JAL

Re: Can't get a working bootloader in my old 8086

Posted: Wed Apr 07, 2010 6:26 am
by Love4Boobies
jal wrote:
Love4Boobies wrote:It's not an implementation choice - the wrong SP value is being pushed.
Intel clearly meant the push operation to always be countered by a pop, not reading the value from the stack. And since the pop does the reverse of push, a push sp followed by a pop sp works as it should.
The way around this is to replace all occurences of "push sp" with:
There's no need for a way around: as long as you pop sp when you have pushed sp, there's no problem. The fact that your expectation is different from what happens does not matter.
It's funny how both your quote from the 80286 manuals and the current Intel manuals seem to agree with me - the software is incompatible and you need a workaround if you are going to rely on the value of SP.
It is a bug as many people on this forum will tell you - the BIOS Boot Specification specifically defines the address 0000:7C00h to make sure that code will always work
The BIOS boot specification was drawn up by Compaq, Phoenix and Intel in the mid nineties. Why people think this is authorative and has anything to say on BIOSes that predate this specification, and are not of those companies, I don't know.
Because it's what BIOS vendors actually use? Why are the PCI specifications relevant to anyone? Maybe all computers have proprietary PCI implementations, the ones from PCI-SIG must be irrelevant... Or maybe they're adopted because jal of OSDev.org likes them and the others are not because jal of OSDev.org doesn't... What do you think of VBE? Maybe it only works on VESA computers :wink: Or EDD? Etc...
the same physical address will not be enough as a simple relative jump will screw everything over
A relative jump works perfectly, methinks. It's absolute jumps within the segment that would screw things up.
I meant short jumps (the ones that specify offsets only). An absolute jump will work because in combination with the segment register, it will resolve to the same physical address.
I meant officially. And to go through unofficial material is more often than not unreliable. I'm also missing the link in your post to such a list
It is called the "Intel 80286 Programmer's Reference Manual".
Erm, did the op ask about 8086 vs. 80286 or current IA-32 CPUs? And not only is that list incomplete (because of later CPUs - for instance notice the lack of the information on shift/rotate by immediate values != 1), it is also incorrect in a few regards, but perhaps the OP doesn't care about that. He probably just asked about some list so he could sleepy happy. Thank you for providing an unrelated answer though.
Gigasoft wrote:One of the very first instructions of BOOTPROG is shl ax, 6, which obviously won't work.
l4b wrote:80386+ CPUs support extended registers, which is the most likely cause of your problems. (Don't worry about fancy instructions, I've never seen them in boot sectors.)
Here, Gs already nailed the problem down, you giving uninformative and in this case wrong answers.
It's funny how my answers are not wrong (except that I indeed missed the shift/rotate by non-1 immediates which seems to really piss you off enough to spam the whole thread about it) and it's also funny how you are missing a post where the OP asks for something else, which is what I was answering. Take your flame some other place, this forum is no place for them.

EDIT: Fixed quote tags.