Hi, I am trying to work in a special configuration where the thread_info is above the stack pointer. The SP though, start from the base stack address + THREAD_SIZE - THREAD_INFO_SECTION_SIZE (that is 128 bytes). The INIT_TSS macro looks like: .esp0 = sizeof(init_stack)-THREAD_INFO_SECTION_SIZE + (long)&init_stack, \ So far it works.
When I am trying to move the init_thread_info to the top of the stack the computer restart itself. What I am doing is replacing the union of the init_thread_info with the following structure: -union thread_union { - struct thread_info thread_info; - unsigned long stack[THREAD_SIZE/sizeof(long)]; -}; +struct thread_union { +unsigned stack[(THREAD_SIZE-THREAD_INFO_SECTION_SIZE)/sizeof(long)]; + struct thread_info thread_info; +}; it means that when I am referencing the thread_info it is in offset (THREAD_SIZE-THREAD_INFO_SECTION_SIZE)/sizeof(long) and not the base address as it was when declared with a union. I have changed other relevant places as in fork.c and so, although the computer even doesn't start, I think its related to the init thread. any clues? -- Eliad
diff -urNp linux-2.6.9.orig/arch/i386/kernel/head.S linux-2.6.9.changes/arch/i386/kernel/head.S --- linux-2.6.9.orig/arch/i386/kernel/head.S 2004-10-18 23:53:13.000000000 +0200 +++ linux-2.6.9.changes/arch/i386/kernel/head.S 2005-07-26 15:42:20.000000000 +0300 @@ -425,7 +425,7 @@ ENTRY(empty_zero_page) .data ENTRY(stack_start) - .long init_thread_union+THREAD_SIZE + .long init_thread_union+THREAD_SIZE-THREAD_INFO_SECTION_SIZE .long __BOOT_DS ready: .byte 0 diff -urNp linux-2.6.9.orig/arch/i386/kernel/init_task.c linux-2.6.9.changes/arch/i386/kernel/init_task.c --- linux-2.6.9.orig/arch/i386/kernel/init_task.c 2004-10-18 23:55:28.000000000 +0200 +++ linux-2.6.9.changes/arch/i386/kernel/init_task.c 2005-07-26 22:56:29.036709328 +0300 @@ -25,9 +25,7 @@ EXPORT_SYMBOL(init_mm); * way process stacks are handled. This is done by having a special * "init_task" linker map entry.. */ -union thread_union init_thread_union - __attribute__((__section__(".data.init_task"))) = - { INIT_THREAD_INFO(init_task) }; +struct thread_union init_thread_union = { {0}, INIT_THREAD_INFO(init_task) }; /* * Initial task structure. diff -urNp linux-2.6.9.orig/arch/i386/kernel/process.c linux-2.6.9.changes/arch/i386/kernel/process.c --- linux-2.6.9.orig/arch/i386/kernel/process.c 2004-10-18 23:53:05.000000000 +0200 +++ linux-2.6.9.changes/arch/i386/kernel/process.c 2005-07-26 22:55:42.853730208 +0300 @@ -364,7 +364,7 @@ int copy_thread(int nr, unsigned long cl struct task_struct *tsk; int err; - childregs = ((struct pt_regs *) (THREAD_SIZE + (unsigned long) p->thread_info)) - 1; + childregs = ((struct pt_regs *) ((THREAD_SIZE-THREAD_INFO_SECTION_SIZE) + (unsigned long) p->thread_info)) - 1; *childregs = *regs; childregs->eax = 0; childregs->esp = esp; @@ -665,8 +665,8 @@ out: return error; } -#define top_esp (THREAD_SIZE - sizeof(unsigned long)) -#define top_ebp (THREAD_SIZE - 2*sizeof(unsigned long)) +#define top_esp ((THREAD_SIZE-THREAD_INFO_SECTION_SIZE) - sizeof(unsigned long)) +#define top_ebp ((THREAD_SIZE-THREAD_INFO_SECTION_SIZE) - 2*sizeof(unsigned long)) unsigned long get_wchan(struct task_struct *p) { diff -urNp linux-2.6.9.orig/drivers/char/ip2main.c linux-2.6.9.changes/drivers/char/ip2main.c --- linux-2.6.9.orig/drivers/char/ip2main.c 2004-10-18 23:55:36.000000000 +0200 +++ linux-2.6.9.changes/drivers/char/ip2main.c 2004-10-18 23:55:36.000000000 +0200 @@ -1179,7 +1179,7 @@ ip2_interrupt_bh(i2eBordStrPtr pB) /* Parameters: irq - interrupt number */ /* pointer to optional device ID structure */ /* pointer to register structure */ -/* Returns: Nothing $ */ +/* Returns: Nothing */ /* */ /* Description: */ /* */ diff -urNp linux-2.6.9.orig/include/asm-i386/processor.h linux-2.6.9.changes/include/asm-i386/processor.h --- linux-2.6.9.orig/include/asm-i386/processor.h 2004-10-18 23:53:07.000000000 +0200 +++ linux-2.6.9.changes/include/asm-i386/processor.h 2005-07-26 15:43:30.000000000 +0300 @@ -450,7 +450,7 @@ struct thread_struct { * be within the limit. */ #define INIT_TSS { \ - .esp0 = sizeof(init_stack) + (long)&init_stack, \ + .esp0 = sizeof(init_stack)-THREAD_INFO_SECTION_SIZE + (long)&init_stack, \ .ss0 = __KERNEL_DS, \ .ss1 = __KERNEL_CS, \ .ldt = GDT_ENTRY_LDT, \ diff -urNp linux-2.6.9.orig/include/asm-i386/thread_info.h linux-2.6.9.changes/include/asm-i386/thread_info.h --- linux-2.6.9.orig/include/asm-i386/thread_info.h 2004-10-18 23:53:21.000000000 +0200 +++ linux-2.6.9.changes/include/asm-i386/thread_info.h 2005-07-26 23:08:59.000000000 +0300 @@ -51,11 +51,13 @@ struct thread_info { #endif +#define THREAD_INFO_SECTION_SIZE 128 + #define PREEMPT_ACTIVE 0x4000000 #ifdef CONFIG_4KSTACKS #define THREAD_SIZE (4096) #else -#define THREAD_SIZE (8192) +#define THREAD_SIZE (4096) #endif #define STACK_WARN (THREAD_SIZE/8) @@ -88,6 +90,7 @@ static inline struct thread_info *curren { struct thread_info *ti; __asm__("andl %%esp,%0; ":"=r" (ti) : "0" (~(THREAD_SIZE - 1))); + ti = (struct thread_info *)((char*)(ti)+(THREAD_SIZE-THREAD_INFO_SECTION_SIZE)); return ti; } diff -urNp linux-2.6.9.orig/include/linux/sched.h linux-2.6.9.changes/include/linux/sched.h --- linux-2.6.9.orig/include/linux/sched.h 2004-10-18 23:53:13.000000000 +0200 +++ linux-2.6.9.changes/include/linux/sched.h 2005-07-26 23:07:30.000000000 +0300 @@ -654,9 +654,9 @@ void yield(void); */ extern struct exec_domain default_exec_domain; -union thread_union { +struct thread_union { + unsigned long stack[(THREAD_SIZE-THREAD_INFO_SECTION_SIZE)/sizeof(long)]; struct thread_info thread_info; - unsigned long stack[THREAD_SIZE/sizeof(long)]; }; #ifndef __HAVE_ARCH_KSTACK_END @@ -669,7 +669,7 @@ static inline int kstack_end(void *addr) } #endif -extern union thread_union init_thread_union; +extern struct thread_union init_thread_union; extern struct task_struct init_task; extern struct mm_struct init_mm; diff -urNp linux-2.6.9.orig/kernel/fork.c linux-2.6.9.changes/kernel/fork.c --- linux-2.6.9.orig/kernel/fork.c 2004-10-18 23:53:13.000000000 +0200 +++ linux-2.6.9.changes/kernel/fork.c 2005-07-26 23:06:24.000000000 +0300 @@ -79,7 +79,9 @@ static kmem_cache_t *task_struct_cachep; void free_task(struct task_struct *tsk) { - free_thread_info(tsk->thread_info); + void * tmp = (void*)(tsk->thread_info); + tmp -= (THREAD_SIZE - THREAD_INFO_SECTION_SIZE); + free_thread_info(tmp); free_task_struct(tsk); } EXPORT_SYMBOL(free_task); @@ -270,6 +272,8 @@ static struct task_struct *dup_task_stru return NULL; } + ti = (struct thread_info*)((char*)ti + (THREAD_SIZE-THREAD_INFO_SECTION_SIZE)); + *ti = *orig->thread_info; *tsk = *orig; tsk->thread_info = ti;