UCHEBA/4 СЕМ/ОПЕРАЦИОННЫЕ СИСТЕМЫ/2 ЛАБА/kernel.cpp

832 lines
20 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/*
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;
// Ча
*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, &currentHours, &currentMinutes, &currentSeconds);
// Преобразуем всё в секунды
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;
}