tss and user space
Re:tss and user space
not necessarily, you could still share much space, but yet still protect them from each other by isolation
but you are right, this would make threads simply a special case of processes
in my OS, every process will have the user stack at the same address, but that isn't important, what is important is that the split thread must have a stack, and that stack must contain the same data, the simplest method of doing this, is COW the stack, and place it on the same space, if you don't do this, then you will have to move the stack, (and could cause broken code within the user code --- bad pointers, bad stack manipulation, etc), and also take a lot more memory -- remember, the programs with lots of threads, will be the same ones that are likly to use more memory, so this also serves as an optimization, because you are no longer must support multiple stacks within a single address space (of course for x86-64 it isn't a huge deal), the cost of switching pages doesn't have to be really great, as you can share many pages, and don't have to reload CR3 -- most of the time, you will only need to repage the first stack page, and the kernel stack page, not really a lot of overhead here
but you are right, this would make threads simply a special case of processes
in my OS, every process will have the user stack at the same address, but that isn't important, what is important is that the split thread must have a stack, and that stack must contain the same data, the simplest method of doing this, is COW the stack, and place it on the same space, if you don't do this, then you will have to move the stack, (and could cause broken code within the user code --- bad pointers, bad stack manipulation, etc), and also take a lot more memory -- remember, the programs with lots of threads, will be the same ones that are likly to use more memory, so this also serves as an optimization, because you are no longer must support multiple stacks within a single address space (of course for x86-64 it isn't a huge deal), the cost of switching pages doesn't have to be really great, as you can share many pages, and don't have to reload CR3 -- most of the time, you will only need to repage the first stack page, and the kernel stack page, not really a lot of overhead here
Re:tss and user space
ok heres the GDT code:
_setup_tss is called in posted c code, thx
Code: Select all
struct gdt_entry
{
unsigned short limit;
unsigned short basel;
unsigned char basem;
unsigned char access;
unsigned char granularity;
unsigned char baseh;
}__attribute__((packed));
struct gdt_entry gdt[3];
struct tab_ptr gp;
void set_a_gdt(int num, unsigned long base, unsigned long limit, unsigned char access, unsigned char gran)
{
gdt[num].basel = (base & 0xFFFF);
gdt[num].basem = (base >> 16) & 0xFF;
gdt[num].baseh = (base >> 24) & 0xFF;
gdt[num].limit = (limit & 0xFFFF);
gdt[num].granularity = ((limit >> 16) & 0x0F);
gdt[num].granularity |= (gran & 0xF0);
gdt[num].access = access;
}
asm:
_setup_gdt:
lgdt [_gp]
mov ax, 0x10
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
jmp 0x08:flush
flush:
ret
_setup_tss:
push ax
mov ax, 5 * 8 ;GDT #5
ltr ax
pop ax
- kataklinger
- Member
- Posts: 381
- Joined: Fri Nov 04, 2005 12:00 am
- Location: Serbia
Re:tss and user space
I gusess your tab_ptr struct looks something like this:
So you must do this before you load GDTR:
That means you must know size of GDT before you load it. And instead creating your GDT(&IDT also) staticlly, try creating it at runtime .
Code: Select all
struct tab_ptr
{
unsinged short limit;
void* address;
};
Code: Select all
gp.limit = number_of_gdt_enteries * 8 - 1;
Re:tss and user space
ok, thx i see, so i did this:
as you can see i made the entery but now i get this:
i would be glad to post any code you want to see, thx
EDIT: p.s. do i need to fill the tss with any thing other than esp0, ss0, and bitmap, do i have to fill cs and stuff???
Code: Select all
void set_gdt()
{
gp.limit = (sizeof(struct gdt_entry) * 6) - 1;
gp.base = (unsigned int) &gdt;
set_a_gdt(0, 0, 0, 0, 0);
set_a_gdt(1, 0, 0xFFFFFFFF, 0x9A, 0xCF); // kernel code
set_a_gdt(2, 0, 0xFFFFFFFF, 0x92, 0xCF); // kernel data
set_a_gdt(3, 0, 0xFFFFFFFF, 0xFA, 0xCF); // user code
set_a_gdt(4, 0, 0xFFFFFFFF, 0xF2, 0xCF); // user data
set_a_gdt(5, (unsigned long)&TSS, sizeof(TSS), 0x89, 0xCF);
setup_gdt();
}
Code: Select all
00006409976p[CPU ] >>PANIC<< iret: return CS selector null
EDIT: p.s. do i need to fill the tss with any thing other than esp0, ss0, and bitmap, do i have to fill cs and stuff???
- kataklinger
- Member
- Posts: 381
- Joined: Fri Nov 04, 2005 12:00 am
- Location: Serbia
Re:tss and user space
Where did you get IRET? Did you set IDT & enable interrupts?
When you return from interrupt handler (execute IRET instruction) you must provide return address (EIP), code selector (CS) and EFLAG on stack, respectively.
When you return from interrupt handler (execute IRET instruction) you must provide return address (EIP), code selector (CS) and EFLAG on stack, respectively.
Re:tss and user space
well i had a working kernel space switcher:
but now i'm making it compatible with user tasks, is there any thing i need to modify, thx
Code: Select all
_task_timer:
pushad
push ds
push es
push fs
push gs
mov ax, 0x10
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
; cli
push esp
mov eax, _task_timer_c
call eax
; sti
pop esp
mov esp, eax
pop gs
pop fs
pop es
pop ds
popad
iretd
Re:tss and user space
depending on the rest of your implementation all what you might need to add is fixing esp0 in the tss according to your current process.
- kataklinger
- Member
- Posts: 381
- Joined: Fri Nov 04, 2005 12:00 am
- Location: Serbia
Re:tss and user space
How does your PCB looks like? And you must change tss.esp0 at every task switch so when interrupt happens processor will use correct stack.
Re:tss and user space
what should my esp0 be set to???, my current esp as of the middle of my task crator code???, thx
Re:tss and user space
Esp0 should be set to the "beginning", the bottom, of the kernel stack. The place that the kernel's esp will be at when there is nothing (or as close to nothing as your kernel gets) on the stack. Ideally, once you switch to userspace nothing should go onto the kernel stack outside of a system call or interrupt, and so the bottom of the stack is where you would first put things into kernel space.
- kataklinger
- Member
- Posts: 381
- Joined: Fri Nov 04, 2005 12:00 am
- Location: Serbia
Re:tss and user space
esp0 will be the address of saved state of CPU registers as well.
Re:tss and user space
[GS] << current ESP pointing here
[FS]
[ES]
[DS]
[EDI]
[ESI]
[EBP]
[ESP]
[EBX]
[EDX]
[ECX]
[EAX]
[EIP]
[CS]
[EFLAGS]
[ESP?]
[SS?] << kstack pointing at stackend should be put in esp0 of tss
if your 'userspace kernel stack' starts always at the same address you might only need to set it at initialising your userspace environment otherwise you need to adjust it each switch.
@ kataklinger - when does it hold the saved state? or is that related to using the hardware based switching?
[FS]
[ES]
[DS]
[EDI]
[ESI]
[EBP]
[ESP]
[EBX]
[EDX]
[ECX]
[EAX]
[EIP]
[CS]
[EFLAGS]
[ESP?]
[SS?] << kstack pointing at stackend should be put in esp0 of tss
if your 'userspace kernel stack' starts always at the same address you might only need to set it at initialising your userspace environment otherwise you need to adjust it each switch.
@ kataklinger - when does it hold the saved state? or is that related to using the hardware based switching?
Re:tss and user space
so how should i point it to my empty stack?? were can i find this value???, thx
- kataklinger
- Member
- Posts: 381
- Joined: Fri Nov 04, 2005 12:00 am
- Location: Serbia
Re:tss and user space
@OZ:
When CPU goes from RING3 to RING0 it puts value of tss.esp0 in ESP register and tss.ss0 to SS register, so if you use POP(A) instructions to save state of registers at beginning of interrupt handler it meens that tss.esp0 points to saved state.
@GLneo:
And first you must allocate memory for the stack ofcorse.
When CPU goes from RING3 to RING0 it puts value of tss.esp0 in ESP register and tss.ss0 to SS register, so if you use POP(A) instructions to save state of registers at beginning of interrupt handler it meens that tss.esp0 points to saved state.
@GLneo:
Code: Select all
tss.esp0 = current_thread_kernel_stack;
Re:tss and user space
well i have something like that:
but i still get errors in bochs:
, thx
Code: Select all
TSS.esp0 = (int)rrq[front].stack;
Code: Select all
00006409601p[CPU ] >>PANIC<< iret: return CS selector null
00006409601i[SYS ] Last time is 1136655276
00006409601i[CPU ] protected mode
00006409601i[CPU ] CS.d_b = 32 bit
00006409601i[CPU ] SS.d_b = 32 bit
00006409601i[CPU ] | EAX=00000002 EBX=00007a00 ECX=000046ee EDX=00000003
00006409601i[CPU ] | ESP=0008ffcc EBP=0008ffe8 ESI=00000000 EDI=0000739c
00006409601i[CPU ] | IOPL=0 NV UP DI PL NZ NA PE NC
00006409601i[CPU ] | SEG selector base limit G D
00006409601i[CPU ] | SEG sltr(index|ti|rpl) base limit G D
00006409601i[CPU ] | DS:0010( 0002| 0| 0) 00000000 000fffff 1 1
00006409601i[CPU ] | ES:0010( 0002| 0| 0) 00000000 000fffff 1 1
00006409601i[CPU ] | FS:0010( 0002| 0| 0) 00000000 000fffff 1 1
00006409601i[CPU ] | GS:0010( 0002| 0| 0) 00000000 000fffff 1 1
00006409601i[CPU ] | SS:0010( 0002| 0| 0) 00000000 000fffff 1 1
00006409601i[CPU ] | CS:0008( 0001| 0| 0) 00000000 000fffff 1 1
00006409601i[CPU ] | EIP=00001a5a (00001a59)
00006409601i[CPU ] | CR0=0x60000011 CR1=0x00000000 CR2=0x00000000
00006409601i[CPU ] | CR3=0x00000000 CR4=0x00000000
00006409601i[ ] restoring default signal behavior
00006409601i[CTRL ] quit_sim called with exit code 1