1
Lowlevel-Coding / RPC geht unter bochs, aber nicht unter qemu
« am: 30. September 2009, 19:38 »
Also ich hab ein Problem(mal wieder).....
Wenn ein Task einen RPC zum Kernel ausführt, funktioniert das ganze ohne probleme, wenn ein Task aber einen RPC zu einem anderen Task macht bekomm ich eine GPF in Qemu und auf einem echten PC, debuggen kann ich das leider schlecht da es unter bochs ohne probleme funktioniert.
Komischerweise tritt dieses Problem nur dann auf wenn die Stackaddresse des callee(so heißt doch der aufgerufene RPC Handler dann, oder?) != 0xF0000000 ist oder BASE_STACK SIZE >= 0x4000, ansonsten funktioniert es ganz normal(jedenfalls im Emulator auf einem echtem Computer bekomm ich auch ne GPF).
Hier mal meine make_rpc Funktion:
Hier die verwendeten Konstanten:
Hoffe ihr könnt mir helfen...
Wenn ein Task einen RPC zum Kernel ausführt, funktioniert das ganze ohne probleme, wenn ein Task aber einen RPC zu einem anderen Task macht bekomm ich eine GPF in Qemu und auf einem echten PC, debuggen kann ich das leider schlecht da es unter bochs ohne probleme funktioniert.
Komischerweise tritt dieses Problem nur dann auf wenn die Stackaddresse des callee(so heißt doch der aufgerufene RPC Handler dann, oder?) != 0xF0000000 ist oder BASE_STACK SIZE >= 0x4000, ansonsten funktioniert es ganz normal(jedenfalls im Emulator auf einem echtem Computer bekomm ich auch ne GPF).
Hier mal meine make_rpc Funktion:
Code: [Auswählen]
// führt einen rpc-aus(zu einem RING0-Task)
void make_rpc(UINT32 callee_pid, rpc_data *data)
{
//den task suchen, dessen rpc-handler afgerufen werden soll
Task *callee = get_task_from_pid(callee_pid);
if(callee == 0)
{
Console_putf("make_rpc: callee %i existiert nicht.\n");
return;
}
// wenn kein rpc-handler vorhanden ---> ende
if(callee->rpc_handler == 0)
{
Console_putf("make_rpc: callee %i hat keinen rpc-handler.\n");
return;
}
UINT32 callee_stack;
if(callee->pid != 0)
{
int i;
for (i = 0; i <= BASE_STACK_SIZE; i+=0x1000)
{
UINT32 va = (VIRT_STACK_ADDR + i);
UINT32 pa = mem_get_phys_addr(VIRT_STACK_ADDR + i, (page*)callee->page_dir);
mem_map(kernel_pd, va, pa);
if (mem_get_phys_addr(va, kernel_pd) != pa)
{
Console_putf("Fehler beim mappen des callee_stacks(i = %x)", i);
}
}
callee_stack = callee->stack;
}
else
{
// ok, den kernel stack brauchen wir icht mappen, da das kernel_pd schon geladen ist
callee_stack = callee->stack;
}
// jetzt dort einen weiteren irq-stack hinzufügen
UINT32 *stack = (UINT32 *) callee_stack;
data->caller_pid = current_task->pid;
// vor den daten wird noch der alte stackpointer gespeichert
data->callee_old_esp = (UINT32) callee_stack;
// jetzt die daten auf den stack
*(--stack) = (UINT32)data;
// die rücksprungaddresse des rpc-hadnler, welche diesen beendet
*(--stack) = (UINT32)rpc_end_stub;
*(--stack) = 0x0202;
// das codesegment(kernel-task = 0x08)
*(--stack) = 0x08;
// der einstiegspunkt(eip)
*(--stack) = callee->rpc_handler;
// WICHTIG: die IRQ-nummer und error-code(weil der timer-interrupt zuständig ist für multitasking)
*(--stack) = 0x00;
*(--stack) = 0x00;
// Allzweckregister
*(--stack) = 0x00;
*(--stack) = 0x00;
*(--stack) = 0x00;
*(--stack) = 0x00;
*(--stack) = 0x00;
*(--stack) = 0x00;
*(--stack) = 0x00;
*(--stack) = 0x00;
// jetzt die datensegment(kernel-task = 0x10)
*(--stack) = 0x10;
*(--stack) = 0x10;
*(--stack) = 0x10;
*(--stack) = 0x10;
// jetzt den stack verschieben
callee->stack = (UINT32)stack;
callee->makes_rpc = 1;
// ok jetzt den caller blocken und zum callee wechseln
current_task->blocked = 1;
callee->last_rpc_data = data;
// ok wenn der callee, schläft, ihn jetzt aufwecken
callee->sleeping = 0;
//while(current_task != callee)
while(current_task->blocked == 1)
{
multitasking_taskswitch();
}
}
Hier die verwendeten Konstanten:
Code: [Auswählen]
#define BASE_STACK_SIZE 0x2000
#define VIRT_STACK_ADDR 0xF0000000
Hoffe ihr könnt mir helfen...