Multiboot规范(2)

4.      例子

警告:以下内容不是该规范文档的一部分,但为了未来的操作系统及启动载入器作者,而包括进来。

4.1        PC注意事项

考虑在Multiboot信息结构体中‘flags’参数的第0位,如果讨论中的启动载入器使用旧的BIOS接口,或最新的不可用(参考关于第6位的描述),那么可能报告一个15或63M的内存最大值。强烈建议启动载入器执行一个详细的内存探测。

至于在Multiboot信息结构体中‘flags’参数的第1位,它顶多被识别为,在一个操作系统上,确定哪个BIOS设备映射到哪个设备驱动不是无关紧要的。对各种操作系统,许多拼凑的处理已经被使用,而不是解决这个问题,它们中的绝大多数在许多条件下会崩溃。为了鼓励这个问题的通用的解决方案,有两种BIOS设备映射技术(参考4.2节【BIOS设备映射技术】,12页)。

考虑在Multiboot信息结构体中‘flags’参数的第6位,重要的是注意到在这里使用的数据结构(由‘BaseAddrLow’开始)是由INT 15h, AX=E820h — 查询系统地址映射(Query System Address Map)调用返回的数据。更多信息参考GRUB手册的“查询系统地址映射”一节。这里的接口是为了允许一个启动载入器,不需要修改就可以与BIOS接口的合理扩展一起工作,根据需要传递任何由操作系统解释的额外数据。

4.2        BIOS设备映射技术

这两个技术应该可以用于任何PC操作系统,而且都不要求驱动本身提供特殊支持。本节将被展开为详细的解释,特别对于I/O限制技术(restriction technique)。

通用的规则是,数据比较技术是快速、肮脏的解决方案。在绝大多数时间,它能够工作,但不能覆盖所有的基点,而且相对简单。

I/O限制技术要复杂得多,但它有在所有条件下解决这个问题的潜力,再加上,当剩下的BIOS设备不都是有操作系统驱动时,也允许访问它们。

15.1.1.     数据比较技术

在激活任意设备驱动之前,在可以被唯一识别的每个硬盘上,从相似的扇区收集足够数据。

在激活该设备驱动之后,比较来自使用操作系统驱动的设备的数据。有希望足够提供这样的一个映射。

问题:

1.     某些BIOS设备上的数据可能是相同的(因此从BIOS读入驱动的部分应该有放弃的机制)。

2.     可能有从BIOS无法访问的额外设备,它与该BIOS使用的某些设备相同(因此也应该能在这种情形下放弃)。

15.1.2.     I/O限制技术

这个第一步可能不是必要的,但首先为写入PC ram的设备驱动构建写时拷贝(copy-on-write)映射。为随后构建的BIOS虚拟机保留原始拷贝。

对于每个在线的设备驱动,确定哪个BIOS设备变成不可访问,通过:

1.     构建一个干净的BIOS虚拟机。

2.     把由这个设备驱动所要求的I/O区域的I/O许可映射设置为不许可(不能读写)。

3.     访问每个设备

4.     记录哪个设备成功了,哪些尝试访问受限I/O区域(足够幸运的话,这将是一个xor的情形)。

对于每个设备驱动, 给定由它归纳的BIOS设备(在这个列表中不应该有缺失),应该很容易确定在控制器上有哪些设备。

通常,给定BIOS号,从每个控制器你至少有2个硬盘,它们几乎总是从控制器上逻辑号最低的设备算起。

4.3        OS代码的例子

在这个发布版本中,包括了Multiboot内核‘kernel’。这个内核只是在屏幕上打印出Multiboot信息结构体,因此你可以使用这个内核来测试一个Multiboot兼容的驱动载入器,并作为如何实现一个Multiboot内核的参考。在Multiboot源代码发布版的‘doc’目录下可以找到源代码。

内核‘kernel’仅包含了3个文件:‘boot.S’,‘kernel.c’及‘multiboot.h’。汇编源代码‘boot.S’以GAS(参考在The GNU assembler中的“GNU assembler”)写就,并包含了Multiboot信息结构体来遵循规范。当一个Multiboot兼容的驱动载入器载入并执行它时,它初始化栈指针及EFLAGS,然后调用在‘kernel.c’中定义的函数cmain。如果cmain返回到这个被调用者,它显示一个消息来通知用户它的停止状态,并永久停止,直到你按下reset键。文件‘kernel.c’包含函数cmain,它检查由启动载入器传入的魔数是否有效等等,及某些在屏幕上打印消息的函数。文件‘multiboot.h’定义了一些宏,比如用于Multiboot头的魔数,Multiboot头结构体及Multiboot信息结构体。

4.3.1.     multiboot.h

这是在‘multiboot.h’中的源代码:

/*multiboot.h - Multiboot header file. */

/*Copyright (C) 1999,2003,2007,2008,2009 Free Software Foundation, Inc.

*

*Permission is hereby granted, free of charge, to any person obtaining a copy

* ofthis software and associated documentation files (the "Software"), to

*deal in the Software without restriction, including without limitation the

*rights to use, copy, modify, merge, publish, distribute, sublicense, and/or

*sell copies of the Software, and to permit persons to whom the Software is

*furnished to do so, subject to the following conditions:

*

*The above copyright notice and this permission notice shall be included in

*all copies or substantial portions of the Software.

*

* THE SOFTWARE IS PROVIDED "AS IS", WITHOUTWARRANTY OFANY KIND, EXPRESS OR

* IMPLIED, INCLUDING BUT NOT LIMITED TO THEWARRANTIES OFMERCHANTABILITY,

* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NOEVENT SHALL ANY

* DEVELOPER OR DISTRIBUTOR BE LIABLE FOR ANY CLAIM, DAMAGES OROTHER LIABILITY,

* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,OUT OF OR

* IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS INTHE SOFTWARE.

*/

#ifndef MULTIBOOT_HEADER

#define MULTIBOOT_HEADER 1

/*How many bytes from the start of the file we search for the header. */

#define MULTIBOOT_SEARCH 8192

/*The magic field should contain this. */

#define MULTIBOOT_HEADER_MAGIC0x1BADB002

/*This should be in %eax. */

#define MULTIBOOT_BOOTLOADER_MAGIC0x2BADB002

/*The bits in the required part of flags field we don’t support. */

#define MULTIBOOT_UNSUPPORTED0x0000fffc

/*Alignment of multiboot modules. */

#define MULTIBOOT_MOD_ALIGN 0x00001000

/*Alignment of the multiboot info structure. */

#define MULTIBOOT_INFO_ALIGN0x00000004

/* Flagsset in the ‘flags’ member of the multiboot header. */

/*Align all boot modules on i386 page (4KB) boundaries. */

#define MULTIBOOT_PAGE_ALIGN0x00000001

/*Must pass memory information to OS. */

#define MULTIBOOT_MEMORY_INFO0x00000002

/*Must pass video information to OS. */

#define MULTIBOOT_VIDEO_MODE0x00000004

/*This flag indicates the use of the address fields in the header. */

#define MULTIBOOT_AOUT_KLUDGE0x00010000

/*Flags to be set in the ‘flags’ member of the multiboot info structure. */

/*is there basic lower/upper memory information? */

#define MULTIBOOT_INFO_MEMORY0x00000001

/*is there a boot device set? */

#define MULTIBOOT_INFO_BOOTDEV0x00000002

/*is the command-line defined? */

#define MULTIBOOT_INFO_CMDLINE0x00000004

/*are there modules to do something with? */

#define MULTIBOOT_INFO_MODS 0x00000008

/*These next two are mutually exclusive */

/*is there a symbol table loaded? */

#define MULTIBOOT_INFO_AOUT_SYMS0x00000010

/*is there an ELF section header table? */

#define MULTIBOOT_INFO_ELF_SHDR0X00000020

/*is there a full memory map? */

#define MULTIBOOT_INFO_MEM_MAP0x00000040

/*Is there drive info? */

#define MULTIBOOT_INFO_DRIVE_INFO0x00000080

/*Is there a config table? */

#define MULTIBOOT_INFO_CONFIG_TABLE0x00000100

/*Is there a boot loader name? */

#defineMULTIBOOT_INFO_BOOT_LOADER_NAME 0x00000200

/*Is there a APM table? */

#define MULTIBOOT_INFO_APM_TABLE0x00000400

/*Is there video information? */

#define MULTIBOOT_INFO_VIDEO_INFO0x00000800

#ifndef ASM_FILE

 

typedef unsigned shortmultiboot_uint16_t;

typedef unsigned intmultiboot_uint32_t;

typedef unsigned long longmultiboot_uint64_t;

 

struct multiboot_header

{

    /* Must be MULTIBOOT MAGIC - see above. */

    multiboot_uint32_t magic;

    /* Feature flags. */

    multiboot_uint32_t flags;

    /* The above fields plus this one must equal 0 mod 2^32. */

    multiboot_uint32_t checksum;

    /* These are only valid if MULTIBOOT AOUT KLUDGE is set. */

    multiboot_uint32_t header_addr;

    multiboot_uint32_t load_addr;

    multiboot_uint32_t load_end_addr;

    multiboot_uint32_t bss_end_addr;

    multiboot_uint32_t entry_addr;

    /* These are only valid if MULTIBOOT VIDEO MODE is set. */

    multiboot_uint32_t mode_type;

    multiboot_uint32_t width;

    multiboot_uint32_t height;

    multiboot_uint32_t depth;

};

/*The symbol table for a.out. */

struct multiboot_aout_symbol_table

{

    multiboot_uint32_t tabsize;

    multiboot_uint32_t strsize;

    multiboot_uint32_t addr;

    multiboot_uint32_t reserved;

};

typedefstructmultiboot_aout_symbol_table multiboot_aout_symbol_table_t;

 

/*The section header table for ELF. */

structmultiboot_elf_section_header_table

{

    multiboot_uint32_t num;

    multiboot_uint32_t size;

    multiboot_uint32_t addr;

    multiboot_uint32_t shndx;

};

typedefstructmultiboot_elf_section_header_table multiboot_elf_section_header_table_t;

 

struct multiboot_info

{

    /* Multiboot info version number */

    multiboot_uint32_t flags;

    /* Available memory from BIOS */

    multiboot_uint32_t mem_lower;

    multiboot_uint32_t mem_upper;

    /* "root" partition */

    multiboot_uint32_t boot_device;

    /* Kernel command line */

    multiboot_uint32_t cmdline;

    /* Boot-Module list */

    multiboot_uint32_t mods_count;

    multiboot_uint32_t mods_addr;

    union

    {

        multiboot_aout_symbol_table_t aout_sym;

        multiboot_elf_section_header_table_telf_sec;

    } u;

    /* Memory Mapping buffer */

    multiboot_uint32_t mmap_length;

    multiboot_uint32_t mmap_addr;

    /* Drive Info buffer */

    multiboot_uint32_t drives_length;

    multiboot_uint32_t drives_addr;

    /* ROM configuration table */

    multiboot_uint32_t config_table;

    /* Boot Loader Name */

    multiboot_uint32_t boot_loader_name;

    /* APM table */

    multiboot_uint32_t apm_table;

    /* Video */

    multiboot_uint32_t vbe_control_info;

    multiboot_uint32_t vbe_mode_info;

    multiboot_uint16_t vbe_mode;

    multiboot_uint16_t vbe_interface_seg;

    multiboot_uint16_t vbe_interface_off;

    multiboot_uint16_t vbe_interface_len;

};

typedefstructmultiboot_info multiboot_info_t;

 

struct multiboot_mmap_entry

{

    multiboot_uint32_t size;

    multiboot_uint64_t addr;

    multiboot_uint64_t len;

    #define MULTIBOOT_MEMORY_AVAILABLE 1

    #define MULTIBOOT_MEMORY_RESERVED 2

    multiboot_uint32_t type;

}__attribute__((packed));

typedefstructmultiboot_mmap_entry multiboot_memory_map_t;

 

struct multiboot_mod_list

{

    /* the memory used goes from bytes ‘mod start’to ‘mod end-1’ inclusive*/

    multiboot_uint32_t mod_start;

    multiboot_uint32_t mod_end;

    /* Module command line */

    multiboot_uint32_t cmdline;

    /* padding to take it to 16 bytes (must bezero) */

    multiboot_uint32_t pad;

};

typedefstructmultiboot_mod_list multiboot_module_t;

 

#endif /* ! ASM FILE */

#endif /* ! MULTIBOOT HEADER */

4.3.2.     boot.s

在文件‘boot.S’中:

/*boot.S - bootstrap the kernel */

/*Copyright (C) 1999, 2001 Free Software Foundation, Inc.

    This program is free software; you canredistribute it and/or modify

    it under the terms of the GNU GeneralPublic License as published by

    the Free Software Foundation; eitherversion 2 of the License, or

     (atyour option) any later version.

    This program is distributed in the hopethat it will be useful,

    but WITHOUT ANY WARRANTY; without even theimplied warranty of

    MERCHANTABILITY or FITNESS FOR A PARTICULARPURPOSE. See the

    GNU General Public License for moredetails.

    You should have received a copy of the GNUGeneral Public License

    along with this program; if not, write tothe Free Software

    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.*/

#define ASM_FILE 1

#include <multiboot.h>

/* Csymbol format. HAVE ASM USCORE is defined by configure. */

#ifdef HAVE_ASM_USCORE

   # define EXT_C(sym) _ ## sym

#else

   # define EXT_C(sym) sym

#endif

/*The size of our stack (16KB). */

#define STACK_SIZE 0x4000

/*The flags for the Multiboot header. */

#ifdef __ELF__

   # define MULTIBOOT_HEADER_FLAGS 0x00000003

#else

   # define MULTIBOOT_HEADER_FLAGS 0x00010003

#endif

            .text

            .globl start, _start

start:

_start:

            jmp multiboot_entry

            /* Align 32 bits boundary. */

            .align 4

            /* Multiboot header. */

multiboot_header:

            /* magic */

            .long MULTIBOOT_HEADER_MAGIC

            /* flags */

            .long MULTIBOOT_HEADER_FLAGS

            /* checksum */

            .long -(MULTIBOOT_HEADER_MAGIC +MULTIBOOT_HEADER_FLAGS)

#ifndef __ELF__

            /* header addr */

            .long multiboot_header

            /* load addr */

            .long _start

            /* load end addr */

            .long _edata

            /* bss end addr */

            .long _end

            /* entry addr */

            .long multiboot_entry

#endif /* ! ELF */

 

multiboot_entry:

            /* Initialize the stack pointer. */

            movl $(stack + STACK_SIZE), %esp

            /* Reset EFLAGS. */

            pushl $0

            popf

            /* Push the pointer to the Multibootinformation structure. */

            pushl %ebx

            /* Push the magic value. */

            pushl %eax

            /* Now enter the C main function... */

            call EXT_C(cmain)

            /* Halt. */

            pushl $halt_message

            call EXT_C(printf)

loop:    hlt

            jmp loop

            halt_message:

            .asciz "Halted."

            /* Our stack area. */

            .comm stack, STACK_SIZE

4.3.3.     kernel.c

而在文件‘kernel.c’里:

/*kernel.c - the C part of the kernel */

/*Copyright (C) 1999 Free Software Foundation, Inc.

 

     This program is free software; you canredistribute it and/or modify

     it under the terms of the GNU GeneralPublic License as published by

     the Free Software Foundation; eitherversion 2 of the License, or

      (atyour option) any later version.

     This program is distributed in the hopethat it will be useful,

     but WITHOUT ANY WARRANTY; without even theimplied warranty of

     MERCHANTABILITY or FITNESS FOR APARTICULAR PURPOSE. See the

     GNU General Public License for moredetails.

     You should have received a copy of the GNUGeneral Public License

     along with this program; if not, write tothe Free Software

     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.*/

 

#include <multiboot.h>

/*Macros. */

/*Check if the bit BIT in FLAGS is set. */

#define CHECK_FLAG(flags,bit) ((flags)& (1 << (bit)))

 

/*Some screen stuff. */

/*The number of columns. */

#define COLUMNS 80

/*The number of lines. */

#define LINES 24

/*The attribute of an character. */

#define ATTRIBUTE 7

/*The video memory address. */

#define VIDEO 0xB8000

 

/*Variables. */

/*Save the X position. */

staticint xpos;

/*Save the Y position. */

static int ypos;

/*Point to the video memory. */

static volatile unsigned char *video;

 

/*Forward declarations. */

voidcmain (unsigned long magic, unsigned long addr);

static void cls (void);

static void itoa (char *buf, intbase, int d);

static void putchar (int c);

voidprintf (const char *format, ...);

 

/*Check if MAGIC is valid and print the Multiboot information structure

     pointed by ADDR. */

void

cmain(unsigned long magic, unsigned long addr)

{

    multiboot_info_t *mbi;

    /* Clear the screen. */

cls ();

 

    /* Am I booted by aMultiboot-compliant boot loader? */

    if (magic != MULTIBOOT_BOOTLOADER_MAGIC)

    {

        printf ("Invalid magic number:0x%x\n", (unsigned) magic);

        return;

     }

 

     /* Set MBI to the address of the Multiboot informationstructure. */

     mbi = (multiboot_info_t *) addr;

 

     /* Print out the flags. */

     printf("flags = 0x%x\n", (unsigned) mbi->flags);

 

     /* Are mem * valid? */

     if (CHECK_FLAG (mbi->flags, 0))

          printf ("mem_lower = %uKB,mem_upper = %uKB\n",

                (unsigned) mbi->mem_lower, (unsigned)mbi->mem_upper);

 

     /* Is boot device valid? */

     if (CHECK_FLAG (mbi->flags, 1))

          printf ("boot_device =0x%x\n", (unsigned) mbi->boot_device);

 

     /* Is the command line passed? */

     if (CHECK_FLAG (mbi->flags, 2))

          printf ("cmdline = %s\n",(char *) mbi->cmdline);

 

     /* Are mods * valid? */

     if (CHECK_FLAG (mbi->flags, 3))

     {

          multiboot_module_t *mod;

          int i;

 

          printf ("mods_count = %d,mods_addr = 0x%x\n",

                     (int) mbi->mods_count, (int)mbi->mods_addr);

          for (i = 0, mod = (multiboot_module_t *)mbi->mods_addr;

                    i < mbi->mods_count;

                    i++, mod++)

               printf (" mod_start = 0x%x, mod_end =0x%x, cmdline = %s\n",

                          (unsigned)mod->mod_start,

                          (unsigned) mod->mod_end,

                          (char *) mod->cmdline);

     }

 

     /* Bits 4 and 5 are mutually exclusive! */

     if (CHECK_FLAG (mbi->flags, 4)&& CHECK_FLAG (mbi->flags, 5))

     {

          printf ("Both bits 4 and 5 areset.\n");

          return;

     }

 

     /* Is the symbol table of a.out valid? */

     if (CHECK_FLAG (mbi->flags, 4))

     {

          multiboot_aout_symbol_table_t*multiboot_aout_sym = &(mbi->u.aout_sym);

 

          printf("multiboot_aout_symbol_table: tabsize = 0x%0x, "

                    "strsize = 0x%x, addr= 0x%x\n",

                     (unsigned) multiboot_aout_sym->tabsize,

                     (unsigned)multiboot_aout_sym->strsize,

                     (unsigned)multiboot_aout_sym->addr);

     }

    

     /* Is the section header table of ELF valid? */

     if (CHECK_FLAG (mbi->flags, 5))

     {

          multiboot_elf_section_header_table_t*multiboot_elf_sec = &(mbi->u.elf_sec);

          printf ("multiboot_elf_sec: num= %u, size = 0x%x,"

                    " addr = 0x%x, shndx =0x%x\n",

                     (unsigned)multiboot_elf_sec->num, (unsigned) multiboot_elf_sec->size,

                     (unsigned)multiboot_elf_sec->addr, (unsigned) multiboot_elf_sec->shndx);

     }

 

     /* Are mmap * valid? */

     if (CHECK_FLAG (mbi->flags, 6))

     {

          multiboot_memory_map_t *mmap;

          printf ("mmap_addr = 0x%x,mmap_length = 0x%x\n",

                     (unsigned) mbi->mmap_addr,(unsigned) mbi->mmap_length);

          for (mmap = (multiboot_memory_map_t *)mbi->mmap_addr;

                     (unsigned long) mmap <mbi->mmap_addr + mbi->mmap_length;

                    mmap =(multiboot_memory_map_t *) ((unsigned long) mmap

                                        +mmap->size + sizeof (mmap->size)))

               printf (" size = 0x%x,base_addr = 0x%x%x,"

                           " length =0x%x%x, type = 0x%x\n",

                          (unsigned) mmap->size,

                          mmap->addr>> 32,

                          mmap->addr& 0xffffffff,

                          mmap->len>> 32,

                          mmap->len& 0xffffffff,

                          (unsigned) mmap->type);

     }

}

 

/*Clear the screen and initialize VIDEO, XPOS and YPOS. */

static void

cls(void)

{

     int i;

     video = (unsigned char *) VIDEO;

 

     for (i = 0; i < COLUMNS * LINES * 2; i++)

          *(video + i) = 0;

 

     xpos = 0;

     ypos = 0;

}

 

/*Convert the integer D to a string and save the string in BUF. If

     BASE is equal to ‘d’, interpret that D is decimal, and ifBASE is

     equal to ‘x’, interpret that D is hexadecimal. */

static void

itoa(char *buf, int base, int d)

{

     char *p = buf;

     char *p1, *p2;

     unsigned long ud = d;

     int divisor = 10;

 

     /* If %d is specified and D is minus, put ‘-’ in the head.*/

     if (base == ‘d’ && d < 0)

     {

          *p++ = ‘-’;

          buf++;

          ud = -d;

     }

     else if (base == ‘x’)

          divisor = 16;

 

     /* Divide UD by DIVISOR until UD == 0. */

     do

     {

          int remainder = ud % divisor;

          *p++ = (remainder < 10) ?remainder + ‘0’ : remainder+ ‘a’ - 10;

     }

     while (ud /= divisor);

 

     /* Terminate BUF. */

     *p = 0;

 

     /* Reverse BUF. */

     p1 = buf;

     p2 = p - 1;

     while (p1 < p2)

     {

          char tmp = *p1;

          *p1 = *p2;

          *p2 = tmp;

          p1++;

          p2--;

     }

}

 

/*Put the character C on the screen. */

static void

putchar(int c)

{

     if (c == ‘\n’ || c == ‘\r’)

     {

          newline:

          xpos = 0;

          ypos++;

          if (ypos >= LINES)

          ypos = 0;

          return;

     }

 

     *(video + (xpos + ypos * COLUMNS) * 2) = c& 0xFF;

     *(video + (xpos + ypos * COLUMNS) * 2 + 1)= ATTRIBUTE;

 

     xpos++;

     if (xpos >= COLUMNS)

          goto newline;

}

 

/*Format a string and print it on the screen, just like the libc

     function printf. */

void

printf(const char *format, ...)

{

     char **arg = (char **) &format;

     int c;

     char buf[20];

     arg++;

     while ((c = *format++) != 0)

     {

          if (c != ‘%’)

          putchar (c);

          else

          {

               char *p;

 

               c = *format++;

               switch (c)

               {

                    case ‘d’:

                    case ‘u’:

                    case ‘x’:

                         itoa (buf, c, *((int*) arg++));

                         p = buf;

                         goto string;

                         break;

                    case ‘s’:

                         p = *arg++;

                         if (! p)

                              p ="(null)";

                         string:

                         while (*p)

                              putchar (*p++);

                         break;

                    default:

                         putchar (*((int *)arg++));

                         break;

               }

          }

     }

}

4.3.4.     其它Multiboot内核

其它有用的信息可以在Multiboot内核中得到,比如GNU Mach及Fiascohttp://os.inf.tu-dresden.de/fiasco/。及值得注意的OSKit http://www.cs.utah.edu/projects/flux/oskit/,它提供了一个支持这个规范的库。

4.3.5.     启动载入器代码例子

GNU GRUB(参考GRUB手册中的“GRUB”一节)项目是一个Multiboot兼容的启动载入器,支持所有在这个规范中所要求及许多可选的特性。源代码可从GNU网站下下载。

 


你可能感兴趣的:(header,video,table,interface,alignment,newline)