Page 1 of 2

Multitasking - again

Posted: Tue Jan 09, 2007 11:02 am
by cg123
Well, I just can't seem to get it right. Now it halts when I call _mtask_start with this message:
LOCK prefix unallowed (op1=0x87, attr=0x300, mod=0xc0, nnn=5)

Any help would be appreciated.

Code: Select all

[extern _sched]
[extern _scrnPc]

[global _Switch]
_Switch:
	REG_SAVE
	call _sched
	cli
	REG_RESTORE_MASTER
	sti
	mov al,0x20
	out 0x20,al


[extern _cProc]

%macro REG_SAVE 0
	cld
	
	pushad
		push ds
		push es
		push fs
		push gs
		
	mov eax,[_cProc]
	mov [eax],esp
%endmacro

%macro REG_RESTORE_MASTER 0
	mov eax,[_cProc]
	mov esp,[eax]
	
		pop gs
		pop fs
		pop es
		pop ds
	popad
	
	iretd
%endmacro

[global _mtask_start]
_mtask_start:
	mov eax,[_cProc]
	mov esp,[eax]
	ret

Code: Select all

unsigned char kstacks[32][KSTACKTOP];
unsigned char ustacks[32][USTACKTOP];
unsigned int procnum;

typedef struct
{
	unsigned int esp;
	unsigned char is;
} proc_t;

proc_t * cProc;
proc_t aProc[32];

void init_task( int task , unsigned epoint )
{
...
}

void sched()
{
	procnum++;
	if (procnum > 32 || aProc[procnum].is != 1)
		procnum = 1;
	cProc = &aProc[procnum];
	//scrnPc('0' + procnum);
}

void t1() {while(1){scrnPc('p');}}
void t2() {while(1){scrnPc('q');}}
void t3() {while(1){scrnPc('r');}}

void km(){for(;;){scrnPc('k');}};

void init_mtask()
{
	init_task(1,(unsigned)km);
	init_task(2,(unsigned)t1);
	init_task(3,(unsigned)t2);
	init_task(4,(unsigned)t3);
	procnum = 1;
	cProc = &aProc[procnum];
	mtask_start();
}

Posted: Tue Jan 09, 2007 11:27 am
by Mikae
What type of multitasking do you use? Hardware or software?

Anyway, general assumption is that you initialize your EIP with wrong value, so CPU interprets data where EIP points, as prefix 'LOCK'.

Posted: Tue Jan 09, 2007 12:39 pm
by cg123
I'm using software.

Well, I added this to _mtask_start:

Code: Select all

[global _mtask_start]
_mtask_start:
	mov eax,[_cProc]
	mov esp,[eax]
	
		pop gs
		pop fs
		pop es
		pop ds
	popad
	
	sti
	
	iretd
	ret
Now it doesn't fault/crash, but it doesn't do anything. It doesn't look like _Switch is being called, I put a call to _scrnPc (print function) and it doesn't look like it's being called.

Posted: Tue Jan 09, 2007 3:37 pm
by Combuster
Tried using bochs' debugger? Helped me out more than once... You can use it to see wether your stacks and all are correct.

Posted: Tue Jan 09, 2007 4:39 pm
by Mikae
Did you write full starting task state to stack of every task?

Posted: Tue Jan 09, 2007 7:47 pm
by cg123
Yes, I think so:

Code: Select all

void init_task( int task , unsigned epoint )
{
	unsigned int *stacksetup;
	stacksetup=(unsigned int*)&kstacks[task][KSTACKTOP]; //esp0
	 stacksetup-- ;         //SS
	*stacksetup--=0x0202;  //flags
	*stacksetup--=0x08;    // CS
	*stacksetup--=epoint;  // Instruction pointer
	*stacksetup--= 0;      //error code
	*stacksetup--=0x20;    // interupt no.
	
	*stacksetup--=0;    //ebp
	*stacksetup--=0;    //esp
	*stacksetup--=0;    //edi
	*stacksetup--=0;    //esi
	*stacksetup--=0;    //edx
	*stacksetup--=0;    //ecx
	*stacksetup--=0;    //ebx
	*stacksetup--=0;    //eax
	
	*stacksetup--=0x20; //ds
	*stacksetup--=0x20; //es
	*stacksetup--=0x20; //fs
	*stacksetup=  0x20; //gs

    aProc[task].esp=(unsigned int)stacksetup;
	aProc[task].is = 1;
}

Posted: Tue Jan 09, 2007 10:18 pm
by Mikae
Well, CPU doesn't push ss:esp on the stack every time when INT occurs -- only when there is a switch between privilege levels. Also, I think that you don't need error code -- interrupts don't generate it. And I didn't understand, what '*stacksetup--=0x20; // interupt no' is? CPU doesn't push INT num onto the stack, and I don't see if you push it by yourself in your code.

Posted: Wed Jan 10, 2007 3:31 am
by AJ
Also, do you *mean* 0x20 for your data segment registers? (You may well do if ss!=ds).

The other thing that may help is that you may need to decrement the stacksetup variable one extra time to leave 4 bytes at the top for esp0. At present, it looks like esp0 is stored at the topmost address of the space assigned to the stack, which means that it could overrun the base of the stack.

Certainly your problem looks like an invalid stack/instruction pointer. The example you have given looks a little complex for starting out with stack switching.

How about starting out with just pushing the kernel stack and then restoring that same stack. Once you have a 'working unit' in this way, you can gradually add more code to incorporate other tasks. In the past, this has worked much better for me than writing the entire module in one go, then trying to debug later.

Hope this helps,
Adam

Posted: Mon Jan 22, 2007 2:17 pm
by cg123
Well, I'm now on my third rewrite of my kernel since I posted that message... it's less, well, incredibly fucked up now that I actually know what I'm doing. :lol:

I've got a different problem now; when it gets to the iret in _asm_task, it triple faults with the message "iret: CS not within stack limits."

mtask.asm:

Code: Select all


%define MAX_PROC 512

struc PROC_STRUCT
	.esp: resd 1
	.is: resb 1
endstruc

extern _procs

global _curproc
_curproc:
	dd 0
	db 0
	
global _procnum
_procnum:
	dd 0
	
extern _proc_stacks

%macro PUSHREGS 0
	pushad
		push ds
		push es
		push fs
		push gs
	
	mov eax,_curproc
	mov [eax],esp
%endmacro

%macro POPREGS 0
	mov eax,_curproc
	mov esp,[eax]
	
		pop gs
		pop fs
		pop es
		pop ds
	popad
	
%endmacro

%macro UNPUSHREGS 0
		pop gs
		pop fs
		pop es
		pop ds
	popad
%endmacro

global _switch_task
_switch_task:
	
	PUSHREGS
	
		call _change_task
		cmp BYTE [_curproc+PROC_STRUCT.is],0
		jnz .go
		jz .fail
		
	.fail: ; should never get here, but to prevent the stack from EATING THE KERNEL OH GOD WHY
		UNPUSHREGS
		ret
	.go:
		POPREGS
	
	iret
	
_change_task:
	
	cmp [_have_started],BYTE 0
	jnz .start
    
	mov [_have_started],BYTE 1
	
	.start
	mov [_have_done],BYTE 0
	.redo:
	mov eax,[_procnum]
	
	mov ecx,[_procs+(PROC_STRUCT_size * eax)]
	mov edx,[_procs+(PROC_STRUCT_size * eax)+PROC_STRUCT.is]
	
	cmp edx,0
	jnz .c
	
	cmp [_have_done],BYTE 1
	jz .l
	
	mov [_have_done],BYTE 1
	mov [_procnum],DWORD 0
	jmp .redo
	
	.l:
	jmp $
	
	.c:
	
	;set process information
	mov [_curproc],ecx
	mov [_curproc+PROC_STRUCT.is],edx
	
	inc eax
	mov [_procnum],eax
	
	pop eax
	
	ret

global _asm_task:
	_asm_task:
		mov esp,[_curproc]
		;i
		iret
	
extern _c_irq
	
extern _setup_irq
_init_mtask:
	call _c_irq
	call _change_task
	

	;sti
	cli
	iret
util.c:

Code: Select all

void stacksetup(unsigned ptr,unsigned int p)
{
	if (p >= 512) return;
	unsigned int *s = (unsigned int*)&(proc_stacks[p][1024]);
	s--;
	*s--=0x202;
	*s--=0x08;
	*s--=ptr;
	*s--=0;
	*s--=0;
	*s--=0;
	*s--=0;
	*s--=0;
	*s--=0;
	*s--=0;
	*s--=0;
	*s--=0x20;
	*s--=0x20;
	*s--=0x20;
	*s--=0x20;
	procs[p].esp = (unsigned int)s;
	procs[p].is = 1;
}

extern void switch_task();

void c_swt(struct regs *r)
{
	switch_task();
}

void etask()
{
	for(;;)putch('1',0x0F);
}

void psetup(unsigned task, int num)
{
	if (num >= 512) return;
	unsigned int* s = (unsigned int*)&proc_stacks[num][1024];
	s--;
	*s--=0x202;
	*s--=0x08;
	*s--=task;
	procs[num].esp = (unsigned int)s;
	procs[num].is = 1;
}

extern void* task_ptr;
extern void asm_task();

void c_irq()
{
	setup_irq(c_swt,0);
	psetup((unsigned)&etask,0);
	asm_task();
}
Any help would be appreciated.

Posted: Wed Jan 24, 2007 3:57 pm
by cg123
Could someone at least tell me what this means, or even just what said 'stack limits' are? :(

Posted: Wed Jan 24, 2007 4:15 pm
by Mikae
Well, some questions:

1. Does it happen when you try to switch between different privilege levels?
2. Can you post your bochsout.txt file here?

Posted: Wed Jan 24, 2007 5:09 pm
by cg123
Mikae wrote: 1. Does it happen when you try to switch between different privilege levels?
No.. I haven't tried to add privilege levels yet, I'm just trying to get it to run more than one process at once.
Mikae wrote: 2. Can you post your bochsout.txt file here?
Ok.

Code: Select all

00000000000i[     ] Bochs x86 Emulator 2.3
00000000000i[     ]   Build from CVS snapshot on August 27, 2006
00000000000i[     ] System configuration
00000000000i[     ]   processors: 1 (cores=1, HT threads=1)
00000000000i[     ]   A20 line support: yes
00000000000i[     ]   APIC support: yes
00000000000i[     ] CPU configuration
00000000000i[     ]   level: 6
00000000000i[     ]   paging support: yes, tlb enabled: yes
00000000000i[     ]   SMP support: no
00000000000i[     ]   FPU support: yes
00000000000i[     ]   MMX support: yes
00000000000i[     ]   SSE support: 1
00000000000i[     ]   v8086 mode support: yes
00000000000i[     ]   VME support: yes
00000000000i[     ]   3dnow! support: no
00000000000i[     ]   PAE support: yes
00000000000i[     ]   PGE support: yes
00000000000i[     ]   PSE support: yes
00000000000i[     ]   x86-64 support: no
00000000000i[     ]   SEP support: yes
00000000000i[     ] Optimization configuration
00000000000i[     ]   Guest2HostTLB support: yes
00000000000i[     ]   RepeatSpeedups support: yes
00000000000i[     ]   Icache support: yes
00000000000i[     ]   Host Asm support: yes
00000000000i[     ]   Fast function calls: yes
00000000000i[     ] Devices configuration
00000000000i[     ]   NE2000 support: yes
00000000000i[     ]   PCI support: yes
00000000000i[     ]   SB16 support: yes
00000000000i[     ]   USB support: yes
00000000000i[     ]   VGA extension support: vbe cirrus
00000000000i[MEM0 ] allocated memory at 00E70020. after alignment, vector=00E71000
00000000000i[MEM0 ] 32.00MB
00000000000i[MEM0 ] rom at 0xffff0000/65536 ('E:\Program Files\Bochs-2.3/BIOS-bochs-latest')
00000000000i[MEM0 ] rom at 0xc0000/38400 ('E:\Program Files\Bochs-2.3/VGABIOS-lgpl-latest')
00000000000i[APIC?] set APIC ID to 0
00000000000i[APIC0] 80686
00000000000i[APIC0] local apic in CPU apicid=00 initializing
00000000000i[IOAP ] initializing I/O APIC
00000000000i[IOAP ] set APIC ID to 1
00000000000i[MEM0 ] Register memory access handlers: fec00000-fec00fff
00000000000i[CMOS ] Using local time for initial clock
00000000000i[CMOS ] Setting initial clock to: Wed Jan 24 15:15:33 2007 (time0=1169680533)
00000000000i[DMA  ] channel 4 used by cascade
00000000000i[DMA  ] channel 2 used by Floppy Drive
00000000000i[FDD  ] fd0: 'E:\xd-os-gen\kernel\grub_disk.img' ro=0, h=2,t=80,spt=18
00000000000i[PCI  ] 440FX Host bridge present at device 0, function 0
00000000000i[PCI  ] PIIX3 PCI-to-ISA bridge present at device 1, function 0
00000000000i[MEM0 ] Register memory access handlers: 000a0000-000bffff
00000000000i[WGUI ] Number of Mouse Buttons = 2
00000000000i[WGUI ] IME disabled
00000000000i[MEM0 ] Register memory access handlers: e0000000-e07fffff
00000000000i[CLVGA] VBE Bochs Display Extension Enabled
00000000000i[CLVGA] interval=40000
00000000000i[     ] init_mem of 'harddrv' plugin device by virtual method
00000000000i[     ] init_mem of 'keyboard' plugin device by virtual method
00000000000i[     ] init_mem of 'serial' plugin device by virtual method
00000000000i[     ] init_mem of 'parallel' plugin device by virtual method
00000000000i[     ] init_mem of 'extfpuirq' plugin device by virtual method
00000000000i[     ] init_mem of 'gameport' plugin device by virtual method
00000000000i[     ] init_mem of 'speaker' plugin device by virtual method
00000000000i[     ] init_mem of 'pci_ide' plugin device by virtual method
00000000000i[     ] init_dev of 'harddrv' plugin device by virtual method
00000000000i[HD   ] Using boot sequence floppy, none, none
00000000000i[HD   ] Floppy boot signature check is enabled
00000000000i[     ] init_dev of 'keyboard' plugin device by virtual method
00000000000i[KBD  ] will paste characters every 1000 keyboard ticks
00000000000i[     ] init_dev of 'serial' plugin device by virtual method
00000000000i[SER  ] com1 at 0x03f8 irq 4
00000000000i[     ] init_dev of 'parallel' plugin device by virtual method
00000000000i[PAR  ] parallel port 1 at 0x0378 irq 7
00000000000i[     ] init_dev of 'extfpuirq' plugin device by virtual method
00000000000i[     ] init_dev of 'gameport' plugin device by virtual method
00000000000i[     ] init_dev of 'speaker' plugin device by virtual method
00000000000i[     ] init_dev of 'pci_ide' plugin device by virtual method
00000000000i[PCI  ] PIIX3 PCI IDE controller present at device 1, function 1
00000000000i[     ] register state of 'harddrv' plugin device by virtual method
00000000000i[     ] register state of 'keyboard' plugin device by virtual method
00000000000i[     ] register state of 'serial' plugin device by virtual method
00000000000i[     ] register state of 'parallel' plugin device by virtual method
00000000000i[     ] register state of 'extfpuirq' plugin device by virtual method
00000000000i[     ] register state of 'gameport' plugin device by virtual method
00000000000i[     ] register state of 'speaker' plugin device by virtual method
00000000000i[     ] register state of 'pci_ide' plugin device by virtual method
00000000000i[SYS  ] bx_pc_system_c::Reset(HARDWARE) called
00000000000i[APIC0] local apic in CPU 0 initializing
00000000000i[     ] reset of 'harddrv' plugin device by virtual method
00000000000i[     ] reset of 'keyboard' plugin device by virtual method
00000000000i[     ] reset of 'serial' plugin device by virtual method
00000000000i[     ] reset of 'parallel' plugin device by virtual method
00000000000i[     ] reset of 'extfpuirq' plugin device by virtual method
00000000000i[     ] reset of 'gameport' plugin device by virtual method
00000000000i[     ] reset of 'speaker' plugin device by virtual method
00000000000i[     ] reset of 'pci_ide' plugin device by virtual method
00000000000i[     ] Warning: no rc file specified.
00000000000i[     ] set SIGINT handler to bx_debug_ctrlc_handler
00000003867i[BIOS ] $Revision: 1.166 $ $Date: 2006/08/11 17:34:12 $
00000318070i[KBD  ] reset-disable command received
00000319692i[PIDE ] new BM-DMA address: 0xc000
00000443911i[VBIOS] VGABios $Id: vgabios.c,v 1.66 2006/07/10 07:47:51 vruppert Exp $

00000443982i[CLVGA] VBE known Display Interface b0c0
00000444014i[CLVGA] VBE known Display Interface b0c4
00000446939i[VBIOS] VBE Bios $Id: vbe.c,v 1.58 2006/08/19 09:39:43 vruppert Exp $
00000480000i[WGUI ] dimension update x=720 y=400 fontheight=16 fontwidth=9 bpp=8
00005746076i[BIOS ] int13_harddisk: function 41, unmapped device for ELDL=80
00005750832i[BIOS ] int13_harddisk: function 08, unmapped device for ELDL=80
00005755474i[BIOS ] *** int 15h function AX=00C0, BX=0000 not yet supported!
00022895357e[CPU0 ] iret: CS not within stack limits
00022895357e[CPU0 ] interrupt(): gate descriptor is not valid sys seg
00022895357e[CPU0 ] interrupt(): gate descriptor is not valid sys seg
00022895357i[CPU0 ] protected mode
00022895357i[CPU0 ] CS.d_b = 32 bit
00022895357i[CPU0 ] SS.d_b = 32 bit
00022895357i[CPU0 ] | EAX=00000000  EBX=0002bdc0  ECX=00000000  EDX=00000012
00022895357i[CPU0 ] | ESP=00000000  EBP=00067f00  ESI=0002bf1f  EDI=0002bf20
00022895357i[CPU0 ] | IOPL=0 id vip vif ac vm RF nt of df if tf sf zf AF pf cf
00022895357i[CPU0 ] | SEG selector     base    limit G D
00022895357i[CPU0 ] | SEG sltr(index|ti|rpl)     base    limit G D
00022895357i[CPU0 ] |  CS:0008( 0001| 0|  0) 00000000 000fffff 1 1
00022895357i[CPU0 ] |  DS:0010( 0002| 0|  0) 00000000 000fffff 1 1
00022895357i[CPU0 ] |  SS:0010( 0002| 0|  0) 00000000 000fffff 1 1
00022895357i[CPU0 ] |  ES:0010( 0002| 0|  0) 00000000 000fffff 1 1
00022895357i[CPU0 ] |  FS:0010( 0002| 0|  0) 00000000 000fffff 1 1
00022895357i[CPU0 ] |  GS:0010( 0002| 0|  0) 00000000 000fffff 1 1
00022895357i[CPU0 ] | EIP=0010031f (0010031f)
00022895357i[CPU0 ] | CR0=0x00000011 CR1=0 CR2=0x00000000
00022895357i[CPU0 ] | CR3=0x00000000 CR4=0x00000000
00022895357i[CPU0 ] >> iretd  : CF
00022895357e[CPU0 ] exception(): 3rd (13) exception with no resolution, shutdown status is 00h, resetting
00022895357i[SYS  ] bx_pc_system_c::Reset(SOFTWARE) called
00022895357i[APIC0] local apic in CPU 0 initializing
00022895357e[CPU0 ] CPU_LOOP bx_guard.interrupt_requested=1
00022899224i[BIOS ] $Revision: 1.166 $ $Date: 2006/08/11 17:34:12 $
00023213541i[KBD  ] reset-disable command received
00023339420i[VBIOS] 
VGABios $Id: vgabios.c,v 1.66 2006/07/10 07:47:51 vruppert Exp $

00023339491i[CLVGA] VBE known Display Interface b0c0
00023339523i[CLVGA] VBE known Display Interface b0c4
00023342448i[VBIOS] VBE Bios $Id: vbe.c,v 1.58 2006/08/19 09:39:43 vruppert Exp $
00023671433i[FDD  ] controller reset in software
00028642126i[BIOS ] int13_harddisk: function 41, unmapped device for ELDL=80
00028646882i[BIOS ] int13_harddisk: function 08, unmapped device for ELDL=80
00028651524i[BIOS ] *** int 15h function AX=00C0, BX=0000 not yet supported!

Posted: Wed Jan 24, 2007 5:17 pm
by Mikae
Ok, but I need some additional info... Show, please, content of your stack just before iret is executed (at least six dwords).

Posted: Wed Jan 24, 2007 8:29 pm
by cg123
Ohh boy. I just realized how utterly stupid of a mistake I made... I forgot to assign _curproc a value, so... the value of ESP was 0 :lol:

Thanks for the help.. sorry for wasting your time.

Posted: Fri Jan 26, 2007 5:05 pm
by cg123
..well, I've got another problem. :(

Now it triple faults on the iret with this message:
fetch_raw_descriptor: LDT: index (105f)20b > limit (0)

...but I don't have an LDT. Is that in itself the problem, or... :?