[Bug target/70220] [x86] interrupt attribute optionally needs to provide read, write and control the set of saved registers

2016-03-15 Thread wink at saville dot com
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70220

--- Comment #19 from Wink Saville  ---
(In reply to H.J. Lu from comment #18)
> (In reply to Wink Saville from comment #17)
> > > 
> > > I assume you were referring to real debugger, like GDB.  Spec won't 
> > > specify
> > > where/how/when any register is saved.
> > 
> > From my perspective the spec defines precisely where the original value of
> > every register is, when "all" is present, except rbp. Will you provide that
> > info?
> 
> Sorry, this is not how compiler works.
> 
> > If not then as for as I can tell I won't be able to use the interrupt
> > attribute for these use cases, which I think is a shame as I really like
> > using it.
> > 
> 
> Well, I guess this feature isn't appropriate for you.
> 
> >  Compiler should generate correct debug
> > > info when -g is given.  GDB should have no problem to access any registers
> > > and variables, including interrupt data passed down by processors.
> > 
> > To debug code -g is not needed, I will not be compiling my isr's with -g to
> > be able to debug code that resides in another thread/process. 
> > But to debug code I must know the original value of every register and be
> > able to change it to any value the user requests, no exceptions.
> 
> -g with GCC should provide information about all registers and
> variables.  You can extract debug info into a separate file
> to exam it.

Oh well, maybe someday, thanks for considering my desires.

[Bug target/70220] [x86] interrupt attribute optionally needs to provide read, write and control the set of saved registers

2016-03-15 Thread wink at saville dot com
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70220

--- Comment #17 from Wink Saville  ---
(In reply to H.J. Lu from comment #16)
> (In reply to Wink Saville from comment #15)
> > (In reply to H.J. Lu from comment #14)
> > > (In reply to Wink Saville from comment #13)
> > > > > Compiler should be free to use rbp in anyway it sees fit. Spec 
> > > > > shouldn't
> > > > > say anything other than rbp is special to compiler.
> > > > 
> > > > If the compiler does decide to change rbp it must save original value,
> > > > correct?
> > > 
> > > Yes.  But you don't know how/when it happens.
> > 
> > For the debugger use case and maybe for the thread context switch I need
> > access to all registers original values, rbp included.
> >
> > I'd like to propose, for the narrow case of using the "all" parameter we
> > specify that the compiler will either always not use rbp or that it always
> > saves rbp at a known location. In all other cases rbp is unavailable for use
> > by C code.
> 
> I assume you were referring to real debugger, like GDB.  Spec won't specify
> where/how/when any register is saved.

>From my perspective the spec defines precisely where the original value of
every register is, when "all" is present, except rbp. Will you provide that
info?

If not then as for as I can tell I won't be able to use the interrupt attribute
for these use cases, which I think is a shame as I really like using it.


 Compiler should generate correct debug
> info when -g is given.  GDB should have no problem to access any registers
> and variables, including interrupt data passed down by processors.

To debug code -g is not needed, I will not be compiling my isr's with -g to be
able to debug code that resides in another thread/process. 
But to debug code I must know the original value of every register and be able
to change it to any value the user requests, no exceptions.

[Bug target/70220] [x86] interrupt attribute optionally needs to provide read, write and control the set of saved registers

2016-03-14 Thread wink at saville dot com
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70220

--- Comment #15 from Wink Saville  ---
(In reply to H.J. Lu from comment #14)
> (In reply to Wink Saville from comment #13)
> > > Compiler should be free to use rbp in anyway it sees fit. Spec shouldn't
> > > say anything other than rbp is special to compiler.
> > 
> > If the compiler does decide to change rbp it must save original value,
> > correct?
> 
> Yes.  But you don't know how/when it happens.

For the debugger use case and maybe for the thread context switch I need access
to all registers original values, rbp included.

I'd like to propose, for the narrow case of using the "all" parameter we
specify that the compiler will either always not use rbp or that it always
saves rbp at a known location. In all other cases rbp is unavailable for use by
C code.

[Bug target/70220] [x86] interrupt attribute optionally needs to provide read, write and control the set of saved registers

2016-03-14 Thread wink at saville dot com
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70220

--- Comment #13 from Wink Saville  ---
(In reply to H.J. Lu from comment #12)
> (In reply to Wink Saville from comment #11)
> > > > The rsp is always saved/restored by the hardware, and your struct frame
> > > > pointer provides access to it so no problem there. It is special because
> > > > when there are local variables the compiler needs to modify it and 
> > > > currently
> > > > it does that after the registers are saved. How will we coordinate the
> > > > compiler initializing rsp and the programming saving the registers?
> > > 
> > > Why is it a problem if IRS doesn't assume what/how compiler does?
> > 
> > I'm in total agreement, the programmer cannot assume anything and must rely
> > on what the interrupt attribute specification says.
> > 
> > At the moment the technique for saving the registers using mov's instead of
> > push/pop's looks to resolve a possible problem of the programmer
> > manipulating rsp. So the only problem seems to be how make rbp accessible
> > because its special. I suggest the interrupt attribute specification say
> > something along the lines of:
> > 
> > "The interrupt attribute takes optional parameters. The parameters are a
> > list of registers that the compiler will NOT save and it will be the
> > responsibility of the programmer to save them. As a convenience to the
> > programmer a single "all" parameter maybe used instead of a specific list.
> > The only register not allowed is RBP as its reserved for use by the 
> > compiler.
> 
> So far so good.
> 
> > If there is a list of registers to not save then original value of rbp will
> > be saved to RAM and rbp will be set to its location."
> 
> Compiler should be free to use rbp in anyway it sees fit. Spec shouldn't
> say anything other than rbp is special to compiler.

If the compiler does decide to change rbp it must save original value, correct?

[Bug target/70220] [x86] interrupt attribute optionally needs to provide read, write and control the set of saved registers

2016-03-14 Thread wink at saville dot com
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70220

--- Comment #11 from Wink Saville  ---
(In reply to H.J. Lu from comment #10)
> (In reply to Wink Saville from comment #9)
> > (In reply to H.J. Lu from comment #8)
> > > (In reply to Wink Saville from comment #7)
> > > >
> > > > In my opinion, even if rbp is special, it still needs to be available 
> > > > in the
> > > > struct full_stack_frame.
> > > 
> > > The whole idea of extending interrupter attribute is to avoid
> > > full_stack_frame.
> > > ISR shouldn't assume that compiler will save and restore registers in any
> > > specific way, order or form.  As far as ISR is concerned, it is just black
> > > magic.
> > 
> > From my perspective the goal is not to avoid struct full_stack_frame but to
> > allow it to be created and always consistent.
> 
> Compiler is free to do whatever is the best.  You shouldn't assume anything
> from compiler beyond the interrupt attribute spec.  If you insist that
> compiler must save registers in certain way, interrupt attribute isn't
> appropriate for your use case.
> 
> > > 
> > > > Also, isn't rsp special? Would the compiler or programmer be 
> > > > responsible for
> > > > initializing it. It seems to me it has to be the compiler, but could be
> > > > wrong.
> > > 
> > > If you change rsp in asm statement, you have to restore it in asm 
> > > statement.
> > 
> > The rsp is always saved/restored by the hardware, and your struct frame
> > pointer provides access to it so no problem there. It is special because
> > when there are local variables the compiler needs to modify it and currently
> > it does that after the registers are saved. How will we coordinate the
> > compiler initializing rsp and the programming saving the registers?
> 
> Why is it a problem if IRS doesn't assume what/how compiler does?

I'm in total agreement, the programmer cannot assume anything and must rely on
what the interrupt attribute specification says.

At the moment the technique for saving the registers using mov's instead of
push/pop's looks to resolve a possible problem of the programmer manipulating
rsp. So the only problem seems to be how make rbp accessible because its
special. I suggest the interrupt attribute specification say something along
the lines of:

"The interrupt attribute takes optional parameters. The parameters are a list
of registers that the compiler will NOT save and it will be the responsibility
of the programmer to save them. As a convenience to the programmer a single
"all" parameter maybe used instead of a specific list. The only register not
allowed is RBP as its reserved for use by the compiler.

If there is a list of registers to not save then original value of rbp will be
saved to RAM and rbp will be set to its location."

[Bug target/70220] [x86] interrupt attribute optionally needs to provide read, write and control the set of saved registers

2016-03-14 Thread wink at saville dot com
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70220

--- Comment #9 from Wink Saville  ---
(In reply to H.J. Lu from comment #8)
> (In reply to Wink Saville from comment #7)
> >
> > In my opinion, even if rbp is special, it still needs to be available in the
> > struct full_stack_frame.
> 
> The whole idea of extending interrupter attribute is to avoid
> full_stack_frame.
> ISR shouldn't assume that compiler will save and restore registers in any
> specific way, order or form.  As far as ISR is concerned, it is just black
> magic.

>From my perspective the goal is not to avoid struct full_stack_frame but to
allow it to be created and always consistent.

> 
> > Also, isn't rsp special? Would the compiler or programmer be responsible for
> > initializing it. It seems to me it has to be the compiler, but could be
> > wrong.
> 
> If you change rsp in asm statement, you have to restore it in asm statement.

The rsp is always saved/restored by the hardware, and your struct frame pointer
provides access to it so no problem there. It is special because when there are
local variables the compiler needs to modify it and currently it does that
after the registers are saved. How will we coordinate the compiler initializing
rsp and the programming saving the registers?

One possibility I see is that the programmer adds struct saved_regs as a local
variable (or TLS or ...) and then saves and restores the registers to/from
there. So assuming rbp is special and always points to itself then maybe
something like:

struct saved_regs {
  ac_u64 rax;
  ac_u64 rdx;
  ac_u64 rcx;
  ac_u64 rbx;
  ac_u64 rsi;
  ac_u64 rdi;
  ac_u64 r8;
  ac_u64 r9;
  ac_u64 r10;
  ac_u64 r11;
  ac_u64 r12;
  ac_u64 r13;
  ac_u64 r14;
  ac_u64 r15;
  ac_u64 rbp;
};

__attribute__((__interrupt__(all)))
void test_isr(struct intr_frame* frame) {
  struct saved_regs sr;

  __asm__ volatile("mov %%rax, %0;" : "=m"(sr.rax));
...
  __asm__ volatile("mov %%r15, %0;" : "=m"(sr.r15));
  __asm__ volatile("mov (%rbp), %rax;");
  __asm__ volatile("mov %%rax, %0;" : "=m"(sr.rbp));

  ac_printf("timer_reschedule_isr sr.rax=%x\n", sr.rax);

  tcb_x86 *ptcb = thread_scheduler((ac_u8*)get_sp(), get_ss());
  __asm__ volatile("movq %0, %%rsp;" :: "rm" (ptcb->sp) : "rsp");
  __asm__ volatile("movw %0, %%ss;" :: "rm" (ptcb->ss));
  set_apic_timer_initial_count(ptcb->slice);

  __atomic_add_fetch(&timer_reschedule_isr_counter, 1, __ATOMIC_RELEASE);

  send_apic_eoi();

  __asm__ volatile("mov %0, %%rax;" :: "m"(sr.rbp));
  __asm__ volatile("mov %rax, (%rbp);");
  __asm__ volatile("mov %0, %%r15;" :: "m"(sr.r15));
...
  __asm__ volatile("mov %0, %%rax;" :: "m"(sr.rax));
}

The current compiler generates:

00100490 :
  100490:   55  push   %rbp
  100491:   48 89 e5mov%rsp,%rbp
  100494:   41 53   push   %r11
  100496:   41 52   push   %r10
  100498:   41 51   push   %r9
  10049a:   41 50   push   %r8
  10049c:   57  push   %rdi
  10049d:   56  push   %rsi
  10049e:   51  push   %rcx
  10049f:   52  push   %rdx
  1004a0:   50  push   %rax
  1004a1:   48 83 e4 f0 and$0xfff0,%rsp
  1004a5:   48 83 c4 80 add$0xff80,%rsp
  1004a9:   fc  cld
  1004aa:   48 89 44 24 08  mov%rax,0x8(%rsp)
  1004af:   4c 89 7c 24 78  mov%r15,0x78(%rsp)
  1004b4:   48 8b 45 00 mov0x0(%rbp),%rax
  1004b8:   48 89 44 24 38  mov%rax,0x38(%rsp)

...

  10050d:   48 8b 44 24 38  mov0x38(%rsp),%rax
  100512:   4c 8b 7c 24 78  mov0x78(%rsp),%r15
  100517:   48 89 45 00 mov%rax,0x0(%rbp)
  10051b:   48 8b 44 24 08  mov0x8(%rsp),%rax
  100520:   48 8d 65 b8 lea-0x48(%rbp),%rsp
  100524:   58  pop%rax
  100525:   5a  pop%rdx
  100526:   59  pop%rcx
  100527:   5e  pop%rsi
  100528:   5f  pop%rdi
  100529:   41 58   pop%r8
  10052b:   41 59   pop%r9
  10052d:   41 5a   pop%r10
  10052f:   41 5b   pop%r11
  100531:   5d  pop%rbp
  100532:   48 cf   iretq  


Obviously the "new" compiler wouldn't be saving/restoring r11..rax, that would
be the programmers responsibility, but it looks like it works.

[Bug target/70220] [x86] interrupt attribute optionally needs to provide read, write and control the set of saved registers

2016-03-14 Thread wink at saville dot com
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70220

--- Comment #7 from Wink Saville  ---
(In reply to H.J. Lu from comment #3)
> (In reply to Wink Saville from comment #2)
> > (In reply to H.J. Lu from comment #1)
> > > (In reply to Wink Saville from comment #0)
> > > > I have identified one possible problem and with this scheme, what if the
> > > > compiler needs to setup a stack frame by pushing rbp and then moving 
> > > > rsp to
> > > > rbp, how would that case be handled.
> > > 
> > > Why should be it a problem unless you don't want to restore RSP and RBP
> > > to its original values upon returning from ISR.  Please provide an example
> > > here.
> > 
> > Here a possible example, I added a printf and local variables to
> > timer_reschedule_isr:
> > 
> > void timer_reschedule_isr(struct intr_frame* frame) {
> >   __asm__ volatile(""::: "rax", "rbx", "rcx", "rdx", "rsi", "rdi", "rbp",
> >  "r8",  "r9",  "r10", "r11", "r12", "r13", "r14",
> > "r15");
> > 
> 
> > If I now remove "rbp" from the clobber list it compiles:
> >
> 
> rbp is special.  Will remove rbp from the clobber list cause any
> problems here?

As I see it removing rbp from the clober list is a problem. In the current code
it changes the order of the pushes so struct full_stack_frame would be wrong.
For example I have two routines "reschedule_isr" is saving "rbp" and
"timer_reschedule_isr" is not saving "rbp":

__attribute__((__interrupt__))
void reschedule_isr(struct intr_frame* frame) {
  __asm__ volatile(""::: "rax", "rbx", "rcx", "rdx", "rsi", "rdi", "rbp",
 "r8",  "r9",  "r10", "r11", "r12", "r13", "r14",
"r15");

  tcb_x86 *ptcb = thread_scheduler((ac_u8*)get_sp(), get_ss());
  __asm__ volatile("movq %0, %%rsp;" :: "rm" (ptcb->sp) : "rsp");
  __asm__ volatile("movw %0, %%ss;" :: "rm" (ptcb->ss));
  set_apic_timer_initial_count(ptcb->slice);
}

__attribute__((__interrupt__))
void timer_reschedule_isr(struct intr_frame* frame) {
  __asm__ volatile(""::: "rax", "rbx", "rcx", "rdx", "rsi", "rdi", // "rbp",
 "r8",  "r9",  "r10", "r11", "r12", "r13", "r14",
"r15");

  volatile ac_u64 array[3];
  array[2] = get_sp();
  ac_printf("timer_reschedule_isr array[0]=%p\n", array[2]);

  tcb_x86 *ptcb = thread_scheduler((ac_u8*)get_sp(), get_ss());
  __asm__ volatile("movq %0, %%rsp;" :: "rm" (ptcb->sp) : "rsp");
  __asm__ volatile("movw %0, %%ss;" :: "rm" (ptcb->ss));
  set_apic_timer_initial_count(ptcb->slice);

  __atomic_add_fetch(&timer_reschedule_isr_counter, 1, __ATOMIC_RELEASE);

  send_apic_eoi();
}


If you look at the prologue/epilogues we see that they are different so that
means struct full_stack_frame would have to be different for the two routines
and that makes the programmers job very hard:

001003b0 :
  1003b0:   41 57   push   %r15
  1003b2:   41 56   push   %r14
  1003b4:   41 55   push   %r13
  1003b6:   41 54   push   %r12
  1003b8:   41 53   push   %r11
  1003ba:   41 52   push   %r10
  1003bc:   41 51   push   %r9
  1003be:   41 50   push   %r8
  1003c0:   55  push   %rbp
  1003c1:   57  push   %rdi
  1003c2:   56  push   %rsi
  1003c3:   53  push   %rbx
  1003c4:   51  push   %rcx
  1003c5:   52  push   %rdx
  1003c6:   50  push   %rax
  1003c7:   fc  cld

...

  1003ed:   58  pop%rax
  1003ee:   5a  pop%rdx
  1003ef:   59  pop%rcx
  1003f0:   5b  pop%rbx
  1003f1:   5e  pop%rsi
  1003f2:   5f  pop%rdi
  1003f3:   5d  pop%rbp
  1003f4:   41 58   pop%r8
  1003f6:   41 59   pop%r9
  1003f8:   41 5a   pop%r10
  1003fa:   41 5b   pop%r11
  1003fc:   41 5c   pop%r12
  1003fe:   41 5d   pop%r13
  100400:   41 5e   pop%r14
  100402:   41 5f   pop%r15
  100404:   48 cf   iretq  
  100406:   66 2e 0f 1f 84 00 00nopw   %cs:0x0(%rax,%rax,1)
  10040d:   00 00 00 

00100410 :
  100410:   55  push   %rbp
  100411:   48 89 e5mov%rsp,%rbp
  100414:   41 57   push   %r15
  100416:   41 56   push   %r14
  100418:   41 55   push   %r13
  10041a:   41 54   push   %r12
  10041c:   41 53   push   %r11
  10041e:   41 52   push   %r10

[Bug target/70220] [x86] interrupt attribute optionally needs to provide read, write and control the set of saved registers

2016-03-14 Thread wink at saville dot com
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70220

--- Comment #5 from Wink Saville  ---
(In reply to H.J. Lu from comment #4)
> (In reply to Wink Saville from comment #0)
> > I'm using the new C interrupt attribute for x86 and its working well. But
> > when I expanded its use to include handling thread context switches, I found
> > that its current implementation lacking.
> > 
> > When using an ISR for a thread context it is necessary to save and restore
> > all registers but by default it saves a few as it thinks are necessary. It
> > is possible to use the clobber list of inline assembly to tell the interrupt
> > attribute code to save additional registers but you can't seem to mention
> > the segment registers in that clobber list, thus to save these additional
> > registers you must manually save them manually.
> > 
> 
> Compiler doesn't use segment registers, except for TLS, which should
> be used in ISR.  ISR needs to save and restore any registers, which
> aren't used by compilers, if they are changed in ISR.

Is there a definitive list of the registers that the compiler uses and their
purpose? I did some searches but didn't come up with any good answers.

[Bug c/70220] [x86] interrupt attribute optionally needs to provide read, write and control the set of saved registers

2016-03-13 Thread wink at saville dot com
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70220

--- Comment #2 from Wink Saville  ---
(In reply to H.J. Lu from comment #1)
> (In reply to Wink Saville from comment #0)
> > I have identified one possible problem and with this scheme, what if the
> > compiler needs to setup a stack frame by pushing rbp and then moving rsp to
> > rbp, how would that case be handled.
> 
> Why should be it a problem unless you don't want to restore RSP and RBP
> to its original values upon returning from ISR.  Please provide an example
> here.

Here a possible example, I added a printf and local variables to
timer_reschedule_isr:

void timer_reschedule_isr(struct intr_frame* frame) {
  __asm__ volatile(""::: "rax", "rbx", "rcx", "rdx", "rsi", "rdi", "rbp",
 "r8",  "r9",  "r10", "r11", "r12", "r13", "r14",
"r15");

  volatile ac_u64 array[3];  // << new
  array[2] = get_sp();  // << new
  ac_printf("timer_reschedule_isr array[0]=%p\n", array[2]); // << new

  tcb_x86 *ptcb = thread_scheduler((ac_u8*)get_sp(), get_ss());
  __asm__ volatile("movq %0, %%rsp;" :: "rm" (ptcb->sp) : "rsp");
  __asm__ volatile("movw %0, %%ss;" :: "rm" (ptcb->ss));
  set_apic_timer_initial_count(ptcb->slice);

  __atomic_add_fetch(&timer_reschedule_isr_counter, 1, __ATOMIC_RELEASE);

  send_apic_eoi();
} // line 254 <


The compiler generates an error on the function's closing brace at line 254:

/home/wink/prgs/sadie/arch/x86/libs/thread_x86/srcs/thread_x86.c: In function
'timer_reschedule_isr':
/home/wink/prgs/sadie/arch/x86/libs/thread_x86/srcs/thread_x86.c:254:1: error:
bp cannot be used in asm here
 }


If I now remove "rbp" from the clobber list it compiles:

void timer_reschedule_isr(struct intr_frame* frame) {
  __asm__ volatile(""::: "rax", "rbx", "rcx", "rdx", "rsi", "rdi", // "rbp", <<
remove
 "r8",  "r9",  "r10", "r11", "r12", "r13", "r14",
"r15");

  volatile ac_u64 array[3];  // << new
  array[2] = get_sp();  // << new
  ac_printf("timer_reschedule_isr array[0]=%p\n", array[2]); // << new

  tcb_x86 *ptcb = thread_scheduler((ac_u8*)get_sp(), get_ss());
  __asm__ volatile("movq %0, %%rsp;" :: "rm" (ptcb->sp) : "rsp");
  __asm__ volatile("movw %0, %%ss;" :: "rm" (ptcb->ss));
  set_apic_timer_initial_count(ptcb->slice);

  __atomic_add_fetch(&timer_reschedule_isr_counter, 1, __ATOMIC_RELEASE);

  send_apic_eoi();
} // line 254 <


And the generated subroutine prologue/epilogue is:

00100410 :
  100410:   55  push   %rbp
  100411:   48 89 e5mov%rsp,%rbp
  100414:   41 57   push   %r15
  100416:   41 56   push   %r14
  100418:   41 55   push   %r13
  10041a:   41 54   push   %r12
  10041c:   41 53   push   %r11
  10041e:   41 52   push   %r10
  100420:   41 51   push   %r9
  100422:   41 50   push   %r8
  100424:   57  push   %rdi
  100425:   56  push   %rsi
  100426:   53  push   %rbx
  100427:   51  push   %rcx
  100428:   52  push   %rdx
  100429:   50  push   %rax
  10042a:   48 83 e4 f0 and$0xfff0,%rsp
  10042e:   48 83 ec 20 sub$0x20,%rsp
  100432:   fc  cld



  10048b:   48 8d 65 90 lea-0x70(%rbp),%rsp
  10048f:   58  pop%rax
  100490:   5a  pop%rdx
  100491:   59  pop%rcx
  100492:   5b  pop%rbx
  100493:   5e  pop%rsi
  100494:   5f  pop%rdi
  100495:   41 58   pop%r8
  100497:   41 59   pop%r9
  100499:   41 5a   pop%r10
  10049b:   41 5b   pop%r11
  10049d:   41 5c   pop%r12
  10049f:   41 5d   pop%r13
  1004a1:   41 5e   pop%r14
  1004a3:   41 5f   pop%r15
  1004a5:   5d  pop%rbp
  1004a6:   48 cf   iretq  

So now the compiler saves/restores rbp and align's and adjusts rsp in the
prologue/epilogue code, is this something the programmer could do properly,
maybe but I was speculating it might be a problem.

[Bug c/70220] New: [x86] interrupt attribute optionally needs to provide read, write and control the set of saved registers

2016-03-13 Thread wink at saville dot com
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70220

Bug ID: 70220
   Summary: [x86] interrupt attribute optionally needs to provide
read, write and control the set of saved registers
   Product: gcc
   Version: unknown
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c
  Assignee: unassigned at gcc dot gnu.org
  Reporter: wink at saville dot com
  Target Milestone: ---

I'm using the new C interrupt attribute for x86 and its working well. But when
I expanded its use to include handling thread context switches, I found that
its current implementation lacking.

When using an ISR for a thread context it is necessary to save and restore all
registers but by default it saves a few as it thinks are necessary. It is
possible to use the clobber list of inline assembly to tell the interrupt
attribute code to save additional registers but you can't seem to mention the
segment registers in that clobber list, thus to save these additional registers
you must manually save them manually.

In addition, there is a second problem. I need to know the location of the
registers so they can be read and written. For thread context switching I only
need to be able to initialize a few registers to specific values, but if the
ISR was being used for debugging such as handling a break point interrupt, then
you need to be able to read/write every register.

My current solution is uses the clobber list technique and then looking at the
generated code to determine where in the stack the registers are saved so they
can be initialized. As I mentioned above the clobber list is only a partial
solution but good enough for proof of concept.

Below are snippets a "working" interrupt service routine:

typedef struct intr_frame {
  ac_uptr ip;
  ac_uptr cs;
  ac_uptr flags;
  ac_uptr sp;
  ac_uptr ss;
} intr_frame;

struct saved_regs {
  ac_u64 rax;
  ac_u64 rdx;
  ac_u64 rcx;
  ac_u64 rbx;
  ac_u64 rsi;
  ac_u64 rdi;
  ac_u64 rbp;
  ac_u64 r8;
  ac_u64 r9;
  ac_u64 r10;
  ac_u64 r11;
  ac_u64 r12;
  ac_u64 r13;
  ac_u64 r14;
  ac_u64 r15;
};

struct full_stack_frame {
  union {
struct saved_regs regs;
ac_u64 regs_array[15];
  };
  struct intr_frame iret_frame;
} __attribute__ ((__packed__));

static void init_stack_frame(ac_u8* pstack, ac_uptr stack_size, ac_uptr flags,
void* (*entry)(void*), void* entry_arg, ac_u8** psp, ac_u16 *pss) {
  ac_u8* tos = pstack + stack_size;
  struct full_stack_frame* sf =
(struct full_stack_frame*)(tos - sizeof(struct full_stack_frame));

  sf->regs.rdi = (ac_u64)entry_arg;
  sf->iret_frame.ip = (ac_uptr)entry;
  sf->iret_frame.cs = 0x8;
  sf->iret_frame.flags = flags;

  sf->iret_frame.sp = (ac_uptr)(tos);
  sf->iret_frame.ss = 0x10;

  *psp = (ac_u8*)sf;
  *pss = sf->iret_frame.ss;
}

__attribute__((__interrupt__))
void timer_reschedule_isr(struct intr_frame* frame) {
  __asm__ volatile(""::: "rax", "rbx", "rcx", "rdx", "rsi", "rdi", "rbp",
 "r8",  "r9",  "r10", "r11", "r12", "r13", "r14",
"r15");

  tcb_x86 *ptcb = thread_scheduler((ac_u8*)get_sp(), get_ss());
  __asm__ volatile("movq %0, %%rsp;" :: "rm" (ptcb->sp) : "rsp");
  __asm__ volatile("movw %0, %%ss;" :: "rm" (ptcb->ss));
  set_apic_timer_initial_count(ptcb->slice);

  __atomic_add_fetch(&timer_reschedule_isr_counter, 1, __ATOMIC_RELEASE);

  send_apic_eoi();
}


I've discussed this with H.J. Lu and currently we are leaning to a solution
where the interrupt attribute can have an optional list of registers to NOT
save and then assume the programmer will provide the code to save the desired
registers, thus all registers can be saved and their location known because the
programmer is in control. I'd also like an "all" to indicate that none of the
registers as I see that as a typical use case. And if possible I'd like the
compiler to detect if a register was used but not saved before being modified.

I have identified one possible problem and with this scheme, what if the
compiler needs to setup a stack frame by pushing rbp and then moving rsp to
rbp, how would that case be handled.

[Bug c/65471] type interpretation in _Generic

2016-02-22 Thread wink at saville dot com
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=65471

Wink Saville  changed:

   What|Removed |Added

 CC||wink at saville dot com

--- Comment #3 from Wink Saville  ---
Tested on on gcc 5.3.0 on an x86_64 Arch Linux machine.

When using bit field as a selector _Generic uses the default path
and in the following test program outputs "unknown":

$ cat test.c

$ cat test.c
#include 

struct S {
  int b0:4;
  unsigned int b1:4;
  unsigned long long int b33:33;
};

#define type2str(__x) _Generic((__x), \
  int : "int", \
  unsigned int : "unsigned int", \
  unsigned long long int : "unsigned long long int", \
  default : "unknown")

int main(void) {
  struct S s = { .b0=3, .b1=4, .b33=0x1 };
  (void)s; // Not used

   // gcc | clang output
  printf("type2str(s.b0):  %s\n", type2str(s.b0)); // unknown | int
  printf("type2str(s.b1):  %s\n", type2str(s.b1)); // unknown | unsigned int
  printf("type2str(s.b33): %s\n", type2str(s.b33));// unknown | unsigned long
long int

  return 0;
}

$ cat Makefile 
CC = gcc
O = 3
STD = c11
M = 32

test: test.c Makefile
$(CC) -O$(O) -m$(M) -Wall -std=$(STD) test.c -o test

clean:
rm -f test


$ make clean ; make CC=gcc ; ./test
rm -f test
gcc -O3 -m32 -Wall -std=c11 test.c -o test
type2str(s.b0):  unknown
type2str(s.b1):  unknown
type2str(s.b33): unknown

$ make clean ;make CC=clang ; ./test
rm -f test
clang -O3 -m32 -Wall -std=c11 test.c -o test
type2str(s.b0):  int
type2str(s.b1):  unsigned int
type2str(s.b33): unsigned long long int


Additional discussion on gcc thread:
https://gcc.gnu.org/ml/gcc/2016-02/msg00255.html