Page 1 of 2
control registers
Posted: Wed Jul 02, 2003 12:55 pm
by slacker
why cant the entire instruction set be used with the control registers cause i tried:
or cr0, 1
...and the compiler doesnt like it
Re:control registers
Posted: Wed Jul 02, 2003 1:26 pm
by Pype.Clicker
because there's no access to CR0 from the ALU, and because an instruction like or <register>,1 is actually encoded something like
db OR_WITH_REGISTER_OPCODE|REGISTER_INDEX 0x01
as there is limited space in "REGISTER_INDEX" bit field, this operation allowed only general registers.
This is very common for an architecture to have 2 type of resources: one on which you can perform the whole ALU operations and the other that you can only load and store.
If you look at a RISC design, you can't even write
"or [memory],1" : you have to
Code: Select all
load r0,memory
or r0,1
store memory,r0
but those RISC processor usually have much more registers.
Re:control registers
Posted: Wed Jul 02, 2003 1:37 pm
by slacker
so then how would i move a 32 bit register into a 16 bit register since im in real mode atr this point..?
Re:control registers
Posted: Wed Jul 02, 2003 1:44 pm
by Tim
Just use EAX etc. as normal. The assembler will insert the appropriate prefix automatically.
Re:control registers
Posted: Wed Jul 02, 2003 3:00 pm
by slacker
Tim Robinson wrote:
The assembler will insert the appropriate prefix automatically.
que? huh?
Re:control registers
Posted: Wed Jul 02, 2003 3:06 pm
by Tim
To use 32-bit registers in a 16-bit code segment, or 16-bit registers in a 32-bit code segment, you have to use an operand size override prefix. This is a 66h or 67h byte (can't remember which) which goes before the instruction. It says to the processor, "look, I know this is 16-bit code, but treat the next instruction as 32-bit, OK?"
Any assembler I know of inserts the prefixes automatically, provided your [BITS 16] or [BITS 32] is set to the bit size of your code segment, so just use the 32-bit registers and don't worry about it.
Re:control registers
Posted: Wed Jul 02, 2003 3:09 pm
by Pype.Clicker
even in real mode (on a 386+), you can access the whole 32bits of your *registers*. You can even use long addressing and write things like "mov eax,[ebx+ecx*4]". However, as this is a 32bits-decoded instruction, it will require a "db 66h, 67h" prefix to be interpreted correctly by the CPU.
"db 66h" acts as a "32-bits operand" escape sequence and "db 67h" as "32bits addressing" escape sequence. Nasm generates them automatically when 32bits instructions are issued in a [bit 16] section or when 16 bits instructions are used in [bits 32] section, so you needn't to worry about anything ...
What you can't do in real mode is generating an offset that is larger than the segment limit (initialized at 64K) because GPF will be raised (yes, it will! believe me or not) and the IDT is unlikely to be set up (unless you're in persistent unreal mode, which hooks reinitialized segments and re-enables unreal mode "on demand")
so you'll get the infamous "3rd Exception Without resolution" which will restart your PC.
It's pretty funny to see that shadowed base, limit, etc. fields are still used in real mode, but in a way that makes it compatible with 8086 (so that the shadowed base for a segment is loaded with value*16 rather than looking up the GDT
Re:control registers
Posted: Wed Jul 02, 2003 4:00 pm
by Tim
You can handle a GPF through the real-move IVT as you would any other exception -- the CPU isn't going to triple fault just because there's no IDT. In fact, in real mode, it's probably not going to triple fault at all, since there's not much that can go wrong when handling a real-mode interrupt.
Re:control registers
Posted: Wed Jul 02, 2003 4:50 pm
by Pype.Clicker
Tim Robinson wrote:
You can handle a GPF through the real-move IVT as you would any other exception -- the CPU isn't going to triple fault just because there's no IDT. In fact, in real mode, it's probably not going to triple fault at all, since there's not much that can go wrong when handling a real-mode interrupt.
For having tested it myself, i can tell you that breaking the 64K limit of a real-mode segment does not call real-mode interrupt #0x0d (that was IRQ5 -- the SoundBlaster). And if you never have set up a protected-mode IDT before, i can guarantee you that it actually resets your computer by having tried it on 386, 486 and pentium in my early tests.
What i saw from a TSR unreal program was that it actually makes the processor execute the protected-mode IDT entry #0x0D in protected mode (if you left proper values in GDTR and IDTR and made sure your old GDT wasn't erased by DOS programs). I know this looks completely surrealist, but that's what the guy did and it looked like it was actually working (at least on 386 and 486).
I wouldn't base a design on this, however. it's more like a piece of museum nowadays ... much like graphic areas in text mode
Re:control registers
Posted: Wed Jul 02, 2003 5:06 pm
by Tim
If you've tried it, I'll take your word for it. I was basing my idea from an old unreal mode demo, but I don't think I ever saw a GPF in real mode.
Re:control registers
Posted: Wed Jul 02, 2003 8:52 pm
by slacker
k im using eax but my booter is still making the PC reboot. it reboots at this slice of code. any ideas?
i know my gdt is set up correctly...
Code: Select all
cli
lgdt [gdtpntr]
mov eax, cr0
inc eax
mov cr0, eax
jmp code:cont
[bits 32]
cont:
mov ax, data
mov ds, ax
mov ss, ax
mov sp, 0x7000
hlt
Re:control registers
Posted: Thu Jul 03, 2003 12:37 am
by Pype.Clicker
beside the fact that you should use "or al,1" rather than "inc eax", no. i don't see an obvious flaw. Maybe you could try it in bochs and see what it complains about ...
just make sure "code" and "data" are your selectors (usually 0x08 and 0x10) and not something else ... beside this, if your GDT and its pointer are *really* correct, i don't see what could be wrong :-/
--
@Tim, usually when switching back to real mode, you have a LIDT which returns to the IVT -- i'm not sure it's actually necessary, but for sure it will nearly guarantee that real-mode vector are not valid IDT descriptors
And when you set up unreal mode, you keep large limits everywhere, so no GPF will arise. What remains unclear in that dude's scheme is how he could keep a valid code descriptor if someone has trashed his pmode segments. maybe it works only if the program that makes an unfriendly pmode switch restores the GDT pointer (saved previously with sgdt) at exit ...
Re:control registers
Posted: Thu Jul 03, 2003 10:26 am
by slacker
heres the entire bootloader
Code: Select all
;(booter)
[bits 16]
[org 0x7c00]
jmp 0x00:boot
gdtpntr:
lim dw 24
base dd gdt
gdt:
null dw 0
dd 0x00
dd 0x00
code dw 0x08
dw 0xffff
dw 0x00
db 0x00
db 0x9a
db 0xdf
db 0x00
data dw 0x10
dw 0xffff
dw 0x00
db 0x00
db 0x92
db 0xdf
db 0x00
kbd_wait:
in al, 0x64
and al, 0x02
jnz kbd_wait
ret
boot:
mov ax, cs
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
mov sp, 0x7000
a20_on:
mov al, 0xd1
out 0x64, al
call kbd_wait
mov al, 0xdf
out 0x60, al
call kbd_wait
cli
lgdt [gdtpntr]
mov eax, cr0
or al,1
mov cr0, eax
jmp code:cont
[bits 32]
cont:
mov ax, data
mov ds, ax
mov ss, ax
mov sp, 0x7000
hlt
times 510-($-$$) db 0
db 0x55
db 0xaa
Re:control registers
Posted: Thu Jul 03, 2003 12:50 pm
by Tim
slacker wrote:Code: Select all
mov ax, data
mov ds, ax
mov ss, ax
This won't do what you want -- it tries to load DS and SS with the address of the data variable, which has a value somewhere around 7C00h. So your code will triple-fault, because this is far in excess of the GDT limit.
What you should do is declare your code and data symbols using EQU instead.
Re:control registers
Posted: Thu Jul 03, 2003 1:19 pm
by Pype.Clicker
one point for Tim
i would add that by inserting "dw" inside of the GDT you're also breaking its beautiful structure, so that even if, by any chance, you loaded DS with the right selector, your descriptor would be bad
follow tim's hint and do a
Code: Select all
CODE_SEL EQU 0x08
DATA_SEL EQU 0x10