refactor: reduce the system timer frequency to 1024.
refactor: make the kprintf re-entrance and reduce the buffer size.
improve: better debugging experience with qemu.
improve: more information when debugging with iret.
#include <lunaix/ds/llist.h>
#include <stdint.h>
-#define SYS_TIMER_FREQUENCY_HZ 2048
+#define SYS_TIMER_FREQUENCY_HZ 1024
#define TIMER_MODE_PERIODIC 0x1
movl %eax, %esp
#ifdef __ASM_INTR_DIAGNOSIS
+ movl %eax, (debug_resv + 8)
movl 56(%esp), %eax
movl %eax, (debug_resv + 4)
#endif
#include <lunaix/syslog.h>
#include <lunaix/tty/tty.h>
-#define MAX_KPRINTF_BUF_SIZE 1024
-#define MAX_XFMT_SIZE 1024
-
-static char buf[MAX_KPRINTF_BUF_SIZE];
+#define MAX_KPRINTF_BUF_SIZE 512
+#define MAX_XFMT_SIZE 512
void
__kprintf(const char* component, const char* fmt, va_list args)
{
+ char buf[MAX_KPRINTF_BUF_SIZE];
if (!fmt)
return;
char log_level = '0';
void
kprint_panic(const char* fmt, ...)
{
+ char buf[MAX_KPRINTF_BUF_SIZE];
va_list args;
va_start(args, fmt);
tty_set_theme(VGA_COLOR_WHITE, VGA_COLOR_RED);
- tty_clear_line(10);
- tty_clear_line(11);
- tty_clear_line(12);
+ tty_clear_line(24);
__sprintf_internal(buf, fmt, MAX_KPRINTF_BUF_SIZE, args);
- tty_put_str_at(buf, 0, 11);
+ tty_put_str_at(buf, 0, 24);
va_end(args);
}
\ No newline at end of file
apic_done_servicing();
asm volatile("pushl %0\n"
- "jmp switch_to\n" ::"r"(proc)); // kernel/asm/x86/interrupt.S
+ "jmp switch_to\n" ::"r"(proc)
+ : "memory"); // kernel/asm/x86/interrupt.S
}
int
[_SIGINT] = default_sighandler_term,
};
+volatile isr_param __temp_save;
// Referenced in kernel/asm/x86/interrupt.S
void*
signal_dispatch()
struct proc_sig* sig_ctx =
(struct proc_sig*)(ustack - sizeof(struct proc_sig));
- sig_ctx->prev_context = __current->intr_ctx;
+ /*
+ 这是一个相当恶心的坑。
+ 问题是出在原本的sig_ctx->prev_context = __current->intr_ctx的上面
+ 这个语句会被gcc在编译时,用更加高效的 rep movsl 来代替。
+
+ 由于我们采用按需分页,所以在很多情况下,用户栈实际被分配的空间不允许我们进行完整的
+ 注入,而需要走page fault handler进行动态分页。
+
+ 竞态条件就出现在这里!
+
+ 假若我们的__current->intr_ctx注入了一半,然后产生page-fault中断,
+ 那么这就会导致我们的__current->intr_ctx被这个page-fault中断导致的
+ 上下文信息覆盖。那么当page-fault handler成功分配了一个页,返回,
+ 拷贝也就得以进行。遗憾的是,只不过这次拷贝的内容和前面的拷贝是没有任何的关系
+ (因为此时的intr_ctx已经不是之前的intr_ctx了!)
+ 而这就会导致我们保存在信号上下文中的进程上下文信息不完整,从而在soft_iret时
+ 触发#GP。
+
+ 解决办法就是先吧intr_ctx拷贝到一个静态分配的区域里,然后再注入到用户栈。
+ */
+ __temp_save = __current->intr_ctx;
+ sig_ctx->prev_context = __temp_save;
+
sig_ctx->sig_num = sig_selected;
sig_ctx->signal_handler = __current->sig_handler[sig_selected];
@sleep 2
run: $(BUILD_DIR)/$(OS_ISO)
- @qemu-system-i386 -cdrom $(BUILD_DIR)/$(OS_ISO) -monitor telnet::$(QEMU_MON_PORT),server,nowait &
+ @qemu-system-i386 -cdrom $(BUILD_DIR)/$(OS_ISO) -d cpu_reset -monitor telnet::$(QEMU_MON_PORT),server,nowait &
@sleep 1
@telnet 127.0.0.1 $(QEMU_MON_PORT)
debug-qemu: all-debug
@${TOOLCHAIN}/i686-elf-objcopy --only-keep-debug $(BIN_DIR)/$(OS_BIN) $(BUILD_DIR)/kernel.dbg
- @qemu-system-i386 -m 1G -rtc base=utc -s -S -cdrom $(BUILD_DIR)/$(OS_ISO) -monitor telnet::$(QEMU_MON_PORT),server,nowait &
+ @qemu-system-i386 -m 1G -rtc base=utc -d cpu_reset -s -S -cdrom $(BUILD_DIR)/$(OS_ISO) -monitor telnet::$(QEMU_MON_PORT),server,nowait &
@sleep 1
@$(QEMU_MON_TERM) -- telnet 127.0.0.1 $(QEMU_MON_PORT)
@gdb -s $(BUILD_DIR)/kernel.dbg -ex "target remote localhost:1234"