refactor: abstract out the code for prdte creation (by imposing a constrain on buffer...
[lunaix-os.git] / lunaix-os / kernel / proc0.c
1 #include <arch/x86/boot/multiboot.h>
2 #include <lunaix/common.h>
3 #include <lunaix/lunistd.h>
4 #include <lunaix/lxconsole.h>
5 #include <lunaix/mm/cake.h>
6 #include <lunaix/mm/pmm.h>
7 #include <lunaix/mm/valloc.h>
8 #include <lunaix/mm/vmm.h>
9 #include <lunaix/peripheral/ps2kbd.h>
10 #include <lunaix/proc.h>
11 #include <lunaix/spike.h>
12 #include <lunaix/syscall.h>
13 #include <lunaix/syslog.h>
14 #include <stddef.h>
15
16 #include <hal/acpi/acpi.h>
17 #include <hal/ahci/ahci.h>
18 #include <hal/apic.h>
19 #include <hal/ioapic.h>
20 #include <hal/pci.h>
21
22 #include <klibc/string.h>
23
24 LOG_MODULE("PROC0")
25
26 extern void
27 _lxinit_main(); /* lxinit.c */
28
29 void
30 init_platform();
31
32 void
33 lock_reserved_memory();
34
35 void
36 unlock_reserved_memory();
37
38 void
39 __do_reserved_memory(int unlock);
40
41 //#define USE_DEMO
42 #define DEMO_SIGNAL
43
44 extern void
45 _pconsole_main();
46
47 extern void
48 _signal_demo_main();
49
50 extern void
51 _lxinit_main();
52
53 void __USER__
54 __proc0_usr()
55 {
56     pid_t p;
57     if (!fork()) {
58         _pconsole_main();
59     }
60
61     if (!(p = fork())) {
62 #ifndef USE_DEMO
63         _exit(0);
64 #elif defined DEMO_SIGNAL
65         _signal_demo_main();
66 #else
67         _lxinit_main();
68 #endif
69     }
70
71     waitpid(p, 0, 0);
72
73     while (1) {
74         yield();
75     }
76 }
77
78 /**
79  * @brief LunaixOS的零号进程,该进程永远为可执行。
80  *
81  * 这主要是为了保证调度器在没有进程可调度时依然有事可做。
82  *
83  * 同时,该进程也负责fork出我们的init进程。
84  *
85  */
86 void
87 __proc0()
88 {
89     init_platform();
90
91     init_proc_user_space(__current);
92
93     asm volatile("movw %0, %%ax\n"
94                  "movw %%ax, %%es\n"
95                  "movw %%ax, %%ds\n"
96                  "movw %%ax, %%fs\n"
97                  "movw %%ax, %%gs\n"
98                  "pushl %0\n"
99                  "pushl %1\n"
100                  "pushl %2\n"
101                  "pushl %3\n"
102                  "retf" ::"i"(UDATA_SEG),
103                  "i"(USTACK_TOP & ~0xf),
104                  "i"(UCODE_SEG),
105                  "r"(__proc0_usr)
106                  : "eax", "memory");
107 }
108
109 extern uint8_t __kernel_start;            /* link/linker.ld */
110 extern uint8_t __kernel_end;              /* link/linker.ld */
111 extern uint8_t __init_hhk_end;            /* link/linker.ld */
112 extern multiboot_info_t* _k_init_mb_info; /* k_init.c */
113
114 char test_sequence[] = "Once upon a time, in a magical land of Equestria. "
115                        "There were two regal sisters who ruled together "
116                        "and created harmony for all the land.";
117
118 void
119 __test_disk_io()
120 {
121     struct hba_port* port = ahci_get_port(0);
122     char* buffer = vcalloc_dma(port->device->block_size);
123     strcpy(buffer, test_sequence);
124     kprintf("WRITE: %s\n", buffer);
125     int result;
126
127     // 写入第一扇区 (LBA=0)
128     result =
129       port->device->ops.write_buffer(port, 0, buffer, port->device->block_size);
130     if (!result) {
131         kprintf(KWARN "fail to write: %x\n", port->device->last_error);
132     }
133
134     memset(buffer, 0, port->device->block_size);
135
136     // 读出我们刚刚写的内容!
137     result =
138       port->device->ops.read_buffer(port, 0, buffer, port->device->block_size);
139     kprintf(KDEBUG "%x, %x\n", port->regs[HBA_RPxIS], port->regs[HBA_RPxTFD]);
140     if (!result) {
141         kprintf(KWARN "fail to read: %x\n", port->device->last_error);
142     } else {
143         kprint_hex(buffer, 256);
144     }
145
146     vfree_dma(buffer);
147 }
148
149 void
150 init_platform()
151 {
152     // 锁定所有系统预留页(内存映射IO,ACPI之类的),并且进行1:1映射
153     lock_reserved_memory();
154
155     cake_init();
156
157     assert_msg(kalloc_init(), "Fail to initialize heap");
158     valloc_init();
159
160     acpi_init(_k_init_mb_info);
161     apic_init();
162     ioapic_init();
163     timer_init(SYS_TIMER_FREQUENCY_HZ);
164     clock_init();
165     ps2_kbd_init();
166     pci_init();
167     ahci_init();
168     ahci_list_device();
169
170     __test_disk_io();
171
172     cake_stats();
173
174     syscall_install();
175
176     console_start_flushing();
177     console_flush();
178
179     unlock_reserved_memory();
180
181     for (size_t i = 0; i < (uintptr_t)(&__init_hhk_end); i += PG_SIZE) {
182         vmm_del_mapping(PD_REFERENCED, (void*)i);
183         pmm_free_page(KERNEL_PID, (void*)i);
184     }
185 }
186
187 void
188 lock_reserved_memory()
189 {
190     __do_reserved_memory(0);
191 }
192
193 void
194 unlock_reserved_memory()
195 {
196     __do_reserved_memory(1);
197 }
198
199 void
200 __do_reserved_memory(int unlock)
201 {
202     multiboot_memory_map_t* mmaps = _k_init_mb_info->mmap_addr;
203     size_t map_size =
204       _k_init_mb_info->mmap_length / sizeof(multiboot_memory_map_t);
205     // v_mapping mapping;
206     for (unsigned int i = 0; i < map_size; i++) {
207         multiboot_memory_map_t mmap = mmaps[i];
208         uint8_t* pa = PG_ALIGN(mmap.addr_low);
209         if (mmap.type == MULTIBOOT_MEMORY_AVAILABLE || pa <= MEM_4MB) {
210             // Don't fuck up our kernel code or any free area!
211             continue;
212         }
213         size_t pg_num = CEIL(mmap.len_low, PG_SIZE_BITS);
214         size_t j = 0;
215         if (!unlock) {
216             for (; j < pg_num; j++) {
217                 uintptr_t _pa = pa + (j << PG_SIZE_BITS);
218                 if (_pa >= KERNEL_MM_BASE) {
219                     // Don't fuck up our kernel space!
220                     break;
221                 }
222                 vmm_set_mapping(PD_REFERENCED, _pa, _pa, PG_PREM_R, VMAP_NULL);
223                 pmm_mark_page_occupied(
224                   KERNEL_PID, _pa >> PG_SIZE_BITS, PP_FGLOCKED);
225             }
226             // Save the progress for later unmapping.
227             mmaps[i].len_low = j * PG_SIZE;
228         } else {
229             for (; j < pg_num; j++) {
230                 uintptr_t _pa = pa + (j << PG_SIZE_BITS);
231                 vmm_del_mapping(PD_REFERENCED, _pa);
232                 if (mmap.type == MULTIBOOT_MEMORY_ACPI_RECLAIMABLE) {
233                     pmm_mark_page_free(_pa >> PG_SIZE_BITS);
234                 }
235             }
236         }
237     }
238 }