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

832 lines
20 KiB
C++
Raw Permalink Normal View History

/*
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;
}