void OS::start() { // Initialize serial port com1.init(); // Print a fancy header FILLINE('='); CAPTION("#include<os> // Literally\n"); FILLINE('='); debug("\t[*] OS class started\n"); srand(time(NULL)); // Heap extern caddr_t heap_end; extern char _end; MYINFO("Heap start: @ %p", heap_end); MYINFO("Current end is: @ %p", &_end); atexit(default_exit); // Set up interrupt handlers IRQ_manager::init(); // Initialize the Interval Timer hw::PIT::init(); // Initialize PCI devices PCI_manager::init(); /** Estimate CPU frequency MYINFO("Estimating CPU-frequency"); INFO2("|"); INFO2("+--(10 samples, %f sec. interval)", (hw::PIT::frequency() / _cpu_sampling_freq_divider_).count()); INFO2("|"); // TODO: Debug why actual measurments sometimes causes problems. Issue #246. cpu_mhz_ = hw::PIT::CPUFrequency(); INFO2("+--> %f MHz", cpu_mhz_.count()); **/ MYINFO("Starting %s", Service::name().c_str()); FILLINE('='); // Everything is ready Service::start(); event_loop(); }
void OS::event_loop() { FILLINE('='); printf(" IncludeOS %s\n", version().c_str()); printf(" +--> Running [ %s ]\n", Service::name().c_str()); FILLINE('~'); while (power_) { IRQ_manager::notify(); debug("<OS> Woke up @ t = %li\n", uptime()); } //Cleanup //Service::stop(); }
void OS::event_loop() { FILLINE('='); printf(" IncludeOS %s\n", version().c_str()); printf(" +--> Running [ %s ]\n", Service::name().c_str()); FILLINE('~'); while (power_) { IRQ_manager::get().process_interrupts(); debug2("OS going to sleep.\n"); OS::halt(); } // Cleanup Service::stop(); // ACPI shutdown sequence hw::ACPI::shutdown(); }
void OS::start(uint32_t boot_magic, uint32_t boot_addr) { atexit(default_exit); default_stdout_handlers(); // Print a fancy header FILLINE('='); CAPTION("#include<os> // Literally\n"); FILLINE('='); auto esp = get_cpu_esp(); MYINFO ("Stack: 0x%x", esp); Expects (esp < 0xA0000 and esp > 0x0 and "Stack location OK"); MYINFO("Boot args: 0x%x (multiboot magic), 0x%x (bootinfo addr)", boot_magic, boot_addr); MYINFO("Max mem (from linker): %i MiB", reinterpret_cast<size_t>(&_MAX_MEM_MIB_)); if (boot_magic == MULTIBOOT_BOOTLOADER_MAGIC) { OS::multiboot(boot_magic, boot_addr); } else { // Fetch CMOS memory info (unfortunately this is maximally 10^16 kb) auto mem = cmos::meminfo(); low_memory_size_ = mem.base.total * 1024; INFO2("* Low memory: %i Kib", mem.base.total); high_memory_size_ = mem.extended.total * 1024; // Use memsize provided by Make / linker unless CMOS knows this is wrong decltype(high_memory_size_) hardcoded_mem = reinterpret_cast<size_t>(&_MAX_MEM_MIB_ - 0x100000) << 20; if (mem.extended.total == 0xffff or hardcoded_mem < mem.extended.total) { high_memory_size_ = hardcoded_mem; INFO2("* High memory (from linker): %i Kib", high_memory_size_ / 1024); } else { INFO2("* High memory (from cmos): %i Kib", mem.extended.total); } } MYINFO("Assigning fixed memory ranges (Memory map)"); auto& memmap = memory_map(); // @ Todo: The first ~600k of memory is free for use. What can we put there? memmap.assign_range({0x0009FC00, 0x0009FFFF, "EBDA", "Extended BIOS data area"}); memmap.assign_range({0x000A0000, 0x000FFFFF, "VGA/ROM", "Memory mapped video memory"}); memmap.assign_range({(uintptr_t)&_LOAD_START_, (uintptr_t)&_end, "ELF", "Your service binary including OS"}); // @note for security we don't want to expose this memmap.assign_range({(uintptr_t)&_end + 1, heap_begin - 1, "Pre-heap", "Heap randomization area (not for use))"}); memmap.assign_range({0x8000, 0x9fff, "Statman", "Statistics"}); memmap.assign_range({0xA000, 0x9fbff, "Kernel / service main stack"}); // Create ranges for heap and the remaining address space // @note : since the maximum size of a span is unsigned (ptrdiff_t) we may need more than one uintptr_t addr_max = std::numeric_limits<std::size_t>::max(); uintptr_t span_max = std::numeric_limits<std::ptrdiff_t>::max(); // Give the rest of physical memory to heap heap_max_ = ((0x100000 + high_memory_size_) & 0xffff0000) - 1; // ...Unless it's more than the maximum for a range // @note : this is a stupid way to limit the heap - we'll change it, but not until // we have a good solution. heap_max_ = std::min(span_max, heap_max_); memmap.assign_range({heap_begin, heap_max_, "Heap", "Dynamic memory", heap_usage }); uintptr_t unavail_start = 0x100000 + high_memory_size_; size_t interval = std::min(span_max, addr_max - unavail_start) - 1; uintptr_t unavail_end = unavail_start + interval; while (unavail_end < addr_max){ INFO2("* Unavailable memory: 0x%x - 0x%x", unavail_start, unavail_end); memmap.assign_range({unavail_start, unavail_end, "N/A", "Reserved / outside physical range" }); unavail_start = unavail_end + 1; interval = std::min(span_max, addr_max - unavail_start); // Increment might wrapped around if (unavail_start > unavail_end + interval or unavail_start + interval == addr_max){ INFO2("* Last chunk of memory: 0x%x - 0x%x", unavail_start, addr_max); memmap.assign_range({unavail_start, addr_max, "N/A", "Reserved / outside physical range" }); break; } unavail_end += interval; } MYINFO("Printing memory map"); for (const auto &i : memory_map()) INFO2("* %s",i.second.to_string().c_str()); // Set up interrupt and exception handlers IRQ_manager::init(); // read ACPI tables hw::ACPI::init(); // setup APIC, APIC timer, SMP etc. hw::APIC::init(); // enable interrupts INFO("BSP", "Enabling interrupts"); IRQ_manager::enable_interrupts(); // Initialize the Interval Timer hw::PIT::init(); // Initialize PCI devices PCI_manager::init(); // Print registered devices hw::Devices::print_devices(); // Estimate CPU frequency MYINFO("Estimating CPU-frequency"); INFO2("|"); INFO2("+--(10 samples, %f sec. interval)", (hw::PIT::frequency() / _cpu_sampling_freq_divider_).count()); INFO2("|"); // TODO: Debug why actual measurments sometimes causes problems. Issue #246. cpu_mhz_ = hw::PIT::CPU_frequency(); INFO2("+--> %f MHz", cpu_mhz_.count()); // cpu_mhz must be known before we can start timer system /// initialize timers hooked up to APIC timer Timers::init( // timer start function hw::APIC_Timer::oneshot, // timer stop function hw::APIC_Timer::stop); // initialize BSP APIC timer hw::APIC_Timer::init( [] { // set final interrupt handler hw::APIC_Timer::set_handler(Timers::timers_handler); // signal that kernel is done with everything Service::ready(); // signal ready // NOTE: this executes the first timers, so we // don't want to run this before calling Service ready Timers::ready(); }); // Realtime/monotonic clock RTC::init(); booted_at_ = RTC::now(); // sleep statistics os_cycles_hlt = &Statman::get().create( Stat::UINT64, std::string("cpu0.cycles_hlt")).get_uint64(); os_cycles_total = &Statman::get().create( Stat::UINT64, std::string("cpu0.cycles_total")).get_uint64(); // Trying custom initialization functions MYINFO("Calling custom initialization functions"); for (auto init : custom_init_) { INFO2("* Calling %s", init.name_); try{ init.func_(); } catch(std::exception& e){ MYINFO("Exception thrown when calling custom init: %s", e.what()); } catch(...){ MYINFO("Unknown exception when calling custom initialization function"); } } // Everything is ready MYINFO("Starting %s", Service::name().c_str()); FILLINE('='); // initialize random seed based on cycles since start srand(cycles_since_boot() & 0xFFFFFFFF); // begin service start Service::start(Service::command_line()); event_loop(); }