From df0ba02a3834a07980f164f444da3e29f443c304 Mon Sep 17 00:00:00 2001 From: Erik van der Kouwe Date: Fri, 23 Jul 2010 14:24:34 +0000 Subject: [PATCH] Multiboot support (contributed by Feiran "Fam" Zheng); 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 --- kernel/arch/i386/Makefile.inc | 12 +- kernel/arch/i386/arch_system.c | 25 +- kernel/arch/i386/include/archconst.h | 3 + kernel/arch/i386/klib.S | 53 ++++ kernel/arch/i386/klib16.S | 78 +++++ kernel/arch/i386/mpx.S | 39 ++- kernel/arch/i386/multiboot.S | 117 ++++++++ kernel/arch/i386/multiboot.h | 136 +++++++++ kernel/arch/i386/pre_init.c | 415 +++++++++++++++++++++++++++ kernel/arch/i386/protect.c | 11 +- kernel/proto.h | 1 + tools/Makefile | 14 +- tools/mkboot | 8 + 13 files changed, 904 insertions(+), 8 deletions(-) create mode 100644 kernel/arch/i386/klib16.S create mode 100644 kernel/arch/i386/multiboot.S create mode 100644 kernel/arch/i386/multiboot.h create mode 100644 kernel/arch/i386/pre_init.c diff --git a/kernel/arch/i386/Makefile.inc b/kernel/arch/i386/Makefile.inc index f1ebb14ef..bf8b79daf 100644 --- a/kernel/arch/i386/Makefile.inc +++ b/kernel/arch/i386/Makefile.inc @@ -1,3 +1,4 @@ + # Makefile for arch-dependent kernel code .include @@ -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} diff --git a/kernel/arch/i386/arch_system.c b/kernel/arch/i386/arch_system.c index bfbe5a2ab..c0e87dc91 100644 --- a/kernel/arch/i386/arch_system.c +++ b/kernel/arch/i386/arch_system.c @@ -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. diff --git a/kernel/arch/i386/include/archconst.h b/kernel/arch/i386/include/archconst.h index 3411845f2..ad38d37b3 100644 --- a/kernel/arch/i386/include/archconst.h +++ b/kernel/arch/i386/include/archconst.h @@ -153,4 +153,7 @@ /* 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 */ diff --git a/kernel/arch/i386/klib.S b/kernel/arch/i386/klib.S index 4d99dd782..a1cfc4267 100644 --- a/kernel/arch/i386/klib.S +++ b/kernel/arch/i386/klib.S @@ -4,9 +4,11 @@ #include #include #include +#include #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 index 000000000..57c2ea2bf --- /dev/null +++ b/kernel/arch/i386/klib16.S @@ -0,0 +1,78 @@ +/* sections */ + + +#include +#include +#include +#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: diff --git a/kernel/arch/i386/mpx.S b/kernel/arch/i386/mpx.S index c37148c30..75557e6fd 100644 --- a/kernel/arch/i386/mpx.S +++ b/kernel/arch/i386/mpx.S @@ -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 index 000000000..fc2d94534 --- /dev/null +++ b/kernel/arch/i386/multiboot.S @@ -0,0 +1,117 @@ +#include "kernel/kernel.h" /* configures the kernel */ +#include +#include +#include +#include +#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 index 000000000..98e833a8e --- /dev/null +++ b/kernel/arch/i386/multiboot.h @@ -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 +/* 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 index 000000000..771f6916d --- /dev/null +++ b/kernel/arch/i386/pre_init.c @@ -0,0 +1,415 @@ +#include "kernel/kernel.h" +#include +#include +/* + * == 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 +#include +#include +#include +#include +#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_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); +} diff --git a/kernel/arch/i386/protect.c b/kernel/arch/i386/protect.c index c638e1e16..da9f0fa54 100644 --- a/kernel/arch/i386/protect.c +++ b/kernel/arch/i386/protect.c @@ -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 */ diff --git a/kernel/proto.h b/kernel/proto.h index 4f71d7c94..4ea0f5a3a 100644 --- a/kernel/proto.h +++ b/kernel/proto.h @@ -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) ); diff --git a/tools/Makefile b/tools/Makefile index 5c5dca4e6..ff40cc5d9 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -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 $@ diff --git a/tools/mkboot b/tools/mkboot index 547422df1..b877fbbf5 100755 --- a/tools/mkboot +++ b/tools/mkboot @@ -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 -- 2.44.0