Fork me on GitHub

root/kernel/multiboot.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. check_parm
  2. parse_arg
  3. parse_cmdline
  4. get_last_boot_addr
  5. multiboot

   1 /*
   2  * fiwix/kernel/multiboot.c
   3  *
   4  * Copyright 2021, Jordi Sanfeliu. All rights reserved.
   5  * Distributed under the terms of the Fiwix License.
   6  */
   7 
   8 #include <fiwix/config.h>
   9 #include <fiwix/kernel.h>
  10 #include <fiwix/multiboot1.h>
  11 #include <fiwix/stdio.h>
  12 #include <fiwix/string.h>
  13 #include <fiwix/limits.h>
  14 #include <fiwix/kparms.h>
  15 #include <fiwix/i386elf.h>
  16 #include <fiwix/ramdisk.h>
  17 #include <fiwix/mm.h>
  18 #include <fiwix/bios.h>
  19 #include <fiwix/vgacon.h>
  20 #include <fiwix/fb.h>
  21 #include <fiwix/fbcon.h>
  22 
  23 Elf32_Shdr *symtab, *strtab;
  24 
  25 /* check the validity of a command line parameter */
  26 static int check_parm(struct kparms *parm, const char *value)
  27 {
  28         int n;
  29 
  30         if(!strcmp(parm->name, "root=")) {
  31                 for(n = 0; parm->value[n]; n++) {
  32                         if(!strcmp(parm->value[n], value)) {
  33                                 _rootdev = parm->sysval[n];
  34                                 strncpy(_rootdevname, value, DEVNAME_MAX);
  35                                 return 0;
  36                         }
  37                 }
  38                 return 1;
  39         }
  40         if(!strcmp(parm->name, "noramdisk")) {
  41                 _noramdisk = 1;
  42                 return 0;
  43         }
  44         if(!strcmp(parm->name, "ramdisksize=")) {
  45                 int size = atoi(value);
  46                 if(!size || size > RAMDISK_MAXSIZE) {
  47                         printk("WARNING: 'ramdisksize' value is out of limits, defaulting to 4096KB.\n");
  48                         _ramdisksize = 0;
  49                 } else {
  50                         _ramdisksize = size;
  51                 }
  52                 return 0;
  53         }
  54         if(!strcmp(parm->name, "initrd=")) {
  55                 if(value[0]) {
  56                         strncpy(_initrd, value, DEVNAME_MAX);
  57                         return 0;
  58                 }
  59         }
  60         if(!strcmp(parm->name, "rootfstype=")) {
  61                 for(n = 0; parm->value[n]; n++) {
  62                         if(!strcmp(parm->value[n], value)) {
  63                                 strncpy(_rootfstype, value, sizeof(_rootfstype));
  64                                 return 0;
  65                         }
  66                 }
  67                 return 1;
  68         }
  69         if(!strcmp(parm->name, "console=")) {
  70                 for(n = 0; parm->value[n]; n++) {
  71                         if(!strcmp(parm->value[n], value)) {
  72                                 if(parm->sysval[n]) {
  73                                         _syscondev = parm->sysval[n];
  74                                         return 0;
  75                                 }
  76                                 printk("WARNING: device name for '%s' is not defined!\n", parm->name);
  77                         }
  78                 }
  79                 return 1;
  80         }
  81         printk("WARNING: the parameter '%s' looks valid but it's not defined!\n", parm->name);
  82         return 0;
  83 }
  84 
  85 static int parse_arg(const char *arg)
  86 {
  87         int n;
  88 
  89         /* '--' marks the beginning of the init arguments */
  90         if(!strcmp(arg, "--")) {
  91                 return 1;
  92         }
  93 
  94         for(n = 0; parm_table[n].name; n++) {
  95                 if(!strncmp(arg, parm_table[n].name, strlen(parm_table[n].name))) {
  96                         arg += strlen(parm_table[n].name);
  97                         if(check_parm(&parm_table[n], arg)) {
  98                                 printk("WARNING: invalid value '%s' in the '%s' parameter.\n", arg, parm_table[n].name);
  99                         }
 100                         return 0;
 101                 }
 102         }
 103         printk("WARNING: invalid cmdline parameter: '%s'.\n", arg);
 104         return 0;
 105 }
 106 
 107 static char * parse_cmdline(const char *str)
 108 {
 109         char *from, *to;
 110         char arg[CMDL_ARG_LEN];
 111         char c;
 112 
 113         from = to = (char *)str;
 114         for(;;) {
 115                 c = *(str++);
 116                 if(c == ' ' || !c) {
 117                         if(to - from < CMDL_ARG_LEN) {
 118                                 memcpy_b(arg, from, to - from);
 119                                 arg[to - from] = NULL;
 120                                 if(arg[0] != NULL) {
 121                                         if(parse_arg(arg)) {
 122                                                 while(*(from++)) {
 123                                                         if(*from != '-' && *from != ' ') {
 124                                                                 break;
 125                                                         }
 126                                                 }
 127                                                 return from;
 128                                         }
 129                                 }
 130                         } else {
 131                                 memcpy_b(arg, from, CMDL_ARG_LEN);
 132                                 arg[CMDL_ARG_LEN - 1] = NULL;
 133                                 printk("WARNING: invalid length of the cmdline parameter '%s'.\n", arg);
 134                         }
 135                         from = ++to;
 136                         if(!c) {
 137                                 break;
 138                         }
 139                         continue;
 140                 }
 141                 to++;
 142         }
 143 
 144         return NULL;
 145 }
 146 
 147 /*
 148  * This function returns the last address used by kernel symbols or the value
 149  * of 'mod_end' (in the module structure) of the last module loaded by GRUB.
 150  *
 151  * This is intended to setup the kernel stack beyond all these addresses.
 152  */
 153 unsigned int get_last_boot_addr(unsigned int info)
 154 {
 155         struct multiboot_info *mbi;
 156         Elf32_Shdr *shdr;
 157         struct multiboot_elf_section_header_table *hdr;
 158         struct multiboot_mod_list *mod;
 159         unsigned short int n;
 160         unsigned int addr;
 161 
 162         symtab = strtab = NULL;
 163         mbi = (struct multiboot_info *)info;
 164         hdr = &(mbi->u.elf_sec);
 165         for(n = 0; n < hdr->num; n++) {
 166                 shdr = (Elf32_Shdr *)(hdr->addr + (n * hdr->size));
 167                 if(shdr->sh_type == SHT_SYMTAB) {
 168                         symtab = shdr;
 169                 }
 170                 if(shdr->sh_type == SHT_STRTAB) {
 171                         strtab = shdr;
 172                 }
 173         }
 174 
 175         addr = strtab->sh_addr + strtab->sh_size;
 176 
 177         /*
 178          * https://www.gnu.org/software/grub/manual/multiboot/multiboot.html
 179          *
 180          * Check if GRUB has loaded some modules and, if so, get the last
 181          * address used by the last one.
 182          */
 183         if(mbi->flags & MULTIBOOT_INFO_MODS) {
 184                 mod = (struct multiboot_mod_list *)mbi->mods_addr;
 185                 for(n = 0; n < mbi->mods_count; n++, mod++) {
 186                         addr = mod->mod_end;
 187                 }
 188         }
 189 
 190         return P2V(addr);
 191 }
 192 
 193 void multiboot(unsigned long magic, unsigned long info)
 194 {
 195         struct multiboot_info mbi;
 196 
 197         memset_b(&video, 0, sizeof(struct video_parms));
 198 
 199         if(magic != MULTIBOOT_BOOTLOADER_MAGIC) {
 200                 printk("WARNING: invalid multiboot magic number: 0x%x. Assuming 4MB of RAM.\n", (unsigned long int)magic);
 201                 memset_b(&mbi, NULL, sizeof(struct multiboot_info));
 202                 _memsize = 640;
 203                 _extmemsize = 3072;
 204                 bios_map_init(NULL, 0);
 205                 video.columns = 80;
 206                 video.lines = 25;
 207                 video.flags = VPF_VGA;
 208                 video.memsize = 384 * 1024;
 209                 return;
 210         }
 211 
 212         memcpy_b(&mbi, (void *)info, sizeof(struct multiboot_info));
 213 
 214         if(mbi.flags & MULTIBOOT_INFO_BOOT_LOADER_NAME) {
 215                 printk("bootloader                 -    %s\n", mbi.boot_loader_name);
 216         }
 217 
 218         if(!(mbi.flags & MULTIBOOT_INFO_MEMORY)) {
 219                 printk("WARNING: values in mem_lower and mem_upper are not valid!\n");
 220         }
 221         _memsize = (unsigned int)mbi.mem_lower;
 222         _extmemsize = (unsigned int)mbi.mem_upper;
 223 
 224 
 225         if(mbi.flags & MULTIBOOT_INFO_CMDLINE) {
 226                 int n, len;
 227                 char c;
 228                 char *p;
 229 
 230                 p = (char *)mbi.cmdline;
 231                 len = strlen(p);
 232                 /* suppress 'fiwix' */
 233                 for(n = 0; n < len; n++) {
 234                         c = *(p++);
 235                         if(c == ' ') {
 236                                 break;
 237                         }
 238                 }
 239                 strcpy(cmdline, p);
 240                 init_args = parse_cmdline(cmdline);
 241         } else {
 242                 printk("WARNING: no cmdline detected!\n");
 243         }
 244         printk("kernel    0x%08X       -    cmdline='%s'\n", KERNEL_ENTRY_ADDR, cmdline);
 245 
 246 
 247         if(mbi.flags & MULTIBOOT_INFO_MODS) {
 248                 int n;
 249                 struct multiboot_mod_list *mod;
 250 
 251                 mod = (struct multiboot_mod_list *)mbi.mods_addr;
 252                 for(n = 0; n < mbi.mods_count; n++, mod++) {
 253                         if(!strcmp((char *)mod->cmdline, _initrd)) {
 254                                 printk("initrd    0x%08X-0x%08X file='%s' size=%dKB\n", mod->mod_start, mod->mod_end, mod->cmdline, (mod->mod_end - mod->mod_start) / 1024);
 255                                 ramdisk_table[0].addr = (char *)mod->mod_start;
 256                         }
 257                 }
 258         }
 259 
 260 
 261         if(!(mbi.flags & MULTIBOOT_INFO_ELF_SHDR)) {
 262                 printk("WARNING: ELF section header table is not valid!\n");
 263         }
 264 
 265         if(mbi.flags & MULTIBOOT_INFO_MEM_MAP) {
 266                 bios_map_init((struct multiboot_mmap_entry *)mbi.mmap_addr, mbi.mmap_length);
 267         } else {
 268                 bios_map_init(NULL, 0);
 269         }
 270 
 271         if(mbi.flags & MULTIBOOT_INFO_VBE_INFO) {
 272                 struct vbe_controller *vbec;
 273                 struct vbe_mode *vbem;
 274                 unsigned long int from, to;
 275 
 276                 vbec = (struct vbe_controller *)mbi.vbe_control_info;
 277                 vbem = (struct vbe_mode *)mbi.vbe_mode_info;
 278 
 279                 video.flags = VPF_VESAFB;
 280                 video.address = (unsigned int *)vbem->phys_base;
 281                 video.port = 0;
 282                 video.memsize = vbec->total_memory * vbem->win_size * 1024;
 283                 strcpy((char *)video.signature, (char *)vbec->signature);
 284                 video.columns = vbem->x_resolution / vbem->x_char_size;
 285                 video.lines = vbem->y_resolution / vbem->y_char_size;
 286                 video.fb_version = vbec->version;
 287                 video.fb_width = vbem->x_resolution;
 288                 video.fb_height = vbem->y_resolution;
 289                 video.fb_char_width = vbem->x_char_size;
 290                 video.fb_char_height = vbem->y_char_size;
 291                 video.fb_bpp = vbem->bits_per_pixel;
 292                 video.fb_pixelwidth = vbem->bits_per_pixel / 8;
 293                 video.fb_pitch = vbem->bytes_per_scanline;
 294                 video.fb_linesize = video.fb_pitch * video.fb_char_height;
 295                 video.fb_size = vbem->x_resolution * vbem->y_resolution * video.fb_pixelwidth;
 296                 video.fb_vsize = video.lines * video.fb_pitch * video.fb_char_height;
 297 
 298                 from = (unsigned long int)video.address;
 299                 to = from + video.memsize;
 300                 bios_map_add(from, to, MULTIBOOT_MEMORY_AVAILABLE, MULTIBOOT_MEMORY_AVAILABLE);
 301                 from = (unsigned long int)video.address - KERNEL_BASE_ADDR;
 302                 to = (from + video.memsize);
 303                 bios_map_add(from, to, MULTIBOOT_MEMORY_AVAILABLE, MULTIBOOT_MEMORY_RESERVED);
 304         } else {
 305                 video.columns = 80;
 306                 video.lines = 25;
 307                 video.flags = VPF_VGA;
 308                 video.memsize = 384 * 1024;
 309         }
 310 }

/* [previous][next][first][last][top][bottom][index][help] */