feat: nearly complete POSIX.1-2008 compliant terminal interface implementation
[lunaix-os.git] / lunaix-os / arch / i386 / boot / mb_parser.c
1 #define __BOOT_CODE__
2
3 #include <lunaix/boot_generic.h>
4 #include <sys/boot/bstage.h>
5 #include <sys/boot/multiboot.h>
6 #include <sys/mm/mempart.h>
7
8 #define BHCTX_ALLOC 4096
9
10 u8_t bhctx_buffer[BHCTX_ALLOC] boot_bss;
11
12 #define check_buffer(ptr)                                                      \
13     if ((ptr) >= ((ptr_t)bhctx_buffer + BHCTX_ALLOC)) {                        \
14         asm("ud2");                                                            \
15     }
16
17 size_t boot_text
18 mb_memcpy(u8_t* destination, u8_t* base, unsigned int size)
19 {
20     unsigned int i = 0;
21     for (; i < size; i++) {
22         *(destination + i) = *(base + i);
23     }
24     return i;
25 }
26
27 size_t boot_text
28 mb_strcpy(char* destination, char* base)
29 {
30     int i = 0;
31     char c = 0;
32     while ((c = base[i])) {
33         destination[i] = c;
34         i++;
35     }
36
37     destination[++i] = 0;
38
39     return i;
40 }
41
42 size_t boot_text
43 mb_strlen(char* s)
44 {
45     int i = 0;
46     while (s[i++])
47         ;
48     return i;
49 }
50
51 size_t boot_text
52 mb_parse_cmdline(struct boot_handoff* bhctx, void* buffer, char* cmdline)
53 {
54 #define SPACE ' '
55
56     size_t slen = mb_strlen(cmdline);
57
58     if (!slen) {
59         return 0;
60     }
61
62     mb_memcpy(buffer, (u8_t*)cmdline, slen);
63
64     cmdline = (char*)buffer;
65     buffer = &cmdline[slen];
66
67     char c, prev = SPACE;
68     int i = 0, argc = 0;
69     ptr_t argptr = (ptr_t)cmdline;
70
71     while ((c = cmdline[i])) {
72         if (c == SPACE && prev != SPACE) {
73             ((ptr_t*)buffer)[argc++] = argptr;
74         } else if (c != SPACE && prev == SPACE) {
75             argptr = (ptr_t)&cmdline[i];
76         }
77         prev = c;
78         i++;
79     }
80
81     bhctx->kexec.argv = (char**)buffer;
82     bhctx->kexec.argc = argc;
83
84     return slen + argc * sizeof(ptr_t);
85 }
86
87 size_t boot_text
88 mb_parse_mmap(struct boot_handoff* bhctx,
89               struct multiboot_info* mb,
90               void* buffer)
91 {
92     struct multiboot_mmap_entry* mb_mmap =
93       (struct multiboot_mmap_entry*)mb->mmap_addr;
94     size_t mmap_len = mb->mmap_length / sizeof(struct multiboot_mmap_entry);
95
96     struct boot_mmapent* bmmap = (struct boot_mmapent*)buffer;
97     for (size_t i = 0; i < mmap_len; i++) {
98         struct boot_mmapent* bmmapent = &bmmap[i];
99         struct multiboot_mmap_entry* mb_mapent = &mb_mmap[i];
100
101         if (mb_mapent->type == MULTIBOOT_MEMORY_AVAILABLE) {
102             bmmapent->type = BOOT_MMAP_FREE;
103         } else if (mb_mapent->type == MULTIBOOT_MEMORY_ACPI_RECLAIMABLE) {
104             bmmapent->type = BOOT_MMAP_RCLM;
105         } else {
106             bmmapent->type = BOOT_MMAP_RSVD;
107         }
108
109         bmmapent->start = mb_mapent->addr_low;
110         bmmapent->size = mb_mapent->len_low;
111     }
112
113     bhctx->mem.size = (mb->mem_upper << 10) + MEM_1M;
114     bhctx->mem.mmap = bmmap;
115     bhctx->mem.mmap_len = mmap_len;
116
117     return mmap_len * sizeof(struct boot_mmapent);
118 }
119
120 size_t boot_text
121 mb_parse_mods(struct boot_handoff* bhctx,
122               struct multiboot_info* mb,
123               void* buffer)
124 {
125     if (!mb->mods_count) {
126         bhctx->mods.mods_num = 0;
127         return 0;
128     }
129
130     struct boot_modent* modents = (struct boot_modent*)buffer;
131     struct multiboot_mod_list* mods = (struct multiboot_mod_list*)mb->mods_addr;
132
133     ptr_t mod_str_ptr = (ptr_t)&modents[mb->mods_count];
134
135     for (size_t i = 0; i < mb->mods_count; i++) {
136         struct multiboot_mod_list* mod = &mods[i];
137         modents[i] = (struct boot_modent){ .start = mod->mod_start,
138                                            .end = mod->mod_end,
139                                            .str = (char*)mod_str_ptr };
140         mod_str_ptr += mb_strcpy((char*)mod_str_ptr, (char*)mod->cmdline);
141     }
142
143     bhctx->mods.mods_num = mb->mods_count;
144     bhctx->mods.entries = modents;
145
146     return mod_str_ptr - (ptr_t)buffer;
147 }
148
149 void boot_text
150 mb_prepare_hook(struct boot_handoff* bhctx)
151 {
152     // nothing to do
153 }
154
155 void boot_text
156 mb_release_hook(struct boot_handoff* bhctx)
157 {
158     // nothing to do
159 }
160
161 #define align_addr(addr) (((addr) + (sizeof(ptr_t) - 1)) & ~(sizeof(ptr_t) - 1))
162
163 struct boot_handoff* boot_text
164 mb_parse(struct multiboot_info* mb)
165 {
166     struct boot_handoff* bhctx = (struct boot_handoff*)bhctx_buffer;
167     ptr_t bhctx_ex = (ptr_t)&bhctx[1];
168
169     /* Parse memory map */
170     if ((mb->flags & MULTIBOOT_INFO_MEM_MAP)) {
171         bhctx_ex += mb_parse_mmap(bhctx, mb, (void*)bhctx_ex);
172         bhctx_ex = align_addr(bhctx_ex);
173     }
174
175     /* Parse cmdline */
176     if ((mb->flags & MULTIBOOT_INFO_CMDLINE)) {
177         bhctx_ex +=
178           mb_parse_cmdline(bhctx, (void*)bhctx_ex, (char*)mb->cmdline);
179         bhctx_ex = align_addr(bhctx_ex);
180     }
181
182     /* Parse sys modules */
183     if ((mb->flags & MULTIBOOT_INFO_MODS)) {
184         bhctx_ex += mb_parse_mods(bhctx, mb, (void*)bhctx_ex);
185         bhctx_ex = align_addr(bhctx_ex);
186     }
187
188     check_buffer(bhctx_ex);
189
190     bhctx->prepare = mb_prepare_hook;
191     bhctx->release = mb_release_hook;
192
193     return bhctx;
194 }