Eigenes OS?
-
Try to use cli(); at start of the handler.
I did, but the GPF didn't leave. In between I was told that C might be not perfect for the task switch. The above presented function for task_switch does not save all registers. That might be the real problem in some situations.
-
Another point in the whole source code is the mixing of physical and virtual memory management in paging.h/paging.c. That has to be separated.
-
Sure it has to be separate, i do, the PMM, VMM and kmalloc, all apart.
What is o_0:
if(!(queue_empty(&roundrobin_prozesse))&&p->prozess_timetorun<1)
the double && looks very bad to me
I checked task switch code with my old, its the same (diff is what I added, like threads and states). I put a cli() just after very first statement. (if(!task)).
And where exactly (line) does the #GP trigger? (just try putting chars like ! on as much as lines as possible, and count numbeer of printed when running)
// PHPnerd
-
just try putting chars like ! on as much as lines as possible, and count numbeer of printed when running
Interesting trick. This I try at once:
!!!!#!!!!#!!!!#General Protection Fault >>> Exception. System Halted! <<<
Hence, I know that the GPF happens in the asm-code:
..
because the last ! did not show up.
-
You really do? Dont be so sure. What does the ASM do? Yes, it switches task, it chnages page directory, and the instrcution pointer after that code, we continue the task, and not the code of the scheduler.
Or am i wrong, and is the ! showed at the other switchs?
// PHP
-
Erhard Henkes schrieb:
In between I was told that C might be not perfect for the task switch. The above presented function for task_switch does not save all registers. That might be the real problem in some situations.
that's true. even if most c-compilers have support for interrupt routines, you can't access cpu registers directly in C (only few compilers for embedded systems support that). you have to code this very low level stuff in assembly. all real life RTOS (although portable among many cpus), with preemptive schedulers, use asm for the heart of the task switcher.
-
Well, you think, the last ! cannot show up. OK, then I have to try a situation where it works correctly.
You are right! If it works, then !!!!#!!!!#!!!!## is presented at the screen. Thus, the last # is given out twice instead of the !
Now I am in a dead-end-street.
-
Are you using Bochs? I hope so, do following for me:
put cli, hlt, for(;;); before the big assembly part. Shutdown, and open the bochsout file. Put the register info in here. Btw: remove any calls to the scheduler and call it the way it will fault. So it will give us the right values.
// PHPnerd
-
/// TEST cli(); asm volatile("hlt;"); for(;;); /// TEST asm volatile(" \ //...
01368000000p[WGUI ] >>PANIC<< POWER button turned off. 01368000000i[CPU0 ] CPU is in protected mode (halted) 01368000000i[CPU0 ] CS.d_b = 32 bit 01368000000i[CPU0 ] SS.d_b = 32 bit 01368000000i[CPU0 ] EFER = 0x00000000 01368000000i[CPU0 ] | RAX=000000000000008f RBX=000000000000d502 01368000000i[CPU0 ] | RCX=00000000000b8000 RDX=00000000000003d5 01368000000i[CPU0 ] | RSP=000000000018ff1c RBP=000000000018ff44 01368000000i[CPU0 ] | RSI=000000000018ffd8 RDI=000000000018fff0 01368000000i[CPU0 ] | R8=0000000000000000 R9=0000000000000000 01368000000i[CPU0 ] | R10=0000000000000000 R11=0000000000000000 01368000000i[CPU0 ] | R12=0000000000000000 R13=0000000000000000 01368000000i[CPU0 ] | R14=0000000000000000 R15=0000000000000000 01368000000i[CPU0 ] | IOPL=0 id vip vif ac vm rf nt of df if tf sf zf af pf cf 01368000000i[CPU0 ] | SEG selector base limit G D 01368000000i[CPU0 ] | SEG sltr(index|ti|rpl) base limit G D 01368000000i[CPU0 ] | CS:0008( 0001| 0| 0) 00000000 000fffff 1 1 01368000000i[CPU0 ] | DS:0010( 0002| 0| 0) 00000000 000fffff 1 1 01368000000i[CPU0 ] | SS:0010( 0002| 0| 0) 00000000 000fffff 1 1 01368000000i[CPU0 ] | ES:0010( 0002| 0| 0) 00000000 000fffff 1 1 01368000000i[CPU0 ] | FS:0010( 0002| 0| 0) 00000000 000fffff 1 1 01368000000i[CPU0 ] | GS:0010( 0002| 0| 0) 00000000 000fffff 1 1 01368000000i[CPU0 ] | MSR_FS_BASE:0000000000000000 01368000000i[CPU0 ] | MSR_GS_BASE:0000000000000000 01368000000i[CPU0 ] | RIP=000000000000d3f9 (000000000000d3f9) 01368000000i[CPU0 ] | CR0=0xe0000011 CR1=0x0 CR2=0x0000000000000000 01368000000i[CPU0 ] | CR3=0x00306000 CR4=0x00000000 01368000000i[CPU0 ] >> add esp, 0x00000010 : 83C410 01368000000i[CMOS ] Last time is 1240781579 (Sun Apr 26 23:32:59 2009) 01368000000i[ ] restoring default signal behavior 01368000000i[CTRL ] quit_sim called with exit code 1
This I did not understand:
remove any calls to the scheduler and call it the way it will fault. So it will give us the right values.
The timer_handler:
void timer_handler(struct regs* r) { ++timer_ticks; if (eticks) --eticks; //TEST static ULONG c = 0; ++c; if(c>200) { task_switch(); settextcolor(getpid(),0); c=0; } //TEST }
-
You see that task_switch() will never be called? you declare a variable, does 1 time incrmeent, and checks for 200?
///////////
Ok, good.
Try the same, but than in the assbly part itself, each time one line, until the GPF occurs. then we know which opcode makes the fault. (Maybe it is just the jump).
If that fails, try getting all values of the registers when GPF triggers (print out all registers etc from the Registers given at the handler and post them, and maybe a disassembly of your schedule() (so we can exactly see when it trigger according to RIP's. We cant put cli hlt etc into the assembly part
// PHPnerd
-
PHPnerd schrieb:
You see that task_switch() will never be called? you declare a variable, does 1 time incrmeent, and checks for 200?
c is declared static, therefore it works:
..
-
What is the info from the #GP?
// PHP
-
Currently, I do not get GPF again. I have done the following:
- I used the clobber list:
asm volatile("..." : : "r"(eip), "r"(esp), "r"(ebp), "r"(current_directory->physicalAddr) : "ebx", "edx");
ebx and edx were accepted, edi and esi gave failure ("can't find a register in class `GENERAL_REGS' while reloading `asm'").
2) I accelerated the task switch://TEST static ULONG c = 0; ++c; if(c>0) { printformat("task_switch\n"); task_switch(); settextcolor(getpid(),0); c=0; } //TEST
output at bochs:
!task_switch
!task_switch
!task_switch
!HEAP start: 40081000h end: 40100000h max: 4FFFF000h kernel mode: 0 read-only: 0ask_switch
!
hole 40081000h hole-size: 0007F000h
after create_heap: placement_address: 0030C020h allocated frames: 795
ask_switch
!
task_switch
!tasking install
!tasking install
after moving stack, ESP: 0018FFD0h ddress: 0030C020h
After k_mallocing kernel_stack), placement_address: 0030C020h kernel_stack: 4010
1000h
VFS & RAM Disk install
ask_switch
!!!!#!!!!#!!!!##
placement_address after ram disk install: 40100000h
ramdisk_start: 40081000h file_data_start: 0000A2F0h file_data_end: 0000B662h
ask_switch
!Page Fault (page not present) at 00D2ECF0h - EIP: 0000D2C9h
Page Fault >>> Exception. System Halted! <<<As you can see, there is one failure free task switch.
But the output looks disturbed.What is the info from the #GP?
Ihave no specific info from GPF. You mentioned a failure analysis routine. Do you have a link for that code or a table with the error flag meanings?
I post the current version with the problematic task switch in the time handler:
http://www.henkessoft.de/OS_Dev/Downloads/37.zipI use gcc.exe (version 3.1) and ld.exe (version 2.13) due to linking aout-format of NASM
http://www.osdever.net/downloads/compilers/DJGPP-Installer-nocpp.exe
-
Well done!
Just, remove the ! and # and task switch printouts
Do you have a keyboard handler? Try to make a simple console system. Use the Function keys to switch to another console. Each task is linked to a console. When switching console, you copy the data from 0xb8000 to the data of current console. And write data of new console to 0xb8000.
Something like that will work.
Then, you will see on each console the output of each task apart nice for testing your multitasker.
About the GP: The code of JamesM tutorials uses the structure registers. Filled in some assebly code. Use that structure to printout eip, esp etc, and get the control registers and print them out too. Error flag meanings can be found in the Intel Manual Volume 1.
// PHPnerd
-
Try to make a simple console system. Use the Function keys to switch to another console. Each task is linked to a console.
This sounds good. I have a keyboard handler and an own circular key queue. A console in your concept is an array of 4000 Bytes which is swapped with the video RAM by the task switcher or by function keys? Not bad.
Well done!
Now I have exchanged the GPF for Page Faults:
paging install
frames: 00300000h NFRAMES: 524288
kernel_directory->physicalAddr: 00306000h
placement_address: 0030B000h allocated frames: 795
HEAP start: 40081000h end: 40100000h max: 4FFFF000h kernel mode: 0 read-only: 0
hole start: 40081000h end: 40100000h max: 4FFFF000h kernel mode: 0 read-only: 0
hole 40081000h hole-size: 0007F000h
after create_heap: placement_address: 0030C020h allocated frames: 795
tasking install
after moving stack, ESP: 0018FFD0h
After init first task (kernel task), placement_address: 0030C020h
After k_mallocing kernel_stack), placement_address: 0030C020h kernel_stack: 4010
1000h
VFS & RAM Disk install
placement_address after ram disk install: 40200000h
ramdisk_start: 40081000h file_data_start: 0000A2E0h file_data_end: 0000B652h
After set_kernel_stack ==> tss_entry.esp0: 40101800h> IRQ 127 <<<
Hello, user world!
Found file dev
(directory)
Found file f1
contents: "PrettyOS: My filename is test1.txt!"
age Fault (page not present) at 0F000123h - EIP: 0F000123h
Page Fault >>> Exception. System Halted! <<<Dependent on the value of c in the timer handler the page fault comes earlier or later. With c=2000 (means 20 sec) it came with the fisrt task switch:
ksldfgjskldfgjldfksjgklsdfgklsdfjgklsdfjglksdfjglksdfjgsklgjklsd;jglkdsfjglkdsfg
jlsk;dfjgskldfjgslkdjglk;sdgjldk;sfjglk;sdfjgl;ksdjgkl;sdgjklsdfgjsl;dkjglsdk;fg
js 0000D794h H: 0000D794h WRITE: 156 Read: 156 *T: g 103 *H: g 103
T: 0000D78Eh H: 0000D78Eh WRITE: 162 Read: 162 *T: f 102 *H: f 102
Page Fault (page not present) at 0040FC20h - EIP: 0040FC20h
Page Fault >>> Exception. System Halted! <<<
...Hence, I think the EIP gets a wrong value under certain circumstances.
The function read_eip() is defined in Assembler (process.asm):global _read_eip _read_eip: pop eax ; Get the return address jmp eax ; Return. Can't use RET because return ; address popped off the stack.
About the GP: The code of JamesM tutorials uses the structure registers. Filled in some assebly code. Use that structure to printout eip, esp etc, and get the control registers and print them out too. Error flag meanings can be found in the Intel Manual Volume 1.
Thanks, great idea.
-
read_eip() is fine. But you could try:
readEip: pop eax push eax ret
You are having some drivers, right?
When switching tasks, you change the registers, and the cr3. When a task does something with a device, and there is not good code implemented to handle multitasking in device drivers, the device will move data. But when in that time a task switch occurs, some problems may come. The task switch at 20seconds is very bad. The process doesn't need to know it is EVER switched. 100Hz may be nice (100 switches each second). Play something with it.
Consoles: you got it
typedef struct { uint32_t id; // console id, just for making some things easier uint8_t keystroke[KEYSTROKE_LENGTH]; // make this the way you did with keystrokes uint32_t *videoBuffer; // a pointer to some place in memory, size: width*height*2 bytes (probably 80*25*2) uint32_t cursorX; uint32_t cursorY; // coordinates of the cursor for this console uint8_t colorAttribute; // attributes curently used by console } console_t struct task { .... console_t *console; // put console in task .... };
That is an example for a console structure. Be sure of:
- Create one console when initializing screen (VGA), set it into a global variable, currentConsole
- Be sure the functions work to the right console. Each time a task switch occurs, it should use another console structure. But not the currentConsole, because that is the console currently SHOWED. En when not watching task 2, it should be able to print text, so the user can see it later.You can determine the console of the current task by just using currentTask->console(->cursorX, ->cursorY etc.)
It is simple, but much work. Also be sure to make a backup from all you have first, it is a lot of work to remove the console code from your VGA driver.
Good luck, I think it will work with this.
// PHPnerd
-
global _read_eip _read_eip: pop eax push eax ret
... looks better and works fine, but does not help with the page fault due to the strange EIP.
Thanks for the consoles' code. Nice feature.
-
Does the page fault trigger after setting eip, or after setting cr3? or something else?
// PHPnerd
-
Ich habe mit HLT im asm-code probiert, der page fault erfolgt beim *jmp %%ecx;
Was bedeutet eigentlich dieser * vor %%ecx ? Wenn ich ihn weglasse, passiert genau das gleiche.
Ich habe eip,esp,ebp,cur_dir->phys direkt vor dem asm-code geloggt:
..
Schalten nach 0,01 sec:task_switch before asm: eip: 0000D306h esp: 0018FF3Ch ebp: 0018FF54h cur_dir->phys: 00001000h
Page Fault (page not present) at 0F000123h - EIP: 0F000123hSchalten nach 1 sec: (dann wurden zumindest die neuen Tasks angelegt)
task_switch before asm: eip: 0000D4C2h esp: 0018FFD8h ebp: 0018FFF0h cur_dir->phys: 0041E000h
Page Fault (page not present) at 0040FCA0h - EIP: 0040FCA0hWenn ich das richtig sehe, liegt das Problem eher bei current_directory->physicalAddr als bei eip, oder?.
Im Lowlevel Forum meinte man dazu, dass das Problem vom C-Compiler kommen könnte (nicht alle register wurden gespeichert und zurück geschrieben), und man empfahl mir das komplett in Assembler zu machen analog tyndur.
Ohne die Clobber List kommt übrigens wieder der GPF:
... jmp %%ecx; " : : "r"(eip), "r"(esp), "r"(ebp), "r"(current_directory->physicalAddr) );
task_switch before asm: eip: 0000D4C2h esp: 0018FFD8h ebp: 0018FFF0h cur_dir->phys: 0041E000h
General Protection Fault >>> Exception. System Halted! <<<Erst, wenn ich sowohl ebx als auch edx "clobbere", kommt der PF, einzeln GPF. edi und esi kann ich leider nicht clobbern wegen Fehlermeldung des Compilers.
Fundstelle zur Clobber List:
http://groups.google.im/group/comp.lang.asm.x86/browse_thread/thread/cf89391bb64126f7
..Das kommt mir inzwischen alles suspekt vor, was gcc da schafft. Mit dem Clobbern habe ich wenig Erfahrung.
-
Erhard Henkes schrieb:
Was bedeutet eigentlich dieser * vor %%ecx ?...
Siehe hier http://www.c-plusplus.net/forum/viewtopic-var-t-is-238553.html