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
This commit is contained in:
parent
9212eab21f
commit
df0ba02a38
13 changed files with 904 additions and 8 deletions
|
@ -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}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
|
78
kernel/arch/i386/klib16.S
Normal file
78
kernel/arch/i386/klib16.S
Normal file
|
@ -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:
|
|
@ -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
|
||||
|
|
117
kernel/arch/i386/multiboot.S
Normal file
117
kernel/arch/i386/multiboot.S
Normal file
|
@ -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
|
136
kernel/arch/i386/multiboot.h
Normal file
136
kernel/arch/i386/multiboot.h
Normal file
|
@ -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__ */
|
415
kernel/arch/i386/pre_init.c
Normal file
415
kernel/arch/i386/pre_init.c
Normal file
|
@ -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);
|
||||
}
|
|
@ -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 */
|
||||
|
||||
|
|
|
@ -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) );
|
||||
|
|
|
@ -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 $@
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
Loading…
Reference in a new issue