About the ESP0 field...
-
- Member
- Posts: 2566
- Joined: Sun Jan 14, 2007 9:15 pm
- Libera.chat IRC: miselin
- Location: Sydney, Australia (I come from a land down under!)
- Contact:
About the ESP0 field...
I have finally been able to have a TSS segment in my GDT without crashing. Now I have a question: what do I put as the ESP0 field when a task switch happens? I know it should be the kernel stack pointer, but what value is that?
which ever value you choose. if you allocate a 16 Kilobyte block then you can use the pointer to that block as ESP0, keep in mind that the ESP0 should point to the end of the block.
so in pseudo code:
so in pseudo code:
Code: Select all
char * stack = kernel_alloc_pages(4);
tss->ESP0 = (int)&stack[16*1024];
Author of COBOS
-
- Member
- Posts: 2566
- Joined: Sun Jan 14, 2007 9:15 pm
- Libera.chat IRC: miselin
- Location: Sydney, Australia (I come from a land down under!)
- Contact:
OK... I get that now.
I also want to ask, how can I stop Invalid Opcode errors?
Edit: OK, I did some debugging and found that the ESP value is ok for the first reschedule, then it starts having issues when the ESP value isn't restored properly...
More debugging is going to follow, I'm going to have to figure out how ESP gets trashed. If anyone can peruse my code and point out better ways/problems than I would be extremely grateful.
Edit 2: Found the source of the ESP trashing. If I remove any function calls from tasks, there are no more issues. Now, how to fix it?
Edit 3: Found a really bad way to fix it... It's caused by functions getting pre-empted, stack getting trashed by the pre-emption etc... If I disable multitasking before each function call it works
I also want to ask, how can I stop Invalid Opcode errors?
Edit: OK, I did some debugging and found that the ESP value is ok for the first reschedule, then it starts having issues when the ESP value isn't restored properly...
More debugging is going to follow, I'm going to have to figure out how ESP gets trashed. If anyone can peruse my code and point out better ways/problems than I would be extremely grateful.
Edit 2: Found the source of the ESP trashing. If I remove any function calls from tasks, there are no more issues. Now, how to fix it?
Edit 3: Found a really bad way to fix it... It's caused by functions getting pre-empted, stack getting trashed by the pre-emption etc... If I disable multitasking before each function call it works
Try giving each process or task it's own kernel stack. Before you switch tasks you can update the value of ss0 in the TSS. Of course this only makes a difference if the kernel is preemptible. Otherwise that is not the problem. I could show you some of the code from my working multitasking if you think that that it could help you.
-
- Member
- Posts: 2566
- Joined: Sun Jan 14, 2007 9:15 pm
- Libera.chat IRC: miselin
- Location: Sydney, Australia (I come from a land down under!)
- Contact:
At the moment I'm writing some spaghetti code from the sixth pm mode tutorial (osdever.net) to try to get hardware multitasking working...
If I can get this to work (properly) then I'll implement it properly into my kernel. If not, well, it's back to the drawing board...
Edit: I have a problem. Every time I try to jump to the TSS selector my OS triple faults, Bochs log says:
Any ideas? Do I need an LDT, or can I just get by by setting the TSS's LDT field to 0?
If I can get this to work (properly) then I'll implement it properly into my kernel. If not, well, it's back to the drawing board...
Edit: I have a problem. Every time I try to jump to the TSS selector my OS triple faults, Bochs log says:
Code: Select all
00029103836i[CPU0 ] task_switch: bad LDT fetch
00029103836i[CPU0 ] task switch: posting exception 10 after commit point
- Kevin McGuire
- Member
- Posts: 843
- Joined: Tue Nov 09, 2004 12:00 am
- Location: United States
- Contact:
-
- Member
- Posts: 2566
- Joined: Sun Jan 14, 2007 9:15 pm
- Libera.chat IRC: miselin
- Location: Sydney, Australia (I come from a land down under!)
- Contact:
I use batch files with hard-coded paths, so I figured I might save some people some time...
Newest happening: Bochs actually posts a panic (log is below)
EVERYTHING there is wrong. The only time I can get the proper values for the GDT in Bochs debugger is when I put in a while( true ); loop...
Edit: also, the CVS hasn't been updated with my new work...
Edit 2: never mind, it's updated now.
Newest happening: Bochs actually posts a panic (log is below)
Code: Select all
00030361472i[CPU0 ] task_switch: bad LDT fetch
00030361472i[CPU0 ] task switch: posting exception 10 after commit point
00030361472p[CPU0 ] >>PANIC<< fetch_raw_descriptor: LDTR.valid=0
00030361472i[CPU0 ] protected mode
00030361472i[CPU0 ] CS.d_b = 32 bit
00030361472i[CPU0 ] SS.d_b = 32 bit
00030361472i[CPU0 ] | EAX=f000efdf EBX=f000ff53 ECX=c0001344 EDX=f000ff53
00030361472i[CPU0 ] | ESP=00177f00 EBP=f000ff53 ESI=f000ff53 EDI=f000ff53
00030361472i[CPU0 ] | IOPL=3 id vip vif ac vm RF NT OF DF IF TF sf ZF AF pf CF
00030361472i[CPU0 ] | SEG selector base limit G D
00030361472i[CPU0 ] | SEG sltr(index|ti|rpl) base limit G D
00030361472i[CPU0 ] | CS:ff53( 1fea| 0| 3) 00000000 000fffff 1 1
00030361472i[CPU0 ] | DS:ff53( 1fea| 0| 3) 00000000 000fffff 1 1
00030361472i[CPU0 ] | SS:ff53( 1fea| 0| 3) 00000000 000fffff 1 1
00030361472i[CPU0 ] | ES:ff53( 1fea| 0| 3) 00000000 000fffff 1 1
00030361472i[CPU0 ] | FS:ff53( 1fea| 0| 3) 00000000 000fffff 1 1
00030361472i[CPU0 ] | GS:ff53( 1fea| 0| 3) 00000000 000fffff 1 1
00030361472i[CPU0 ] | EIP=f00099ff (f00099ff)
00030361472i[CPU0 ] | CR0=0x00000019 CR1=0 CR2=0x00000000
00030361472i[CPU0 ] | CR3=0x00000000 CR4=0x00000000
00030361472i[CPU0 ] >> (invalid) : FFFF
Edit: also, the CVS hasn't been updated with my new work...
Edit 2: never mind, it's updated now.
- Kevin McGuire
- Member
- Posts: 843
- Joined: Tue Nov 09, 2004 12:00 am
- Location: United States
- Contact:
I tried compiling everything, and assembling anything I could into one big blob in a directory but it appears that some files might still be missing?
It seems like they are going to be some assembler source, or am I wrong?
The linker is having problems finding the isrXX routines, and quite a few others.
It seems like they are going to be some assembler source, or am I wrong?
The linker is having problems finding the isrXX routines, and quite a few others.
- Kevin McGuire
- Member
- Posts: 843
- Joined: Tue Nov 09, 2004 12:00 am
- Location: United States
- Contact:
I think I will wait until you get a decent build script working.
I feel a little discouraged after finally getting it to link only to find that there are more errors and problem.
nasm loader.asm -f elf
gcc loader.o ./net/*.c ./stdlib/*.c ./hdd_pio/*.c ./fdc/*.c ./*.c -fleading-underscore -ffreestanding -o kernel -nostdlib -Xlinker link.link
objdump kernel -x > /tmp/x
grep "MultiBootHeader" /tmp/x
Never the less the whole experienced has bored me so much I am about to start jumping up and down.
\\edit\\
And. I just realized you put the MultiBootHeader in the .text section instead of the data as I was expecting with the linker script...
I feel a little discouraged after finally getting it to link only to find that there are more errors and problem.
nasm loader.asm -f elf
gcc loader.o ./net/*.c ./stdlib/*.c ./hdd_pio/*.c ./fdc/*.c ./*.c -fleading-underscore -ffreestanding -o kernel -nostdlib -Xlinker link.link
objdump kernel -x > /tmp/x
grep "MultiBootHeader" /tmp/x
Code: Select all
080480c0 1 .text 00000000 MultiBootHeader
\\edit\\
And. I just realized you put the MultiBootHeader in the .text section instead of the data as I was expecting with the linker script...
-
- Member
- Posts: 2566
- Joined: Sun Jan 14, 2007 9:15 pm
- Libera.chat IRC: miselin
- Location: Sydney, Australia (I come from a land down under!)
- Contact:
OK, I've been reading and it seems the LDT (according to some code I looked at) can be pointed to the NULL descriptor in the GDT... The problem is, Bochs still complains about an invalid LDT - 'Bad LDT Fetch...'.
I'm about to start pulling my hair out, I've tried so much stuff to make it work! The latest thing I've done is make an LDT with 2 entries which matched the CS and DS selectors in the GDT. I still have problems (Bochs panics, saying LDTR.valid = 0). I've looked at the Bochs source to try to figure out why it's not working but nothing has come up.
Can anyone tell me how to easily setup software multitasking that works, without crashing?
@frank - could you show me your scheduler and task creation code?
Edit: Ok, the problem is in this line:
0x20 is the index of the first task's TSS entry n the GDT (ATM the GDT holds one TSS per task, just for testing purposes). Whenver this line executes I get the error.
I'm about to start pulling my hair out, I've tried so much stuff to make it work! The latest thing I've done is make an LDT with 2 entries which matched the CS and DS selectors in the GDT. I still have problems (Bochs panics, saying LDTR.valid = 0). I've looked at the Bochs source to try to figure out why it's not working but nothing has come up.
Can anyone tell me how to easily setup software multitasking that works, without crashing?
@frank - could you show me your scheduler and task creation code?
Edit: Ok, the problem is in this line:
Code: Select all
__asm__ __volatile__ ( "ljmp $0x20,$0" );
Ok, here comes the easy list:
1. write some queue management code for the scheduler
2. allocate one stack for each thread, and store info, any required list pointers for the queues, and whatever somewhere. Easiest is at the beginning of the stack area, but separate table is fine as well.
3. write a routine that picks the first thread from the scheduler queue, and switches the current stack to the new threads stack, and stores the old ESP into the old threads info block, such that you can later switch back to it.. this is your scheduler now. it should also add the old thread back into the queue.
4. do some manual "co-operative" multi-threading in kernel without enabling interrupts to make sure everything works correctly and you can have at least three threads switch to each other multiple times. edit: my experience is that stuff that works with two threads might break with a third, but once it works with three, it probably works with ten
5. make sure you have working interrupts and a working clock
6. make the clock drive the scheduling, that is, call the scheduler from the clock interrupts (actually you want to count down a timeshare first, but that's easy to add)
7. test that it works, still without going out of kernel, but this time enable interrupts, and make sure every threads gets run for some time at some points (have one print 'A' and another print 'B' and so on, or something)
8. create a TSS, put it into GDT and load it with LDT. only relevant field is SS0 which should be kernel stack segment. ESP0 we fill in the next step.
9. every time your going out of the kernel, store the address of the byte immediately after the current threads stack in TSS's ESP0 field.. next time you'll come to kernel, it will become your stack again...
10. on kernel entry push all registers, on exit (return) pop them in the same order... you can leave them in the stack while you're in kernel, but get a pointer to them if you need to modify them (you can modify them while they are in the stack).
11. make sure it works.
---
The alternative is to use a single kernel thread, and not do multi-threading in kernel, in which case you can have the same value ESP0 all the time. I actually used that approach initially, but it becomes really mess really fast, and is harder to get working because you'll be debugging ten things at once.
1. write some queue management code for the scheduler
2. allocate one stack for each thread, and store info, any required list pointers for the queues, and whatever somewhere. Easiest is at the beginning of the stack area, but separate table is fine as well.
3. write a routine that picks the first thread from the scheduler queue, and switches the current stack to the new threads stack, and stores the old ESP into the old threads info block, such that you can later switch back to it.. this is your scheduler now. it should also add the old thread back into the queue.
4. do some manual "co-operative" multi-threading in kernel without enabling interrupts to make sure everything works correctly and you can have at least three threads switch to each other multiple times. edit: my experience is that stuff that works with two threads might break with a third, but once it works with three, it probably works with ten
5. make sure you have working interrupts and a working clock
6. make the clock drive the scheduling, that is, call the scheduler from the clock interrupts (actually you want to count down a timeshare first, but that's easy to add)
7. test that it works, still without going out of kernel, but this time enable interrupts, and make sure every threads gets run for some time at some points (have one print 'A' and another print 'B' and so on, or something)
8. create a TSS, put it into GDT and load it with LDT. only relevant field is SS0 which should be kernel stack segment. ESP0 we fill in the next step.
9. every time your going out of the kernel, store the address of the byte immediately after the current threads stack in TSS's ESP0 field.. next time you'll come to kernel, it will become your stack again...
10. on kernel entry push all registers, on exit (return) pop them in the same order... you can leave them in the stack while you're in kernel, but get a pointer to them if you need to modify them (you can modify them while they are in the stack).
11. make sure it works.
---
The alternative is to use a single kernel thread, and not do multi-threading in kernel, in which case you can have the same value ESP0 all the time. I actually used that approach initially, but it becomes really mess really fast, and is harder to get working because you'll be debugging ten things at once.
The real problem with goto is not with the control transfer, but with environments. Properly tail-recursive closures get both right.
Make pre-empted multi-threading in kernel work first, worry about TSS then. ESP0 isn't loaded if you get an interrupts while your in kernel, so no need to worry about that.
The real problem with goto is not with the control transfer, but with environments. Properly tail-recursive closures get both right.