[haiku-commits] r42092 - in haiku/trunk/src/system/boot/platform: bios_ia32 pxe_ia32

  • From: ingo_weinhold@xxxxxx
  • To: haiku-commits@xxxxxxxxxxxxx
  • Date: Sat, 11 Jun 2011 02:08:43 +0200 (CEST)

Author: bonefish
Date: 2011-06-11 02:08:42 +0200 (Sat, 11 Jun 2011)
New Revision: 42092
Changeset: https://dev.haiku-os.org/changeset/42092

Added:
   haiku/trunk/src/system/boot/platform/bios_ia32/bios.cpp
   haiku/trunk/src/system/boot/platform/bios_ia32/bios_asm.S
   haiku/trunk/src/system/boot/platform/bios_ia32/interrupts.cpp
   haiku/trunk/src/system/boot/platform/bios_ia32/interrupts.h
   haiku/trunk/src/system/boot/platform/bios_ia32/interrupts_asm.S
Removed:
   haiku/trunk/src/system/boot/platform/bios_ia32/bios.S
Modified:
   haiku/trunk/src/system/boot/platform/bios_ia32/Jamfile
   haiku/trunk/src/system/boot/platform/bios_ia32/debug.cpp
   haiku/trunk/src/system/boot/platform/bios_ia32/debug.h
   haiku/trunk/src/system/boot/platform/bios_ia32/mmu.cpp
   haiku/trunk/src/system/boot/platform/bios_ia32/shell.S
   haiku/trunk/src/system/boot/platform/bios_ia32/start.cpp
   haiku/trunk/src/system/boot/platform/pxe_ia32/Jamfile
Log:
* The boot loader does now set up an IDT that allows it to catch processor
  exceptions (page faults and the like). The handler dumps possibly interesting
  information (registers, a (numerical) stack trace) to the serial output, and,
  if possible, also to the screen. That should help debugging boot loader
  crashes.
* For the IDT the boot loader sets up for the kernel the descriptors are set up
  the same way, so until the kernel initializes the IDT itself (arch_init()) the
  facility is still in place and can thus catch very early kernel boot crashes.
  Unfortunately the on-screen output doesn't seem to work anymore at that point,
  so the output only goes to the serial port...
* ... and to the debug syslog -- dprintf() does now append it there after
  debug_cleanup() has been called. Seems to work fine in qemu, but when I tested
  it on real hardware the debug syslog was gone.


Modified: haiku/trunk/src/system/boot/platform/bios_ia32/Jamfile
===================================================================
--- haiku/trunk/src/system/boot/platform/bios_ia32/Jamfile      2011-06-10 
22:31:33 UTC (rev 42091)
+++ haiku/trunk/src/system/boot/platform/bios_ia32/Jamfile      2011-06-11 
00:08:42 UTC (rev 42092)
@@ -21,7 +21,8 @@
        shell.S
        start.cpp
        debug.cpp
-       bios.S
+       bios.cpp
+       bios_asm.S
        console.cpp
        serial.cpp
        devices.cpp
@@ -37,6 +38,8 @@
        video.cpp
        apm.cpp
        hpet.cpp
+       interrupts.cpp
+       interrupts_asm.S
 
        # VESA/DDC EDID
        decode_edid.c

Added: haiku/trunk/src/system/boot/platform/bios_ia32/bios.cpp
===================================================================
--- haiku/trunk/src/system/boot/platform/bios_ia32/bios.cpp                     
        (rev 0)
+++ haiku/trunk/src/system/boot/platform/bios_ia32/bios.cpp     2011-06-11 
00:08:42 UTC (rev 42092)
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2011, Ingo Weinhold, ingo_weinhold@xxxxxxx
+ * Distributed under the terms of the MIT License.
+ */
+
+
+#include "bios.h"
+
+#include "interrupts.h"
+
+
+extern "C" void call_bios_internal(uint8 num, struct bios_regs* regs);
+
+
+void
+call_bios(uint8 num, struct bios_regs* regs)
+{
+       restore_bios_idt();
+       call_bios_internal(num, regs);
+       set_debug_idt();
+
+}

Copied: haiku/trunk/src/system/boot/platform/bios_ia32/bios_asm.S (from rev 
42078, haiku/trunk/src/system/boot/platform/bios_ia32/bios.S)
===================================================================
--- haiku/trunk/src/system/boot/platform/bios_ia32/bios_asm.S                   
        (rev 0)
+++ haiku/trunk/src/system/boot/platform/bios_ia32/bios_asm.S   2011-06-11 
00:08:42 UTC (rev 42092)
@@ -0,0 +1,295 @@
+/*
+ * Copyright 2004-2010, Axel Dörfler, axeld@xxxxxxxxxxxxxxxxx
+ * Distributed under the terms of the MIT License.
+ */
+
+
+/*!    This file contains code to call BIOS functions out of a protected
+       mode environment. It doesn't use the virtual86 mode - it switches
+       to real mode, make the BIOS call, and switch back to protected
+       mode again. It's meant to be used in a single-threaded boot loader,
+       not in a multi-tasking operating system.
+       It relies on the real mode segment descriptors found in shell.S.
+*/
+
+
+#define FUNCTION(x) .globl x ; x ## :
+
+#define REAL_MODE_STACK        0x9000
+       // the location of the stack in real mode
+
+#define SAVED_ESP              0x10000
+#define SAVED_CR3              0x10004
+#define SAVED_EAX              0x10008
+#define SAVED_ES               0x1000c
+#define SAVED_FLAGS            0x10010
+#define SAVED_EBP              0x10014
+       // we're overwriting the start of our boot loader to hold some
+       // temporary values - the first 1024 bytes of it are used at
+       // startup only, and we avoid some linking issues this way
+
+
+.text
+.code32
+
+
+/*!    This function brings you back to protected mode after you've
+       switched to it using switch_to_real_mode().
+       Should restore the whole environment to what it looked like
+       before. Clobbers %eax.
+*/
+FUNCTION(switch_to_protected_mode)
+       cli                                             // turn off interrupts
+
+       .code16
+       movl    %cr0, %eax              // set the PE bit (0) to switch to 
protected mode
+       orb             $0x1, %al
+       movl    %eax, %cr0
+
+       .code32
+       .byte   0x66                    // jump to the protected mode segment
+       ljmp    $0x8, $_protected_code_segment
+_protected_code_segment:
+       movw    $0x10, %ax              // setup data and stack selectors
+       movw    %ax, %ds
+       movw    %ax, %es
+       movw    %ax, %fs
+       movw    %ax, %gs
+       movw    %ax, %ss
+
+       // turn on paging again
+       movl    SAVED_CR3, %eax // restore the saved page directory
+       orl             %eax, %eax              // is there a paging directory 
at all?
+       jz              _no_paging;
+
+       movl    %eax, %cr3
+
+       movl    %cr0, %eax              // set the PG bit (31) to enable paging
+       orl             $0x80000000, %eax
+       movl    %eax, %cr0
+
+_no_paging:
+       // save the return address so that we can pick it up again later
+       movl    (%esp), %eax
+       movl    %eax, REAL_MODE_STACK
+
+       // setup protected stack frame again
+       movl    SAVED_ESP, %eax
+       movl    %eax, %esp
+       movl    SAVED_EBP, %ebp
+
+       // copy the return address to the current stack
+       movl    REAL_MODE_STACK, %eax
+       movl    %eax, (%esp)
+
+       ret
+
+//--------------------------------------------------------------
+
+
+/*!    Switches from protected mode back to real mode.
+       It will disable paging and set the real mode segment selectors to 
0x1000,
+       except for the stack selector, which will be 0x0 (the stack is at 0x9000
+       which is where the BFS boot loader puts it as well).
+       Clobbers %eax.
+*/
+FUNCTION(switch_to_real_mode)
+       // save the %esp register
+       movl    %esp, %eax
+       movl    %eax, SAVED_ESP
+
+       movl    %ebp, SAVED_EBP
+
+       // put the return address on the real mode stack
+       movl    (%esp), %eax
+       movl    %eax, REAL_MODE_STACK
+
+       // disable paging
+       movl    %cr3, %eax                      // save the page directory 
address
+       movl    %eax, SAVED_CR3
+
+       movl    %cr0, %eax
+       andl    $0x7fffffff, %eax       // clear PG bit (31)
+       movl    %eax, %cr0
+
+       xor             %eax, %eax                      // clear page directory 
to flush TLBs
+       movl    %eax, %cr3
+
+       // setup real mode stack
+       movl    $REAL_MODE_STACK, %eax
+       movl    %eax, %esp
+       movl    %eax, %ebp
+
+       // setup selectors to point to our 16 bit segments
+       movw    $0x20, %ax
+       movw    %ax, %ds
+       movw    %ax, %es
+       movw    %ax, %fs
+       movw    %ax, %gs
+       movw    $0x28, %ax
+       movw    %ax, %ss
+
+       ljmp    $0x18, $(_almost_real_code_segment - 0x10000)
+
+_almost_real_code_segment:
+       movl    %cr0, %eax                      // switch to real mode
+       andb    $0xfe, %al                      // clear PE bit (0)
+       movl    %eax, %cr0
+
+       .byte   0x66
+       ljmp    $0x1000, $(_real_code_segment - 0x10000)
+
+_real_code_segment:
+       .code16
+       movw    $0x1000, %ax            // setup data & stack segments
+       movw    %ax, %ds                        // data in segment 0x1000,
+       movw    %ax, %es
+       movw    %ax, %fs
+       movw    %ax, %gs
+
+       xor             %ax, %ax                        // stack in segment 0x0
+       movw    %ax, %ss
+
+       sti                                                     // turn on 
interrupts again
+       ret
+
+       .code32
+
+//--------------------------------------------------------------
+
+
+/*!    void call_bios_internal(uint8 num, struct bios_regs *regs)
+       Does a BIOS call by triggering a software interrupt in real
+       mode.
+*/
+FUNCTION(call_bios_internal)
+       pushal
+       pushfl
+
+       // make sure the correct IDT is in place
+       lidt    idt_descriptor
+
+       // get the interrupt vector and patch the instruction at the target 
address
+       movl    40(%esp), %eax
+       mov             %al, int_number
+
+       // Fills registers from the passed in structure
+       // Since switch_to_real_mode() clobbers %eax, we have to handle
+       // it specially here (by temporarily storing it to an arbitrary
+       // memory location, SAVED_EAX)
+       movl    44(%esp), %ebp
+
+       movl    (%ebp), %eax
+       movl    %eax, SAVED_EAX
+       movl    4(%ebp), %ebx
+       movl    8(%ebp), %ecx
+       movl    12(%ebp), %edx
+       movl    16(%ebp), %esi
+       movl    20(%ebp), %edi
+       movw    24(%ebp), %ax
+       movw    %ax, SAVED_ES
+
+       call    switch_to_real_mode
+
+       .code16
+
+       // restore %eax and %es from saved location
+       movl    (SAVED_EAX - 0x10000), %eax
+       movw    (SAVED_ES - 0x10000), %es
+
+       // call the interrupt (will be dynamically changed above)
+       .byte   0xcd
+int_number:
+       .byte   0
+
+       // we're interested in the flags state as well
+       pushf
+
+       // save %eax from the call
+       movl    %eax, (SAVED_EAX - 0x10000)
+
+       // save flags from the call
+       pop             %ax
+       movw    %ax, (SAVED_FLAGS - 0x10000)
+
+       // back to protected mode
+       call    switch_to_protected_mode
+       .code32
+
+       // store the register state into the structure that has been passed in
+       movl    44(%esp), %eax
+
+       movl    %ebx, 4(%eax)
+       movl    %ecx, 8(%eax)
+       movl    %edx, 12(%eax)
+       movl    %esi, 16(%eax)
+       movl    %edi, 20(%eax)
+       movl    SAVED_EAX, %ecx         // special handling for %eax and flags
+       movl    %ecx, (%eax)
+       movw    SAVED_FLAGS, %cx
+       movw    %cx, 26(%eax)
+
+       popfl
+       popal
+
+       ret
+
+//--------------------------------------------------------------
+
+
+/*!    uint32  boot_key_in_keyboard_buffer()
+       Search keyboard buffer for the keycodes for space in the first run, and,
+       if not found - for the escape key at the last two positions of this 
buffer
+*/
+FUNCTION(boot_key_in_keyboard_buffer)
+       pushal
+       pushfl
+
+       // make sure the correct IDT is in place
+       lidt    idt_descriptor
+
+       call    switch_to_real_mode
+       .code16
+
+       cld
+       push    %ds
+       xorl    %eax, %eax
+       mov             %ax, %ds
+       mov             $0x41E, %si             // BIOS kbd buffer
+search_cycle1:
+       lodsw
+       cmp             $0x3920, %ax    // test space key
+       jz              to_ret
+       cmp             $0x440, %si
+       jnz             search_cycle1
+
+       addw    0x41C, %si
+       movw    -0x42(%si), %ax
+       cmp             $0x011B, %ax    // test ESC key
+       jz              to_ret
+       movw    -0x44(%si), %ax
+       cmp             $0x011B, %ax    // test ESC key
+to_ret:
+       pop             %ds
+
+       // save %eax
+       movl    %eax, (SAVED_EAX - 0x10000)
+
+       call    switch_to_protected_mode
+       .code32
+
+       popfl
+       popal
+
+       // restore %eax
+       movl    SAVED_EAX, %eax
+
+       ret
+
+//--------------------------------------------------------------
+
+
+.globl idt_descriptor
+idt_descriptor:
+       .short  0x7ff                           // IDT at 0x0, default real 
mode location
+       .long   0x0

Modified: haiku/trunk/src/system/boot/platform/bios_ia32/debug.cpp
===================================================================
--- haiku/trunk/src/system/boot/platform/bios_ia32/debug.cpp    2011-06-10 
22:31:33 UTC (rev 42091)
+++ haiku/trunk/src/system/boot/platform/bios_ia32/debug.cpp    2011-06-11 
00:08:42 UTC (rev 42092)
@@ -6,7 +6,6 @@
 
 #include "debug.h"
 
-#include <stdarg.h>
 #include <string.h>
 
 #include <boot/platform.h>
@@ -26,8 +25,35 @@
 static uint32 sBufferPosition;
 
 static ring_buffer* sDebugSyslogBuffer = NULL;
+static bool sPostCleanup = false;
 
 
+static void
+dprintf_args(const char *format, va_list args)
+{
+       char buffer[512];
+       int length = vsnprintf(buffer, sizeof(buffer), format, args);
+
+       if (length >= (int)sizeof(buffer))
+               length = sizeof(buffer) - 1;
+
+       if (sPostCleanup && sDebugSyslogBuffer != NULL) {
+               ring_buffer_write(sDebugSyslogBuffer, (const uint8*)buffer, 
length);
+       } else if (sBufferPosition + length < sizeof(sBuffer)) {
+               memcpy(sBuffer + sBufferPosition, buffer, length);
+               sBufferPosition += length;
+       }
+
+       serial_puts(buffer, length);
+
+       if (platform_boot_options() & BOOT_OPTION_DEBUG_OUTPUT)
+               fprintf(stderr, "%s", buffer);
+}
+
+
+// #pragma mark -
+
+
 /*!    This works only after console_init() was called.
 */
 void
@@ -54,26 +80,29 @@
 void
 dprintf(const char *format, ...)
 {
-       char buffer[512];
-       va_list list;
-       int length;
+       va_list args;
 
-       va_start(list, format);
-       length = vsnprintf(buffer, sizeof(buffer), format, list);
-       va_end(list);
+       va_start(args, format);
+       dprintf_args(format, args);
+       va_end(args);
+}
 
-       if (length >= (int)sizeof(buffer))
-               length = sizeof(buffer) - 1;
 
-       if (sBufferPosition + length < sizeof(sBuffer)) {
-               memcpy(sBuffer + sBufferPosition, buffer, length);
-               sBufferPosition += length;
-       }
+void
+kprintf(const char *format, ...)
+{
+       va_list args;
 
-       serial_puts(buffer, length);
+       va_start(args, format);
 
-       if (platform_boot_options() & BOOT_OPTION_DEBUG_OUTPUT)
-               fprintf(stderr, "%s", buffer);
+       // print to console, if available
+       if (stdout != NULL)
+               vfprintf(stdout, format, args);
+
+       // always print to serial line
+       dprintf_args(format, args);
+
+       va_end(args);
 }
 
 
@@ -120,7 +149,8 @@
                if (gKernelArgs.keep_debug_output_buffer) {
                        // copy the output gathered so far into the ring buffer
                        ring_buffer_clear(sDebugSyslogBuffer);
-                       ring_buffer_write(sDebugSyslogBuffer, (uint8*)sBuffer, 
sBufferPosition);
+                       ring_buffer_write(sDebugSyslogBuffer, (uint8*)sBuffer,
+                               sBufferPosition);
 
                        memcpy(buffer, kDebugSyslogSignature, signatureLength);
                } else {
@@ -137,4 +167,6 @@
                        gKernelArgs.debug_size = sBufferPosition;
                }
        }
+
+       sPostCleanup = true;
 }

Modified: haiku/trunk/src/system/boot/platform/bios_ia32/debug.h
===================================================================
--- haiku/trunk/src/system/boot/platform/bios_ia32/debug.h      2011-06-10 
22:31:33 UTC (rev 42091)
+++ haiku/trunk/src/system/boot/platform/bios_ia32/debug.h      2011-06-11 
00:08:42 UTC (rev 42092)
@@ -6,6 +6,8 @@
 #define DEBUG_H
 
 
+#include <stdarg.h>
+
 #include <SupportDefs.h>
 
 

Added: haiku/trunk/src/system/boot/platform/bios_ia32/interrupts.cpp
===================================================================
--- haiku/trunk/src/system/boot/platform/bios_ia32/interrupts.cpp               
                (rev 0)
+++ haiku/trunk/src/system/boot/platform/bios_ia32/interrupts.cpp       
2011-06-11 00:08:42 UTC (rev 42092)
@@ -0,0 +1,249 @@
+/*
+ * Copyright 2011, Ingo Weinhold, ingo_weinhold@xxxxxxx
+ * Distributed under the terms of the MIT License.
+ */
+
+
+#include "interrupts.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include <algorithm>
+
+#include <KernelExport.h>
+
+#include <boot/platform.h>
+#include <boot/platform/generic/text_console.h>
+
+#include <arch_cpu.h>
+#include <descriptors.h>
+
+#include "debug.h"
+#include "keyboard.h"
+
+
+//#define TRACE_INTERRUPTS
+#ifdef TRACE_INTERRUPTS
+#      define TRACE(x...) dprintf(x)
+#else
+#      define TRACE(x...) ;
+#endif
+
+
+// interrupt function prototypes
+#define INTERRUPT_FUNCTION(vector) \
+       extern "C" void interrupt_function##vector();
+INTERRUPT_FUNCTIONS()
+#undef INTERRUPT_FUNCTION
+
+#define INTERRUPT_FUNCTION(vector) \
+       extern "C" void exception_interrupt_function##vector();
+INTERRUPT_FUNCTIONS()
+#undef INTERRUPT_FUNCTION
+
+
+static const char *kInterruptNames[DEBUG_IDT_SLOT_COUNT] = {
+       /*  0 */ "Divide Error Exception",
+       /*  1 */ "Debug Exception",
+       /*  2 */ "NMI Interrupt",
+       /*  3 */ "Breakpoint Exception",
+       /*  4 */ "Overflow Exception",
+       /*  5 */ "BOUND Range Exceeded Exception",
+       /*  6 */ "Invalid Opcode Exception",
+       /*  7 */ "Device Not Available Exception",
+       /*  8 */ "Double Fault Exception",
+       /*  9 */ "Coprocessor Segment Overrun",
+       /* 10 */ "Invalid TSS Exception",
+       /* 11 */ "Segment Not Present",
+       /* 12 */ "Stack Fault Exception",
+       /* 13 */ "General Protection Exception",
+       /* 14 */ "Page-Fault Exception",
+       /* 15 */ "-",
+       /* 16 */ "x87 FPU Floating-Point Error",
+       /* 17 */ "Alignment Check Exception",
+       /* 18 */ "Machine-Check Exception",
+       /* 19 */ "SIMD Floating-Point Exception",
+};
+
+
+struct interrupt_frame {
+    uint32 vector;
+    uint32 edi;
+    uint32 esi;
+    uint32 ebp;
+    uint32 esp;
+    uint32 ebx;
+    uint32 edx;
+    uint32 ecx;
+    uint32 eax;
+       uint32 error_code;
+       uint32 eip;
+       uint32 cs;
+       uint32 eflags;
+};
+
+struct interrupt_descriptor {
+       uint32 a;
+       uint32 b;
+};
+
+
+static interrupt_descriptor sDebugIDT[DEBUG_IDT_SLOT_COUNT];
+
+static gdt_idt_descr sBIOSIDTDescriptor;
+static gdt_idt_descr sDebugIDTDescriptor = { sizeof(sDebugIDT) - 1, sDebugIDT 
};
+
+
+static void
+set_interrupt_gate(int n, void (*function)())
+{
+       if (n >= DEBUG_IDT_SLOT_COUNT)
+               return;
+
+       sDebugIDT[n].a = (KERNEL_CODE_SEG << 16) | (0x0000ffff & 
(addr_t)function);
+       sDebugIDT[n].b = (0xffff0000 & (addr_t)function) | 0x8e00;
+}
+
+
+static void
+set_idt(const gdt_idt_descr& idtDescriptor)
+{
+       asm("lidt       %0;" : : "m" (idtDescriptor));
+}
+
+
+extern "C" void
+handle_exception_exception()
+{
+       while (true);
+}
+
+
+extern "C" void
+handle_exception(interrupt_frame frame)
+{
+       // Before doing anything else, set the interrupt gates so that
+       // handle_exception_exception() is called. This way we may avoid
+       // triple-faulting, if e.g. the stack is messed up and the user has at
+       // least the already printed output.
+       #define INTERRUPT_FUNCTION(vector) \
+               set_interrupt_gate(vector, 
&exception_interrupt_function##vector);
+       INTERRUPT_FUNCTIONS()
+       #undef INTERRUPT_FUNCTION
+
+       // If the console is already/still initialized, clear the screen and 
prepare
+       // for output.
+       if (stdout != NULL) {
+               console_set_color(RED, BLACK);
+               console_clear_screen();
+               console_set_cursor(0, 0);
+               console_hide_cursor();
+       }
+
+       // print exception name
+       if (frame.vector < DEBUG_IDT_SLOT_COUNT)
+               kprintf("%s", kInterruptNames[frame.vector]);
+       else
+               kprintf("Unknown exception %" B_PRIu32, frame.vector);
+
+       // additional info for page fault
+       if (frame.vector == 14) {
+               uint32 cr2;
+               asm("movl %%cr2, %0" : "=r"(cr2));
+               kprintf(": %s fault at address: %#" B_PRIx32,
+                       (frame.error_code & 0x2) != 0 ? "write" : "read", cr2);
+       }
+
+       kprintf("\n");
+
+       // print greeting and registers
+       kprintf("Welcome to Boot Loader Death Land!\n");
+       kprintf("\n");
+
+       #define REG(name)       " " #name " %-#10" B_PRIx32
+
+       kprintf(REG(eax) "   " REG(ebx) "    " REG(ecx) " " REG(edx) "\n",
+               frame.eax, frame.ebx, frame.ecx, frame.edx);
+       kprintf(REG(esi) "   " REG(edi) "    " REG(ebp) " " REG(esp) "\n",
+               frame.esi, frame.edi, frame.ebp, frame.esp);
+       kprintf(REG(eip) REG(eflags) "\n", frame.eip, frame.eflags);
+
+       #undef REG
+
+       // print stack trace (max 10 frames)
+       kprintf("\n       frame    return address\n");
+
+       struct x86_stack_frame {
+               x86_stack_frame*        next;
+               void*                           return_address;
+       };
+
+       x86_stack_frame* stackFrame = (x86_stack_frame*)frame.ebp;
+       void* instructionPointer = (void*)frame.eip;
+
+       for (int32 i = 0; i < 10 && stackFrame != NULL; i++) {
+               kprintf("  %p        %p\n", stackFrame, instructionPointer);
+
+               instructionPointer = stackFrame->return_address;
+               stackFrame = stackFrame->next;
+       }
+
+       if (stdout != NULL) {
+               kprintf("\nPress a key to reboot.\n");
+               clear_key_buffer();
+               wait_for_key();
+               platform_exit();
+       }
+
+       while (true);
+}
+
+
+void
+interrupts_init()
+{
+       // get the IDT
+       asm("sidt       %0;" : : "m" (sBIOSIDTDescriptor));
+
+       TRACE("IDT: base: %p, limit: %u\n", sBIOSIDTDescriptor.base,
+               sBIOSIDTDescriptor.limit);
+
+       // set interrupt gates
+       #define INTERRUPT_FUNCTION(vector) \
+               set_interrupt_gate(vector, &interrupt_function##vector);
+       INTERRUPT_FUNCTIONS()
+       #undef INTERRUPT_FUNCTION
+
+       // set the debug IDT
+       set_debug_idt();
+}
+
+
+void
+restore_bios_idt()
+{
+       set_idt(sBIOSIDTDescriptor);
+}
+
+
+void
+set_debug_idt()
+{
+       set_idt(sDebugIDTDescriptor);
+}
+
+
+void
+interrupts_init_kernel_idt(void* idt, size_t idtSize)
+{
+       // clear it but copy the descriptors we've set up for the exceptions
+       memset(idt, 0, idtSize);
+       memcpy(idt, sDebugIDT, sizeof(sDebugIDT));
+
+       // load the idt
+       gdt_idt_descr idtDescriptor;
+       idtDescriptor.limit = idtSize - 1;
+       idtDescriptor.base = idt;
+       set_idt(idtDescriptor);
+}

Added: haiku/trunk/src/system/boot/platform/bios_ia32/interrupts.h
===================================================================
--- haiku/trunk/src/system/boot/platform/bios_ia32/interrupts.h                 
        (rev 0)
+++ haiku/trunk/src/system/boot/platform/bios_ia32/interrupts.h 2011-06-11 
00:08:42 UTC (rev 42092)
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2011, Ingo Weinhold, ingo_weinhold@xxxxxxx
+ * Distributed under the terms of the MIT License.
+ */
+#ifndef INTERRUPTS_H
+#define INTERRUPTS_H
+
+
+#ifndef _ASSEMBLER
+
+
+#include <sys/cdefs.h>
+
+#include <SupportDefs.h>
+
+
+struct gdt_idt_descr {
+       uint16  limit;
+       void*   base;
+} _PACKED;
+
+
+__BEGIN_DECLS
+
+
+void interrupts_init();
+void set_debug_idt();
+void restore_bios_idt();
+void interrupts_init_kernel_idt(void* idt, size_t idtSize);
+
+
+__END_DECLS
+
+
+#endif // _ASSEMBLER
+
+#define INTERRUPT_FUNCTION_ERROR(vector)       INTERRUPT_FUNCTION(vector)
+
+#define INTERRUPT_FUNCTIONS5(vector1, vector2, vector3, vector4, vector5)      
\
+       INTERRUPT_FUNCTION(vector1)                                             
                                                \
+       INTERRUPT_FUNCTION(vector2)                                             
                                                \
+       INTERRUPT_FUNCTION(vector3)                                             
                                                \
+       INTERRUPT_FUNCTION(vector4)                                             
                                                \
+       INTERRUPT_FUNCTION(vector5)
+
+#define INTERRUPT_FUNCTIONS()                          \
+       INTERRUPT_FUNCTIONS5(0, 1, 2, 3, 4)             \
+       INTERRUPT_FUNCTIONS5(5, 6, 7, 8, 9)             \
+       INTERRUPT_FUNCTION_ERROR(10)                    \
+       INTERRUPT_FUNCTION_ERROR(11)                    \
+       INTERRUPT_FUNCTION_ERROR(12)                    \
+       INTERRUPT_FUNCTION_ERROR(13)                    \
+       INTERRUPT_FUNCTION_ERROR(14)                    \
+       INTERRUPT_FUNCTION(15)                                  \
+       INTERRUPT_FUNCTION(16)                                  \
+       INTERRUPT_FUNCTION_ERROR(17)                    \
+       INTERRUPT_FUNCTION(18)                                  \
+       INTERRUPT_FUNCTION(19)
+
+#define DEBUG_IDT_SLOT_COUNT   20
+
+
+#endif // INTERRUPTS_H

Added: haiku/trunk/src/system/boot/platform/bios_ia32/interrupts_asm.S
===================================================================
--- haiku/trunk/src/system/boot/platform/bios_ia32/interrupts_asm.S             
                (rev 0)
+++ haiku/trunk/src/system/boot/platform/bios_ia32/interrupts_asm.S     
2011-06-11 00:08:42 UTC (rev 42092)
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2011, Ingo Weinhold, ingo_weinhold@xxxxxxx
+ * Distributed under the terms of the MIT License.
+ */
+
+
+#include <asm_defs.h>
+
+#include "interrupts.h"
+
+
+// #pragma mark - interrupt functions
+
+
+#define INTERRUPT_FUNCTION(vector)                     \
+.align 8;                                                                      
\
+FUNCTION(interrupt_function##vector):          \
+       pushl   $0;                                                             
\
+       pusha;                                                                  
\
+       pushl   $vector;                                                \
+       call    handle_exception;
+
+#undef INTERRUPT_FUNCTION_ERROR
+#define INTERRUPT_FUNCTION_ERROR(vector)       \
+.align 8;                                                                      
\
+FUNCTION(interrupt_function##vector):          \
+       pusha;                                                                  
\
+       pushl   $vector;                                                \
+       call    handle_exception;
+
+INTERRUPT_FUNCTIONS()
+
+
+// #pragma mark - interrupt functions during exception
+
+
+#undef INTERRUPT_FUNCTION
+#define INTERRUPT_FUNCTION(vector)                                     \
+.align 8;                                                                      
                \
+FUNCTION(exception_interrupt_function##vector):                \
+       call    handle_exception_exception;
+
+#undef INTERRUPT_FUNCTION_ERROR
+#define INTERRUPT_FUNCTION_ERROR(vector)       INTERRUPT_FUNCTION(vector)
+
+INTERRUPT_FUNCTIONS()

Modified: haiku/trunk/src/system/boot/platform/bios_ia32/mmu.cpp
===================================================================
--- haiku/trunk/src/system/boot/platform/bios_ia32/mmu.cpp      2011-06-10 
22:31:33 UTC (rev 42091)
+++ haiku/trunk/src/system/boot/platform/bios_ia32/mmu.cpp      2011-06-11 
00:08:42 UTC (rev 42092)
@@ -7,21 +7,23 @@
 
 
 #include "mmu.h"
-#include "bios.h"
 
+#include <string.h>
+
+#include <OS.h>
+
+#include <arch/cpu.h>
+#include <arch_kernel.h>
 #include <boot/platform.h>
 #include <boot/stdio.h>
 #include <boot/kernel_args.h>
 #include <boot/stage2.h>
-#include <arch/cpu.h>
-#include <arch_kernel.h>
 #include <kernel.h>
 
-#include <OS.h>
+#include "bios.h"
+#include "interrupts.h"
 
-#include <string.h>
 
-
 /*!    The (physical) memory layout of the boot loader is currently as follows:
          0x0500 - 0x10000      protected mode stack
          0x0500 - 0x09000      real mode stack
@@ -58,11 +60,6 @@
        // for output to work.
 
 
-struct gdt_idt_descr {
-       uint16 limit;
-       uint32 *base;
-} _PACKED;
-
 // memory structure returned by int 0x15, ax 0xe820
 struct extended_memory {
        uint64 base_addr;
@@ -491,7 +488,6 @@
        TRACE("mmu_init_for_kernel\n");
        // set up a new idt
        {
-               struct gdt_idt_descr idtDescriptor;
                uint32 *idt;
 
                // find a new idt
@@ -504,19 +500,10 @@
                gKernelArgs.arch_args.vir_idt = (uint32)get_next_virtual_page();
                map_page(gKernelArgs.arch_args.vir_idt, (uint32)idt, 
kDefaultPageFlags);
 
-               // clear it out
-               uint32* virtualIDT = (uint32*)gKernelArgs.arch_args.vir_idt;
-               for (int32 i = 0; i < IDT_LIMIT / 4; i++) {
-                       virtualIDT[i] = 0;
-               }
+               // initialize it
+               interrupts_init_kernel_idt((void*)gKernelArgs.arch_args.vir_idt,
+                       IDT_LIMIT);
 
-               // load the idt
-               idtDescriptor.limit = IDT_LIMIT - 1;
-               idtDescriptor.base = (uint32 *)gKernelArgs.arch_args.vir_idt;
-
-               asm("lidt       %0;"
-                       : : "m" (idtDescriptor));
-
                TRACE("idt at virtual address 0x%lx\n", 
gKernelArgs.arch_args.vir_idt);
        }
 
@@ -561,7 +548,7 @@
 
                // load the GDT
                gdtDescriptor.limit = GDT_LIMIT - 1;
-               gdtDescriptor.base = (uint32 *)gKernelArgs.arch_args.vir_gdt;
+               gdtDescriptor.base = (void*)gKernelArgs.arch_args.vir_gdt;
 
                asm("lgdt       %0;"
                        : : "m" (gdtDescriptor));

Modified: haiku/trunk/src/system/boot/platform/bios_ia32/shell.S
===================================================================
--- haiku/trunk/src/system/boot/platform/bios_ia32/shell.S      2011-06-10 
22:31:33 UTC (rev 42091)
+++ haiku/trunk/src/system/boot/platform/bios_ia32/shell.S      2011-06-11 
00:08:42 UTC (rev 42092)
@@ -103,7 +103,7 @@
 
 
 /**    Loads %di sectors from floppy disk, starting at head %dh, sector %cx.
- *     The data is loaded to %es:%bx. On exit, %es:%bx will point immediately 
+ *     The data is loaded to %es:%bx. On exit, %es:%bx will point immediately
  *     behind the loaded data, so that you can continue to read in data.
  *     %ax, %cx, %dx, %bp, %di and %si will be clobbered.
  */
@@ -127,7 +127,7 @@
        mov             %cx, %si                // and remember it
        pop             %cx
        pop             %bx
-       
+
 load_track:
        mov             %di, %ax                // limit the sector count to 
track boundaries
        add             %cl, %al
@@ -292,8 +292,10 @@
        mov             %ax, %gs
        mov             %ax, %ss
 
-       mov             $0x10000, %ebp  // setup new stack
-       mov             %ebp, %esp
+       movl    $0x10000, %esp  // setup new stack
+       pushl   $0                              // terminate stack frame chain 
(next frame and
+       pushl   $0                              // return address)
+       mov             %esp, %ebp
 
        call    _start
 

Modified: haiku/trunk/src/system/boot/platform/bios_ia32/start.cpp
===================================================================
--- haiku/trunk/src/system/boot/platform/bios_ia32/start.cpp    2011-06-10 
22:31:33 UTC (rev 42091)
+++ haiku/trunk/src/system/boot/platform/bios_ia32/start.cpp    2011-06-11 
00:08:42 UTC (rev 42092)
@@ -20,6 +20,7 @@
 #include "cpu.h"
 #include "debug.h"
 #include "hpet.h"
+#include "interrupts.h"
 #include "keyboard.h"
 #include "mmu.h"
 #include "multiboot.h"
@@ -84,6 +85,10 @@
        smp_init_other_cpus();
        debug_cleanup();
        mmu_init_for_kernel();
+
+       // We're about to enter the kernel -- disable console output.
+       stdout = NULL;
+
        smp_boot_other_cpus();
 
        dprintf("kernel entry at %lx\n",

[... truncated: 33 lines follow ...]

Other related posts:

  • » [haiku-commits] r42092 - in haiku/trunk/src/system/boot/platform: bios_ia32 pxe_ia32 - ingo_weinhold