OSDev.org https://forum.osdev.org/ |
|
Having an odd problem with mulitasking https://forum.osdev.org/viewtopic.php?f=1&t=16794 |
Page 1 of 1 |
Author: | Pyrofan1 [ Sun Apr 13, 2008 1:27 am ] |
Post subject: | Having an odd problem with mulitasking |
Multitasking in my kernel work, except that it GPFs after a while. Here's what will happen, my kernel will say Quote: switching from 0 to 1 switching from 1 to 2 Switching from 2 to 0 GPF I've also had it do this Quote: Switching from 0 to 2
Switching from 2 to 0 Switching from 0 to 2 GPF Here's my task creation code Code: void create_task(void (*task)(),char *name,unsigned char access) { unsigned int *stack; unsigned short c; for(c=0;c<MAX_TASKS;c++) { if(tasks[c].status==0) break; } stack=kmalloc(4096)+4096; *stack--=0x202; *stack--=0x08; *stack--=(unsigned int)task; *stack--=0; *stack--=0; *stack--=0; *stack--=0; *stack--=0; *stack--=0; *stack--=0; *stack--=0; *stack--=0x10; *stack--=0x10; *stack--=0x10; *stack--=0x10; tasks[c].esp=(unsigned int)stack; tasks[c].status=TASK_ACTIVE; strcpy(tasks[c].name,name); } my task switching code Code: unsigned int task_switcher(unsigned int addr) { unsigned short buffer=current_task; unsigned short c; buffer++; if(tasks[buffer].status!=0) { Printf("switching from %d to %d\n",current_task,buffer); if(just_init) { just_init=0; buffer=current_task; current_task++; return tasks[buffer].esp; } else { tasks[current_task].esp=addr; current_task=buffer; return tasks[current_task].esp; } } else { c=current_task; c++; while(tasks[c].status==0) { if(c>=MAX_TASKS) break; c++; } if(c>=MAX_TASKS) c=0; Printf("Switching from %d ",current_task); current_task=c; Printf("to %d\n",current_task); return tasks[current_task].esp; } } my IRQ 0 code Code: pusha mov %ds, %eax push %eax mov %es, %eax push %eax mov %fs, %eax push %eax mov %gs, %eax push %eax mov %esp, %eax push %eax call task_switcher mov %eax, %esp mov $0x20, %al out %al, $0x20 pop %eax pop %eax pop %eax pop %eax pop %eax popa sti iret the code for my tasks Code: void idle_task(void) //0
{ for(;;); } void task1(void) //1 { for(;;); } void task2(void) //2 { for(;;); } Has anybody had a similar problem? or any ideas as to why this is happening? |
Author: | Ready4Dis [ Sun Apr 13, 2008 10:03 am ] |
Post subject: | |
Try this for your irq0 Code: cli
pusha push %ds push %es push %fs push %gs push %esp call task_switcher mov %eax, %esp pop %gs pop %fs pop %es pop %ds mov $0x20, %al out %al, $0x20 popa sti iret This is pretty much how mine works, except that I also set ds,es,fs,gs to my kernel data section and use my kernel stack (this is for usermode- >kernel switches). Also, since when each task is FIRST run, it doesn't have a valid value to pop off the stack for the pop %esp call, so you must also update your create_task function with one more value, and since it's discarded, the value can just be 0 . I chose to just remove the pop %eax, it makes things a bit simpler, since you already stored the ESP, and you wipe this out on the next call after the pop, there is no reason for it. Unless I missed something, this should work alright, I rearranged some things and tried to make it simpler to read. I don't typically use AT&T syntax (read, almost never), so if there is a syntax problem, sorry . |
Author: | AJ [ Sun Apr 13, 2008 1:00 pm ] |
Post subject: | |
Hi, In my experience, multitasking crashing after a certain interval tends to be due to "stack creep". Ensure that when your IRQ happens, the value of ESP isn't gradually creeping down in memory due to dodgy updating of TSS or similar. Cheers, Adam |
Author: | iammisc [ Mon Apr 14, 2008 4:56 pm ] |
Post subject: | |
Code: mov %esp, %eax push %eax call task_switcher and then Code: tasks[current_task].esp=addr;
At the end of each entry into kernel mode, you should set the current kernel stack pointer to the base of the stack. What is happening is that the task starts at the original stack(lets say at 0x1000). Then the irq is called and you push values and now the stack is (0xFEE, these are just examples.) Now when the task is schedule again, the kernel stack base is 0xFEE. Then on the next task switch you again push everything and you save the current stack pointer so your stack goes down again(maybe 0xFCC). As you can see your stack gets lower and lower. So sooner or later it will reach an unmapped address or something like that. Hope that helps. |
Author: | Ready4Dis [ Mon Apr 14, 2008 8:58 pm ] |
Post subject: | |
That entire task_switcher routine looks somewhat fishy though. Like, why should it being just initialized mean that you need to do somethin special? The ESP value should be correct on start, and if you pushed the registers of the current task on the current stack (whatever stack your actual kernel is using), it won't screw with any of your tasks anyways, you could easily make that much simpler to read. Disregard what the guy above said, he obviously didn't read your code or missed something sinc you are obviously poping values back off the stack after storing ESP, i have no clue where he got that from (pulled from his a$$?) Like I mentioned you have the extra pop in there, fix that and let us know, also I will post a bit later on how to fix your task_switch so it doesn't look so clustered and waste time with those checks every time after it's started. --- Edit --- Ok, here is how mine works (mine uses pointers so it's a bit simpler, but i'll show you how with an array like you're using). Code: #define MAX_TASKS 32
struct Task_S TaskList[MAX_TASKS]; long CurrentTask=0; unsigned int task_switcher(unsigned int addr) { TaskList[CurrentTask].esp = addr; do{ CurrentTask= (CurrentTask+1)%MAX_TASKS; //Automagically circle } while (TaskList[CurrentTask].status == 0); return TaskList[CurrentTask].esp; } void InitMulttasking(void) { TaskList[0].status = TASK_ACTIVE; strcpy(TaskList[0].name,"Idle Thread"); //Add whatever other tasks you want here... create_task(kernel_thread,"Kernel",0); EnableInterrupt(TimerInt); //start your timer going :P //Now, if you don't like having an idle thread, we can kill it whenever it runs again.. TaskList[0].status = 0; //Kill me off, set me as useable! //If you have a way to switch tasks already (or directly call the interrupt), //you can do that here instead of this for loop :). for (;;) asm("hlt"); //do nothing until we get interrupted and never called again! } See how much simpler your task_switch is now, and since it's called a lot, it will make a difference! Please keep us updated on how it's going if you got it working yet or not . |
Author: | Pyrofan1 [ Mon Apr 14, 2008 10:38 pm ] |
Post subject: | |
There's a good reason i have the extra pop %eax. For whatever reason when task_switcher gets called. It doesn't pop the last value off the stack, and if i remove the pop eax, it corrupts the stack and causes a GPF. --Edit-- Okay, i figured out how to create a proper bootable image using grub, so now i can run my OS in bochs here's what it tells me The actual screen Quote: Created task PID: 0, stack: 0x001241D4 Created task PID: 1, stack: 0x001251D4 Created task PID: 2, stack: 0x001261D4 Created task PID: 3, stack: 0x001271D4 Switching from 0 To 1 Switching from 1 To 2 Switching from 2 To 3 Switching from 3 To 0 PyroS has encountered an error General Protection Fault Exception, interrupt 13, error 512 Registers: eax: 0x00103B6F ebx: 0x00000000 ecx: 0x00000000 edx: 0x00000000 esp: 0x001241F4 ebp: 0x00124204 esi: 0x00124210 edi: 0x00000000 eip: 0x00103CE4 gs: 0x00000010 cs: 0x00000008 ds: 0x00000010 es: 0x00000010 fs: 0x00000010 eflags: 0x00010206 Task that caused this exception PID: 0 Name: idle task Access: Kernel what the log says Quote: 00246160795e[CPU0 ] fetch_raw_descriptor: GDT: index (207)40 > limit (17)
00246187558i[CPU0 ] WARNING: HLT instruction with IF=0! 13572406000p[WGUI ] >>PANIC<< POWER button turned off. 13572406000i[CPU0 ] CPU is in protected mode (halted) 13572406000i[CPU0 ] CS.d_b = 32 bit 13572406000i[CPU0 ] SS.d_b = 32 bit 13572406000i[CPU0 ] EFER = 0x00000000 13572406000i[CPU0 ] | RAX=0000000000000000 RBX=0000000000109640 13572406000i[CPU0 ] | RCX=0000000000000000 RDX=00000000000b076c 13572406000i[CPU0 ] | RSP=0000000000124190 RBP=00000000001241b8 13572406000i[CPU0 ] | RSI=0000000000124210 RDI=0000000000000000 13572406000i[CPU0 ] | R8=0000000000000000 R9=0000000000000000 13572406000i[CPU0 ] | R10=0000000000000000 R11=0000000000000000 13572406000i[CPU0 ] | R12=0000000000000000 R13=0000000000000000 13572406000i[CPU0 ] | R14=0000000000000000 R15=0000000000000000 13572406000i[CPU0 ] | IOPL=0 id vip vif ac vm rf nt of df if tf sf ZF af PF cf 13572406000i[CPU0 ] | SEG selector base limit G D 13572406000i[CPU0 ] | SEG sltr(index|ti|rpl) base limit G D 13572406000i[CPU0 ] | CS:0008( 0001| 0| 0) 00000000 000fffff 1 1 13572406000i[CPU0 ] | DS:0010( 0002| 0| 0) 00000000 000fffff 1 1 13572406000i[CPU0 ] | SS:0010( 0002| 0| 0) 00000000 000fffff 1 1 13572406000i[CPU0 ] | ES:0010( 0002| 0| 0) 00000000 000fffff 1 1 13572406000i[CPU0 ] | FS:0010( 0002| 0| 0) 00000000 000fffff 1 1 13572406000i[CPU0 ] | GS:0010( 0002| 0| 0) 00000000 000fffff 1 1 13572406000i[CPU0 ] | MSR_FS_BASE:0000000000000000 13572406000i[CPU0 ] | MSR_GS_BASE:0000000000000000 13572406000i[CPU0 ] | RIP=0000000000102afb (0000000000102afb) 13572406000i[CPU0 ] | CR0=0x00000011 CR1=0x0 CR2=0x0000000000000000 13572406000i[CPU0 ] | CR3=0x00000000 CR4=0x00000000 13572406000i[CPU0 ] >> add esp, 0x00000024 : 83C424 |
Author: | Ready4Dis [ Tue Apr 15, 2008 12:01 pm ] |
Post subject: | |
Well, then something is wrong somewhere, here is a walkthrough of your code: esp = 0x1000 (for simplicity) pusha ;Pushes 8 dwords, 32 bytes ;esp = 0xFE0 mov %ds, %eax push %eax ;4 more bytes ;esp = 0xFDC mov %es, %eax push %eax ;4 more bytes ;esp = 0xFD8 mov %fs, %eax push %eax ; and 4 more ;esp = 0xFD4 mov %gs, %eax push %eax ;and 4 more... ;esp = 0xFD0 mov %esp, %eax ; Here we are pushing ESP, so EAX = 0xFD0 push %eax ;esp = 0xFCC (but remember, we pushed FD0, not FCC!) call task_switcher ;Returns the STORED ESP value mov %eax, %esp ;restore ESP to 0xFD0 mov $0x20, %al ;eoi for pic out %al, $0x20 pop %eax ;esp = 0xFD4 pop %eax ;esp = 0xFD8 pop %eax ;esp = 0xFDC pop %eax ;esp = 0xFE0 pop %eax ;esp = 0xFE4 popa ;esp = 0x1004 ;Uh-oh, we blew past our stack start, this is a problem! ;Crap, now if we iret, we will jump to the incorrect EIP, and GPF occurs Please tell me what i'm missing, because you have more pop's than pushes as demonstrated, it will destroy your stack, and the wrong values are ending up in the wrong registers. if you remove that pop, and it's still crashing, then start looking in your other functions and let us know. This is how the stack works, you cannot fool the stack, if you aren't pushing the correct # of values to the stack on task creation (i push more than you do, so possible problem), then it will work on the first run through (poping a bogus value from the stack for it to work and put the EIP in the correct location for the first iret, then never work again when the task is called, which looks to be your problem). Every time you switch BACK to a task, it will crash, if you had 15 tasks, each one would run ONCE then GPF when the first task is called again. So, again, please remove that pop and let me know what happens, and we can try to find the ACTUAL problem. I know how a stack works, i'm not trying to point you in a wrong direction i promise. Also, for me, I had to put an additional *stack--=0x10 to compensate for the pushed SS value. |
Author: | Pyrofan1 [ Tue Apr 15, 2008 12:27 pm ] |
Post subject: | |
Quote: please remove that pop and let me know what happens, This is what happens when i remove the pop It doesn't even go through the list once Quote: 00035167062p[CPU0 ] >>PANIC<< fetch_raw_descriptor: LDTR.valid=0
00035167062i[CPU0 ] CPU is in protected mode (active) 00035167062i[CPU0 ] CS.d_b = 32 bit 00035167062i[CPU0 ] SS.d_b = 32 bit 00035167062i[CPU0 ] EFER = 0x00000000 00035167062i[CPU0 ] | RAX=0000000000000000 RBX=0000000000000000 00035167062i[CPU0 ] | RCX=0000000000000000 RDX=0000000000000000 00035167062i[CPU0 ] | RSP=0000000000124204 RBP=0000000000000000 00035167062i[CPU0 ] | RSI=0000000000000000 RDI=0000000000000010 00035167062i[CPU0 ] | R8=0000000000000000 R9=0000000000000000 00035167062i[CPU0 ] | R10=0000000000000000 R11=0000000000000000 00035167062i[CPU0 ] | R12=0000000000000000 R13=0000000000000000 00035167062i[CPU0 ] | R14=0000000000000000 R15=0000000000000000 00035167062i[CPU0 ] | IOPL=0 id vip vif ac vm rf nt of df IF tf sf zf af pf cf 00035167062i[CPU0 ] | SEG selector base limit G D 00035167062i[CPU0 ] | SEG sltr(index|ti|rpl) base limit G D 00035167062i[CPU0 ] | CS:0008( 0001| 0| 0) 00000000 000fffff 1 1 00035167062i[CPU0 ] | DS:0010( 0002| 0| 0) 00000000 000fffff 1 1 00035167062i[CPU0 ] | SS:0010( 0002| 0| 0) 00000000 000fffff 1 1 00035167062i[CPU0 ] | ES:0010( 0002| 0| 0) 00000000 000fffff 1 1 00035167062i[CPU0 ] | FS:0010( 0002| 0| 0) 00000000 000fffff 1 1 00035167062i[CPU0 ] | GS:0010( 0002| 0| 0) 00000000 000fffff 1 1 00035167062i[CPU0 ] | MSR_FS_BASE:0000000000000000 00035167062i[CPU0 ] | MSR_GS_BASE:0000000000000000 00035167062i[CPU0 ] | RIP=0000000000103ce2 (0000000000103ce1) 00035167062i[CPU0 ] | CR0=0x00000011 CR1=0x0 CR2=0x0000000000000000 00035167062i[CPU0 ] | CR3=0x00000000 CR4=0x00000000 00035167062i[CPU0 ] >> iretd : CF |
Author: | Ready4Dis [ Tue Apr 15, 2008 12:45 pm ] |
Post subject: | |
Ok, so now that you are there, try a few extra things... firstly, try putting known values into eax, ebx, ecx, etc in your create task function, then before your interrupt can return (right before the sti I would) hlt the cpu or put an infinite loop, then exit out and check if the correct values are put into the correct registers. If they differ, then you can see which values ended up where and have an idea on what is going on. Once you figure this out, you can proceed to the next trouble shooting step. this is why bochs is great, it allows you to stop the CPU and see what is going on inside at any point. I would use something closer to how my code is (actually push/pop es,ds,gs, and fs) that way, if you ever want to do other code/dats segments, you are already popping the correct values into their perspective registers (rather than just incrementing esp by poping the values into EAX). This will also help determine if they are popping the correct values as you are expecting. also, in your create task function, trying pushing another value for SS at the start (as the first value put on the stack). |
Author: | Pyrofan1 [ Tue Apr 15, 2008 1:09 pm ] |
Post subject: | |
Getting closer to having this working The value that's in ebp should be in ecx which means the stack is off my 16 bytes Quote: Created task PID: 0, stack: 0x001241D4
Created task PID: 1, stack: 0x001251D4 Created task PID: 2, stack: 0x001261D4 Created task PID: 3, stack: 0x001271D4 PyroS has encountered an error General Protection Fault Exception, interrupt 13, error 15212 Registers: eax: 0x00000000 ebx: 0x00000000 ecx: 0x00000000 edx: 0x00000000 esp: 0x001241F0 ebp: 0x1BADB00B esi: 0x00000000 edi: 0x00000010 eip: 0x00103CE1 gs: 0x00000010 cs: 0x00000008 ds: 0x00000010 es: 0x00000010 fs: 0x00000010 eflags: 0x00010202 Task that caused this exception PID: 0 Name: idle task Access: Kernel |
Author: | Ready4Dis [ Tue Apr 15, 2008 7:09 pm ] |
Post subject: | |
So, this is how bug tracing typically goes with Bochs. So, you see your stack is off by 16-bytes, which is 4 dwords. So, how are you first starting your task switching? Are you just letting the interrupt fire? calling a function or sorts, etc? Any clue where those 16 bytes could come from? Also, are you sure that you are reading them properly, remember, that the stack starts at the top, and moves downwards, so it should push in this order: ss eflags cs eip eax ecx edx ebx esp ebp esi edi ds es fs gs Now, also, look at your ESP value... in your print out, it says the stack is at 0x001241D4... then in your printout, it shows it at 0x001241F0... what value are you printing (before the stack is moved or after?) These things can give you hints on the problem. You appear to be pushing the correct # of things onto the stack (although I would add one more *stack-- = 0x10 at the beginning to reserve it for ss). Now, one BIG thing that I did notice, is that you're post decrementing..., you need to pre-decrement... *--stack = xxx;. The reason for this is, the stack grows downwards right.. lets assume 0x1000 for ease of use again: esp = 0x1000 *stack-- = 0x10; Lets break this down: *stack = 0x10; stack--; So, you are setting 0x1000 = 0x10, when indeed you are trying to set 0xFFC = 0x10; So you must predecrement: *--stack = 0x10, etc, etc. This was your reason for off by one, hence why you had to add the extra pop in there to get it to even fire each task once (which doesn't work once the tasks is reentered due to the off by one problem). So, I hope this concludes this lessons learned, and you should have a functioning multi-tasker once you fix the post/pre decrement, and have that extra pop instruction removed. I hope you learned a bit about bug-hunting and can learn from this and move forward. If you're still having issues, post your updated code so I can see what you're currently working with and can assist further. Like I said, I wasn't trying to lead you astray telling you you had an extra pop in there, it WAS a problem masking the real problem (post decrement rather than pre), so putting it back allowed us to find the actual problem. |
Author: | Pyrofan1 [ Tue Apr 15, 2008 9:28 pm ] |
Post subject: | |
I guess that pre-decrementing was the answer. It works perfectly now. Thanks for all your help. |
Author: | Ready4Dis [ Tue Apr 15, 2008 10:33 pm ] |
Post subject: | |
Glad it's working, hope you got some stuff out of troubleshooting a bit. Now if I could only figure out the bugs in my own kernel i'd be set . Anyways, let us know if you run into more issues and don't be affraid to put endless loops, etc to check outputs in bochs to see what is going on with the registers, and think it through logically (like I did when I described what was happening with ESP when it is calling your function to prove why you didn't want that extra pop in there, to figure out the problem was else where). |
Page 1 of 1 | All times are UTC - 6 hours |
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group http://www.phpbb.com/ |