OSDev.org
https://forum.osdev.org/

virtual mode...
https://forum.osdev.org/viewtopic.php?f=1&t=14084
Page 2 of 5

Author:  xyjamepa [ Fri Jun 01, 2007 4:52 pm ]
Post subject: 

Hi...
Now I've changed my code a little bit my multitasking consists of two tasks
main() and task() and both they are PL0.
when I enabled the VM bit in EFLAGS I didn't get any exceptions, but
when I made a long call "lcall" to the selector of the virtual task
unfortunately I got general protection fault...
here's my code and an IMG, also please note paging isn't enabled.


Thanx.

Attachments:
File comment: IMG
a.tar.gz [46.97 KiB]
Downloaded 27 times
File comment: kernel
knl.tar.gz [15.03 KiB]
Downloaded 32 times

Author:  pcmattman [ Fri Jun 01, 2007 5:44 pm ]
Post subject: 

First of all - get a debugger.

Second - GPFs in Virtual Mode occur on privileged instructions. Read the intel manuals on virtual mode and you can see what you need to emulate as a virtual mode monitor.

Edit: Downloaded your image, running it works alright, apart from the GPF. I have a few questions: is your task under the 1MB mark? Do you have a mode monitor that emulates privileged instructions (read the Intel manual, and search Google). You can't expect us to upload fixed code. You have to do this yourself.

It took me a month. It's worth doing it yourself.

As I type, this is what I notice in my Bochs log:
Code:
call_protected: EIP not within CS limits


You cannot switch tasks via a long call in virtual mode (read the manuals). Why can't you use preemptive tasking, whereby a timer tick allows a reschedule to occur. What you're doing now looks to me like cooperative tasking.

Author:  xyjamepa [ Sat Jun 02, 2007 12:47 pm ]
Post subject: 

Hi...

Quote:
is your task under the 1MB mark


how can I make sure that my task is 1MB mark?

Quote:
You can't expect us to upload fixed code.


I'm not, I just need your opinion and experience to explain to me why
my virtual task doesn't work.

Thanx.

Author:  pcmattman [ Sat Jun 02, 2007 4:36 pm ]
Post subject: 

When I was testing virtual mode, this is what I did:

Code:
char* data = (char*) 0x1000; // pointer to location < 1MB
*dat++ = 0xCD;
*dat++ = 0x03; // int 0x03
*dat++ = 0xEB;
*dat++ = 0xFE; // jmp $
/** create task, set base to 0x1000 **/


If you are using a C function, you just need to get the pointer to the function and copy enough of it's code to a location under 1 MB to be able to have it run... something like
Code:
memcpy( (void*) 0x1000, &task1, 1024 ); // you could also run until you found 'ret' (is it C3, or C9? keep getting Z80 opcodes mixed up...)


Good luck!

Author:  xyjamepa [ Sat Jun 02, 2007 5:22 pm ]
Post subject: 

Hi...
unfortunately it didn't work I got general protection fault again.
I'm starting to pull my hair up......I'm so confused,I don't know
what the wrong I'm doing?????? now I believe enabling virtual mode
harder than brain surgery. :( :( :(
So now I'm sure that my virtual task is marked 1MB,what else should
I take care of?
guys I really need your help.

Thanx.

Author:  pcmattman [ Sat Jun 02, 2007 6:58 pm ]
Post subject: 

As I've said so many times, GPF comes from a privileged instruction!

Find out whether you're in virtual mode on a GPF, then read in the opcode from the CS:EIP that the fault occurred at. Handle the opcodes that Intel says are privileged. Return (after incrementing EIP).

In the least, make your GPF handler print out CPU state before the crash and the opcodes at the last executed location.

Author:  xyjamepa [ Sun Jun 03, 2007 4:37 am ]
Post subject: 

Hi...
First of all @pcmattman thank you for your help.
Now my task doesn't have any instructions just an infinit loop.
but as soon as I make the call to the selector of the virtual task
I get general protection fault.
Also Intel manual says:

Quote:
Task switch when the VM flag is set to 1 in the EFLAGS register image stored in the TSS
for the task. Here the task switch can be initiated in either of two ways:
— A CALL or JMP instruction.
— An IRET instruction, where the NT flag in the EFLAGS image is set to 1.


I'm using CALL instruction so this should be fine,my EFLAGS value is 0x23202L
so the VM bit is set,my task is 1MB marked,Also I'm sure about my multitasking.
what's wrong with my code....

Thanx.

Author:  frank [ Sun Jun 03, 2007 7:00 am ]
Post subject: 

While debugging your code in bochs I have noticed that it throws the gpf right at the switch to the task, not after trying to execute any code. So the problem must be in the values that you are putting in the tss. Also, all code that is going to be run in virtual mode must be below the 1mb mark. Not at it not above it. Since your whole kernel is at the 1mb mark the function you are trying to call must be above the 1mb mark. Have you tried what pcmattman says about using memcpy to get the code below the 1mb mark?

Question for someone who knows, Aren't the values entered into the TSS for segment descriptors supposed to be real mode values and not segment descriptors?

Author:  xyjamepa [ Sun Jun 03, 2007 8:42 am ]
Post subject: 

Hi...

Quote:
I have noticed that it throws the gpf right at the switch to the task

This means it throws the gpf when I do the long call "lcall" to the
selector of my virtual task

Quote:
So the problem must be in the values that you are putting in the tss.


here are my values:
Code:
i=0;
for(i;i<max_tasks;i++)
  {
   tss[i].trace=0;
   tss[i].io_map_addr=sizeof(TSS);
   tss[i].ldtr=0;
   if (i) {
   tss[i].fs=tss[i].gs=0;
   tss[i].ds=tss[i].es=tss[i].ss=0x10;
   tss[i].cs=0x8;
   tss[i].eflags=0x23202L ;      //VM=1 ,IOPL=3, interrupts are enabled
   tss[i].esp=(dword)&task_stack[i];   // sp points to task stack top /
   tss[i].ss0=0x10;
   tss[i].esp0=(dword)&pl0_stack[i];   //stack for kernel
   }
  }
tss[1].eip=(dword)&task;      //my virtual task

memcpy( (void*) 0x1000, &task, 1024 );

ltr(0x28);            //selector of the main()


Have you tried what pcmattman says about using memcpy to get the code below the 1mb mark?
Yes,I did.

Thanx.

Author:  jnc100 [ Sun Jun 03, 2007 9:50 am ]
Post subject: 

abuashraf wrote:
Code:
tss[1].eip=(dword)&task;      //my virtual task

memcpy( (void*) 0x1000, &task, 1024 );


frank wrote:
Have you tried what pcmattman says about using memcpy to get the code below the 1mb mark?

Yes,I did.


I think he also meant: copy it there _and_ set the eip in the task structure to point to the new address of the task's code.

Code:
tss[1].eip = 0x1000;


and link your 'task' program to run at 0x1000?

Regards,
John.

Author:  xyjamepa [ Sun Jun 03, 2007 10:38 am ]
Post subject: 

Hi...

I tried tss[1].eip = 0x1000;
but this time I got Invalid opcode exception. :( :( :( :(
I'm so grateful for your help guys,
this my EIP=00100fc2 after the exception , using QEMU monitor.
here's an updated IMG file it might help,I don't know

:?: :?: :?: :?:

Thanx.

Attachments:
File comment: IMG
a.tar.gz [47.49 KiB]
Downloaded 60 times

Author:  jnc100 [ Sun Jun 03, 2007 11:16 am ]
Post subject: 

Okay, so I just tested it.

Your code successfully jumps to 0x1000 with VM set.

Unfortunately, the contents at 0x1000 are a NOP followed by lots of zeros? Does your memcpy work? Is the location you're copying from correct?

Regards,
John.

Author:  xyjamepa [ Sun Jun 03, 2007 12:37 pm ]
Post subject: 

Hi...

Quote:
Does your memcpy work?


Here's my memcpy:

Code:
unsigned char *memcpy(unsigned char *dest,unsigned char *src,int count)
{
const char *s = (const char *)src;
char *d = (char *)dest;
for(; count!=0; count--) *d++ = *s++;
return dest;
}


Quote:
Is the location you're copying from correct?


Yes,I think so,the *src is &task "address of my virtual task"
Would you please take a look at init_task it may has some bugs
Code:
void init_task()
{
disable();
unsigned int i=0;
for(i;i<max_tasks;i++)
  {
   tss[i].trace=0;
   tss[i].io_map_addr=sizeof(TSS);
   tss[i].ldtr=0;
   if (i) {
   tss[i].fs=tss[i].gs=0;
   tss[i].ds=tss[i].es=tss[i].ss=0x10;
   tss[i].cs=0x8;
   tss[i].eflags=0x23202L ;      //VM=1,IOPL=3,interrupts are enabled
   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
   }
  }
memcpy( (void*) 0x1000, &task, 1024 );
tss[1].eip=0x1000;
ltr(0x28);
enable();
}


Thanx

Author:  frank [ Sun Jun 03, 2007 2:48 pm ]
Post subject: 

You are supposed to use real mode values for the segment descriptors. Right now you are using 0x8 for cs. When you do real mode addressing the final address ends up being 0x1080 (0x8 * 16 + 0x1000). Try it with 0 as the value you enter for all of the segment registers cs, ds, es, fs, gs, and ss. That will fix the problem.

Author:  xyjamepa [ Sun Jun 03, 2007 3:53 pm ]
Post subject: 

Hi...

Once again it didn't work Bochs gave me a panic message:
interrupt(): SS selector null
Also QEMU just halt, I couldn't dump any values ... :( :(
so here's another updated IMG ,guys we are so close
I'm really grateful for your help.


Thanx.

Attachments:
File comment: IMG
a.tar.gz [47.48 KiB]
Downloaded 56 times

Page 2 of 5 All times are UTC - 6 hours
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group
http://www.phpbb.com/