C 如何创建中断堆栈?
我希望我的中断服务例程使用不同的堆栈(可能是它自己的),而不是使用调用线程的堆栈C 如何创建中断堆栈?,c,stack,interrupt,C,Stack,Interrupt,我希望我的中断服务例程使用不同的堆栈(可能是它自己的),而不是使用调用线程的堆栈 thread_entry (){ do_something(); --> Interrupt occurs do_otherstuff(); } void interrupt_routine () { uint8_t read_byte; // I don't want this to be part of caller thread's stack
thread_entry (){
do_something();
--> Interrupt occurs
do_otherstuff();
}
void interrupt_routine ()
{
uint8_t read_byte; // I don't want this to be part of caller thread's stack
read_byte= hw_read();
}
是否可能&如何实现这一点?Linux的GNU C库有方法控制信号执行的堆栈。有关详细信息,请参阅 基本思想是为堆栈分配内存并调用函数
sigstack()
指定此堆栈可用于信号处理。然后使用
sigaction()
函数为特定信号注册处理程序并指定标志值
SA_ONSTACK
该处理程序在特殊堆栈上运行
下面是一个显示模式的代码片段,它是从示例中“借用”来的
操作系统和中断处理程序所需的堆栈是在初始化时设置的。这也是特定于体系结构的代码。对于ARM处理器,它有一个独特的R13,当处理器处于中断模式时使用。同样,该寄存器在启动时初始化。您希望通过这种设计解决什么问题。这里是一个简单的x86内联汇编实现。您有一个包装器函数,可以更改堆栈并调用实际例程
const uint32_t interrupt_stack_size = 4096;
uint8_t interrupt_stack[interrupt_stack_size];
void interrupt_routine_wrap()
{
static int thread_esp;
// Stack grows towards lower addresses, so start at the bottom
static int irq_esp = (int) interrupt_stack + interrupt_stack_size;
// Store the old esp
asm mov dword ptr thread_esp, esp;
// Set the new esp
asm mov esp, dword ptr irq_esp;
// Execute the real interrupt routine
interrupt_routine();
// Restore old esp
asm mov esp, dword ptr thread_esp;
}
我在这里完全忽略了段寄存器(ss
),但是不同的内存模型可能需要将其与sp
一起存储
您可以通过使用setjmp
/longjmp
读取/写入所有寄存器来摆脱内联程序集。这是一种更便于携带的方法
还要注意,我没有在这里保留任何寄存器,内联汇编可能会混淆编译器。也许值得在包装器例程周围添加一个
pusha
/popa
对。如果您将函数指定为interrupt
,编译器可能会为您执行此操作。检查生成的二进制文件以确定。这是什么编程语言?实际代码是C语言。我在这里放了一种伪代码。很抱歉。让变量静态
(取决于您有多少ram)怎么样?@vlp类似于静态
变量的概念,您可以拥有所有ISRs变量的全局并集,因此它们共享相同的全局内存。@mtijanic Nice idea…还记得在使用前初始化这些变量(在适当的情况下).谢谢,这似乎是一个可行的解决方案。
const uint32_t interrupt_stack_size = 4096;
uint8_t interrupt_stack[interrupt_stack_size];
void interrupt_routine_wrap()
{
static int thread_esp;
// Stack grows towards lower addresses, so start at the bottom
static int irq_esp = (int) interrupt_stack + interrupt_stack_size;
// Store the old esp
asm mov dword ptr thread_esp, esp;
// Set the new esp
asm mov esp, dword ptr irq_esp;
// Execute the real interrupt routine
interrupt_routine();
// Restore old esp
asm mov esp, dword ptr thread_esp;
}