Fork me on GitHub

root/kernel/main.c

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

DEFINITIONS

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

   1 /*
   2  * fiwix/kernel/main.c
   3  *
   4  * Copyright 2018, Jordi Sanfeliu. All rights reserved.
   5  * Distributed under the terms of the Fiwix License.
   6  */
   7 
   8 #include <fiwix/asm.h>
   9 #include <fiwix/kernel.h>
  10 #include <fiwix/mm.h>
  11 #include <fiwix/system.h>
  12 #include <fiwix/timer.h>
  13 #include <fiwix/sched.h>
  14 #include <fiwix/sleep.h>
  15 #include <fiwix/cpu.h>
  16 #include <fiwix/pic.h>
  17 #include <fiwix/fs.h>
  18 #include <fiwix/devices.h>
  19 #include <fiwix/console.h>
  20 #include <fiwix/keyboard.h>
  21 #include <fiwix/ramdisk.h>
  22 #include <fiwix/version.h>
  23 #include <fiwix/limits.h>
  24 #include <fiwix/segments.h>
  25 #include <fiwix/syscalls.h>
  26 #include <fiwix/stdio.h>
  27 #include <fiwix/string.h>
  28 #include <fiwix/kparms.h>
  29 #include <fiwix/i386elf.h>
  30 #include <fiwix/bios.h>
  31 
  32 /*
  33  * check if the bit BIT in Multiboot FLAGS is set
  34  * ----------------------------------------------
  35  * bit 11 -> vbe_*
  36  * bit 10 -> apm_table
  37  * bit  9 -> boot_loader_name
  38  * bit  8 -> config_table
  39  * bit  7 -> drives_length and drives_addr
  40  * bit  6 -> mmap_length and mmap_addr
  41  * bit  5 -> ELF symbols
  42  * bit  4 -> a.out symbols
  43  * bit  3 -> mods_count and mods_addr
  44  * bit  2 -> cmdline
  45  * bit  1 -> boot_device
  46  * bit  0 -> mem_lower and mem_upper values
  47  */
  48 #define CHECK_FLAG(flags,bit)   ((flags) & (1 << (bit)))
  49 
  50 Elf32_Shdr *symtab, *strtab;
  51 unsigned int _last_data_addr;
  52 int _memsize;
  53 int _extmemsize;
  54 int _rootdev;
  55 int _noramdisk;
  56 int _ramdisksize;
  57 char _rootfstype[10];
  58 char _rootdevname[DEVNAME_MAX + 1];
  59 char _initrd[DEVNAME_MAX + 1];
  60 int _syscondev;
  61 char *init_args;
  62 
  63 char cmdline[NAME_MAX + 1];
  64 
  65 struct new_utsname sys_utsname = {
  66         UTS_SYSNAME,
  67         UTS_NODENAME,
  68         UTS_RELEASE,
  69         UTS_VERSION,
  70         "",
  71         UTS_DOMAINNAME,
  72 };
  73 
  74 struct kernel_stat kstat;
  75 
  76 /*
  77  * This function returns the last address used by kernel symbols or the value
  78  * of 'mod_end' (in the module structure) of the last module loaded by GRUB.
  79  *
  80  * This is intended to setup the kernel stack beyond all these addresses.
  81  */
  82 unsigned int get_last_boot_addr(unsigned int info)
  83 {
  84         multiboot_info_t *mbi;
  85         Elf32_Shdr *shdr;
  86         elf_section_header_table_t *hdr;
  87         struct module *mod;
  88         unsigned short int n;
  89         unsigned int addr;
  90 
  91         symtab = strtab = NULL;
  92         mbi = (multiboot_info_t *)info;
  93         hdr = &(mbi->u.elf_sec);
  94         for(n = 0; n < hdr->num; n++) {
  95                 shdr = (Elf32_Shdr *)(hdr->addr + (n * hdr->size));
  96                 if(shdr->sh_type == SHT_SYMTAB) {
  97                         symtab = shdr;
  98                 }
  99                 if(shdr->sh_type == SHT_STRTAB) {
 100                         strtab = shdr;
 101                 }
 102         }
 103 
 104         addr = strtab->sh_addr + strtab->sh_size;
 105 
 106         /*
 107          * https://www.gnu.org/software/grub/manual/multiboot/multiboot.html
 108          *
 109          * Check if GRUB has loaded some modules and, if so, get the last
 110          * address used by the last one.
 111          */
 112         if(CHECK_FLAG(mbi->flags, 3)) {
 113                 mod = (struct module *)mbi->mods_addr;
 114                 for(n = 0; n < mbi->mods_count; n++, mod++) {
 115                         addr = mod->mod_end;
 116                 }
 117         }
 118 
 119         return P2V(addr);
 120 }
 121 
 122 /* check the validity of a command line parameter */
 123 static int check_parm(struct kparms *parm, const char *value)
 124 {
 125         int n;
 126 
 127         if(!strcmp(parm->name, "root=")) {
 128                 for(n = 0; parm->value[n]; n++) {
 129                         if(!strcmp(parm->value[n], value)) {
 130                                 _rootdev = parm->sysval[n];
 131                                 strncpy(_rootdevname, value, DEVNAME_MAX);
 132                                 return 0;
 133                         }
 134                 }
 135                 return 1;
 136         }
 137         if(!strcmp(parm->name, "noramdisk")) {
 138                 _noramdisk = 1;
 139                 return 0;
 140         }
 141         if(!strcmp(parm->name, "ramdisksize=")) {
 142                 int size = atoi(value);
 143                 if(!size || size > RAMDISK_MAXSIZE) {
 144                         printk("WARNING: 'ramdisksize' value is out of limits, defaulting to 4096KB.\n");
 145                         _ramdisksize = 0;
 146                 } else {
 147                         _ramdisksize = size;
 148                 }
 149                 return 0;
 150         }
 151         if(!strcmp(parm->name, "initrd=")) {
 152                 if(value[0]) {
 153                         strncpy(_initrd, value, DEVNAME_MAX);
 154                         return 0;
 155                 }
 156         }
 157         if(!strcmp(parm->name, "rootfstype=")) {
 158                 for(n = 0; parm->value[n]; n++) {
 159                         if(!strcmp(parm->value[n], value)) {
 160                                 strncpy(_rootfstype, value, sizeof(_rootfstype));
 161                                 return 0;
 162                         }
 163                 }
 164                 return 1;
 165         }
 166         if(!strcmp(parm->name, "console=")) {
 167                 for(n = 0; parm->value[n]; n++) {
 168                         if(!strcmp(parm->value[n], value)) {
 169                                 if(parm->sysval[n]) {
 170                                         _syscondev = parm->sysval[n];
 171                                         return 0;
 172                                 }
 173                                 printk("WARNING: device name for '%s' is not defined!\n", parm->name);
 174                         }
 175                 }
 176                 return 1;
 177         }
 178         printk("WARNING: the parameter '%s' looks valid but it's not defined!\n", parm->name);
 179         return 0;
 180 }
 181 
 182 static int parse_arg(const char *arg)
 183 {
 184         int n;
 185 
 186         /* '--' marks the beginning of the init arguments */
 187         if(!strcmp(arg, "--")) {
 188                 return 1;
 189         }
 190 
 191         for(n = 0; parm_table[n].name; n++) {
 192                 if(!strncmp(arg, parm_table[n].name, strlen(parm_table[n].name))) {
 193                         arg += strlen(parm_table[n].name);
 194                         if(check_parm(&parm_table[n], arg)) {
 195                                 printk("WARNING: invalid value '%s' in the '%s' parameter.\n", arg, parm_table[n].name);
 196                         }
 197                         return 0;
 198                 }
 199         }
 200         printk("WARNING: invalid cmdline parameter: '%s'.\n", arg);
 201         return 0;
 202 }
 203 
 204 static char * parse_cmdline(const char *str)
 205 {
 206         char *from, *to;
 207         char arg[CMDL_ARG_LEN];
 208         char c;
 209 
 210         from = to = (char *)str;
 211         for(;;) {
 212                 c = *(str++);
 213                 if(c == ' ' || !c) {
 214                         if(to - from < CMDL_ARG_LEN) {
 215                                 memcpy_b(arg, from, to - from);
 216                                 arg[to - from] = NULL;
 217                                 if(arg[0] != NULL) {
 218                                         if(parse_arg(arg)) {
 219                                                 while(*(from++)) {
 220                                                         if(*from != '-' && *from != ' ') {
 221                                                                 break;
 222                                                         }
 223                                                 }
 224                                                 return from;
 225                                         }
 226                                 }
 227                         } else {
 228                                 memcpy_b(arg, from, CMDL_ARG_LEN);
 229                                 arg[CMDL_ARG_LEN - 1] = NULL;
 230                                 printk("WARNING: invalid length of the cmdline parameter '%s'.\n", arg);
 231                         }
 232                         from = ++to;
 233                         if(!c) {
 234                                 break;
 235                         }
 236                         continue;
 237                 }
 238                 to++;
 239         }
 240 
 241         return NULL;
 242 }
 243 
 244 void start_kernel(unsigned long magic, unsigned long info, unsigned int stack)
 245 {
 246         struct proc *init, *p_kswapd;
 247         multiboot_info_t mbi;
 248 
 249         /* default kernel values */
 250         strcpy(_rootfstype, "ext2");            /* filesystem is ext2 */
 251         _syscondev = MKDEV(VCONSOLES_MAJOR, 0); /* console is /dev/tty0 */
 252 
 253         pic_init();
 254         idt_init();
 255         dev_init();
 256         tty_init();
 257 
 258         printk("                                Welcome to %s\n", UTS_SYSNAME);
 259         printk("                     Copyright (c) 2018-2020, Jordi Sanfeliu\n");
 260         printk("\n");
 261         printk("                      kernel v%s for i386 architecture\n", UTS_RELEASE);
 262         printk("               (GCC %s, built on %s)\n", __VERSION__, UTS_VERSION);
 263         printk("\n");
 264         printk("DEVICE    ADDRESS         IRQ   COMMENT\n");
 265         printk("-------------------------------------------------------------------------------\n");
 266 
 267         if(magic != MULTIBOOT_BOOTLOADER_MAGIC) {
 268                 printk("WARNING: invalid multiboot-bootloader magic number: 0x%x.\n\n", (unsigned long int)magic);
 269                 memset_b(&mbi, NULL, sizeof(struct multiboot_info));
 270         } else {
 271                 memcpy_b(&mbi, (void *)info, sizeof(struct multiboot_info));
 272         }
 273 
 274         memset_b(&kstat, NULL, sizeof(kstat));
 275 
 276         cpu_init();
 277 
 278         /* check if a command line was supplied */
 279         if(CHECK_FLAG(mbi.flags, 2)) {
 280                 int n, len;
 281                 char c;
 282                 char *p;
 283 
 284                 p = (char *)mbi.cmdline;
 285                 len = strlen(p);
 286                 /* suppress 'fiwix' */
 287                 for(n = 0; n < len; n++) {
 288                         c = *(p++);
 289                         if(c == ' ') {
 290                                 break;
 291                         }
 292                 }
 293                 strcpy(cmdline, p);
 294                 init_args = parse_cmdline(cmdline);
 295         } else {
 296                 printk("WARNING: no cmdline detected!\n");
 297         }
 298 
 299         printk("kernel    0x%08X       -    cmdline='%s'\n", KERNEL_ENTRY_ADDR, cmdline);
 300 
 301         if(CHECK_FLAG(mbi.flags, 3)) {
 302                 int n;
 303                 struct module *mod;
 304 
 305                 mod = (struct module *)mbi.mods_addr;
 306                 for(n = 0; n < mbi.mods_count; n++, mod++) {
 307                         if(!strcmp((char *)mod->string, _initrd)) {
 308                                 printk("initrd    0x%08X-0x%08X file='%s' size=%dKB\n", mod->mod_start, mod->mod_end, mod->string, (mod->mod_end - mod->mod_start) / 1024);
 309                                 ramdisk_table[0].addr = (char *)mod->mod_start;
 310                         }
 311                 }
 312         }
 313 
 314         if(!CHECK_FLAG(mbi.flags, 0)) {
 315                 printk("WARNING: values in mem_lower and mem_upper are not valid!\n");
 316         }
 317         _memsize = (unsigned int)mbi.mem_lower;
 318         _extmemsize = (unsigned int)mbi.mem_upper;
 319 
 320         if(CHECK_FLAG(mbi.flags, 6)) {
 321                 bios_map_init((memory_map_t *)mbi.mmap_addr, mbi.mmap_length);
 322         } else {
 323                 bios_map_init(NULL, 0);
 324         }
 325 
 326         timer_init();
 327         get_video_parms();
 328 
 329         _last_data_addr = stack - KERNEL_BASE_ADDR;
 330         mem_init();
 331 
 332         keyboard_init();
 333         vconsole_init();
 334         proc_init();
 335 
 336         if(!(CHECK_FLAG(mbi.flags, 5))) {
 337                 printk("WARNING: ELF section header table is not valid!\n");
 338         }
 339 
 340         /* IDLE is now the current process */
 341         set_tss(current);
 342         load_tr(TSS);
 343         current->tss.cr3 = (unsigned int)kpage_dir;
 344         current->flags |= PF_KPROC;
 345 
 346         /* reserve the slot 1 for the INIT process */
 347         init = get_proc_free();
 348         proc_slot_init(init);
 349         init->pid = get_unused_pid();
 350 
 351         /* create and setup kswapd process */
 352         p_kswapd = kernel_process(kswapd);
 353 
 354         /* kswapd will take over the rest of the kernel initialization */
 355         p_kswapd->state = PROC_RUNNING;
 356         need_resched = 1;
 357 
 358         STI();          /* let's rock! */
 359         cpu_idle();
 360 }
 361 
 362 void stop_kernel(void)
 363 {
 364         struct proc *p;
 365         int n;
 366 
 367         /* stop and disable all interrupts! */
 368         CLI();
 369         for(n = 0; n < NR_IRQS; n++) {
 370                 disable_irq(n);
 371         }
 372 
 373         printk("\n");
 374         printk("**    Safe to Power Off    **\n");
 375         printk("            -or-\n");
 376         printk("** Press Any Key to Reboot **\n");
 377         any_key_to_reboot = 1;
 378 
 379         /* put all processes to sleep and reset all pending signals */
 380         FOR_EACH_PROCESS(p) {
 381                 p->state = PROC_SLEEPING;
 382                 p->sigpending = 0;
 383         }
 384 
 385         /* enable keyboard only */
 386         STI();
 387         enable_irq(KEYBOARD_IRQ);
 388 
 389         /* switch to IDLE process */
 390         if(current) {
 391                 do_sched();
 392         }
 393 
 394         cpu_idle();
 395 }

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