Page 1 of 1
User mode and offset questions
Posted: Sat Apr 05, 2008 8:53 am
by pietro10
Hello. I have programs running in my OS at last, but I face a single problem:
When I assemble a program, the offsets of the data items (all in the CS) relative to 0. However, when I run the program, I have to adjust the offsets to where the loader put them. To demonstrate, here is an excerpt from syscall.c:
Code: Select all
case SYSCALL_PUTSTR:
putstr((char *) (r.esi + getcrnttaskptr()->baseaddr));
break;
In this code, r.esi is the ESI register, where the offset of the string to print (putstr) is. The function getcrnttaskptr() returns a pointer to the task structure:
Code: Select all
typedef struct task {
U32 *stack; /* stack */
U32 *esp; /* current stack pointer */
Exchange e; /* an exchange for message passing */
U32 *pdir; /* page directory */
U32 baseaddr; /* the address where the loader put the program */
} Task;
Now for the interesting part: I use 4MB pages, and in the user's page directory, I set the first entry to the baseaddr.
So why do I need to add the baseaddr?
Thanks.
Posted: Mon Apr 07, 2008 7:09 pm
by pcmattman
Have you tried printing out the baseaddr, to make sure that it's what you're expecting it to be? You have to add the baseaddr to all references to ensure that the relative-to-0 addressing used in the binary points to correct code.
If baseaddr is something like 0x1234567, when you do the mapping it'll end up pointing to 0x1234000, which means that your offsets will be wrong. You can fix this by mapping it to the first entry, and then keeping track of a page offset (0x1234567 % 0xFFF = 0x567) which you add to all memory access.
Hope this helps.
Posted: Mon Apr 07, 2008 7:20 pm
by pietro10
pcmattman wrote:If baseaddr is something like 0x1234567, when you do the mapping it'll end up pointing to 0x1234000, which means that your offsets will be wrong. You can fix this by mapping it to the first entry, and then keeping track of a page offset (0x1234567 % 0xFFF = 0x567) which you add to all memory access.
When I allocate the page that will hold the user's code, I ensure it is page aligned; this won't happen. But, as you can see:
Code: Select all
#define PAGEMASK 0xFFF00000 /* Page alignment - is this right? */
#define KPFLAGS 0x83 /* Supervisor level, read/write, present */
U32 *duppdir(void)
{
U32 *tmp;
tmp = (U32 *) kmalloca(1024 * sizeof (U32));
memcpy(tmp, kdir, 1024 * sizeof (U32));
return tmp;
}
U32 addrtopage(void *addr)
{
return ((U32) addr & PAGEMASK) | KPFLAGS;
}
U32 loadexec(U32 inumber)
{
char *sector;
sector = (char *) kmalloca(1024 * sizeof (char));
readinto(0, inumber, 1, sector);
return doregistertask((void (*)(void)) sector, 1);
}
static U32 doregistertask(void (*f)(void), int map)
{
U32 *st, *ebp, i;
cli();
if (nTasks >= 256)
panic("no more tasks");
tasks[nTasks].stack = kmalloca(STACKSIZE * sizeof (U32));
st = &tasks[nTasks].stack[STACKSIZE];
if (map)
*--st = 0;
else
*--st = (U32) f;
for (i = 0; i < 8; i++) /* the eight registers of pusha */
*--st = 0;
tasks[nTasks].esp = st;
tasks[nTasks].e.inuse = 0;
if (map) {
tasks[nTasks].pdir = duppdir();
tasks[nTasks].pdir[0] = addrtopage(f);
} else
tasks[nTasks].pdir = samepdir();
tasks[nTasks].baseaddr = (U32) f;
nTasks++;
sti();
return nTasks - 1;
}
the page directory is set to ensure that the address is made to 0. What I don't understand, however, is why I have to add the baseaddr when the page directory is set. It's like the processor is ignoring the page directory's first item.
Another bit of awkwardness: when I look at the directory entry in the syscall handler, the bit that is supposed to be 0 is set to 1. I don't know what it means...
Posted: Mon Apr 07, 2008 7:26 pm
by pcmattman
The point is that if the baseaddr isn't page aligned your offsets will be wrong, because the binary won't be starting at exactly 0.
Posted: Mon Apr 07, 2008 8:34 pm
by pietro10
pcmattman wrote:The point is that if the baseaddr isn't page aligned your offsets will be wrong, because the binary won't be starting at exactly 0.
Yes, but I just showed that the baseaddr is page aligned, as noted by kmalloc
a in the loadexec function.
The question is why I have to add baseaddr when the page directory is set up to have physical baseaddr at linear 0.
Posted: Mon Apr 07, 2008 8:59 pm
by pcmattman
Are you sure that the entry is being mapped properly? Have you invalidated the mapping in the TLB (invlpg instruction), and are you working within the correct page directory?
Posted: Mon Apr 14, 2008 6:14 pm
by pietro10
pcmattman wrote:Are you sure that the entry is being mapped properly? Have you invalidated the mapping in the TLB (invlpg instruction), and are you working within the correct page directory?
Could you please elaborate?
Posted: Mon Apr 14, 2008 6:17 pm
by pcmattman
Check that your page tables have the right bits set as well (present, read/write, user etc...) as well as the entries.
Use the INVLPG (see the wiki) instruction to remove the entry for a page from the processor cache.
The Intel Manuals (volume 3A has all the paging stuff) will help.
Posted: Mon Apr 14, 2008 8:38 pm
by pietro10
pcmattman wrote:Check that your page tables have the right bits set as well (present, read/write, user etc...) as well as the entries.
4MB pages don't use page tables (there's only a page directory - 4MB * 1024M pdir entries = 4GB, so a page directory maps everything), so I don't think that's the root problem.
pcmattman wrote:Use the INVLPG (see the wiki) instruction to remove the entry for a page from the processor cache.
I'll look at it tomorrow.
Posted: Tue Apr 15, 2008 5:10 pm
by pietro10
pcmattman wrote:Use the INVLPG (see the wiki) instruction to remove the entry for a page from the processor cache.
No, that doesn't do it, sorry.
Posted: Tue Apr 15, 2008 5:33 pm
by iammisc
Now for the interesting part: I use 4MB pages, and in the user's page directory, I set the first entry to the baseaddr.
So why do I need to add the baseaddr?
Thanks.
If I understand properly, you map the program at 0(a very bad idea as null program references are ignored) and at baseaddr right? Well if you do, then you don't need to add baseaddr.
Or maybe you meant that baseaddr is a physical address in which case you should first make sure it really is a physical address and then you should make sure you actually are using paging(did you enable it right). Your ignorance of invlpg makes me very doubtful that you understand paging properly, but I could be wrong.[/quote]
Posted: Sat Apr 19, 2008 11:35 am
by pietro10
Turns out the problem was in kmalloca.
should have been