virtual mode...

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.
User avatar
xyjamepa
Member
Member
Posts: 397
Joined: Fri Sep 29, 2006 8:59 am

Post by xyjamepa »

Hi...
I'm so sorry because I didn't get you right from the first time.
so here's my registers values:

Code: Select all

eax:0x00100f88, ebx:0x00000000, ecx:0x00000000, edx:0x00100f87
ebp:0x001078e8, esp:0x001078e0, esi:0x0000000a, edi:0x00000000
eip:0x00100fc2, eflags:0x00003002, inhibit_mask:0
cs:s=0x0008, dl=0x0000ffff, dh=0x00c09a00, valid=1
ss:s=0x0010, dl=0x0000ffff, dh=0x00c09300, valid=7
ds:s=0x0010, dl=0x0000ffff, dh=0x00c09300, valid=7
es:s=0x0010, dl=0x0000ffff, dh=0x00c09300, valid=1
fs:s=0x0010, dl=0x0000ffff, dh=0x00c09300, valid=1
gs:s=0x0010, dl=0x0000ffff, dh=0x00c09300, valid=1
ldtr:s=0x0000, dl=0x00000000, dh=0x00000000, valid=0
tr:s=0x0030, dl=0x68e80068, dh=0x00808910, valid=1
gdtr:base=0x00106820, limit=0x37
idtr:base=0x00106020, limit=0x7ff
dr0:0x00000000, dr1:0x00000000, dr2:0x00000000
dr3:0x00000000, dr6:0xffff0ff0, dr7:0x00000400
cr0:0x00000019, cr1:0x00000000, cr2:0x00000000
cr3:0x00000000, cr4:0x00000000
All this values after the exception.
Also here's an IMG file it might help if you want more information.
I'm grateful for your help guys.

Thanx.
Attachments
a.tar.gz
IMg
(47.52 KiB) Downloaded 165 times
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Post by Combuster »

The switch to v8086 mode seems to work ok.

However, there is nothing meaningful at 0000:1000 - only garbage is being executed which will at some point cause an random exception.
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
pcmattman
Member
Member
Posts: 2566
Joined: Sun Jan 14, 2007 9:15 pm
Libera.chat IRC: miselin
Location: Sydney, Australia (I come from a land down under!)
Contact:

Post by pcmattman »

@abuashraf: try it without using a C function for the task. Do this, for instance:

Code: Select all

char* dat = (char*) 0x1000;
/* comment out until you need to test your virtual mode monitor
*dat++ = 0xCD;
*dat++ = 0x03;
*/
*dat++ = 0xEB;
*dat++ = 0xFE;
If that doesn't work, I don't know what will!
User avatar
xyjamepa
Member
Member
Posts: 397
Joined: Fri Sep 29, 2006 8:59 am

Post by xyjamepa »

Hi...

I tried this:

Code: Select all

char* dat = (char*) 0x1000; 
/* comment out until you need to test your virtual mode monitor 
*dat++ = 0xCD; 
*dat++ = 0x03; 
*/ 
*dat++ = 0xEB; 
*dat++ = 0xFE; 
Now bochs didn't gave me any exception :) :) :) :) ,If we wrote our virtual task usign assembly will this work fine?
If yes would you give me very very simple function written in assembly
and pointed to 0x1000,I'm soooo bad in assembly stuff.

Thanx.
pcmattman
Member
Member
Posts: 2566
Joined: Sun Jan 14, 2007 9:15 pm
Libera.chat IRC: miselin
Location: Sydney, Australia (I come from a land down under!)
Contact:

Post by pcmattman »

No, not yet.

First, uncomment my comments, and write a virtual mode monitor. If you need help, post here.
User avatar
xyjamepa
Member
Member
Posts: 397
Joined: Fri Sep 29, 2006 8:59 am

Post by xyjamepa »

Hi...

:oops:

Okay I uncommented your comments but I got general protection faults.
So to be clear my registers values are:

Code: Select all

void init_task()
{
 disable();
 for(i=0;i<max_tasks;i++)
  {

   tss[i].trace=0;
   tss[i].io_map_addr=sizeof(TSS);
   tss[i].ldtr=0;

   tss[i].fs=tss[i].gs=0;
   tss[i].ds=tss[i].es=tss[i].ss=0x0;
   tss[i].cs=0x0;
   tss[i].eflags=0x23202L;		//0x23202L VM=1 ,IOPL=3
   tss[i].esp=(dword)&task_stack[i];	//points to task() stack top
   tss[i].ss0=0x10;
   tss[i].esp0=(dword)&pl0_stack[i];	//stack for kernel

  }

 char* dat = (char*)0x1000; 
 *dat++ = 0xCD; 
 *dat++ = 0x03; 
 *dat++ = 0xEB; 
 *dat++ = 0xFE;

 tss[1].eip=(dword *)0x1000;

 ltr(0x28);	//selector of main()
 
 enable();
}
So now my virtual task became what you wrote,I commented
the old task(),do you see any wrong with reg values? eip,ss,ss0,esp...?

Also I found pcmattman values 0xfeeb03cd at 0x1000
and Combuster already said switching to virtual mode seems to work ok.
so now I think the problem with wrong reg values,to be more specific
the regs are esp,eip,sep0,ss0 but not quite sure.

Thanx
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Post by Combuster »

abuashraf wrote:Okay I uncommented your comments but I got general protection faults.
Security test passed :D - the code tries to call an interrupt handler that it isnt supposed to call.
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
User avatar
xyjamepa
Member
Member
Posts: 397
Joined: Fri Sep 29, 2006 8:59 am

Post by xyjamepa »

Hi...

It's been a week and we still tring to enable virtual mode.
Could someone guide me please I'm kind of lost here.
*switching to virtual mode is working.
*values that pcmattman wrote saved at 0x1000 successfuly,but
what should I do with this values.
*I pointed eip of the virtual task to 0x1000
like this tss[1].eip=(dword *)0x1000
Even with all this stuff I'm still getting gpf. :(
I'm afraid that some of my regs loaded with wrong values.
would you please take a look at the code above and see
if there is any thing wrong,and what else should I do?
I'm grateful for your help.


Thanx.
Last edited by xyjamepa on Wed Jun 06, 2007 11:03 am, edited 1 time in total.
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Post by Combuster »

Everything is working as it should.

The only thing you need to is to write the vmm. In the meantime anything interesting the v8086 task tries to do will result in a gpf or the like.
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
User avatar
xyjamepa
Member
Member
Posts: 397
Joined: Fri Sep 29, 2006 8:59 am

Post by xyjamepa »

Hi...
Everything is working as it should.
This means I can't even print a message without implementing virtual mode
monitor,am I right?
I'm confused little bit now,my EFLAGS after the exception equal to 0x00003002
would someone please explain to me what does this mean?
If I want to enable virtual mode and not to do any thing,let's
say I don't want to print any message,but also I don't want to get a gpf,
are this the right steps:
*Enabling VM bit in EFLAGS.
*virtual task should be 1MB mark.
*pointing the eip field of the virtual task tss to virtual task address.
like this tss[1].eip=(dword *)0x1000.
*virtual task is emptylike this:
void task()
{
//no thing
}

*Is there any thing else?

One last thing and I already said that,my virtual task works in PL0,
what about the vmm,what kind of PL does it work in?PL0 or PL3?

Thanx.
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Post by Combuster »

abuashraf wrote:
Everything is working as it should.
This means I can't even print a message without implementing virtual mode monitor,am I right?
Its possible to keep away from vmm-calling operations, but its not easy and you'll need the vmm later on anyway.
I'm confused little bit now,my EFLAGS after the exception equal to 0x00003002
Nothing strange about it. That's just IOPL and the reserved one bit. When you entered the v8086 task all flags were clear, and they still are since there is no code changing that, and after the exception vm is cleared (for the change to protected mode), and your interrupt handler clears IF.
If I want to enable virtual mode and not to do any thing,let's
say I don't want to print any message,but also I don't want to get a gpf,
are this the right steps:
*Enabling VM bit in EFLAGS.
*virtual task should be 1MB mark.
*pointing the eip field of the virtual task tss to virtual task address.
like this tss[1].eip=(dword *)0x1000.
*virtual task is emptylike this:
void task()
{
//no thing
}
* You can not put code for a v8086 task above the 1MB mark. That's the limit for real mode, and it still is for virtual tasks.
* You should point CS:(e)IP at the location where you put your v8086 task's code.
* You can not normally use GCC to generate code for virtual 8086 tasks. This is because GCC generates 32-bit code while in virtual mode code is executed as 16 bits. The easiest way is to write 16-bit assembly with nasm/yasm and use that.
One last thing and I already said that,my virtual task works in PL0,
what about the vmm,what kind of PL does it work in?PL0 or PL3?
Like said many times before, a virtual8086 task ALWAYS runs in PL3. The vmm is normally executed in ring 0, though you can always route exceptions back to ring 3 if you so desire.
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
pcmattman
Member
Member
Posts: 2566
Joined: Sun Jan 14, 2007 9:15 pm
Libera.chat IRC: miselin
Location: Sydney, Australia (I come from a land down under!)
Contact:

Post by pcmattman »

Christmas comes early for you:

This is the Mattise virtual mode monitor. 'r' is a pointer of type 'struct regs', it just points to the ESP at the time of calling with all sorts of data on the stack.

Code: Select all

	// check if it's a GPF and we're in V8086 mode
	if( r->eflags & 0x20000 && r->int_no == 13 )
	{		
		// the IVT
		uint16_t* ivt = (uint16_t*) 0;
		
		// the stack, in 16-bit and 32-bit
		uint16_t* stack = (uint16_t*) FP_TO_LINEAR( 0x20, r->useresp );
		uint32_t* stack32 = (uint32_t*) stack;
		
		// instruction pointer
		uint8_t* ip = (uint8_t*) FP_TO_LINEAR( r->cs, r->eip );
		
		// index of execution
		uint32_t exc = 0;
		
		// operand and address sizes
		bool Op32 = false, Addr32 = false;
		
		// safe op?
		bool SafeOp = true;
		
		// knock out any extra stuff at the front
		while( SafeOp )
		{
			switch( ip[0] )
			{
				// 32-bit operand
				case 0x66:
				
					// we are using 32-bit operands
					Op32 = true;
					
					// increment the IP
					ip++;
					
					// set the new EIP in the stack
					r->eip++;
					
					break;
				
				// 32-bit address
				case 0x67:
				
					// 32-bit addresses
					Addr32 = true;
					
					// increment the IP
					ip++;
					
					// set the new EIP in the stack
					r->eip++;
					
					break;

				// PUSHF
				case 0x9C:
				
					// check for 32-bit
					if( Op32 )
					{
						// decrement the stack by 4 bytes
						r->useresp = ( ( r->useresp & 0xFFFF ) - 4 ) & 0xFFFF;
						
						// decrement the stack
						stack32--;
						
						// put the flags on the stack
						stack32[0] = r->eflags & 0xDFF;
						
						// see if we have interrupts enabled
						if( r->eflags & 0x200 )
							stack32[0] |= 0x200; // enable in flags
						else
							stack32[0] ^= 0x200; // disable
					}
					else
					{
						// decrement the stack by 2 bytes
						r->useresp = ( ( r->useresp & 0xFFFF ) - 2 ) & 0xFFFF;
						
						// decrement the stack
						stack--;
						
						// put the flags on the stack
						stack[0] = r->eflags;
						
						// see if we have interrupts enabled
						if( r->eflags & 0x200 )
							stack[0] |= 0x200; // enable in flags
						else
							stack[0] ^= 0x200; // disable
					}
						
					// increment eip
					r->eip++;
					
					// go back to task
					return;
				
				// POPF
				case 0x9D:
				
					// check for 32-bit
					if( Op32 )
					{
						// set the EFLAGS
						r->eflags = 0x20200 | ( stack32[0] & 0xDDF );
						
						// set the new stack pointer
						r->useresp = ( ( r->useresp & 0xFFFF ) + 4 ) & 0xFFFF;
					}
					else
					{
						// set the EFLAGS
						r->eflags = 0x20200 | stack[0];
						
						// set the new stack pointer
						r->useresp = ( ( r->useresp & 0xFFFF ) + 2 ) & 0xFFFF;
					}
					
					// increment eip
					r->eip++;
					
					// return to the task
					return;
				
				// CLI
				case 0xFA:
				
					// take out the interrupt flag
					if( r->eflags & 0x200 )
						r->eflags ^= 0x200;
					
					// increment eip
					r->eip++;
					
					// return to the task
					return;
				
				// STI
				case 0xFB:
				
					// put in the interrupt flag
					if( ( r->eflags & 0x200 ) == 0 )
						r->eflags &= 0x200;
					
					// increment eip
					r->eip++;
					
					// return to the task
					return;
					
				// 0xCD: INT n
				case 0xCD:
				
					// int80 = kill current task
					if( ip[1] == 0x80 )
					{						
						// set the current task's registers
						SetRegs( currpid(), r );
						
						// kill it
						kill( currpid() );
						
						// reschedule
						resched();
						
						// set the new esp
						r->esp = current_task[0].esp;
						
						// increment the eip too
						r->eip += 2;
						
						// return to the new task
						return;
					}
					
					// decrement the stack 3 times
					stack -= 3;
					
					// put the data on the stack
					stack[0] = (uint16_t) ( r->eip + exc + 2 );
					stack[1] = r->cs;
					stack[2] = (uint16_t) r->eflags;
					
					// set the new stack pointer
					r->useresp = ( ( r->useresp & 0xFFFF ) - 6 ) & 0xFFFF;
					
					// set eflags
					if( r->eflags & 0x200 )
						r->eflags ^= 0x200;
					
					// jump to the necessary location
					r->cs = ivt[ ip[exc+1] * 2 + 1 ];
					r->eip = ivt[ ip[exc+1] * 2 ];
					
					// return, this will take us to the interrupt handler
					return;
				
				// IRET
				case 0xCF:
				
					// set EFLAGS, CS and EIP, then refresh Ring3ESP
					r->eip = stack[0];
					r->cs = stack[1];
					r->eflags = stack[2] | 0x20200;
					
					// new stack pointer
					r->useresp = ( ( r->useresp & 0xFFFF ) + 6 ) & 0xFFFF;
					
					// return to the new place
					return;

				default:
				
					// oops!
					kprintf( "Unknown opcode: 0x%x!\n", ip[0] );
					
					// break free from the loop
					SafeOp = false;
			}
		}
		
		// loop forever - dud op
		while( true );
	}
Good luck.

By the way:
You can not normally use GCC to generate code for virtual 8086 tasks. This is because GCC generates 32-bit code while in virtual mode code is executed as 16 bits. The easiest way is to write 16-bit assembly with nasm/yasm and use that.
That's true. I used NASM to write 16-bit code for my VBE switcher, that I put onto a hard drive and used

Code: Select all

fread( (void*) 0x1000, /** offset **/ 0, /** count **/ fp.size, fp );
(i have an unusual fread)

The reason you use NASM is that 16- and 32-bit opcodes are different.
User avatar
xyjamepa
Member
Member
Posts: 397
Joined: Fri Sep 29, 2006 8:59 am

Post by xyjamepa »

Hi...
GCC generates 32-bit code while in virtual mode code is executed as 16 bits. The easiest way is to write 16-bit assembly with nasm/yasm and use that.
You mean when I want to use BIOS INTs I have to write the code and compile it with nasm,am I right?
One last thing:
* You can not put code for a v8086 task above the 1MB mark. That's the limit for real mode, and it still is for virtual tasks.
I "as you adviced me" did this:

memcpy((void *)0x1000,&task,1000);
ts[1].eip=(dword *)0x1000;

so my virtual task now 1MB mark and eip field of its tss point to it,
am I right?
if yes after the exception my eip value was 0x00100FC2 and never changed,why do you think?


@pcmattman thank you for your code.

Thanx.
User avatar
AJ
Member
Member
Posts: 2646
Joined: Sun Oct 22, 2006 7:01 am
Location: Devon, UK
Contact:

Post by AJ »

Hi,
abuashraf wrote: You mean when I want to use BIOS INTs I have to write the code and compile it with nasm,am I right?
Yes - you have to have your real mode IVT in place (in other words, don't mess about with the memory region 0-0x500 physical), be running in v86 mode, and have used 16 bit code (the [USE 32] or [BITS 32] directive, depending on what assembler you are using).
abuashraf wrote: if yes after the exception my eip value was 0x00100FC2 and never changed,why do you think?
Have you actually organised your code with an entry point of 0x1000 [ORG 0x1000]? If you are using C, you will need to link to entry point 0x1000.

If not, I strongly suspect there is a JMP or CALL 0x00100FC2 somewhere in your code.

Cheers,
Adam
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Post by Combuster »

abuashraf wrote:Hi...
GCC generates 32-bit code while in virtual mode code is executed as 16 bits. The easiest way is to write 16-bit assembly with nasm/yasm and use that.
You mean when I want to use BIOS INTs I have to write the code and compile it with nasm,am I right?
Nasm is an assembler, not a compiler.
One last thing:
* You can not put code for a v8086 task above the 1MB mark. That's the limit for real mode, and it still is for virtual tasks.
I "as you adviced me" did this:

memcpy((void *)0x1000,&task,1000);
ts[1].eip=(dword *)0x1000;

so my virtual task now 1MB mark and eip field of its tss point to it,
am I right?
The virtual mode task is *NOT* at the 1MB mark, its at 4K, exactly where you copied it to.
if yes after the exception my eip value was 0x00100FC2 and never changed,why do you think?
After an exception control is transferred to the kernel which DOES live above the 1MB mark. You are looking at the EIP of a JMP $ instruction inside the kernel. :shock:
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
Post Reply