mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 15:32:46 +00:00 
			
		
		
		
	 8b1154f5f2
			
		
	
	
		8b1154f5f2
		
	
	
	
	
		
			
			This implements a basic 8250 UART serial port driver. It does not currently handle (or enable) interrupts, nor any runtime configuration.
		
			
				
	
	
		
			236 lines
		
	
	
	
		
			6.4 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			236 lines
		
	
	
	
		
			6.4 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| #include "KSyms.h"
 | |
| #include "PIC.h"
 | |
| #include "Process.h"
 | |
| #include "RTC.h"
 | |
| #include "Scheduler.h"
 | |
| #include "i8253.h"
 | |
| #include "kmalloc.h"
 | |
| #include <AK/Types.h>
 | |
| #include <Kernel/Arch/i386/CPU.h>
 | |
| #include <Kernel/Devices/BXVGADevice.h>
 | |
| #include <Kernel/Devices/DebugLogDevice.h>
 | |
| #include <Kernel/Devices/DiskPartition.h>
 | |
| #include <Kernel/Devices/FullDevice.h>
 | |
| #include <Kernel/Devices/IDEDiskDevice.h>
 | |
| #include <Kernel/Devices/KeyboardDevice.h>
 | |
| #include <Kernel/Devices/MBRPartitionTable.h>
 | |
| #include <Kernel/Devices/NullDevice.h>
 | |
| #include <Kernel/Devices/PS2MouseDevice.h>
 | |
| #include <Kernel/Devices/RandomDevice.h>
 | |
| #include <Kernel/Devices/SerialDevice.h>
 | |
| #include <Kernel/Devices/ZeroDevice.h>
 | |
| #include <Kernel/FileSystem/DevPtsFS.h>
 | |
| #include <Kernel/FileSystem/Ext2FileSystem.h>
 | |
| #include <Kernel/FileSystem/ProcFS.h>
 | |
| #include <Kernel/FileSystem/VirtualFileSystem.h>
 | |
| #include <Kernel/KParams.h>
 | |
| #include <Kernel/Multiboot.h>
 | |
| #include <Kernel/Net/E1000NetworkAdapter.h>
 | |
| #include <Kernel/Net/NetworkTask.h>
 | |
| #include <Kernel/TTY/PTYMultiplexer.h>
 | |
| #include <Kernel/TTY/VirtualConsole.h>
 | |
| #include <Kernel/VM/MemoryManager.h>
 | |
| 
 | |
| //#define STRESS_TEST_SPAWNING
 | |
| 
 | |
| VirtualConsole* tty0;
 | |
| VirtualConsole* tty1;
 | |
| VirtualConsole* tty2;
 | |
| VirtualConsole* tty3;
 | |
| KeyboardDevice* keyboard;
 | |
| PS2MouseDevice* ps2mouse;
 | |
| DebugLogDevice* dev_debuglog;
 | |
| NullDevice* dev_null;
 | |
| SerialDevice* ttyS0;
 | |
| SerialDevice* ttyS1;
 | |
| SerialDevice* ttyS2;
 | |
| SerialDevice* ttyS3;
 | |
| VFS* vfs;
 | |
| 
 | |
| #ifdef STRESS_TEST_SPAWNING
 | |
| [[noreturn]] static void spawn_stress()
 | |
| {
 | |
|     dword last_sum_alloc = sum_alloc;
 | |
| 
 | |
|     for (unsigned i = 0; i < 10000; ++i) {
 | |
|         int error;
 | |
|         Process::create_user_process("/bin/true", (uid_t)100, (gid_t)100, (pid_t)0, error, {}, {}, tty0);
 | |
|         dbgprintf("malloc stats: alloc:%u free:%u eternal:%u !delta:%u\n", sum_alloc, sum_free, kmalloc_sum_eternal, sum_alloc - last_sum_alloc);
 | |
|         last_sum_alloc = sum_alloc;
 | |
|         sleep(60);
 | |
|     }
 | |
|     for (;;) {
 | |
|         asm volatile("hlt");
 | |
|     }
 | |
| }
 | |
| #endif
 | |
| 
 | |
| [[noreturn]] static void init_stage2()
 | |
| {
 | |
|     Syscall::initialize();
 | |
| 
 | |
|     auto dev_zero = make<ZeroDevice>();
 | |
|     auto dev_full = make<FullDevice>();
 | |
|     auto dev_random = make<RandomDevice>();
 | |
|     auto dev_ptmx = make<PTYMultiplexer>();
 | |
| 
 | |
|     auto root = KParams::the().get("root");
 | |
|     if (root.is_empty()) {
 | |
|         root = "/dev/hda";
 | |
|     }
 | |
| 
 | |
|     if (!root.starts_with("/dev/hda")) {
 | |
|         kprintf("init_stage2: root filesystem must be on the first IDE hard drive (/dev/hda)\n");
 | |
|         hang();
 | |
|     }
 | |
| 
 | |
|     auto dev_hd0 = IDEDiskDevice::create();
 | |
| 
 | |
|     Retained<DiskDevice> root_dev = dev_hd0.copy_ref();
 | |
| 
 | |
|     root = root.substring(strlen("/dev/hda"), root.length() - strlen("/dev/hda"));
 | |
| 
 | |
|     if (root.length()) {
 | |
|         bool ok;
 | |
|         unsigned partition_number = root.to_uint(ok);
 | |
| 
 | |
|         if (!ok) {
 | |
|             kprintf("init_stage2: couldn't parse partition number from root kernel parameter\n");
 | |
|             hang();
 | |
|         }
 | |
| 
 | |
|         if (partition_number < 1 || partition_number > 4) {
 | |
|             kprintf("init_stage2: invalid partition number %d; expected 1 to 4\n", partition_number);
 | |
|             hang();
 | |
|         }
 | |
| 
 | |
|         MBRPartitionTable mbr(root_dev.copy_ref());
 | |
|         if (!mbr.initialize()) {
 | |
|             kprintf("init_stage2: couldn't read MBR from disk\n");
 | |
|             hang();
 | |
|         }
 | |
| 
 | |
|         auto partition = mbr.partition(partition_number);
 | |
|         if (!partition) {
 | |
|             kprintf("init_stage2: couldn't get partition %d\n", partition_number);
 | |
|             hang();
 | |
|         }
 | |
| 
 | |
|         root_dev = *partition;
 | |
|     }
 | |
| 
 | |
|     auto e2fs = Ext2FS::create(root_dev.copy_ref());
 | |
|     if (!e2fs->initialize()) {
 | |
|         kprintf("init_stage2: couldn't open root filesystem\n");
 | |
|         hang();
 | |
|     }
 | |
| 
 | |
|     vfs->mount_root(e2fs.copy_ref());
 | |
| 
 | |
|     dbgprintf("Load ksyms\n");
 | |
|     load_ksyms();
 | |
|     dbgprintf("Loaded ksyms\n");
 | |
| 
 | |
|     vfs->mount(ProcFS::the(), "/proc");
 | |
|     vfs->mount(DevPtsFS::the(), "/dev/pts");
 | |
| 
 | |
|     int error;
 | |
| 
 | |
|     auto* system_server_process = Process::create_user_process("/bin/SystemServer", (uid_t)100, (gid_t)100, (pid_t)0, error, {}, {}, tty0);
 | |
|     if (error != 0) {
 | |
|         dbgprintf("init_stage2: error spawning SystemServer: %d\n", error);
 | |
|         hang();
 | |
|     }
 | |
|     system_server_process->set_priority(Process::HighPriority);
 | |
| 
 | |
| #ifdef STRESS_TEST_SPAWNING
 | |
|     Process::create_kernel_process("spawn_stress", spawn_stress);
 | |
| #endif
 | |
| 
 | |
|     current->process().sys$exit(0);
 | |
|     ASSERT_NOT_REACHED();
 | |
| }
 | |
| 
 | |
| extern "C" {
 | |
| multiboot_info_t* multiboot_info_ptr;
 | |
| }
 | |
| 
 | |
| extern "C" [[noreturn]] void init()
 | |
| {
 | |
|     sse_init();
 | |
| 
 | |
|     kmalloc_init();
 | |
|     init_ksyms();
 | |
| 
 | |
|     // must come after kmalloc_init because we use AK_MAKE_ETERNAL in KParams
 | |
|     new KParams(String(reinterpret_cast<const char*>(multiboot_info_ptr->cmdline)));
 | |
| 
 | |
|     vfs = new VFS;
 | |
|     dev_debuglog = new DebugLogDevice;
 | |
| 
 | |
|     auto console = make<Console>();
 | |
| 
 | |
|     RTC::initialize();
 | |
|     PIC::initialize();
 | |
|     gdt_init();
 | |
|     idt_init();
 | |
| 
 | |
|     keyboard = new KeyboardDevice;
 | |
|     ps2mouse = new PS2MouseDevice;
 | |
|     dev_null = new NullDevice;
 | |
|     ttyS0 = new SerialDevice(SERIAL_COM1_ADDR, 64);
 | |
|     ttyS1 = new SerialDevice(SERIAL_COM2_ADDR, 65);
 | |
|     ttyS2 = new SerialDevice(SERIAL_COM3_ADDR, 66);
 | |
|     ttyS3 = new SerialDevice(SERIAL_COM4_ADDR, 67);
 | |
| 
 | |
|     VirtualConsole::initialize();
 | |
|     tty0 = new VirtualConsole(0, VirtualConsole::AdoptCurrentVGABuffer);
 | |
|     tty1 = new VirtualConsole(1);
 | |
|     tty2 = new VirtualConsole(2);
 | |
|     tty3 = new VirtualConsole(3);
 | |
|     VirtualConsole::switch_to(0);
 | |
| 
 | |
|     kprintf("Starting Serenity Operating System...\n");
 | |
| 
 | |
|     MemoryManager::initialize();
 | |
|     PIT::initialize();
 | |
| 
 | |
|     new BXVGADevice;
 | |
| 
 | |
|     auto e1000 = E1000NetworkAdapter::autodetect();
 | |
| 
 | |
|     Retained<ProcFS> new_procfs = ProcFS::create();
 | |
|     new_procfs->initialize();
 | |
| 
 | |
|     auto devptsfs = DevPtsFS::create();
 | |
|     devptsfs->initialize();
 | |
| 
 | |
|     Process::initialize();
 | |
|     Thread::initialize();
 | |
|     Process::create_kernel_process("init_stage2", init_stage2);
 | |
|     Process::create_kernel_process("syncd", [] {
 | |
|         for (;;) {
 | |
|             Syscall::sync();
 | |
|             current->sleep(1 * TICKS_PER_SECOND);
 | |
|         }
 | |
|     });
 | |
|     Process::create_kernel_process("Finalizer", [] {
 | |
|         g_finalizer = current;
 | |
|         current->process().set_priority(Process::LowPriority);
 | |
|         for (;;) {
 | |
|             Thread::finalize_dying_threads();
 | |
|             current->block(Thread::BlockedLurking);
 | |
|             Scheduler::yield();
 | |
|         }
 | |
|     });
 | |
|     Process::create_kernel_process("NetworkTask", NetworkTask_main);
 | |
| 
 | |
|     Scheduler::pick_next();
 | |
| 
 | |
|     sti();
 | |
| 
 | |
|     // This now becomes the idle process :^)
 | |
|     for (;;) {
 | |
|         asm("hlt");
 | |
|     }
 | |
| }
 |