Stack and interrupt problems
Posted: Sun Dec 28, 2014 5:37 pm
In my interrupt handlers, including the interrupt handler for system calls, it seems that the stack keeps breaking (values suddenly change). The kernel is preemptive, so interrupts can occur in kernel mode, while the system calls are being handled. Before it was preemptive though, the stack was never breaking. For some reason, most of the time when the stack breaks, a #PF or #GP happens in this function:
When I look at the instructions that causes the #PF or #GP, it is always a different instruction but in every case I found so far, it is taking a pointer from the stack and deferences it. This leads me to ask:
I know that when an interrupt occurs in user mode, the CPU sets the RSP to the value RSP0 from the TSS. And as far as I know, if an interrupt occurs in kernel mode, the interrupt stack from is pushed onto the current stack - it does not take the value from RSP0, is that correct?
When I do a task switch, I change the value of RSP0 in the TSS to a distinct per-thread value, so I do not see how the stack could be breaking. On the other hand, the fact that parsePath() seems to be throwing those exceptions MOST (but not all) of the time, I think something could be wrong with it, but it does appear correct.
If I am right about the RSP0 thing, then what else could be causing the stack to break? And if I'm wrong, how can I make the kernel preemptive without breaking the stack?
Code: Select all
Dir *parsePath(const char *path, int flags, int *error)
{
kprintf_debug("start of parsePath()\n");
*error = VFS_NO_FILE; // default error
// TODO: relative paths
if (path[0] != '/')
{
return NULL;
};
SplitPath spath;
if (resolveMounts(path, &spath) != 0)
{
return NULL;
};
char token[128];
char *end = (char*) &token[127];
const char *scan = spath.filename;
if (spath.fs->openroot == NULL)
{
return NULL;
};
Dir *dir = (Dir*) kmalloc(sizeof(Dir));
memset(dir, 0, sizeof(Dir));
if (spath.fs->openroot(spath.fs, dir, sizeof(Dir)) != 0)
{
kfree(dir);
return NULL;
};
while (1)
{
char *put = token;
while ((*scan != 0) && (*scan != '/'))
{
if (put == end)
{
*put = 0;
panic("parsePath(): token too long: '%s'\n", token);
};
*put++ = *scan++;
};
*put = 0;
kprintf_debug("token '%s'\n", token);
if (strlen(token) == 0)
{
if (*scan == 0)
{
return dir;
};
if (dir->close != NULL) dir->close(dir);
kfree(dir);
return NULL;
};
while (strcmp(dir->dirent.d_name, token) != 0)
{
if (dir->next(dir) != 0)
{
if (dir->close != NULL) dir->close(dir);
kfree(dir);
return NULL;
};
};
if (*scan == '/')
{
if ((dir->stat.st_mode & VFS_MODE_DIRECTORY) == 0)
{
*error = VFS_NOT_DIR;
if (dir->close != NULL) dir->close(dir);
kfree(dir);
return NULL;
};
if ((!vfsCanCurrentThread(&dir->stat, 1)) && (flags & VFS_CHECK_ACCESS))
{
if (dir->close != NULL) dir->close(dir);
kfree(dir);
*error = VFS_PERM;
return NULL;
};
Dir *subdir = (Dir*) kmalloc(sizeof(Dir));
memset(subdir, 0, sizeof(Dir));
if (dir->opendir(dir, subdir, sizeof(Dir)) != 0)
{
kfree(subdir);
if (dir->close != NULL) dir->close(dir);
kfree(dir);
return NULL;
};
if (dir->close != NULL) dir->close(dir);
kfree(dir);
dir = subdir;
scan++; // skip over '/'
}
else
{
return dir;
};
};
};
I know that when an interrupt occurs in user mode, the CPU sets the RSP to the value RSP0 from the TSS. And as far as I know, if an interrupt occurs in kernel mode, the interrupt stack from is pushed onto the current stack - it does not take the value from RSP0, is that correct?
When I do a task switch, I change the value of RSP0 in the TSS to a distinct per-thread value, so I do not see how the stack could be breaking. On the other hand, the fact that parsePath() seems to be throwing those exceptions MOST (but not all) of the time, I think something could be wrong with it, but it does appear correct.
If I am right about the RSP0 thing, then what else could be causing the stack to break? And if I'm wrong, how can I make the kernel preemptive without breaking the stack?