25 /* Amount of physical memory, in 4 kB pages. */
28 static void ram_init (void);
29 static void gdt_init (void);
30 static void argv_init (void);
31 void power_off (void);
34 main_thread (void *aux UNUSED)
46 /* Initialize prerequisites for calling printk(). */
52 printk ("Booting cnachos86 with %'d kB RAM...\n", ram_pages * 4);
54 /* Initialize memory system. */
63 /* Initialize interrupt handlers. */
68 /* Do everything else in a system thread. */
70 thread_start (thread_create ("main", main_thread, NULL));
74 make_seg_desc (uint32_t base,
76 enum seg_system system,
79 enum seg_granularity granularity)
81 uint32_t e0 = ((limit & 0xffff) /* Limit 15:0. */
82 | (base << 16)); /* Base 15:0. */
83 uint32_t e1 = (((base >> 16) & 0xff) /* Base 23:16. */
84 | (system << 12) /* 0=system, 1=code/data. */
85 | (type << 8) /* Segment type. */
86 | (dpl << 13) /* Descriptor privilege. */
87 | (1 << 15) /* Present. */
88 | (limit & 0xf0000) /* Limit 16:19. */
89 | (1 << 22) /* 32-bit segment. */
90 | (granularity << 23) /* Byte/page granularity. */
91 | (base & 0xff000000)); /* Base 31:24. */
92 return e0 | ((uint64_t) e1 << 32);
96 make_code_desc (int dpl)
98 return make_seg_desc (0, 0xfffff, SYS_CODE_DATA, TYPE_CODE | TYPE_READABLE,
103 make_data_desc (int dpl)
105 return make_seg_desc (0, 0xfffff, SYS_CODE_DATA, TYPE_WRITABLE,
110 make_tss_desc (void *vaddr)
112 return make_seg_desc ((uint32_t) vaddr,
113 0x67, SYS_SYSTEM, TYPE_TSS_32_A, 0, GRAN_BYTE);
116 uint64_t gdt[SEL_CNT];
120 /* Sets up a proper GDT. The bootstrap loader's GDT didn't
121 include user-mode selectors or a TSS. */
125 uint64_t gdtr_operand;
127 /* Our TSS is never used in a call gate or task gate, so only a
128 few fields of it are ever referenced, and those are the only
129 ones we initialize. */
130 tss = palloc_get (PAL_ASSERT | PAL_ZERO);
131 tss->esp0 = (uint32_t) ptov(0x20000);
132 tss->ss0 = SEL_KDSEG;
133 tss->bitmap = 0xdfff;
135 /* Initialize GDT. */
136 gdt[SEL_NULL / sizeof *gdt] = 0;
137 gdt[SEL_KCSEG / sizeof *gdt] = make_code_desc (0);
138 gdt[SEL_KDSEG / sizeof *gdt] = make_data_desc (0);
139 gdt[SEL_UCSEG / sizeof *gdt] = make_code_desc (3);
140 gdt[SEL_UDSEG / sizeof *gdt] = make_data_desc (3);
141 gdt[SEL_TSS / sizeof *gdt] = make_tss_desc (tss);
144 gdtr_operand = make_dtr_operand (sizeof gdt - 1, gdt);
145 asm volatile ("lgdt %0" :: "m" (gdtr_operand));
146 asm volatile ("ltr %w0" :: "r" (SEL_TSS));
152 /* The "BSS" is a segment that should be initialized to zeros.
153 It isn't actually stored on disk or zeroed by the kernel
154 loader, so we have to zero it ourselves.
156 The start and end of the BSS segment is recorded by the
157 linker as _start_bss and _end_bss. See kernel.lds. */
158 extern char _start_bss, _end_bss;
159 memset (&_start_bss, 0, &_end_bss - &_start_bss);
161 /* Get RAM size from loader. */
162 ram_pages = *(uint32_t *) ptov (LOADER_RAM_PAGES);
165 /* This should be sufficient because the command line buffer is
166 only 128 bytes and arguments are space-delimited. */
170 char *argv[ARGC_MAX + 1];
175 char *cmd_line = ptov (LOADER_CMD_LINE);
178 for (arg = strtok_r (cmd_line, " \t\r\n\v", &pos); arg != NULL;
179 arg = strtok_r (NULL, " \t\r\n\v", &pos))
181 ASSERT (argc < ARGC_MAX);
190 const char s[] = "Shutdown";
193 printk ("Powering off...\n");
194 for (p = s; *p != '\0'; p++)