/* as --32 -o bootsect.o bootsect.asm ld -Ttext 0x7c00 --oformat binary -m elf_i386 -o bootsect.bin bootsect.o g++ -ffreestanding -m32 -o kernel.o -c kernel.cpp ld --oformat binary -Ttext 0x10000 -o kernel.bin --entry=kmain -m elf_i386 kernel.o qemu -fda bootsect.bin -fdb kernel.bin */ __asm("jmp kmain"); #define NWORD 456 #define CLR 0x02 #define VIDEO_BUF_PTR (0xb8000) #define IDT_TYPE_INTR (0x0E) #define IDT_TYPE_TRAP (0x0F) #define PIC1_PORT (0x20) #define CURSOR_PORT (0x3D4) #define VIDEO_WIDTH (80) #define GDT_CS (0x8) char avb_letter[27] = { 0 }; int avb_letter_cnt[26] = { 0 }; int rand = 0x12000; const char* empty_str = " "; int str_num = 0; int offset = 0; unsigned int ticks = 0; char time_os_loaded[15] = { 0 }; unsigned short mem_h = 0; unsigned short mem_l = 0; char strlen(const char *str) { const char *s; for (s = str; *s; ++s) ; return (s - str); } char strncmp(char *s1, char* s2, int len) { int i = 0; while (*s1 && *s2 && i < len) { if (*s1 != *s2) { return (*s1 - *s2); } s1++; s2++; i++; } if (i == len) { s1--; s2--; } return (*s1 - *s2); } unsigned int kbd_scan[44] = { 0x1e, 0x30, 0x2e, 0x20, 0x12, 0x21, 0x22, 0x23, 0x17, 0x24, 0x25, 0x26, 0x32, 0x31, 0x18, 0x19, 0x10, 0x13, 0x1f, 0x14, 0x16, 0x2f, 0x11, 0x2d, 0x15, 0x2c, 0x39, 0x0d, 0x0c, 0x35, 0x1c, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0e, 0x2a, 0xAA }; char alphabet[32] = "abcdefghijklmnopqrstuvwxyz +-/*"; bool is_shift_pressed = false; char command[41] = { 0 }; //OBRABOTKA PRERIVANIY KLAVIATURY ////////////////////////////////////////////////////////////////// static inline unsigned char inb(unsigned short port) { unsigned char data; asm volatile ("inb %w1, %b0": "=a" (data) : "Nd" (port)); return data; } static inline void outb(unsigned short port, unsigned char data) { asm volatile ("outb %b0, %w1" : : "a" (data), "Nd" (port)); } ////////////////////////////////////////////////////////////////// static inline void outw(unsigned short port, unsigned short data) { asm volatile ("outw %w0, %w1" : : "a" (data), "Nd" (port)); } void get_cpu_vendor_id(char *vendor_id) { unsigned int eax, ebx, ecx, edx; // Выполняем инструкцию CPUID с EAX = 0 для получения Vendor ID eax = 0; asm volatile ( "cpuid" : "=b"(ebx), "=d"(edx), "=c"(ecx), "=a"(eax) // Выходные операнды : "a"(eax) // Входной операнд, EAX = 0 ); // Копируем Vendor ID в строку *((unsigned int *)&vendor_id[0]) = ebx; *((unsigned int *)&vendor_id[4]) = edx; *((unsigned int *)&vendor_id[8]) = ecx; // Добавляем нуль-терминатор vendor_id[12] = '\0'; } //MOVE CURSORE TO POSITION /////////////////////////////////////////////////////////////////////// void cursor_moveto(unsigned int strnum, unsigned int pos) { unsigned short new_pos = (strnum * VIDEO_WIDTH) + pos; outb(CURSOR_PORT, 0x0F); outb(CURSOR_PORT + 1, (unsigned char)(new_pos & 0xFF)); outb(CURSOR_PORT, 0x0E); outb(CURSOR_PORT + 1, (unsigned char)((new_pos >> 8) & 0xFF)); } //////////////////////////////////////////////////////////////////////// // Функция для получения времени unsigned char get_time(unsigned char reg) { outb(0x70, reg); // Записываем интересующий регистр в порт 0x70 return inb(0x71); // Читаем текущее значение из порта 0x71 } void curtime(char* buffer, unsigned int buffer_size) { unsigned char seconds = get_time(0); // Читаем секунды unsigned char minutes = get_time(2); // Читаем минуты unsigned char hours = get_time(4); // Читаем часы // Преобразуем BCD в десятичный формат seconds = (seconds & 0x0F) + ((seconds >> 4) * 10); minutes = (minutes & 0x0F) + ((minutes >> 4) * 10); hours = ((hours & 0x0F) + ((hours >> 4) * 10) + 3) % 24; // Формируем строку времени char* ptr = buffer; // Чаcы *ptr++ = (hours / 10) + '0'; *ptr++ = (hours % 10) + '0'; *ptr++ = ':'; // Минуты *ptr++ = (minutes / 10) + '0'; *ptr++ = (minutes % 10) + '0'; *ptr++ = ':'; // Секунды *ptr++ = (seconds / 10) + '0'; *ptr++ = (seconds % 10) + '0'; // Завершаем строку *ptr++ = '\0'; } // void clear() { unsigned char* video_buf = (unsigned char*)VIDEO_BUF_PTR; // Очищаем весь видеобуфер for (unsigned int i = 0; i < 80 * 25; i++) { video_buf[i * 2] = (unsigned char)' '; // Установка пробела } // Сбрасываем курсор на начало str_num = 0; offset = 0; cursor_moveto(str_num, offset); } void get_str(char* ptr, int strnum) { unsigned char* video_buf = (unsigned char*)VIDEO_BUF_PTR; video_buf += 80 * 2 * strnum; for (int i = 0; i < 40; i++, video_buf += 2) { ptr[i] = *video_buf; } } void print_str(const char* ptr, unsigned int strnum); void skip() { if (str_num != 25) return; char temp[41] = { 0 }; for (int i = 0; i < 24; i++) { get_str(temp, i + 1); print_str(temp, i); } print_str(empty_str, 24); str_num = 24; } void print_str(const char* ptr, unsigned int strnum) { unsigned char* video_buf = (unsigned char*)VIDEO_BUF_PTR; video_buf += 80 * 2 * strnum; while (*ptr) { video_buf[0] = (unsigned char)*ptr; video_buf[1] = CLR; video_buf += 2; ptr++; } str_num++; offset = 0; skip(); cursor_moveto(str_num, offset); } void print_char(char chr) { unsigned char* video_buf = (unsigned char*)VIDEO_BUF_PTR; video_buf += 80 * 2 * str_num + offset * 2; video_buf[0] = (unsigned char)chr; video_buf[1] = CLR; offset++; cursor_moveto(str_num, offset); } //SHUTDOWN //////////////////////////////////////////// void shutdown_power_off (void) { const char s[] = "Shutdown"; const char *p; str_num++; offset = 0; skip(); print_str("Powering off...", str_num); outw (0xB004, 0x2000); outw (0x604, 0x2000); for (p = s; *p != '\0'; p++) outb (0x8900, *p); asm("cli"); asm("hlt"); } /////////////////////////////////////////////// struct idt_entry { unsigned short base_lo; unsigned short segm_sel; unsigned char always0; unsigned char flags; unsigned short base_hi; } __attribute__((packed)); struct idt_ptr { unsigned short limit; unsigned int base; } __attribute__((packed)); //////////////////////////////////////////////////// // Функция для преобразования ticks в строку void uint_to_string(unsigned int num, char* str_ticks) { if (num == 0) { str_ticks[0] = '0'; str_ticks[1] = '\0'; // Завершаем строку return; } char buffer[9 + 1]; // +1 для завершающего нуля int i = 0; // Заполнение буфера цифрами в обратном порядке while (num > 0) { buffer[i++] = '0' + (num % 10); // Получаем последнюю цифру num /= 10; // Убираем последнюю цифру } // Обратный порядок в строке for (int j = 0; j < i; j++) { str_ticks[j] = buffer[i - 1 - j]; } str_ticks[i] = '\0'; // Завершаем строку } /////////////////////////////////////////////////// void parseTime(char* timeStr, int* hours, int* minutes, int* seconds) { *hours = (timeStr[0] - '0') * 10 + (timeStr[1] - '0'); *minutes = (timeStr[3] - '0') * 10 + (timeStr[4] - '0'); *seconds = (timeStr[6] - '0') * 10 + (timeStr[7] - '0'); } void formatUptime(int totalSeconds, char* buffer) { int hours = totalSeconds / 3600; int minutes = (totalSeconds % 3600) / 60; int seconds = totalSeconds % 60; char* ptr = buffer; // Форматируем часы if (hours > 0) { // Преобразуем часы в строку if (hours >= 10) { *ptr++ = (hours / 10) + '0'; *ptr++ = (hours % 10) + '0'; } else { *ptr++ = hours + '0'; } *ptr++ = ' '; // Пробел после часов // Добавляем "hour" или "hours" if (hours == 1) { *ptr++ = 'h'; *ptr++ = 'o'; *ptr++ = 'u'; *ptr++ = 'r'; } else { *ptr++ = 'h'; *ptr++ = 'o'; *ptr++ = 'u'; *ptr++ = 'r'; *ptr++ = 's'; } // Проверяем, нужны ли запятые if (minutes > 0 || seconds > 0) { *ptr++ = ','; *ptr++ = ' '; } } // Форматируем минуты if (minutes > 0) { // Преобразуем минуты в строку if (minutes >= 10) { *ptr++ = (minutes / 10) + '0'; *ptr++ = (minutes % 10) + '0'; } else { *ptr++ = minutes + '0'; } *ptr++ = ' '; // Пробел после минут // Добавляем "minute" или "minutes" if (minutes == 1) { *ptr++ = 'm'; *ptr++ = 'i'; *ptr++ = 'n'; *ptr++ = 'u'; *ptr++ = 't'; *ptr++ = 'e'; } else { *ptr++ = 'm'; *ptr++ = 'i'; *ptr++ = 'n'; *ptr++ = 'u'; *ptr++ = 't'; *ptr++ = 'e'; *ptr++ = 's'; } // Проверяем, нужны ли запятые if (seconds > 0) { *ptr++ = ','; *ptr++ = ' '; } } // Форматируем секунды if (seconds >= 10) { *ptr++ = (seconds / 10) + '0'; *ptr++ = (seconds % 10) + '0'; } else { *ptr++ = seconds + '0'; } *ptr++ = ' '; // Пробел после секунд // Добавляем "second" или "seconds" if (seconds == 1) { *ptr++ = 's'; *ptr++ = 'e'; *ptr++ = 'c'; *ptr++ = 'o'; *ptr++ = 'n'; *ptr++ = 'd'; } else { *ptr++ = 's'; *ptr++ = 'e'; *ptr++ = 'c'; *ptr++ = 'o'; *ptr++ = 'n'; *ptr++ = 'd'; *ptr++ = 's'; } *ptr = '\0'; // Завершаем строку } int calculateUptime(char* bootTime, char* currentTime, char* uptimeStr) { int bootHours, bootMinutes, bootSeconds; int currentHours, currentMinutes, currentSeconds; parseTime(bootTime, &bootHours, &bootMinutes, &bootSeconds); parseTime(currentTime, ¤tHours, ¤tMinutes, ¤tSeconds); // Преобразуем всё в секунды int bootTotalSeconds = bootHours * 3600 + bootMinutes * 60 + bootSeconds; int currentTotalSeconds = currentHours * 3600 + currentMinutes * 60 + currentSeconds; // Вычисляем общее время работы системы int uptimeTotalSeconds = currentTotalSeconds - bootTotalSeconds; // Если текущее время меньше времени включения (например, переход через полночь) if (uptimeTotalSeconds < 0) { uptimeTotalSeconds += 24 * 3600; // Добавляем 24 часа в секундах } formatUptime(uptimeTotalSeconds, uptimeStr); return uptimeTotalSeconds; } /////////////////////////////////////////////////// void meminfo_command() { unsigned int size = mem_h * 64 + mem_l; char buffer[20]; uint_to_string(size, buffer); print_str(buffer, str_num); print_str("Kilobytes", str_num); } //VYPOLNENIYE COMMAND //////////////////////////////////////////////////// void cmd_exec() { int command_switch = 0; if ('\0' == strncmp(command, "info", 4)) { command_switch = 1; } else if ('\0' == strncmp(command, "help", 4)) { command_switch = 2; } else if ('\0' == strncmp(command, "clear ", 5)) { command_switch = 3; } else if ('\0' == strncmp(command, "curtime", 7)) { command_switch = 4; } else if ('\0' == strncmp(command, "shutdown", 8)) { command_switch = 5; } else if ('\0' == strncmp(command, "cpuid", 5)) { command_switch = 6; } else if ('\0' == strncmp(command, "ticks", 5)) { command_switch = 7; } else if ('\0' == strncmp(command, "loadtime", 8)) { command_switch = 8; } else if ('\0' == strncmp(command, "uptime", 6)) { command_switch = 9; } else if ('\0' == strncmp(command, "meminfo", 7)) { command_switch = 10; } else { command_switch = 0; } switch (command_switch) { case 1: { print_str("Made by ...", str_num); print_str("...", str_num); print_str("with: GNU Assembler, GCC, Intel syntax", str_num); break; } case 2: { print_str("+ info - System information", str_num); print_str("+ help - List of supported commands", str_num); print_str("+ clear - Clear command history", str_num); print_str("+ ticks - ticks number since the start", str_num); print_str("+ loadtime - The time the OS was booted", str_num); print_str("+ curtime - Current time", str_num); print_str("+ uptime - Uptime in a readable format", str_num); print_str("+ meminfo - Inf about available memory", str_num); print_str("+ cpuid - Specifies the processor model", str_num); print_str("+ shutdown - Computer shutdown", str_num); break; } case 3: { clear(); break; } case 4: { char time_str[50]; // Буфер для строки времени curtime(time_str, sizeof(time_str)); print_str(time_str, str_num); break; } case 5: { shutdown_power_off(); break; } case 6: { char vendor_id[13]; get_cpu_vendor_id(vendor_id); print_str(vendor_id, str_num); break; } case 7: { char str_ticks[10]; uint_to_string(ticks, str_ticks); print_str(str_ticks, str_num); break; } case 8: { print_str(time_os_loaded, str_num); break; } case 9: { char currentTime[50]; // Буфер для строки времени curtime(currentTime, sizeof(currentTime)); char uptimeStr[100]; // Буфер для строки uptime calculateUptime(time_os_loaded, currentTime, uptimeStr); print_str(uptimeStr, str_num); break; } case 10: { meminfo_command(); break; } default: { print_str("wrong input", str_num); break; } } } //////////////////////////////////////////////////////////////////// //NAZHATIE KLAVISH //////////////////////////////////////////////////////////////////// void on_key(unsigned int scan_code) { int i; for (i = 0; i < 43; i++) { if (scan_code == kbd_scan[i]) break; } if (i == 43) return; if (i >= 0 && i <= 25) { if (is_shift_pressed == true) { command[offset] = alphabet[i] - (char)0x20; print_char(alphabet[i] - (char)0x20); } else { command[offset] = alphabet[i]; print_char(alphabet[i]); } } else if (i >= 26 && i <= 29) { command[offset] = alphabet[i]; print_char(alphabet[i]); } else if (i == 30) { str_num++; skip(); offset = 0; cursor_moveto(str_num, offset); cmd_exec(); for (int i = 0; i < 41; i++) command[i] = '\0'; str_num++; skip(); offset = 0; cursor_moveto(str_num, offset); } else if (i >= 31 && i <= 40) { if (is_shift_pressed) { command[offset] = '*'; print_char('*'); } else { char num = (char)((kbd_scan[i] - 1) % 10 + '0'); command[offset] = num - '0'; print_char(num); } } else { if (offset == 0) return; offset--; command[offset] = '\0'; print_char(' '); offset--; cursor_moveto(str_num, offset); } } ////////////////////////////////////////////////////////////////////// //SCHITIVANIE POSTUPAYSHEGO SIMVOLA ////////////////////////////////////////////////////////// void process_shift(unsigned int scan_code) { if (scan_code == kbd_scan[42]) { is_shift_pressed = true; } else if (scan_code == kbd_scan[43]) { is_shift_pressed = false; } else if (scan_code < 128 || scan_code == 0x135) { on_key(scan_code); } } void keyb_process_keys() { if (inb(0x64) & 0x01) { unsigned int scan_code; scan_code = (unsigned int)inb(0x60) & 0x1FF; if (offset == 40 && scan_code != kbd_scan[30]) { return; } process_shift(scan_code); } } //////////////////////////////////////////////////////////////////// //OBRABOTCHIK PRERIVANIY //////////////////////////////////////////////////////////////////// void keyb_handler() { asm("pusha"); keyb_process_keys(); outb(PIC1_PORT, 0x20); asm("popa; leave; iret"); } ///////////////////////////////////////////////////////////////////// // Обработчик тиков ///////////////////////////////////////////////////////////////////// void timer_handler() { asm("pusha"); ticks++; // Инкрементируем счетчик тиков outb(PIC1_PORT, 0x20); // Посылаем сигнал завершения прерывания asm("popa; leave; iret"); } ///////////////////////////////////////////////////////////////////// //PROCEDURA OBRABOTCHIK PRERIVANIY ///////////////////////////////////////////////////////////////////// struct idt_entry g_idt[256]; struct idt_ptr g_idtp; void default_interrupt_handler() { asm("pusha"); asm("popa; leave; iret"); } typedef void(*interrupt_handler)(); void interrupt_reg_handler(int num, unsigned short segm_sel, unsigned short flags, interrupt_handler hndlr) { unsigned int hndlr_addr = (unsigned int)hndlr; g_idt[num].base_lo = (unsigned short)(hndlr_addr & 0xFFFF); g_idt[num].segm_sel = segm_sel; g_idt[num].always0 = 0; g_idt[num].flags = flags; g_idt[num].base_hi = (unsigned short)(hndlr_addr >> 16); } void keyb_init() { interrupt_reg_handler(0x09, GDT_CS, 0x80 | IDT_TYPE_INTR, keyb_handler); outb(PIC1_PORT + 1, 0xFF ^ 0x02); } void timer_init() { // Регистрация обработчика прерывания interrupt_reg_handler(8, GDT_CS, 0x80 | IDT_TYPE_INTR, timer_handler); // segm_sel=0x8, P=1, DPL=0, Type=Intr // Разрешение только прерываний клавиатуры от контроллера 8259 outb(PIC1_PORT + 1, 0xFF ^ 0x01); // 0xFF - все прерывания, 0x02 - бит IRQ1 (клавиатура) // Разрешены будут только прерывания, чьи биты установлены в 0 } void interrupt_init() { int i; int idt_count = sizeof(g_idt) / sizeof(g_idt[0]); for (i = 0; i < idt_count; i++) interrupt_reg_handler(i, GDT_CS, 0x80 | IDT_TYPE_INTR, default_interrupt_handler); } void interrupt_start() { int idt_count = sizeof(g_idt) / sizeof(g_idt[0]); g_idtp.base = (unsigned int)(&g_idt[0]); g_idtp.limit = (sizeof(struct idt_entry) * idt_count) - 1; asm("lidt %0" : : "m" (g_idtp)); } void interrupt_enable() { asm("sti"); } void interrupt_disable() { asm("cli"); } extern "C" int kmain() { interrupt_init(); timer_init(); interrupt_disable(); keyb_init(); interrupt_start(); interrupt_enable(); cursor_moveto(str_num, offset); curtime(time_os_loaded, sizeof(time_os_loaded)); char m1, m2; m1 = (*(char*)(0x3400)); m2 = (*(char*)(0x3420)); mem_l = (unsigned short)m1; mem_h = (unsigned short)m2; const char* hello = ".:: WELCOME TO INFO_OS ::."; print_str(hello , str_num); while (1) { outb(PIC1_PORT + 1, 0xFF ^ 0x02); outb(PIC1_PORT + 1, 0xFF ^ 0x01); asm("hlt"); } return 0; }