mirror of https://github.com/0Nera/BMOSP.git
Переименовал проект в БМПОС
This commit is contained in:
parent
8591760539
commit
fbd3e2712e
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"C_Cpp.errorSquiggles": "disabled"
|
||||
}
|
27
README.md
27
README.md
|
@ -1,9 +1,9 @@
|
|||
# MSEOS: минимальная студенческая обучающая операционная система
|
||||
# БМПОС: Базовая Модульная Платформа Операционных Систем
|
||||
|
||||
[![CI BUILD](https://github.com/0Nera/MSEOS/actions/workflows/build.yml/badge.svg?branch=master)](https://github.com/0Nera/MSEOS/actions/workflows/build.yml)
|
||||
[![Github pages](https://github.com/0Nera/MSEOS/actions/workflows/pages/pages-build-deployment/badge.svg?branch=pages)](https://github.com/0Nera/MSEOS/actions/workflows/pages/pages-build-deployment)
|
||||
[![CI сборка](https://github.com/0Nera/BMOSP/actions/workflows/build.yml/badge.svg?branch=master)](https://github.com/0Nera/MSEOS/actions/workflows/build.yml)
|
||||
[![Github pages сайт](https://github.com/0Nera/BMOSP/actions/workflows/pages/pages-build-deployment/badge.svg?branch=pages)](https://github.com/0Nera/MSEOS/actions/workflows/pages/pages-build-deployment)
|
||||
|
||||
MSEOS - минимальная студенческая обучающая операционная система с открытым исходным кодом для платформы x86_64(BIOS/UEFI). Это отечественная операционная система.
|
||||
БМПОС - Базовая Модульная Платформа Операционных Систем для платформы x86_64 (BIOS/UEFI). Это отечественное программное обеспечение, созданное при поддержке Синапс ОС на языке программирования C++.
|
||||
|
||||
Система:
|
||||
- [ ] Менеджер памяти
|
||||
|
@ -41,11 +41,20 @@ MSEOS - минимальная студенческая обучающая оп
|
|||
|
||||
- <https://vk.com/mseos> Страница вконтакте
|
||||
- <https://mseos.ru> Вебсайт
|
||||
- <https://wiki.synapseos.ru/index.php?title=MSEOS> Страница на вики
|
||||
- <https://wiki.synapseos.ru/index.php?title=БМПОС> Страница на вики
|
||||
|
||||
### Зеркала
|
||||
|
||||
- <https://git.synapseos.ru/Aren/MSEOS> - доверенный сервер(главный репозиторий)
|
||||
- <https://github.com/0Nera/MSEOS> - зеркало
|
||||
- <https://tvoygit.ru/0Nera/mseos> - зеркало
|
||||
- <https://hub.mos.ru/synapseos/mseos> - неактивное зеркало
|
||||
- <https://git.synapseos.ru/Aren/BMOSP> - доверенный сервер(главный репозиторий)
|
||||
- <https://github.com/0Nera/BMOSP> - зеркало
|
||||
- <https://tvoygit.ru/0Nera/BMOSP> - зеркало
|
||||
- <https://hub.mos.ru/synapseos/BMOSP> - неактивное зеркало
|
||||
|
||||
### Использованные ресурсы
|
||||
|
||||
- https://github.com/limine-bootloader/limine (BSD 2-Clause)
|
||||
- https://github.com/nothings/stb (MIT, Общественное достояние)
|
||||
- https://en.wikipedia.org/wiki/CPUID
|
||||
- https://github.com/klange/toaruos (NCSA)
|
||||
- https://wiki.osdev.org/Model_Specific_Registers
|
||||
- https://sandpile.org/x86/msr.htm
|
61
build.py
61
build.py
|
@ -5,14 +5,46 @@ import time
|
|||
from multiprocessing import Pool
|
||||
|
||||
|
||||
CC = "g++"
|
||||
ARCH_FLAGS = "-m64 -march=x86-64 -mabi=sysv -mno-80387 -mno-red-zone -mcmodel=kernel -MMD -MP"
|
||||
WARN_FLAGS = "-w -Wall -Wextra"
|
||||
ARCH_FLAGS = "-m64 -march=x86-64 -mabi=sysv -mno-red-zone -mcmodel=kernel -MMD -MP"
|
||||
WARN_FLAGS = "-w -Wall -Wextra -nostdlib"
|
||||
STANDART_FLAGS = "-std=gnu11"
|
||||
PROTECT_FLAGS = "-O0 -pipe -ffreestanding -fno-stack-protector -fno-lto -fno-stack-check -fno-PIC -fno-PIE"
|
||||
CHARSET_FLAGS = "-finput-charset=UTF-8 -fexec-charset=cp1251"
|
||||
LIBS_FLAGS = "-Ilimine -Iinclude"
|
||||
|
||||
def version_build():
|
||||
with open("include/version.h", "r") as file:
|
||||
lines = file.readlines()
|
||||
|
||||
major = 0
|
||||
minor = 0
|
||||
build = 0
|
||||
|
||||
with open("include/version.h", "w") as file:
|
||||
for line in lines:
|
||||
if line.startswith("#define VERSION_BUILD"):
|
||||
parts = line.split()
|
||||
build = int(parts[2]) + 1
|
||||
if build > 255:
|
||||
build = 0
|
||||
minor += 1
|
||||
file.write(f"#define VERSION_MINOR {minor}\n")
|
||||
file.write(f"#define VERSION_BUILD {build}\n")
|
||||
elif line.startswith("#define VERSION_MAJOR"):
|
||||
parts = line.split()
|
||||
major = int(parts[2])
|
||||
file.write(line)
|
||||
elif line.startswith("#define VERSION_MINOR"):
|
||||
parts = line.split()
|
||||
minor = int(parts[2])
|
||||
file.write(line)
|
||||
else:
|
||||
file.write(line)
|
||||
|
||||
return [major, minor, build]
|
||||
|
||||
def sort_strings(strings):
|
||||
return sorted(strings, key=lambda x: not x.endswith('.s.o'))
|
||||
|
||||
def find_files(directory, extensions):
|
||||
file_list = []
|
||||
|
@ -24,6 +56,7 @@ def find_files(directory, extensions):
|
|||
|
||||
|
||||
def compile(file: str):
|
||||
CC = "g++" if file.endswith('cpp') else "gcc"
|
||||
output_file = file.replace('/', '_')
|
||||
obj_file = f"bin/{output_file}.o"
|
||||
cmd = f"{CC} {WARN_FLAGS} {PROTECT_FLAGS} {ARCH_FLAGS} {CHARSET_FLAGS} {LIBS_FLAGS} -c {file} -o {obj_file}"
|
||||
|
@ -33,7 +66,8 @@ def compile(file: str):
|
|||
|
||||
|
||||
def compile_all():
|
||||
file_list = find_files("kernel/", [".c", ".cpp", ".s"])
|
||||
file_list = find_files("kernel/", [".s", ".cpp", ".c"])
|
||||
file_list += find_files("kernel/*/*", [".s", ".cpp", ".c"])
|
||||
|
||||
with Pool() as pool:
|
||||
results = pool.map(compile, file_list)
|
||||
|
@ -42,7 +76,7 @@ def compile_all():
|
|||
print(results)
|
||||
time.sleep(1)
|
||||
print(results)
|
||||
cmd = f"ld -nostdlib -static -m elf_x86_64 -z max-page-size=0x1000 -T configs/linker.ld -o kernel.elf {' '.join(results)}"
|
||||
cmd = f"ld -nostdlib -static -m elf_x86_64 -z max-page-size=0x1000 -T configs/linker.ld -o kernel.elf {' '.join(sort_strings(results))}"
|
||||
print(cmd)
|
||||
os.system(cmd)
|
||||
|
||||
|
@ -77,13 +111,16 @@ def create_hdd(IMAGE_NAME):
|
|||
subprocess.run(["sgdisk", IMAGE_NAME+".hdd", "-n", "1:2048", "-t", "1:ef00"])
|
||||
subprocess.run(["./limine/limine", "bios-install", IMAGE_NAME+".hdd"])
|
||||
subprocess.run(["mformat", "-i", IMAGE_NAME+".hdd@@1M"])
|
||||
subprocess.run(["mmd", "-i", IMAGE_NAME+".hdd@@1M", "::/mod", "::/EFI", "::/EFI/BOOT"])
|
||||
subprocess.run(["mmd", "-i", IMAGE_NAME+".hdd@@1M", "::/mod", "::/EFI", "::/EFI/BOOT", "::/user"])
|
||||
subprocess.run(["mcopy", "-i", IMAGE_NAME+".hdd@@1M",
|
||||
"kernel.elf", "configs/limine.cfg", "limine/limine-bios.sys", "::/"])
|
||||
subprocess.run(["mcopy", "-i", IMAGE_NAME+".hdd@@1M",
|
||||
"modules/com/com.elf", "modules/helloworld/helloworld.elf", "::/mod"])
|
||||
subprocess.run(["mcopy", "-i", IMAGE_NAME+".hdd@@1M",
|
||||
"limine/BOOTX64.EFI", "limine/BOOTIA32.EFI", "::/EFI/BOOT"])
|
||||
subprocess.run(["mcopy", "-i", IMAGE_NAME+".hdd@@1M",
|
||||
"boot.png", "::/"])
|
||||
subprocess.run(["./limine/limine", "bios-install", IMAGE_NAME+".hdd"])
|
||||
|
||||
|
||||
def create_iso(IMAGE_NAME):
|
||||
|
@ -91,12 +128,12 @@ def create_iso(IMAGE_NAME):
|
|||
subprocess.run(["rm", "-rf", "iso_root"])
|
||||
subprocess.run(["mkdir", "-p", "iso_root"])
|
||||
subprocess.run(["cp", "-v", "iso_root/"])
|
||||
subprocess.run(["cp", "-v", "kernel.elf",
|
||||
subprocess.run(["cp", "-v", "kernel.elf", "boot.png",
|
||||
"configs/limine.cfg", "limine/limine-bios.sys",
|
||||
"limine/limine-bios-cd.bin", "limine/limine-uefi-cd.bin",
|
||||
"iso_root/"])
|
||||
subprocess.run(["mkdir", "-p", "iso_root/EFI/BOOT"])
|
||||
subprocess.run(["mkdir", "-p", "iso_root/mod/"])
|
||||
subprocess.run(["mkdir", "-p", "iso_root/mod"])
|
||||
subprocess.run(["cp", "-v", "modules/helloworld/helloworld.elf", "iso_root/mod/"])
|
||||
subprocess.run(["cp", "-v", "modules/com/com.elf", "iso_root/mod/"])
|
||||
subprocess.run(["cp", "-v", "limine/BOOTX64.EFI", "iso_root/EFI/BOOT/"])
|
||||
|
@ -107,7 +144,6 @@ def create_iso(IMAGE_NAME):
|
|||
"-efi-boot-part", "--efi-boot-image", "--protective-msdos-label",
|
||||
"iso_root", "-o", IMAGE_NAME+".iso"])
|
||||
subprocess.run(["./limine/limine", "bios-install", IMAGE_NAME+".iso"])
|
||||
subprocess.run(["rm", "-rf", "iso_root"])
|
||||
|
||||
if __name__ == "__main__":
|
||||
os.system("""find . \( -name "*.c" -o -name "*.h" -o -name "*.cpp" -o -name "*.hpp" \) -print0 | xargs -0 clang-format -i -style=file""")
|
||||
|
@ -123,7 +159,8 @@ if __name__ == "__main__":
|
|||
check_limine()
|
||||
check_tools()
|
||||
compile_all()
|
||||
create_iso("mseos")
|
||||
create_hdd("mseos")
|
||||
create_iso("bmosp")
|
||||
create_hdd("bmosp")
|
||||
|
||||
print("qemu-system-x86_64 -M q35 -m 8G -smp 8 -bios ovmf/OVMF.fd -hda mseos.hdd")
|
||||
major, minor, build = version_build()
|
||||
print(f"Не забудьте сохранить изменения! Номер сборки: {major}.{minor}, {build}")
|
|
@ -1,20 +1,23 @@
|
|||
GRAPHICS=yes
|
||||
TIMEOUT=5
|
||||
DEFAULT_ENTRY=0
|
||||
INTERFACE_BRANDING=By Aren Elchinyan
|
||||
|
||||
BACKGROUND_STYLE=stretched
|
||||
BACKGROUND_PATH=boot:///boot.png
|
||||
#TERM_FONT=boot:///CYRILL2.F16
|
||||
#TERM_FONT_SIZE=8x16
|
||||
|
||||
:MSEOS (KASLR on)
|
||||
:BMOSP (KASLR on)
|
||||
#RESOLUTION=1280x720
|
||||
PROTOCOL=limine
|
||||
KASLR=no
|
||||
KERNEL_PATH=boot:///kernel.elf
|
||||
|
||||
MODULE_PATH=boot:///kernel.elf
|
||||
MODULE_CMDLINE=boot:///kernel.elf
|
||||
|
||||
MODULE_PATH=boot:///mod/helloworld.elf
|
||||
MODULE_CMDLINE=helloworld
|
||||
|
||||
MODULE_PATH=boot:///mod/com.elf
|
||||
MODULE_CMDLINE=com
|
||||
MODULE_CMDLINE=com
|
||||
|
||||
MODULE_PATH=boot:///boot.png
|
||||
MODULE_CMDLINE=bootimage
|
|
@ -0,0 +1,2 @@
|
|||
#!/bin/sh
|
||||
sudo dd if=mseos.hdd of=/dev/sdc
|
|
@ -0,0 +1,3 @@
|
|||
#define VERSION_MAJOR 0
|
||||
#define VERSION_MINOR 1
|
||||
#define VERSION_BUILD 2
|
|
@ -1,15 +1,23 @@
|
|||
#include <limine.h>
|
||||
|
||||
namespace arch {
|
||||
static volatile struct limine_kernel_address_request kernel_address_request = {
|
||||
.id = LIMINE_KERNEL_ADDRESS_REQUEST,
|
||||
.revision = 0,
|
||||
.response = (struct limine_kernel_address_response *)0
|
||||
};
|
||||
|
||||
struct limine_kernel_address_response *kernel_address_response;
|
||||
|
||||
void init( ) {
|
||||
kernel_address_response = kernel_address_request.response;
|
||||
}
|
||||
#include <limine.h>
|
||||
|
||||
extern "C" {
|
||||
void gdt_init( );
|
||||
|
||||
void idt_init( );
|
||||
}
|
||||
|
||||
namespace arch {
|
||||
static volatile struct limine_kernel_address_request kernel_address_request = {
|
||||
.id = LIMINE_KERNEL_ADDRESS_REQUEST,
|
||||
.revision = 0,
|
||||
.response = (struct limine_kernel_address_response *)0
|
||||
};
|
||||
|
||||
struct limine_kernel_address_response *kernel_address_response;
|
||||
|
||||
void init( ) {
|
||||
kernel_address_response = kernel_address_request.response;
|
||||
gdt_init( );
|
||||
idt_init( );
|
||||
}
|
||||
} // namespace arch
|
|
@ -1,168 +1,170 @@
|
|||
#include <fb.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <tool.h>
|
||||
|
||||
namespace cpu {
|
||||
static bool acpi_msrs_support = false;
|
||||
static bool mmx_support = false;
|
||||
static bool sse2_support = false;
|
||||
static bool avx_support = false;
|
||||
static bool rdrnd_support = false;
|
||||
|
||||
void cpuid(uint32_t leaf, uint32_t *eax, uint32_t *ebx, uint32_t *ecx,
|
||||
uint32_t *edx) {
|
||||
asm volatile("cpuid"
|
||||
: "=a"(*eax), "=b"(*ebx), "=c"(*ecx), "=d"(*edx)
|
||||
: "a"(leaf));
|
||||
}
|
||||
|
||||
void msr_get(uint32_t msr, uint32_t *lo, uint32_t *hi) {
|
||||
asm volatile("rdmsr" : "=a"(*lo), "=d"(*hi) : "c"(msr));
|
||||
}
|
||||
|
||||
void msr_set(uint32_t msr, uint32_t lo, uint32_t hi) {
|
||||
asm volatile("wrmsr" : : "a"(lo), "d"(hi), "c"(msr));
|
||||
}
|
||||
|
||||
uint64_t get_cpu_temperature( ) {
|
||||
uint32_t lo, hi;
|
||||
|
||||
// Чтение температуры из MSR
|
||||
cpu::msr_get(0x19C, &lo, &hi);
|
||||
|
||||
uint64_t temp = ((uint64_t)hi << 32) | (uint64_t)lo;
|
||||
|
||||
// Преобразование значения температуры
|
||||
uint64_t temperature = (temp >> 16) / 256;
|
||||
|
||||
return temperature;
|
||||
}
|
||||
|
||||
void l2_cache( ) {
|
||||
unsigned int eax, ebx, ecx, edx;
|
||||
unsigned int lsize, assoc, cache;
|
||||
|
||||
cpuid(0x80000005, &eax, &ebx, &ecx, &edx);
|
||||
lsize = ecx & 0xFF;
|
||||
fb::printf("Кэш L1: %d KB\n", lsize);
|
||||
|
||||
cpuid(0x80000006, &eax, &ebx, &ecx, &edx);
|
||||
lsize = ecx & 0xFF;
|
||||
assoc = (ecx >> 12) & 0x0F;
|
||||
cache = (ecx >> 16) & 0xFF;
|
||||
|
||||
fb::printf("Кэш L2: %d KB\n", lsize);
|
||||
}
|
||||
|
||||
void do_amd( ) {
|
||||
uint32_t eax, ebx, ecx, edx;
|
||||
uint32_t eggs[4];
|
||||
uint32_t cpu_model;
|
||||
uint32_t cpu_family;
|
||||
char eggs_string[13];
|
||||
|
||||
cpuid(0x8FFFFFFF, &eggs[0], &eggs[1], &eggs[2], &eggs[3]);
|
||||
tool::memcpy(eggs_string, eggs, 12);
|
||||
|
||||
cpuid(1, &eax, &ebx, &ecx, &edx);
|
||||
cpu_model = (eax >> 4) & 0x0F;
|
||||
cpu_family = (eax >> 8) & 0x0F;
|
||||
|
||||
fb::printf("Используется процессор AMD, 8FFFFFFF = [%s]\n", eggs_string);
|
||||
fb::printf("cpu_model = [%u]\n", cpu_model);
|
||||
fb::printf("cpu_family = [%u]\n", cpu_family);
|
||||
}
|
||||
|
||||
void brandname( ) {
|
||||
uint32_t eax, ebx, ecx, edx;
|
||||
char brand_string[49];
|
||||
uint32_t brand[12];
|
||||
uint32_t manufacturer[4];
|
||||
char manufacturer_string[13];
|
||||
|
||||
cpuid(0, &manufacturer[3], &manufacturer[0], &manufacturer[2],
|
||||
&manufacturer[1]);
|
||||
tool::memcpy(manufacturer_string, manufacturer, 12);
|
||||
|
||||
brand_string[48] = 0;
|
||||
manufacturer_string[12] = 0;
|
||||
|
||||
fb::printf("[CPUID] manufacturer [%s]\n", manufacturer_string);
|
||||
|
||||
cpuid(0x80000000, &eax, &ebx, &ecx, &edx);
|
||||
if (eax >= 0x80000004) {
|
||||
cpuid(0x80000002, &brand[0], &brand[1], &brand[2], &brand[3]);
|
||||
cpuid(0x80000003, &brand[4], &brand[5], &brand[6], &brand[7]);
|
||||
cpuid(0x80000004, &brand[8], &brand[9], &brand[10], &brand[11]);
|
||||
tool::memcpy(brand_string, brand, 48);
|
||||
fb::printf("[CPUID] 0x80000002:0x80000004 [%s]\n", brand_string);
|
||||
}
|
||||
|
||||
if (manufacturer[0] == 0x68747541) { do_amd( ); }
|
||||
}
|
||||
|
||||
void sse_init( ) {
|
||||
asm volatile("clts\n"
|
||||
"mov %%cr0, %%rax\n"
|
||||
"and $0xFFFD, %%ax\n"
|
||||
"or $0x10, %%ax\n"
|
||||
"mov %%rax, %%cr0\n"
|
||||
"fninit\n"
|
||||
"mov %%cr0, %%rax\n"
|
||||
"and $0xfffb, %%ax\n"
|
||||
"or $0x0002, %%ax\n"
|
||||
"mov %%rax, %%cr0\n"
|
||||
"mov %%cr4, %%rax\n"
|
||||
"or $0x600, %%rax\n"
|
||||
"mov %%rax, %%cr4\n"
|
||||
"push $0x1F80\n"
|
||||
"ldmxcsr (%%rsp)\n"
|
||||
"addq $8, %%rsp\n"
|
||||
:
|
||||
:
|
||||
: "rax");
|
||||
}
|
||||
|
||||
void init( ) {
|
||||
uint32_t eax, ebx, ecx, edx;
|
||||
cpuid(1, &eax, &ebx, &ecx, &edx);
|
||||
|
||||
if ((edx >> 0) & 1) { fb::printf("FPU(x87) подерживается!\n"); }
|
||||
|
||||
if ((edx >> 22) & 1) {
|
||||
acpi_msrs_support = true;
|
||||
fb::printf("Встроенный терморегулятор MSRS для ACPI\n");
|
||||
fb::printf("Температура: %u\n", get_cpu_temperature( ));
|
||||
}
|
||||
|
||||
if ((edx >> 23) & 1) {
|
||||
mmx_support = true;
|
||||
fb::printf("MMX подерживается!\n");
|
||||
}
|
||||
|
||||
if ((edx >> 25) & 1) {
|
||||
sse2_support = true;
|
||||
fb::printf("SSE2 подерживается!\n");
|
||||
sse_init( );
|
||||
}
|
||||
|
||||
if ((edx >> 29) & 1) {
|
||||
fb::printf("Термоконтроллер автоматически ограничивает температуру\n");
|
||||
}
|
||||
|
||||
if ((ecx >> 28) & 1) {
|
||||
avx_support = true;
|
||||
fb::printf("AVX подерживается!\n");
|
||||
}
|
||||
|
||||
cpuid(0x7, &eax, &ebx, &ecx, &edx);
|
||||
if ((ebx >> 30) & 1) {
|
||||
rdrnd_support = true;
|
||||
fb::printf("RDRND подерживается!\n");
|
||||
}
|
||||
|
||||
brandname( );
|
||||
l2_cache( );
|
||||
}
|
||||
#include <fb.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <tool.h>
|
||||
|
||||
namespace cpu {
|
||||
static bool acpi_msrs_support = false;
|
||||
static bool mmx_support = false;
|
||||
static bool sse2_support = false;
|
||||
static bool avx_support = false;
|
||||
static bool rdrnd_support = false;
|
||||
|
||||
void cpuid(uint32_t leaf, uint32_t *eax, uint32_t *ebx, uint32_t *ecx,
|
||||
uint32_t *edx) {
|
||||
asm volatile("cpuid"
|
||||
: "=a"(*eax), "=b"(*ebx), "=c"(*ecx), "=d"(*edx)
|
||||
: "a"(leaf));
|
||||
}
|
||||
|
||||
void msr_get(uint32_t msr, uint32_t *lo, uint32_t *hi) {
|
||||
asm volatile("rdmsr" : "=a"(*lo), "=d"(*hi) : "c"(msr));
|
||||
}
|
||||
|
||||
void msr_set(uint32_t msr, uint32_t lo, uint32_t hi) {
|
||||
asm volatile("wrmsr" : : "a"(lo), "d"(hi), "c"(msr));
|
||||
}
|
||||
|
||||
uint64_t get_cpu_temperature( ) {
|
||||
uint32_t lo, hi;
|
||||
|
||||
// Чтение температуры из MSR
|
||||
cpu::msr_get(0x19C, &lo, &hi);
|
||||
|
||||
uint64_t temp = ((uint64_t)hi << 32) | (uint64_t)lo;
|
||||
|
||||
// Преобразование значения температуры
|
||||
uint64_t temperature = (temp >> 16) / 256;
|
||||
|
||||
return temperature;
|
||||
}
|
||||
|
||||
void l2_cache( ) {
|
||||
unsigned int eax, ebx, ecx, edx;
|
||||
unsigned int lsize, assoc, cache;
|
||||
|
||||
cpuid(0x80000005, &eax, &ebx, &ecx, &edx);
|
||||
lsize = ecx & 0xFF;
|
||||
fb::printf("Кэш L1: %d KB\n", lsize);
|
||||
|
||||
cpuid(0x80000006, &eax, &ebx, &ecx, &edx);
|
||||
lsize = ecx & 0xFF;
|
||||
assoc = (ecx >> 12) & 0x0F;
|
||||
cache = (ecx >> 16) & 0xFF;
|
||||
|
||||
fb::printf("Кэш L2: %d KB\n", lsize);
|
||||
}
|
||||
|
||||
void do_amd( ) {
|
||||
uint32_t eax, ebx, ecx, edx;
|
||||
uint32_t eggs[4];
|
||||
uint32_t cpu_model;
|
||||
uint32_t cpu_family;
|
||||
char eggs_string[13];
|
||||
|
||||
cpuid(0x8FFFFFFF, &eggs[0], &eggs[1], &eggs[2], &eggs[3]);
|
||||
tool::memcpy(eggs_string, eggs, 12);
|
||||
|
||||
cpuid(1, &eax, &ebx, &ecx, &edx);
|
||||
cpu_model = (eax >> 4) & 0x0F;
|
||||
cpu_family = (eax >> 8) & 0x0F;
|
||||
|
||||
fb::printf("Используется процессор AMD, 0x8FFFFFFF = [%s]\n", eggs_string);
|
||||
fb::printf("cpu_model = [%u]\n", cpu_model);
|
||||
fb::printf("cpu_family = [%u]\n", cpu_family);
|
||||
}
|
||||
|
||||
void brandname( ) {
|
||||
uint32_t eax, ebx, ecx, edx;
|
||||
char brand_string[49];
|
||||
uint32_t brand[12];
|
||||
uint32_t manufacturer[4];
|
||||
char manufacturer_string[13];
|
||||
|
||||
cpuid(0, &manufacturer[3], &manufacturer[0], &manufacturer[2],
|
||||
&manufacturer[1]);
|
||||
tool::memcpy(manufacturer_string, manufacturer, 12);
|
||||
|
||||
brand_string[48] = 0;
|
||||
manufacturer_string[12] = 0;
|
||||
|
||||
fb::printf("[CPUID] manufacturer [%s]\n", manufacturer_string);
|
||||
|
||||
cpuid(0x80000000, &eax, &ebx, &ecx, &edx);
|
||||
if (eax >= 0x80000004) {
|
||||
cpuid(0x80000002, &brand[0], &brand[1], &brand[2], &brand[3]);
|
||||
cpuid(0x80000003, &brand[4], &brand[5], &brand[6], &brand[7]);
|
||||
cpuid(0x80000004, &brand[8], &brand[9], &brand[10], &brand[11]);
|
||||
tool::memcpy(brand_string, brand, 48);
|
||||
fb::printf("[CPUID] 0x80000002:0x80000004 [%s]\n", brand_string);
|
||||
}
|
||||
|
||||
if (manufacturer[0] == 0x68747541) { do_amd( ); }
|
||||
}
|
||||
|
||||
void sse_init( ) {
|
||||
asm volatile("clts\n"
|
||||
"mov %%cr0, %%rax\n"
|
||||
"and $0xFFFD, %%ax\n"
|
||||
"or $0x10, %%ax\n"
|
||||
"mov %%rax, %%cr0\n"
|
||||
"fninit\n"
|
||||
"mov %%cr0, %%rax\n"
|
||||
"and $0xfffb, %%ax\n"
|
||||
"or $0x0002, %%ax\n"
|
||||
"mov %%rax, %%cr0\n"
|
||||
"mov %%cr4, %%rax\n"
|
||||
"or $0x600, %%rax\n"
|
||||
"mov %%rax, %%cr4\n"
|
||||
"push $0x1F80\n"
|
||||
"ldmxcsr (%%rsp)\n"
|
||||
"addq $8, %%rsp\n"
|
||||
:
|
||||
:
|
||||
: "rax");
|
||||
}
|
||||
|
||||
void init( ) {
|
||||
uint32_t eax, ebx, ecx, edx;
|
||||
cpuid(1, &eax, &ebx, &ecx, &edx);
|
||||
|
||||
if ((edx >> 0) & 1) { fb::printf("FPU(x87) подерживается!\n"); }
|
||||
|
||||
if ((edx >> 22) & 1) {
|
||||
acpi_msrs_support = true;
|
||||
fb::printf("Температура: %u\n", get_cpu_temperature( ));
|
||||
fb::printf("Встроенный терморегулятор MSRS для ACPI\n");
|
||||
}
|
||||
|
||||
if ((edx >> 23) & 1) {
|
||||
mmx_support = true;
|
||||
fb::printf("MMX подерживается!\n");
|
||||
}
|
||||
|
||||
if ((edx >> 25) & 1) {
|
||||
sse2_support = true;
|
||||
fb::printf("SSE2 подерживается!\n");
|
||||
sse_init( );
|
||||
}
|
||||
|
||||
cpuid(1, &eax, &ebx, &ecx, &edx);
|
||||
if ((edx >> 29) & 1) {
|
||||
fb::printf("Термоконтроллер автоматически ограничивает температуру\n");
|
||||
}
|
||||
|
||||
if ((ecx >> 28) & 1) {
|
||||
avx_support = true;
|
||||
fb::printf("AVX подерживается!\n");
|
||||
}
|
||||
|
||||
if ((ecx >> 26) & 1) { fb::printf("XSAVE подерживается!\n"); }
|
||||
|
||||
if ((ecx >> 30) & 1) {
|
||||
rdrnd_support = true;
|
||||
fb::printf("RDRND подерживается!\n");
|
||||
}
|
||||
|
||||
brandname( );
|
||||
l2_cache( );
|
||||
}
|
||||
} // namespace cpu
|
|
@ -0,0 +1,61 @@
|
|||
#include <arch.h>
|
||||
#include <fb.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <tool.h>
|
||||
|
||||
extern "C" {
|
||||
|
||||
typedef struct __attribute__((packed)) {
|
||||
uint16_t limit;
|
||||
uint16_t base_16;
|
||||
uint8_t base_middle_16;
|
||||
uint8_t access;
|
||||
uint8_t granularity;
|
||||
uint8_t base_hight_8;
|
||||
} gdt_entry_t;
|
||||
|
||||
typedef struct __attribute__((packed)) {
|
||||
uint16_t limit;
|
||||
uint64_t base;
|
||||
} gdt_reg_t;
|
||||
|
||||
gdt_entry_t gdt[11];
|
||||
gdt_reg_t gdtr;
|
||||
|
||||
extern void load_gdt(uint64_t gdtr);
|
||||
|
||||
void gdt_load( ) {
|
||||
gdtr.limit = (sizeof(gdt) - 1);
|
||||
gdtr.base = (uint64_t)&gdt;
|
||||
|
||||
load_gdt((uint64_t)&gdtr);
|
||||
}
|
||||
|
||||
void set_gdt_entry(gdt_entry_t *entry, uint16_t limit, uint64_t base,
|
||||
uint8_t access, uint8_t granularity) {
|
||||
entry->limit = limit;
|
||||
entry->base_16 = base & 0xFFFF;
|
||||
entry->base_middle_16 = (base >> 16) & 0xFF;
|
||||
entry->base_hight_8 = (base >> 24) & 0xFF;
|
||||
entry->access = access;
|
||||
entry->granularity = granularity;
|
||||
}
|
||||
|
||||
void gdt_init( ) {
|
||||
set_gdt_entry(&gdt[0], 0, 0, 0, 0);
|
||||
set_gdt_entry(&gdt[1], 0xFFFF, 0, 0x9A, 0);
|
||||
set_gdt_entry(&gdt[2], 0xFFFF, 0, 0x92, 0);
|
||||
set_gdt_entry(&gdt[3], 0xFFFF, 0, 0x9A, 0xCF);
|
||||
set_gdt_entry(&gdt[4], 0xFFFF, 0, 0x92, 0xCF);
|
||||
set_gdt_entry(&gdt[5], 0, 0, 0x9A, 0x20);
|
||||
set_gdt_entry(&gdt[6], 0, 0, 0x92, 0);
|
||||
set_gdt_entry(&gdt[7], 0, 0, 0xFA, 0x20);
|
||||
set_gdt_entry(&gdt[8], 0, 0, 0xF2, 0);
|
||||
set_gdt_entry(&gdt[9], 104, 0, 0x89, 0);
|
||||
set_gdt_entry(&gdt[10], 0, 0, 0, 0);
|
||||
|
||||
gdt_load( );
|
||||
fb::printf("GDT инициализирован\n");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,154 @@
|
|||
#include <arch.h>
|
||||
#include <fb.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <tool.h>
|
||||
|
||||
extern "C" {
|
||||
typedef struct __attribute__((packed)) {
|
||||
uint16_t limit;
|
||||
uint64_t base;
|
||||
} idt_ptr_t;
|
||||
|
||||
typedef struct __attribute__((packed)) {
|
||||
uint16_t offset_16;
|
||||
uint16_t selector;
|
||||
uint8_t ist;
|
||||
uint8_t flags;
|
||||
uint16_t offset_middle_16;
|
||||
uint32_t offset_high_32;
|
||||
uint32_t reserved;
|
||||
} idt_gate_t;
|
||||
|
||||
struct frame {
|
||||
uint64_t rbp;
|
||||
uint64_t rbx;
|
||||
uint64_t r15;
|
||||
uint64_t r14;
|
||||
uint64_t r13;
|
||||
uint64_t r12;
|
||||
uint64_t r11;
|
||||
uint64_t r10;
|
||||
uint64_t r9;
|
||||
uint64_t r8;
|
||||
uint64_t rax;
|
||||
uint64_t rcx;
|
||||
uint64_t rdx;
|
||||
uint64_t rsi;
|
||||
uint64_t rdi;
|
||||
uint64_t int_number;
|
||||
uint64_t err;
|
||||
uint64_t rip;
|
||||
uint64_t cs;
|
||||
uint64_t rflags;
|
||||
uint64_t rsp;
|
||||
uint64_t ss;
|
||||
} __attribute__((packed));
|
||||
|
||||
static idt_gate_t idt[256];
|
||||
void *isr[256];
|
||||
extern void *isr_stubs[];
|
||||
static idt_ptr_t idtr;
|
||||
|
||||
#define NO_NAME "Не задано название"
|
||||
|
||||
const char *exception_names[] = { "Деление на ноль",
|
||||
"Отладка",
|
||||
"NMI",
|
||||
"Точка останова",
|
||||
"Переполнение",
|
||||
"Выход за границы",
|
||||
"Недопустимая операция",
|
||||
"Устройство недоступно",
|
||||
"Двойное исключение",
|
||||
NO_NAME,
|
||||
"Недопустимый TSS",
|
||||
"Сегмент не присутствует",
|
||||
"Ошибка сегмента стека",
|
||||
"Общая защитная ошибка",
|
||||
"Ошибка страницы",
|
||||
NO_NAME,
|
||||
"x87 исключение",
|
||||
"Проверка выравнивания",
|
||||
"Ошибка машины",
|
||||
"SIMD исключение",
|
||||
"Виртуализация",
|
||||
NO_NAME,
|
||||
NO_NAME,
|
||||
NO_NAME,
|
||||
NO_NAME,
|
||||
NO_NAME,
|
||||
NO_NAME,
|
||||
NO_NAME,
|
||||
NO_NAME,
|
||||
"Безопасность" };
|
||||
|
||||
void idt_load( ) {
|
||||
asm volatile("lidt %0" : : "m"(idtr));
|
||||
asm volatile("sti");
|
||||
}
|
||||
|
||||
static void encode_idt_entry(uint8_t vector, void *handler, uint8_t flags) {
|
||||
uint64_t ptr = (uint64_t)handler;
|
||||
|
||||
idt[vector].offset_16 = (uint16_t)ptr;
|
||||
idt[vector].selector = 0x28;
|
||||
idt[vector].ist = 0;
|
||||
idt[vector].flags = flags;
|
||||
idt[vector].offset_middle_16 = (uint16_t)(ptr >> 16);
|
||||
idt[vector].offset_high_32 = (uint32_t)(ptr >> 32);
|
||||
idt[vector].reserved = 0;
|
||||
}
|
||||
|
||||
static void exception_handler(struct frame state) {
|
||||
fb::printf("\nПОЛУЧЕНО ИСКЛЮЧЕНИЕ: %s\n",
|
||||
exception_names[state.int_number]);
|
||||
|
||||
fb::printf(" RAX=%x RBX=%x\n"
|
||||
" RCX=%x RDX=%x\n"
|
||||
" RSI=%x RDI=%x\n"
|
||||
" RBP=%x RSP=%x\n"
|
||||
" R08=%x R09=%x\n"
|
||||
" R10=%x R11=%x\n"
|
||||
" R12=%x R13=%x\n"
|
||||
" R14=%x R15=%x\n"
|
||||
" RIP=%x RFLAGS=%x\n"
|
||||
" CS=%x SS=%x\n"
|
||||
" ERR=%x INT=%u",
|
||||
state.rax, state.rbx, state.rcx, state.rdx, state.rsi, state.rdi,
|
||||
state.rbp, state.rsp, state.r8, state.r9, state.r10, state.r11,
|
||||
state.r12, state.r13, state.r14, state.r15, state.rip,
|
||||
state.rflags, state.cs, state.ss, state.err, state.int_number);
|
||||
|
||||
asm volatile("cli; hlt");
|
||||
}
|
||||
|
||||
void isr_generic(struct frame state) {
|
||||
if (state.int_number < 32) {
|
||||
exception_handler(state);
|
||||
} else {
|
||||
fb::printf("\nПрерывание! %u необработано :(\n", state.int_number);
|
||||
}
|
||||
}
|
||||
|
||||
void idt_init( ) {
|
||||
idtr = (idt_ptr_t){ .limit = sizeof(idt) - 1, .base = (uint64_t)idt };
|
||||
|
||||
for (uint64_t i = 0; i < 256; i++) {
|
||||
if (i < 32) {
|
||||
encode_idt_entry(i, isr_stubs[i], 0x8e);
|
||||
isr[i] = (void *)exception_handler;
|
||||
} else {
|
||||
encode_idt_entry(i, isr_stubs[i], 0x8e);
|
||||
isr[i] = (void *)isr_generic;
|
||||
}
|
||||
}
|
||||
|
||||
idt_load( );
|
||||
fb::printf("IDT инициализирован.\n");
|
||||
}
|
||||
|
||||
void idt_set_ist(uint8_t vector, uint8_t ist) {
|
||||
idt[vector].ist = ist;
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,15 @@
|
|||
.global load_gdt
|
||||
load_gdt:
|
||||
cli
|
||||
lgdt (%rdi)
|
||||
movw $0x30, %ax
|
||||
mov %ax, %ds
|
||||
mov %ax, %es
|
||||
mov %ax, %fs
|
||||
mov %ax, %gs
|
||||
mov %ax, %ss
|
||||
pop %rdi
|
||||
mov $0x28, %rax
|
||||
push %rax
|
||||
push %rdi
|
||||
retfq
|
|
@ -0,0 +1,10 @@
|
|||
|
||||
void assert(int x) {}
|
||||
|
||||
void *malloc(int size) {}
|
||||
|
||||
void *realloc(void *pointer, int new_size) {}
|
||||
|
||||
void free(void *pointer) {}
|
||||
|
||||
void main( ) {}
|
120
kernel/mem.cpp
120
kernel/mem.cpp
|
@ -4,6 +4,7 @@
|
|||
#include <tool.h>
|
||||
|
||||
#define BLOCK_SIZE 4096
|
||||
|
||||
static volatile struct limine_memmap_request memmap_request = {
|
||||
.id = LIMINE_MEMMAP_REQUEST,
|
||||
.revision = 0,
|
||||
|
@ -20,34 +21,129 @@ namespace mem {
|
|||
#define HHDM_OFFSET (hhdm_request.response->offset)
|
||||
|
||||
struct limine_memmap_response *memmap_response;
|
||||
struct limine_memmap_entry *memmap_entry;
|
||||
|
||||
// Битовая карта для отслеживания занятых и свободных фреймов памяти
|
||||
uint8_t *bitmap;
|
||||
// Объем доступных блоков
|
||||
uint64_t bitmap_available = 0;
|
||||
// Объем блоков
|
||||
uint64_t bitmap_limit = 0;
|
||||
// Верхняя граница доступной памяти
|
||||
uint64_t limit;
|
||||
// Объем всего доступного физического адресного пространства
|
||||
uint64_t usable = 0;
|
||||
// Объем доступной виртуальной памяти
|
||||
uint64_t available = 0;
|
||||
// Наивысший адрес в available space
|
||||
uint64_t highest = 0;
|
||||
// Количество записей в карте памяти
|
||||
uint64_t mmmap_count = 0;
|
||||
|
||||
lock_t lock = LOCK_INIT;
|
||||
// Массив с описаниями типов памяти
|
||||
char memory_types[8][82] = {
|
||||
"Доступно", "Зарезервировано", "ACPI, можно освободить",
|
||||
"ACPI NVS", "Плохая память", "Загрузчик, можно освободить",
|
||||
"Ядро и модули", "Буфер кадра"
|
||||
};
|
||||
|
||||
void init( ) {
|
||||
memmap_response = memmap_request.response;
|
||||
mmmap_count = memmap_response->entry_count;
|
||||
|
||||
fb::printf("В карте памяти: %u записей.\n", memmap_response->entry_count);
|
||||
void free(void *ptr, uint64_t frames) {
|
||||
// Проход по фреймам памяти и очистка битов в битовой карте
|
||||
uint64_t frame = (uint64_t)ptr / BLOCK_SIZE;
|
||||
for (uint64_t i = frame; i < frames + frame; i++) { BIT_CLEAR(i); }
|
||||
bitmap_available++;
|
||||
}
|
||||
|
||||
void free(void *ptr, uint64_t frames) {}
|
||||
// Функция выделения памяти
|
||||
void *alloc(uint64_t wanted_frames) {
|
||||
void *ptr;
|
||||
|
||||
void *malloc(uint64_t count) {
|
||||
uint64_t available_frames = 0;
|
||||
for (uint64_t frame = 1; frame < limit; frame++) {
|
||||
if (!BIT_GET(frame)) {
|
||||
available_frames++;
|
||||
} else if (available_frames != wanted_frames) {
|
||||
available_frames = 0;
|
||||
continue;
|
||||
}
|
||||
if (available_frames == wanted_frames) {
|
||||
uint64_t i;
|
||||
for (i = 0; i < wanted_frames; i++) { BIT_SET(frame - i); }
|
||||
frame -= i - 1;
|
||||
|
||||
ptr = (void *)(BLOCK_SIZE * frame);
|
||||
return ptr;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *calloc(uint64_t frames) {
|
||||
return (void *)0;
|
||||
void *ptr = alloc(frames);
|
||||
tool::memset(ptr + HHDM_OFFSET, 0, frames * BLOCK_SIZE);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void *alloc(uint64_t size) {
|
||||
return (void *)0;
|
||||
// Инициализация менеджера памяти
|
||||
void init( ) {
|
||||
// Получение информации о доступной памяти из Limine bootloader
|
||||
memmap_response = memmap_request.response;
|
||||
mmmap_count = memmap_response->entry_count;
|
||||
struct limine_memmap_entry **mmaps = memmap_response->entries;
|
||||
|
||||
fb::printf("В карте памяти: %u записей.\n", memmap_response->entry_count);
|
||||
|
||||
// Обработка каждой записи в карте памяти
|
||||
for (int i = 0; i < mmmap_count; i++) {
|
||||
available += mmaps[i]->length;
|
||||
|
||||
// fb::printf("\t%d: 0x%x\tдлина: 0x%x\tтип: %s\n", i + 1,
|
||||
// mmaps[i]->base, mmaps[i]->length, memory_types[mmaps[i]->type]);
|
||||
|
||||
// Пропускаем записи, не являющиеся доступными памятью
|
||||
if (!mmaps[i]->type == LIMINE_MEMMAP_USABLE) { continue; }
|
||||
|
||||
usable += mmaps[i]->length;
|
||||
uint64_t top = mmaps[i]->base + mmaps[i]->length;
|
||||
if (top > highest) highest = top;
|
||||
}
|
||||
|
||||
limit = highest / BLOCK_SIZE;
|
||||
uint64_t bitmap_size = ALIGN_UP(highest / BLOCK_SIZE / 8, BLOCK_SIZE);
|
||||
|
||||
// Находим доступное место для битовой карты и устанавливаем ее
|
||||
for (uint64_t i = 0; i < mmmap_count; i++) {
|
||||
if (!mmaps[i]->type == LIMINE_MEMMAP_USABLE) continue;
|
||||
|
||||
if (mmaps[i]->length >= bitmap_size) {
|
||||
bitmap = (uint8_t *)mmaps[i]->base;
|
||||
tool::memset(bitmap, 0xFF, bitmap_size);
|
||||
mmaps[i]->length -= bitmap_size;
|
||||
mmaps[i]->base += bitmap_size;
|
||||
available -= bitmap_size;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Освобождаем все доступные фреймы памяти
|
||||
for (uint64_t i = 0; i < mmmap_count; i++) {
|
||||
for (uint64_t t = 0; t < mmaps[i]->length; t += BLOCK_SIZE) {
|
||||
bitmap_limit++;
|
||||
}
|
||||
if (!(mmaps[i]->type == LIMINE_MEMMAP_USABLE ||
|
||||
mmaps[i]->type == LIMINE_MEMMAP_BOOTLOADER_RECLAIMABLE)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (uint64_t t = 0; t < mmaps[i]->length; t += BLOCK_SIZE) {
|
||||
free((void *)mmaps[i]->base + t, 1);
|
||||
}
|
||||
}
|
||||
|
||||
fb::printf("%u МБ объем доступной памяти, %u МБ объем виртуальной памяти\n",
|
||||
usable / 1024 / 1024, available / 1024 / 1024);
|
||||
|
||||
fb::printf("%u / %u блоков доступно\n", bitmap_available, bitmap_limit);
|
||||
fb::printf("Размер битовой карты: %u\n", bitmap_size);
|
||||
}
|
||||
|
||||
} // namespace mem
|
|
@ -5,15 +5,36 @@
|
|||
#include <mem.h>
|
||||
#include <mod.h>
|
||||
#include <tool.h>
|
||||
#include <version.h>
|
||||
|
||||
extern "C" void main( );
|
||||
|
||||
void pause( ) {
|
||||
for (uint64_t i = 0; i < 1024; i++) {
|
||||
for (uint64_t j = 0; j < 1024; j++) {
|
||||
// for (uint64_t q = 0; q < 1; q++) { asm volatile("pause"); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Точка входа
|
||||
extern "C" void _start( ) {
|
||||
asm volatile("cli");
|
||||
|
||||
fb::init( );
|
||||
fb::printf("Привет, мир!!\n");
|
||||
pause( );
|
||||
arch::init( );
|
||||
pause( );
|
||||
cpu::init( );
|
||||
pause( );
|
||||
mem::init( );
|
||||
fb::printf("\t\t\t\t *** БМПОС %u.%u.%u.%u ***\n", VERSION_MAJOR,
|
||||
VERSION_MINOR, VERSION_BUILD);
|
||||
fb::printf("\t\t\t\t *** Дата сборки: %s %s ***\n", __DATE__, __TIME__);
|
||||
mod::init( );
|
||||
pause( );
|
||||
|
||||
asm volatile("int $0");
|
||||
|
||||
for (;;) { asm volatile("hlt"); }
|
||||
}
|
|
@ -90,7 +90,7 @@ void format(void (*putc)(char c), const char *format_string, va_list args) {
|
|||
if (rem < 10) {
|
||||
buffer[i++] = '0' + rem;
|
||||
} else {
|
||||
buffer[i++] = 'a' + (rem - 10);
|
||||
buffer[i++] = 'A' + (rem - 10);
|
||||
}
|
||||
arg /= 16;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
#!/bin/sh
|
||||
qemu-system-x86_64 -cpu max -m 2G -smp 1 -bios ovmf/OVMF.fd -hda mseos.hdd
|
|
@ -0,0 +1,18 @@
|
|||
# Генерируем код для isr_stubs
|
||||
isr_stubs_code = ''
|
||||
for i in range(256):
|
||||
isr_stubs_code += f'\t.quad isr_stub_{i}\n'
|
||||
|
||||
# Генерируем код для isr_stub
|
||||
isr_stub_code = ''
|
||||
for i in range(256):
|
||||
isr_stub_code += f'stub {i}\n'
|
||||
|
||||
# Сохраняем код в файл
|
||||
with open('output.s', 'w') as file:
|
||||
file.write('.section .text\n')
|
||||
file.write(isr_stub_code)
|
||||
file.write('.global isr_stubs\n')
|
||||
file.write('.section .data\n')
|
||||
file.write('isr_stubs:\n')
|
||||
file.write(isr_stubs_code)
|
Loading…
Reference in New Issue