]> Zhao Yanbai Git Server - minix.git/commitdiff
Multiboot support (contributed by Feiran "Fam" Zheng);
authorErik van der Kouwe <erik@minix3.org>
Fri, 23 Jul 2010 14:24:34 +0000 (14:24 +0000)
committerErik van der Kouwe <erik@minix3.org>
Fri, 23 Jul 2010 14:24:34 +0000 (14:24 +0000)
keep in mind that GRUB needs to be patched to read MFS for now;
use /boot/image_latest to boot the last compiled image in GRUB

13 files changed:
kernel/arch/i386/Makefile.inc
kernel/arch/i386/arch_system.c
kernel/arch/i386/include/archconst.h
kernel/arch/i386/klib.S
kernel/arch/i386/klib16.S [new file with mode: 0644]
kernel/arch/i386/mpx.S
kernel/arch/i386/multiboot.S [new file with mode: 0644]
kernel/arch/i386/multiboot.h [new file with mode: 0644]
kernel/arch/i386/pre_init.c [new file with mode: 0644]
kernel/arch/i386/protect.c
kernel/proto.h
tools/Makefile
tools/mkboot

index f1ebb14ef2d389948f2844329d037896e99578bf..bf8b79daf43d8de2bcc9eeef53364256e018f7db 100644 (file)
@@ -1,3 +1,4 @@
+
 # Makefile for arch-dependent kernel code
 .include <bsd.own.mk>
 
@@ -20,10 +21,19 @@ SRCS+=      arch_do_vmctl.c \
        io_outl.S \
        io_outw.S \
        klib.S \
+       klib16.S \
+       multiboot.S \
        memory.c \
        oxpcie.c \
        protect.c \
        arch_system.c \
        apic.c \
        apic_asm.S \
-       arch_watchdog.c
+       arch_watchdog.c \
+       pre_init.c
+
+I86CPPFLAGS =  -mi86
+I86LDFLAGS =   -mi86
+
+CPPFLAGS.klib16.S =    ${I86CPPFLAGS}
+LDFLAGS.klib16.S  =    ${I86LDFLAGS}
index bfbe5a2ab75fbc48b1701848a10c44f543bef219..c0e87dc9148ba9f5bfcc2ad795cee210368e917d 100644 (file)
@@ -22,6 +22,7 @@
 #include "oxpcie.h"
 #include "kernel/proc.h"
 #include "kernel/debug.h"
+#include "multiboot.h"
 
 #ifdef CONFIG_APIC
 #include "apic.h"
@@ -29,6 +30,9 @@
 
 PRIVATE int osfxsr_feature; /* FXSAVE/FXRSTOR instructions support (SSEx) */
 
+extern void poweroff_jmp();
+extern void poweroff16();
+extern void poweroff16_end();
 
 /* set MP and NE flags to handle FPU exceptions in native mode. */
 #define CR0_MP_NE      0x0022
@@ -44,6 +48,22 @@ PUBLIC __dead void arch_monitor(void)
        monitor();
 }
 
+PUBLIC void arch_bios_poweroff(void)
+{
+       u32_t cr0;
+       
+       /* Disable paging */
+       cr0 = read_cr0();
+       cr0 &= ~I386_CR0_PG;
+       write_cr0(cr0);
+       /* Copy 16-bit poweroff code to below 1M */
+       phys_copy(
+               FUNC2PHY(&poweroff16),
+               BIOS_POWEROFF_ENTRY,
+               (u32_t)&poweroff16_end-(u32_t)&poweroff16);
+       poweroff_jmp();
+}
+
 PUBLIC int cpu_has_tsc;
 
 PUBLIC __dead void arch_shutdown(const int how)
@@ -107,7 +127,10 @@ PUBLIC __dead void arch_shutdown(const int how)
 
                        arch_set_params(mybuffer, strlen(mybuffer)+1);
                }
-               arch_monitor();
+               if(mon_return)
+                       arch_monitor();
+               else
+                       arch_bios_poweroff();
        } else {
                /* Reset the system by forcing a processor shutdown. First stop
                 * the BIOS memory test by setting a soft reset flag.
index 3411845f2eab4c84540f1990b41848e9e62de093..ad38d37b372875ecfd66b03cb3ec2965527558c2 100644 (file)
 /* fpu context should be saved in 16-byte aligned memory */
 #define FPUALIGN               16
 
+/* Poweroff 16-bit code address */
+#define BIOS_POWEROFF_ENTRY 0x1000
+
 #endif /* _I386_ACONST_H */
index 4d99dd782595ef288076a7c2ed7c37398da3a03f..a1cfc4267e665ec4bc96d59cf07d9fc866e7e4ac 100644 (file)
@@ -4,9 +4,11 @@
 #include <minix/config.h>
 #include <minix/const.h>
 #include <machine/interrupt.h>
+#include <i386/vm.h>
 #include "archconst.h"
 #include "kernel/const.h"
 #include "sconst.h"
+#include "multiboot.h"
 
 /*
  * This file contains a number of assembly code utility routines needed by the
@@ -908,3 +910,54 @@ _switch_address_space:
 0:
        ret
 
+/*===========================================================================*/
+/*                             poweroff                                             */
+/*===========================================================================*/
+/* PUBLIC void poweroff(); */
+/* Jump to 16-bit poweroff code */
+.globl _poweroff_jmp
+_poweroff_jmp:
+       cli
+       /* Make real mode descriptor */
+       mov     $(_gdt + SS_SELECTOR), %edi
+       mov     $0x100, %eax
+       movw %ax, 2(%edi)
+       shr     $16, %eax
+       movb    %al, 4(%edi)
+       and     $0xff00, %ax
+       andw    $0xff, 6(%edi)
+       or      %ax, 6(%edi)
+       mov     $0xffff, %eax
+       movw    %ax, (%edi)
+       shr     $16, %eax
+       and     $0xf, %ax
+       andb    $0xf0, 6(%edi)
+       or      %ax, 6(%edi)
+       
+       /* Flush TLB */
+       xor     %eax, %eax
+       mov     %eax, %cr3
+       
+       xor     %esp, %esp /* clear esp for real mode*/
+       
+       /* Reset IDTR */
+       lidt    idt_ptr
+       
+       mov     $SS_SELECTOR, %ax
+       mov     %ax, %ds
+       mov     %ax, %es
+       mov     %ax, %fs
+       mov     %ax, %gs
+       mov     %ax, %ss
+       
+       /* Save real mode cr0 in eax */
+       mov     %cr0, %eax
+       andl    $~I386_CR0_PE, %eax
+       
+       /* Jump to 16-bit code that is copied to below 1MB */
+       ljmp    $MON_CS_SELECTOR, $0
+       
+.data
+idt_ptr:
+       .short 0x3ff
+       .long 0x0
diff --git a/kernel/arch/i386/klib16.S b/kernel/arch/i386/klib16.S
new file mode 100644 (file)
index 0000000..57c2ea2
--- /dev/null
@@ -0,0 +1,78 @@
+/* sections */
+
+
+#include <minix/config.h>
+#include <minix/const.h>
+#include <machine/interrupt.h>
+#include "archconst.h"
+#include "kernel/const.h"
+#include "sconst.h"
+#include "multiboot.h"
+
+/*
+ * This file contains a number of 16-bit assembly code utility routines needed by the
+ * kernel.  They are:
+ */
+
+.globl _poweroff16 /* enter real mode */
+.globl _poweroff16_end
+
+.text
+
+/*===========================================================================*/
+/*                             poweroff16                                           */
+/*===========================================================================*/
+/* PUBLIC void poweroff16(); */
+/* Power down system */
+_poweroff16:
+       /* Assume eax is already set to required value of cr0*/
+.byte  0x0F,0x22,0xC0  /* mov %cr0,%eax */
+       jmpf    $0,$(BIOS_POWEROFF_ENTRY + real_mode - _poweroff16)
+real_mode:
+       mov     $((BIOS_POWEROFF_ENTRY >> 4) + 0x200),%ax
+       mov     %ax, %ds
+       mov     %ax, %es
+       mov     %ax, %ss
+       mov     $0x1000, %sp
+
+       xorb    %ah, %ah
+/* Close gate A20 */
+gate_A20:
+       call    kb_wait
+       movb    $0xD1,%al
+       outb    0x64
+       call    kb_wait
+       movb    $0xDD,%al
+       orb             %ah,%al
+       outb    0x60
+       call    kb_wait
+       movb    $0xFF,%al
+       outb    0x64
+       call    kb_wait
+       
+       /* Connect to APM */
+       mov     $0x5301,%ax
+       mov     $0x0,%bx
+       int     0x15
+       
+       /* Enable power management */
+       mov     $0x5308,%ax
+       mov     $0x1,%bx
+       mov     $0x1,%cx
+       int     0x15
+       
+       /* Set power state to off */
+       mov     $0x5307,%ax
+       mov     $0x01,%bx
+       mov     $0x3,%cx
+       int     0x15
+0:     hlt
+       jmp     0b
+       
+kb_wait:
+       inb     0x64
+       testb   $0x02,%al
+       jnz     kb_wait
+       ret
+/*mark the end for copy*/
+_poweroff16_end:
index c37148c30b48b2d7f4bce584cea4d688f7afc8a5..75557e6fdb212005f72a3bf731dc9b52d347c17a 100644 (file)
@@ -6,7 +6,7 @@
  * good environment for main(). 
  *
  * Kernel is entered either because of kernel-calls, ipc-calls, interrupts or
- * exceptions. TSS is set so that the kernel stack is loaded. The user cotext is
+ * exceptions. TSS is set so that the kernel stack is loaded. The user context is
  * saved to the proc table and the handler of the event is called. Once the
  * handler is done, switch_to_user() function is called to pick a new process,
  * finish what needs to be done for the next process to run, sets its context
@@ -52,6 +52,7 @@ begbss:
 #include "kernel/const.h"
 #include "kernel/proc.h"
 #include "sconst.h"
+#include "multiboot.h"
 
 /* Selected 386 tss offsets. */
 #define TSS3_S_SP0     4
@@ -133,11 +134,44 @@ flags:
  */
 .short 0x03FD  
        nop     /* extra byte to sync up disassembler */
-over_flags:
+       
+/* Multiboot header here*/
+
+.balign 8
+
+multiboot_magic:
+       .long MULTIBOOT_HEADER_MAGIC
+multiboot_flags:
+       .long MULTIBOOT_FLAGS
+multiboot_checksum:
+       .long -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_FLAGS)
+multiboot_header_addr:
+       .long (MULTIBOOT_LOAD_ADDRESS + MULTIBOOT_ENTRY_OFFSET + multiboot_magic)
+multiboot_load_addr:
+       .long MULTIBOOT_LOAD_ADDRESS
+multiboot_load_end_addr:
+       .long 0
+multiboot_bss_end_addr:
+       .long 0
+multiboot_entry_addr:
+       .long (MULTIBOOT_LOAD_ADDRESS + MULTIBOOT_ENTRY_OFFSET + multiboot_init)
+/* Video mode */
+multiboot_mode_type:
+       .long MULTIBOOT_VIDEO_MODE_EGA
+multiboot_width:
+       .long MULTIBOOT_CONSOLE_COLS
+multiboot_height:
+       .long MULTIBOOT_CONSOLE_LINES
+multiboot_depth:
+       .long 0
 
+over_flags:
 /* Set up a C stack frame on the monitor stack.  (The monitor sets cs and ds */
 /* right.  The ss descriptor still references the monitor data segment.) */
        movzwl  %sp, %esp       /* monitor stack is a 16 bit stack */
+
+.globl kernel_init
+kernel_init: /* after pre-init*/
        push    %ebp
        mov     %esp, %ebp
        push    %esi
@@ -658,7 +692,6 @@ _reload_cr3:
 .data
 #endif
 .short 0x526F  /* this must be the first data entry (magic #) */
-
 .bss
 /*
  * the kernel stack
diff --git a/kernel/arch/i386/multiboot.S b/kernel/arch/i386/multiboot.S
new file mode 100644 (file)
index 0000000..fc2d945
--- /dev/null
@@ -0,0 +1,117 @@
+#include "kernel/kernel.h" /* configures the kernel */
+#include <minix/config.h>
+#include <minix/const.h>
+#include <minix/com.h>
+#include <machine/interrupt.h>
+#include "archconst.h"
+#include "kernel/const.h"
+#include "kernel/proc.h"
+#include "sconst.h"
+#include "multiboot.h"
+
+#define GDT_SET_ENTRY(selector, base, limit) \
+       mov     %ebp, %edi; \
+       add     $(_gdt + selector), %edi; \
+       mov     base, %eax; \
+       movw %ax, 2(%edi); \
+       shr     $16, %eax; \
+       movb    %al, 4(%edi); \
+       and     $0xff00, %ax; \
+       andw    $0xff, 6(%edi); \
+       or      %ax, 6(%edi); \
+       mov     limit, %eax; \
+       movw    %ax, (%edi); \
+       shr     $16, %eax; \
+       and     $0xf, %ax; \
+       andb    $0xf0, 6(%edi); \
+       or      %ax, 6(%edi); \
+       
+.globl _pre_init
+.globl multiboot_init
+.globl kernel_init
+
+multiboot_init:
+       /* Get size of kernel text */
+       mov     MULTIBOOT_LOAD_ADDRESS + MULTIBOOT_KERNEL_a_text, %ecx
+       
+       /* Get size of kernel text and ceil to 0x1000, and it's the offset
+          of data seg */
+       mov     %ecx, %eax
+       dec     %eax
+       and     $0xfffff000, %eax
+       add     $0x1000, %eax
+
+       /* Calculate and save kernel data base address */
+       mov     $(MULTIBOOT_LOAD_ADDRESS + MULTIBOOT_ENTRY_OFFSET), %ebp
+       add     %eax, %ebp
+       mov     %ebp, _kernel_data_addr(%ebp)
+       
+       /* Init text seg */
+       GDT_SET_ENTRY(CS_SELECTOR, \
+                               $(MULTIBOOT_LOAD_ADDRESS + MULTIBOOT_ENTRY_OFFSET), \
+                               %ecx)
+       
+       /* Init data seg */
+       GDT_SET_ENTRY(DS_SELECTOR, \
+                               %ebp, \
+                               MULTIBOOT_LOAD_ADDRESS + MULTIBOOT_KERNEL_a_total)
+       
+       /* Make up monitor data seg, the same value as DS, different entry */
+       GDT_SET_ENTRY(SS_SELECTOR, \
+                               %ebp, \
+                               MULTIBOOT_LOAD_ADDRESS + MULTIBOOT_KERNEL_a_total)
+       
+       /* Make up monitor text seg, used to return to real mode when poweroff */
+       GDT_SET_ENTRY(MON_CS_SELECTOR, \
+                               $BIOS_POWEROFF_ENTRY, \
+                               $0xffff)
+       
+       mov     $(GDT_SIZE*DESC_SIZE), %eax
+       mov     %ebp, %edi
+       add     $(_gdt + GDT_SELECTOR), %edi
+       mov     %ax, (%edi)
+       mov     %ebp, %eax
+       add     $_gdt, %eax
+       mov     %eax, 2(%edi)
+       lgdt    (%edi)
+       
+       ljmp    $(CS_SELECTOR), $reload_cs
+       
+reload_cs:
+       mov     $DS_SELECTOR, %eax
+       mov     %eax, %ds
+       mov     %eax, %ss
+       mov     %eax, %es
+       
+       mov     $(multiboot_stack + MULTIBOOT_STACK_SIZE), %esp
+
+       push    %ebx
+       call    _pre_init
+       
+       add     $4, %esp
+       
+       /* return to old boot code of kernel */
+       push    %eax
+       push    $MULTIBOOT_PARAM_BUF_SIZE
+       push    $_multiboot_param_buf
+       push    $0
+       
+       mov     $ES_SELECTOR, %eax
+       mov     %eax, %es
+       
+       jmp     kernel_init
+
+.data
+.globl _kernel_data_addr
+_kernel_data_addr:
+.long  0
+.globl _a_out_headers
+_a_out_headers:
+.space NR_BOOT_PROCS * 32 /* is A_MINHDR */
+
+.globl _multiboot_param_buf
+_multiboot_param_buf:
+.space MULTIBOOT_PARAM_BUF_SIZE
+
+multiboot_stack:
+.space MULTIBOOT_STACK_SIZE + 4
diff --git a/kernel/arch/i386/multiboot.h b/kernel/arch/i386/multiboot.h
new file mode 100644 (file)
index 0000000..98e833a
--- /dev/null
@@ -0,0 +1,136 @@
+#ifndef __MULTIBOOT_H__
+#define __MULTIBOOT_H__
+
+#define MULTIBOOT_HEADER_MAGIC 0x1BADB002
+
+#define MULTIBOOT_BOOTLOADER_MAGIC 0x2BADB002
+
+/* Must pass memory information to OS. */
+#define MULTIBOOT_MEMORY_INFO 0x00000002
+
+#define MULTIBOOT_VIDEO_MODE 0x00000004
+
+#define MULTIBOOT_AOUT_KLUDGE 0x00010000
+
+#define MULTIBOOT_FLAGS (MULTIBOOT_MEMORY_INFO | \
+                                               MULTIBOOT_VIDEO_MODE | \
+                                               MULTIBOOT_AOUT_KLUDGE)
+                                               
+/* consts used for Multiboot pre-init */
+
+#define MULTIBOOT_ENTRY_OFFSET 0x200
+
+#define MULTIBOOT_LOAD_ADDRESS 0x200000-MULTIBOOT_ENTRY_OFFSET
+
+#define MULTIBOOT_VIDEO_MODE_EGA 1
+
+#define MULTIBOOT_VIDEO_BUFFER 0xB8000
+
+/* Usable lower memory chunk has a upper bound */
+#define MULTIBOOT_LOWER_MEM_MAX 0x7f800
+
+#define MULTIBOOT_CONSOLE_LINES 25
+#define MULTIBOOT_CONSOLE_COLS 80
+
+
+#define MULTIBOOT_STACK_SIZE 4096
+#define MULTIBOOT_PARAM_BUF_SIZE 1024
+
+#define MULTIBOOT_KERNEL_a_text 0x48
+#define MULTIBOOT_KERNEL_a_data (0x48+4)
+#define MULTIBOOT_KERNEL_a_total (0x48+16)
+
+/* Flags to be set in the â€™flags’ member of the multiboot info structure. */
+
+#define MULTIBOOT_INFO_MEMORY 0x00000001
+
+/* Is there a boot device set? */
+#define MULTIBOOT_INFO_BOOTDEV 0x00000002
+
+/* Is the command-line defined? */
+#define MULTIBOOT_INFO_CMDLINE 0x00000004
+
+/* Are there modules to do something with? */
+#define MULTIBOOT_INFO_MODS 0x00000008
+
+/* get physical address by data pointer*/
+#define PTR2PHY(ptr) (kernel_data_addr+(u32_t)(ptr))
+
+/* get data pointer by physical address*/
+#define PHY2PTR(phy) ((char *)((u32_t)(phy)-kernel_data_addr))
+
+/* Get physical address by function pointer*/
+#define FUNC2PHY(fun) (MULTIBOOT_LOAD_ADDRESS + MULTIBOOT_ENTRY_OFFSET + (u32_t)(fun))
+
+#ifndef __ASSEMBLY__
+
+#include <minix/types.h>
+/* The symbol table for a.out. */
+struct multiboot_aout_symbol_table
+{
+       u32_t tabsize;
+       u32_t strsize;
+       u32_t addr;
+       u32_t reserved;
+};
+/* The section header table for ELF. */
+struct multiboot_elf_section_header_table
+{
+       u32_t num;
+       u32_t size;
+       u32_t addr;
+       u32_t shndx;
+};
+
+typedef struct multiboot_elf_section_header_table multiboot_elf_section_header_table_t;
+typedef struct multiboot_aout_symbol_table multiboot_aout_symbol_table_t;
+
+struct multiboot_info
+{
+       /* Multiboot info version number */
+       u32_t flags;
+       /* Available memory from BIOS */
+       u32_t mem_lower;
+       u32_t mem_upper;
+       /* "root" partition */
+       u32_t boot_device;
+       /* Kernel command line */
+       u32_t cmdline;
+       /* Boot-Module list */
+       u32_t mods_count;
+       u32_t mods_addr;
+       union
+       {
+               multiboot_aout_symbol_table_t aout_sym;
+               multiboot_elf_section_header_table_t elf_sec;
+       } u;
+       /* Memory Mapping buffer */
+       u32_t mmap_length;
+       u32_t mmap_addr;
+       /* Drive Info buffer */
+       u32_t drives_length;
+       u32_t drives_addr;
+       /* ROM configuration table */
+       u32_t config_table;
+       /* Boot Loader Name */
+       u32_t boot_loader_name;
+       /* APM table */
+       u32_t apm_table;
+       /* Video */
+       u32_t vbe_control_info;
+       u32_t vbe_mode_info;
+       u16_t vbe_mode;
+       u16_t vbe_interface_seg;
+       u16_t vbe_interface_off;
+       u16_t vbe_interface_len;
+};
+typedef struct multiboot_info multiboot_info_t;
+
+/* Buffer for multiboot parameters */
+extern char multiboot_param_buf[];
+
+/* Physical address of kernel data segment */
+extern phys_bytes kernel_data_addr;
+
+#endif /* __ASSEMBLY__ */
+#endif /* __MULTIBOOT_H__ */
diff --git a/kernel/arch/i386/pre_init.c b/kernel/arch/i386/pre_init.c
new file mode 100644 (file)
index 0000000..771f691
--- /dev/null
@@ -0,0 +1,415 @@
+#include "kernel/kernel.h"
+#include <minix/minlib.h>
+#include <minix/const.h>
+/*
+ * == IMPORTANT == 
+ * Routines in this file can not use any variable in kernel BSS, 
+ * since before image is extracted, no BSS is allocated. 
+ * So pay attention to any external call (including library call).
+ * 
+ * */
+#include <minix/types.h>
+#include <minix/type.h>
+#include <minix/com.h>
+#include <minix/a.out.h>
+#include <machine/partition.h>
+#include "../../../boot/image.h"
+#include "string.h"
+#include "proto.h"
+#include "multiboot.h"
+
+/* Granularity used in image file and copying */
+#define GRAN 512
+#define SECT_CEIL(x) ((((x) - 1) / GRAN + 1) * GRAN)
+
+/* String length used for mb_itoa */
+#define ITOA_BUFFER_SIZE 20
+
+/* The a.out headers to pass to kernel. 
+ * Not using struct exec because only using short form */
+extern char a_out_headers[];
+
+#define mb_load_phymem(buf, phy, len) \
+               phys_copy((phy), PTR2PHY(buf), (len))
+
+#define mb_save_phymem(buf, phy, len) \
+               phys_copy(PTR2PHY(buf), (phy), (len))
+
+PRIVATE void mb_phys_move(u32_t src, u32_t dest, u32_t len) 
+{
+       char data[GRAN + 1];
+       int i;
+       /* Move upward (start moving from tail), block by block 
+       * len should be aligned to GRAN 
+       */
+       if (len % GRAN) {
+               mb_print("fatal: not aligned phys move");
+               /* Spin here */
+               while (1)
+                       ;
+       }
+
+       len /= GRAN;
+       for (i = len - 1; i >= 0; i--) {
+               mb_load_phymem(data, src + i * GRAN, GRAN);
+               mb_save_phymem(data, dest + i * GRAN, GRAN);
+       }
+}
+
+PRIVATE void mb_itoa(u32_t val, char * out) 
+{
+       char ret[ITOA_BUFFER_SIZE];
+       int i = ITOA_BUFFER_SIZE - 2;
+       /* Although there's a library version of itoa(int n), 
+       * we can't use it since that implementation relies on BSS segment
+       */
+       ret[ITOA_BUFFER_SIZE - 2] = '0';
+       if (val) {
+               for (; i >= 0; i--) {
+                       char c;
+                       if (val == 0) break;
+                       c = val % 10;
+                       val = val / 10;
+                               c += '0';
+                       ret[i] = c;
+               }
+       }
+       else
+               i--;
+       ret[ITOA_BUFFER_SIZE - 1] = 0;
+       strcpy(out, ret + i + 1);
+}
+
+PRIVATE void mb_itox(u32_t val, char *out) 
+{
+       char ret[9];
+       int i = 7;
+       /* Convert a number to hex string */
+       ret[7] = '0';
+       if (val) {
+               for (; i >= 0; i--) {
+                       char c;
+                       if (val == 0) break;
+                       c = val & 0xF;
+                       val = val >> 4;
+                       if (c > 9)
+                               c += 'A' - 10;
+                       else
+                               c += '0';
+                       ret[i] = c;
+               }       
+       }
+       else
+               i--;
+       ret[8] = 0;
+       strcpy(out, ret + i + 1);
+}
+
+PRIVATE void mb_put_char(char c, int line, int col) 
+{
+       /* Write a char to vga display buffer. */
+       if (line<MULTIBOOT_CONSOLE_LINES&&col<MULTIBOOT_CONSOLE_COLS)
+               mb_save_phymem(
+                       &c, 
+                       MULTIBOOT_VIDEO_BUFFER 
+                               + line * MULTIBOOT_CONSOLE_COLS * 2 
+                               + col * 2, 
+                       1);
+}
+
+PRIVATE char mb_get_char(int line, int col) 
+{
+       char c;
+       /* Read a char to from display buffer. */
+       if (line < MULTIBOOT_CONSOLE_LINES && col < MULTIBOOT_CONSOLE_COLS)
+               mb_load_phymem(
+                       &c, 
+                       MULTIBOOT_VIDEO_BUFFER 
+                       + line * MULTIBOOT_CONSOLE_COLS * 2 
+                       + col * 2, 
+                       1);
+       return c;
+}
+
+/* Give non-zero values to avoid them in BSS */
+PRIVATE int print_line = 1, print_col = 1;
+       
+PRIVATE void mb_cls(void) 
+{
+       int i, j;
+       /* Clear screen */
+       for (i = 0; i < MULTIBOOT_CONSOLE_LINES; i++ )
+               for (j = 0; j < MULTIBOOT_CONSOLE_COLS; j++ )
+                       mb_put_char(0, i, j);
+       print_line = print_col = 0;
+}
+
+PRIVATE void mb_scroll_up(int lines) 
+{
+       int i, j;
+       for (i = 0; i < MULTIBOOT_CONSOLE_LINES - lines; i++ ) {
+               for (j = 0; j < MULTIBOOT_CONSOLE_COLS; j++ )
+                       mb_put_char(mb_get_char(i + lines, j), i, j);
+       }
+       print_line-= lines;
+}
+
+PRIVATE void mb_print(char *str) 
+{
+       while (*str) {
+               if (*str == '\n') {
+                       str++;
+                       print_line++;
+                       print_col = 0;
+                       continue;
+               }
+               mb_put_char(*str++, print_line, print_col++);
+               if (print_col >= MULTIBOOT_CONSOLE_COLS) {
+                       print_line++;
+                       print_col = 0;
+               }
+               while (print_line >= MULTIBOOT_CONSOLE_LINES)
+                       mb_scroll_up(1);
+       }
+}
+
+PRIVATE void mb_print_hex(u32_t value) 
+{
+       int i;
+       char c;
+       char out[9] = "00000000";
+       /* Print a hex value */
+       for (i = 7; i >= 0; i--) {
+               c = value % 0x10;
+               value /= 0x10;
+               if (c < 10) 
+                       c += '0';
+               else
+                       c += 'A'-10;
+               out[i] = c;
+       }
+       mb_print(out);
+}
+
+PRIVATE int mb_set_param(char *name, char *value) 
+{
+       char *p = multiboot_param_buf;
+       char *q;
+       int namelen = strlen(name);
+       int valuelen = strlen(value);
+       
+       /* Delete the item if already exists */
+       while (*p) {
+               if (strncmp(p, name, namelen) == 0 && p[namelen] == '=') {
+                       q = p;
+                       while (*q) q++;
+                       for (q++; 
+                               q < multiboot_param_buf + MULTIBOOT_PARAM_BUF_SIZE; 
+                               q++, p++)
+                               *p = *q;
+                       break;
+               }
+               while (*p++)
+                       ;
+               p++;
+       }
+       
+       for (p = multiboot_param_buf;
+               p < multiboot_param_buf + MULTIBOOT_PARAM_BUF_SIZE 
+                       && (*p || *(p + 1));
+               p++)
+               ;
+       if (p > multiboot_param_buf) p++;
+       
+       /* Make sure there's enough space for the new parameter */
+       if (p + namelen + valuelen + 3 
+               > multiboot_param_buf + MULTIBOOT_PARAM_BUF_SIZE)
+               return -1;
+       
+       strcpy(p, name);
+       p[namelen] = '=';
+       strcpy(p + namelen + 1, value);
+       p[namelen + valuelen + 1] = 0;
+       p[namelen + valuelen + 2] = 0;
+       return 0;
+}
+
+PRIVATE void get_parameters(multiboot_info_t *mbi) 
+{
+       char mem_value[40], temp[ITOA_BUFFER_SIZE];
+       int i, r, processor;
+       int dev;
+       int ctrlr;
+       int disk, prim, sub;
+       int var_i,value_i;
+       char *p;
+       const static int dev_cNd0[] = { 0x0300, 0x0800, 0x0A00, 0x0C00, 0x1000 };
+       static char mb_cmd_buff[GRAN] = "add some value to avoid me in BSS";
+       static char var[GRAN] = "add some value to avoid me in BSS";
+       static char value[GRAN] = "add some value to avoid me in BSS";
+       for (i = 0; i < MULTIBOOT_PARAM_BUF_SIZE; i++)
+               multiboot_param_buf[i] = 0;
+       
+       if (mbi->flags & MULTIBOOT_INFO_BOOTDEV) {
+               sub = 0xff;
+               disk = ((mbi->boot_device&0xff000000) >> 24)-0x80;
+               prim = (mbi->boot_device&0xff0000) == 0xff0000 ? 
+                       0 : (mbi->boot_device & 0xff0000) >> 16;
+               ctrlr = 0;
+               dev = dev_cNd0[ctrlr];
+               /* Determine the value of rootdev */
+               if ((mbi->boot_device & 0xff00) == 0xff00) {
+                       dev += disk * (NR_PARTITIONS + 1) + (prim + 1);
+               } else {
+                       sub = (mbi->boot_device & 0xff00) >> 8;
+                       dev += 0x80
+                                + (disk * NR_PARTITIONS + prim) * NR_PARTITIONS 
+                                + sub;
+               }
+               mb_itoa(dev, temp);
+               mb_set_param("rootdev", temp);
+               mb_set_param("ramimagedev", temp);
+       }
+       mb_set_param("ramsize", "0");
+       mb_set_param("hz", "60");
+       processor = getprocessor();
+       if (processor == 1586) processor = 686;
+       mb_itoa(processor, temp);
+       mb_set_param("processor", temp);
+       mb_set_param("bus", "at");
+       mb_set_param("video", "ega");
+       mb_set_param("chrome", "color");
+       
+       if (mbi->flags & MULTIBOOT_INFO_MEMORY)
+       {
+               strcpy(mem_value, "800:");
+               mb_itox(
+                       mbi->mem_lower * 1024 > MULTIBOOT_LOWER_MEM_MAX ? 
+                               MULTIBOOT_LOWER_MEM_MAX : mbi->mem_lower * 1024, 
+                       temp);
+               strcat(mem_value, temp);
+               strcat(mem_value, ",100000:");
+               mb_itox(mbi->mem_upper * 1024, temp);
+               strcat(mem_value, temp);
+               mb_set_param("memory", mem_value);
+       }
+       
+       /* FIXME: this is dummy value, 
+        * we can't get real image file name from multiboot */
+       mb_set_param("image", "boot/image_latest");
+       
+       if (mbi->flags&MULTIBOOT_INFO_CMDLINE) {
+               /* Override values with cmdline argument */
+               p = mb_cmd_buff;
+               mb_load_phymem(mb_cmd_buff, mbi->cmdline, GRAN);
+               while (*p) {
+                       var_i = 0;
+                       value_i = 0;
+                       while (*p == ' ') p++;
+                       if (!*p) break;
+                       while (*p && *p != '=' && var_i < GRAN - 1) 
+                               var[var_i++] = *p++ ;
+                       var[var_i] = 0;
+                       p++; /* skip '=' */
+                       while (*p && *p != ' ' && value_i < GRAN - 1) 
+                               value[value_i++] = *p++ ;
+                       value[value_i] = 0;
+                       
+                       mb_set_param(var, value);
+               }
+       }
+}
+
+PRIVATE void mb_extract_image(void)
+{
+       int i;
+       u32_t text_addr[NR_BOOT_PROCS];
+       u32_t imghdr_addr = MULTIBOOT_LOAD_ADDRESS;
+       int off_sum = 0;
+       struct exec *aout_hdr;
+       int empty, clear_size, j;
+       u32_t p;
+       /* Extract the image to align segments and clear up BSS 
+        */
+       for (i = 0; i < LAST_SPECIAL_PROC_NR + 2; i++) {
+               aout_hdr = (struct exec *) (a_out_headers + A_MINHDR * i);
+               mb_load_phymem(aout_hdr, imghdr_addr + IM_NAME_MAX + 1, A_MINHDR);
+               text_addr[i] = imghdr_addr + GRAN;
+               if (aout_hdr->a_flags & A_SEP) {
+                       off_sum += CLICK_CEIL(aout_hdr->a_total)
+                                       - SECT_CEIL(aout_hdr->a_data)
+                                       + CLICK_CEIL(aout_hdr->a_text)
+                                       - SECT_CEIL(aout_hdr->a_text)
+                                       - GRAN;
+                       imghdr_addr += SECT_CEIL(aout_hdr->a_text)
+                                       + SECT_CEIL(aout_hdr->a_data)
+                                       + GRAN;
+               } else {
+                       off_sum += CLICK_CEIL(aout_hdr->a_total) 
+                                       - SECT_CEIL(aout_hdr->a_data + aout_hdr->a_text)
+                                       - GRAN;
+                       imghdr_addr += SECT_CEIL(aout_hdr->a_text + aout_hdr->a_data)
+                                       + GRAN;
+               }
+       }
+       for (i = LAST_SPECIAL_PROC_NR + 1; i >= 0;i--) {
+               struct exec * aout_hdr = (struct exec *) (a_out_headers + A_MINHDR * i);
+               if (aout_hdr->a_flags & A_SEP)
+                       off_sum -= CLICK_CEIL(aout_hdr->a_total) 
+                                       - SECT_CEIL(aout_hdr->a_data)
+                                       + CLICK_CEIL(aout_hdr->a_text)
+                                       - SECT_CEIL(aout_hdr->a_text)
+                                       - GRAN;
+               else
+                       off_sum -= CLICK_CEIL(aout_hdr->a_total) 
+                                       - SECT_CEIL(aout_hdr->a_data + aout_hdr->a_text)
+                                       - GRAN;
+               if (i > 0) { /* if not kernel */
+                       if (aout_hdr->a_flags & A_SEP)  {
+                               mb_phys_move(text_addr[i], text_addr[i] + off_sum, 
+                                       SECT_CEIL(aout_hdr->a_text));
+                               mb_phys_move(text_addr[i] + SECT_CEIL(aout_hdr->a_text), 
+                                       text_addr[i] + off_sum + CLICK_CEIL(aout_hdr->a_text), 
+                                       SECT_CEIL(aout_hdr->a_data));
+                       } else {
+                               mb_phys_move(text_addr[i], text_addr[i] + off_sum, 
+                                       SECT_CEIL(aout_hdr->a_text + aout_hdr->a_data));
+                       }
+               }
+               aout_hdr->a_syms = text_addr[i] + off_sum;
+               
+               /* Clear out for expanded text, BSS and stack */
+               empty = 0;
+               if (aout_hdr->a_flags & A_SEP) {
+                       p = text_addr[i] + off_sum
+                               + CLICK_CEIL(aout_hdr->a_text) 
+                               + aout_hdr->a_data;
+                       clear_size = CLICK_CEIL(aout_hdr->a_total) - aout_hdr->a_data;
+               } else {
+                       p = text_addr[i] + off_sum
+                               + aout_hdr->a_text
+                               + aout_hdr->a_data;
+                       clear_size = CLICK_CEIL(aout_hdr->a_total) 
+                               - aout_hdr->a_data
+                               - aout_hdr->a_text;
+               }
+               /* FIXME: use faster function */
+               for (j = 0; j < clear_size; j++)
+                       mb_save_phymem(&empty, p + j, 1);
+       }
+}
+
+PUBLIC u32_t pre_init(u32_t ebx)
+{
+       multiboot_info_t mbi;
+       /* Do pre-initialization for multiboot, returning physical address of
+       * a_out_headers 
+       */
+       mb_cls();
+       mb_print("\nMINIX booting... ");
+       mb_load_phymem(&mbi, ebx, sizeof(mbi));
+       get_parameters(&mbi);
+       mb_print("\nLoading image... ");
+       mb_extract_image();
+       return PTR2PHY(a_out_headers);
+}
index c638e1e16f56e0c3e40d7788d181fa3066504b76..da9f0fa54fc2e0387f2c802d36af051f63bf4122 100644 (file)
@@ -25,7 +25,16 @@ struct gatedesc_s {
   u16_t offset_high;
 };
 
-PUBLIC struct segdesc_s gdt[GDT_SIZE];         /* used in klib.s and mpx.s */
+PUBLIC struct segdesc_s gdt[GDT_SIZE]=         /* used in klib.s and mpx.s */
+{      {0},
+       {0,0,0,0},                              /* GDT descriptor */
+       {0,0,0,0},                              /* IDT descriptor */
+       {0xffff,0,0,0x92,0x4f,0},       /* kernel DS */
+       {0xffff,0,0,0x92,0xcf,0},       /* kernel ES (386: flag 4 Gb at startup) */
+       {0xffff,0,0,0x92,0x4f,0},       /* kernel SS (386: monitor SS at startup) */
+       {0xffff,0,0,0x9a,0x4f,0},       /* kernel CS */
+       {0xffff,0,0,0x9a,0x0f,0},       /* temp for BIOS (386: monitor CS at startup) */
+};
 PRIVATE struct gatedesc_s idt[IDT_SIZE];       /* zero-init so none present */
 PUBLIC struct tss_s tss;                       /* zero init */
 
index 4f71d7c94c8a1d4188b342d078ed4141c4f6a429..4ea0f5a3a8174d2d51ad0c9797fbe51059022f2d 100644 (file)
@@ -171,6 +171,7 @@ _PROTOTYPE( void arch_init, (void)                                     );
 _PROTOTYPE( void ser_putc, (char)                                              );
 _PROTOTYPE( __dead void arch_shutdown, (int)                           );
 _PROTOTYPE( __dead void arch_monitor, (void)                           );
+_PROTOTYPE( void arch_bios_poweroff, (void)                                    );
 _PROTOTYPE( void arch_get_aout_headers, (int i, struct exec *h)                );
 _PROTOTYPE( void restore_user_context, (struct proc * p)                );
 _PROTOTYPE( void read_tsc, (unsigned long *high, unsigned long *low)    );
index 5c5dca4e6556da1c79ca7f54a6be527a9cd118e7..ff40cc5d94d6e14919fb771f964fef71daeaaaac 100644 (file)
@@ -4,7 +4,7 @@ u=/usr
 MDEC=  /usr/mdec
 
 # Specify the programs that are part of the system image.
-PROGRAMS=      ../kernel/kernel \
+PROGRAMS=      kernel \
        ../servers/ds/ds \
        ../servers/rs/rs \
        ../servers/pm/pm \
@@ -42,7 +42,17 @@ usage:
 
 all: services image
 
+# for fast complie kernel and generate image, skip servers and drivers
+image_mb: includes
+       cd ../kernel && $(MAKE)
+       padtext ../kernel/kernel kernel
+       installboot -image $@ $(PROGRAMS)
+       
 image:  includes services
+       cd ../kernel && $(MAKE)
+       cd ../servers && $(MAKE) all
+       cd ../drivers && $(MAKE) all
+       padtext ../kernel/kernel kernel
        installboot -image $@ $(PROGRAMS)
 
 # rebuild the program or system libraries
@@ -79,7 +89,7 @@ clean:
        $(MAKE) -C ../kernel $@
        $(MAKE) -C ../servers $@
        $(MAKE) -C ../drivers $@
-       rm -rf *.bak image *.iso *.iso.gz cdfdimage rootimage src
+       rm -rf *.bak image kernel *.iso *.iso.gz cdfdimage rootimage src
 
 cleandepend::
        $(MAKE) -C ../kernel $@
index 547422df1bd498eb20615354229a1350de26aae4..b877fbbf556c459e01e76666d4f9e0d97d7d0a01 100755 (executable)
@@ -109,6 +109,14 @@ hdboot)
        echo "install image $root:/boot/image/$target"
        install -o root -m 600 image $rootdir/boot/image/$target || exit
 
+       # Tell GRUB which image is newest
+       image_latest="`ls -t $rootdir/boot/image | head -n 1`"
+       if [ -f "$rootdir/boot/image/$image_latest" ]
+       then image_latest="/boot/image/$image_latest"
+       else image_latest=/boot/image_big
+       fi
+       ln -f $image_latest $rootdir/boot/image_latest
+
        # Save the revision number.
        test "$revision" != "$oldrev" && echo $revision >revision