Page 1 of 3

About the ESP0 field...

Posted: Fri Apr 27, 2007 2:50 am
by pcmattman
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?

Posted: Fri Apr 27, 2007 3:09 am
by os64dev
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:

Code: Select all

char *  stack = kernel_alloc_pages(4);
tss->ESP0 = (int)&stack[16*1024];

Posted: Fri Apr 27, 2007 4:02 pm
by pcmattman
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 :D

Posted: Fri Apr 27, 2007 7:22 pm
by pcmattman
Can anyone help me here? I've got a rubbish multitasker that I would like to replace with a better one but all my attempts have failed.

Posted: Sat Apr 28, 2007 8:21 pm
by frank
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.

Posted: Sat Apr 28, 2007 8:26 pm
by pcmattman
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:

Code: Select all

00029103836i[CPU0 ] task_switch: bad LDT fetch
00029103836i[CPU0 ] task switch: posting exception 10 after commit point
Any ideas? Do I need an LDT, or can I just get by by setting the TSS's LDT field to 0?

Posted: Sat Apr 28, 2007 9:19 pm
by Kevin McGuire
I downloaded the cvs repository using rsync, and I checkout out the latest copy from the local cvs repository but I am unable to find you're build scripts or some sort?

Posted: Sat Apr 28, 2007 9:23 pm
by pcmattman
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)

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
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.

Posted: Sat Apr 28, 2007 9:30 pm
by Kevin McGuire
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.

Posted: Sat Apr 28, 2007 9:31 pm
by pcmattman
Assemble loader.asm, has to be linked in first, has to be elf.

Posted: Sat Apr 28, 2007 10:46 pm
by Kevin McGuire
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

Code: Select all

080480c0 1 .text 00000000 MultiBootHeader
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...

Posted: Sun Apr 29, 2007 2:45 am
by pcmattman
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:

Code: Select all

__asm__ __volatile__ ( "ljmp $0x20,$0" );
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.

Posted: Sun Apr 29, 2007 3:41 am
by mystran
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.

Posted: Sun Apr 29, 2007 3:49 am
by pcmattman
What you wrote is what I had.

Unfortunately, as I said earlier, the stack got trashed when function calls got pre-empted. I have no idea how to fix that, and I'm currently re-writing my multitasker (with all code in main(), until it works) to figure out how to make it work properly.

Posted: Sun Apr 29, 2007 4:02 am
by mystran
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.