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                                 _syscondev = parm->sysval[n];
 170                                 return 0;
 171                         }
 172                 }
 173                 return 1;
 174         }
 175         printk("WARNING: the parameter '%s' looks valid but it's not defined!\n", parm->name);
 176         return 0;
 177 }
 178 
 179 static int parse_arg(const char *arg)
 180 {
 181         int n;
 182 
 183         /* '--' marks the beginning of the init arguments */
 184         if(!strcmp(arg, "--")) {
 185                 return 1;
 186         }
 187 
 188         for(n = 0; parm_table[n].name; n++) {
 189                 if(!strncmp(arg, parm_table[n].name, strlen(parm_table[n].name))) {
 190                         arg += strlen(parm_table[n].name);
 191                         if(check_parm(&parm_table[n], arg)) {
 192                                 printk("WARNING: invalid value '%s' in the '%s' parameter.\n", arg, parm_table[n].name);
 193                         }
 194                         return 0;
 195                 }
 196         }
 197         printk("WARNING: invalid cmdline parameter: '%s'.\n", arg);
 198         return 0;
 199 }
 200 
 201 static char * parse_cmdline(const char *str)
 202 {
 203         char *from, *to;
 204         char arg[CMDL_ARG_LEN];
 205         char c;
 206 
 207         from = to = (char *)str;
 208         for(;;) {
 209                 c = *(str++);
 210                 if(c == ' ' || !c) {
 211                         if(to - from < CMDL_ARG_LEN) {
 212                                 memcpy_b(arg, from, to - from);
 213                                 arg[to - from] = NULL;
 214                                 if(arg[0] != NULL) {
 215                                         if(parse_arg(arg)) {
 216                                                 while(*(from++)) {
 217                                                         if(*from != '-' && *from != ' ') {
 218                                                                 break;
 219                                                         }
 220                                                 }
 221                                                 return from;
 222                                         }
 223                                 }
 224                         } else {
 225                                 memcpy_b(arg, from, CMDL_ARG_LEN);
 226                                 arg[CMDL_ARG_LEN - 1] = NULL;
 227                                 printk("WARNING: invalid length of the cmdline parameter '%s'.\n", arg);
 228                         }
 229                         from = ++to;
 230                         if(!c) {
 231                                 break;
 232                         }
 233                         continue;
 234                 }
 235                 to++;
 236         }
 237 
 238         return NULL;
 239 }
 240 
 241 void start_kernel(unsigned long magic, unsigned long info, unsigned int stack)
 242 {
 243         struct proc *init, *p_kswapd;
 244         multiboot_info_t mbi;
 245 
 246         /* default kernel values */
 247         strcpy(_rootfstype, "ext2");            /* filesystem is ext2 */
 248         _syscondev = MKDEV(VCONSOLES_MAJOR, 0); /* console is /dev/tty0 */
 249 
 250         pic_init();
 251         idt_init();
 252         dev_init();
 253         tty_init();
 254 
 255         printk("                                Welcome to %s\n", UTS_SYSNAME);
 256         printk("                     Copyright (c) 2018-2020, Jordi Sanfeliu\n");
 257         printk("\n");
 258         printk("                      kernel v%s for i386 architecture\n", UTS_RELEASE);
 259         printk("               (GCC %s, built on %s)\n", __VERSION__, UTS_VERSION);
 260         printk("\n");
 261         printk("DEVICE    ADDRESS         IRQ   COMMENT\n");
 262         printk("-------------------------------------------------------------------------------\n");
 263 
 264         if(magic != MULTIBOOT_BOOTLOADER_MAGIC) {
 265                 printk("WARNING: invalid multiboot-bootloader magic number: 0x%x.\n\n", (unsigned long int)magic);
 266                 memset_b(&mbi, NULL, sizeof(struct multiboot_info));
 267         } else {
 268                 memcpy_b(&mbi, (void *)info, sizeof(struct multiboot_info));
 269         }
 270 
 271         memset_b(&kstat, NULL, sizeof(kstat));
 272 
 273         cpu_init();
 274 
 275         /* check if a command line was supplied */
 276         if(CHECK_FLAG(mbi.flags, 2)) {
 277                 int n, len;
 278                 char c;
 279                 char *p;
 280 
 281                 p = (char *)mbi.cmdline;
 282                 len = strlen(p);
 283                 /* suppress 'fiwix' */
 284                 for(n = 0; n < len; n++) {
 285                         c = *(p++);
 286                         if(c == ' ') {
 287                                 break;
 288                         }
 289                 }
 290                 strcpy(cmdline, p);
 291                 init_args = parse_cmdline(cmdline);
 292         } else {
 293                 printk("WARNING: no cmdline detected!\n");
 294         }
 295 
 296         printk("kernel    0x%08X       -    cmdline='%s'\n", KERNEL_ENTRY_ADDR, cmdline);
 297 
 298         timer_init();
 299         vconsole_init();
 300         keyboard_init();
 301 
 302         if(CHECK_FLAG(mbi.flags, 3)) {
 303                 int n;
 304                 struct module *mod;
 305 
 306                 mod = (struct module *)mbi.mods_addr;
 307                 for(n = 0; n < mbi.mods_count; n++, mod++) {
 308                         if(!strcmp((char *)mod->string, _initrd)) {
 309                                 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);
 310                                 ramdisk_table[0].addr = (char *)mod->mod_start;
 311                         }
 312                 }
 313         }
 314 
 315         if(!CHECK_FLAG(mbi.flags, 0)) {
 316                 printk("WARNING: values in mem_lower and mem_upper are not valid!\n");
 317         }
 318         _memsize = (unsigned int)mbi.mem_lower;
 319         _extmemsize = (unsigned int)mbi.mem_upper;
 320 
 321         if(CHECK_FLAG(mbi.flags, 6)) {
 322                 bios_map_init((memory_map_t *)mbi.mmap_addr, mbi.mmap_length);
 323         } else {
 324                 bios_map_init(NULL, 0);
 325         }
 326 
 327         _last_data_addr = stack - KERNEL_BASE_ADDR;
 328         mem_init();
 329         proc_init();
 330 
 331         if(!(CHECK_FLAG(mbi.flags, 5))) {
 332                 printk("WARNING: ELF section header table is not valid!\n");
 333         }
 334 
 335         /* IDLE is now the current process */
 336         set_tss(current);
 337         load_tr(TSS);
 338         current->tss.cr3 = (unsigned int)kpage_dir;
 339         current->flags |= PF_KPROC;
 340 
 341         /* reserve the slot 1 for the INIT process */
 342         init = get_proc_free();
 343         proc_slot_init(init);
 344         init->pid = get_unused_pid();
 345 
 346         /* create and setup kswapd process */
 347         p_kswapd = kernel_process(kswapd);
 348 
 349         /* kswapd will take over the rest of the kernel initialization */
 350         p_kswapd->state = PROC_RUNNING;
 351         need_resched = 1;
 352 
 353         STI();          /* let's rock! */
 354         cpu_idle();
 355 }
 356 
 357 void stop_kernel(void)
 358 {
 359         struct proc *p;
 360 
 361         printk("\n");
 362         printk("**    Safe to Power Off    **\n");
 363         printk("            -or-\n");
 364         printk("** Press Any Key to Reboot **\n");
 365         any_key_to_reboot = 1;
 366 
 367         /* put all processes to sleep and reset all pending signals */
 368         FOR_EACH_PROCESS(p) {
 369                 p->state = PROC_SLEEPING;
 370                 p->sigpending = 0;
 371         }
 372 
 373         /* TODO: disable all interrupts */
 374         CLI();
 375         disable_irq(TIMER_IRQ);
 376 
 377         /* switch to IDLE process */
 378         if(current) {
 379                 do_sched();
 380         }
 381 
 382         STI();
 383         enable_irq(KEYBOARD_IRQ);
 384         cpu_idle();
 385 }

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