control registers

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
slacker

control registers

Post 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
User avatar
Pype.Clicker
Member
Member
Posts: 5964
Joined: Wed Oct 18, 2006 2:31 am
Location: In a galaxy, far, far away
Contact:

Re:control registers

Post 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.
slacker

Re:control registers

Post 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..?
Tim

Re:control registers

Post by Tim »

Just use EAX etc. as normal. The assembler will insert the appropriate prefix automatically.
slacker

Re:control registers

Post by slacker »

Tim Robinson wrote: The assembler will insert the appropriate prefix automatically.
que? huh?
Tim

Re:control registers

Post 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.
User avatar
Pype.Clicker
Member
Member
Posts: 5964
Joined: Wed Oct 18, 2006 2:31 am
Location: In a galaxy, far, far away
Contact:

Re:control registers

Post 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 ;)
Tim

Re:control registers

Post 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.
User avatar
Pype.Clicker
Member
Member
Posts: 5964
Joined: Wed Oct 18, 2006 2:31 am
Location: In a galaxy, far, far away
Contact:

Re:control registers

Post 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 :)
Tim

Re:control registers

Post 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.
slacker

Re:control registers

Post 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
User avatar
Pype.Clicker
Member
Member
Posts: 5964
Joined: Wed Oct 18, 2006 2:31 am
Location: In a galaxy, far, far away
Contact:

Re:control registers

Post 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 ...
slacker

Re:control registers

Post 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

Tim

Re:control registers

Post 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.
User avatar
Pype.Clicker
Member
Member
Posts: 5964
Joined: Wed Oct 18, 2006 2:31 am
Location: In a galaxy, far, far away
Contact:

Re:control registers

Post 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
Post Reply