Почему ОС не запускается на Virtual box, а на QEMU запускаеться?
-enable-kvm
, то оно тоже не будет работать.ret
в реализацию GDT::load_gdt()
и не вызывать load_tss()
то оно начинает в qemu-kvm работать:diff --git a/src/GDT/GDT_impl.s b/src/GDT/GDT_impl.s
index 4f69835abd9d..5476837f3d0a 100644
--- a/src/GDT/GDT_impl.s
+++ b/src/GDT/GDT_impl.s
@@ -2,6 +2,7 @@
.extern _ZN8SimpleOS3GDT7gdt_ptrE
_ZN8SimpleOS3GDT8load_gdtEv:
lgdt _ZN8SimpleOS3GDT7gdt_ptrE
+ ret
.global _ZN8SimpleOS3GDT8load_tssEv
_ZN8SimpleOS3GDT8load_tssEv:
map::copy
, вот в этом месте. Нельзя копировать сложные объекты функцией memcpy()
, потому что при удалении копии её деструктор освободит данные оригинала. Для такого копирования следует либо использовать placement new, либо копировать целиком объект Node, типа того. Для того чтобы это работало потребуется реализовать глобальный оператор new, типа того. С этими изменениями конкретно описанная в топике проблема решается, но я вижу, что и другие методы класса map
реализованы с похожими ошибками, так что не расслабляйся и не думай, что это была единственная проблема в коде.FileSystem::get_root()
копирует всё дерево файловой системы, когда FileSystem::tree()
явно не собирается его менять, можно было бы в этом случае обойтись константной ссылкой. В чем может быть проблема?
struct IDTPtr {
uint16_t limit;
uint32_t base;
};
packed
, иначе компилятор вставляет паддинг для выравнивания поля base
на границу uint32_t
, из-за чего в IDT загружается неверный адрес.iret
из середины с++-функции, потому что компилятор организовал в ней кадр стека и вместо возврата iret
снимает и интерпретирует мусор из этого кадра:001000e6 <SimpleOS::IDT::dividing_by_zero()>:
1000e6: 55 push %ebp
1000e7: 89 e5 mov %esp,%ebp
1000e9: 53 push %ebx
1000ea: 83 ec 04 sub $0x4,%esp
1000ed: e8 15 01 00 00 call 100207 <__x86.get_pc_thunk.ax>
1000f2: 05 06 11 00 00 add $0x1106,%eax
1000f7: 83 ec 0c sub $0xc,%esp
1000fa: 8d 90 08 fe ff ff lea -0x1f8(%eax),%edx
100100: 52 push %edx
100101: 89 c3 mov %eax,%ebx
100103: e8 4c 00 00 00 call 100154 <SimpleOS::Terminal::print(char const*)>
100108: 83 c4 10 add $0x10,%esp
10010b: fa cli
10010c: cf iret
10010d: 90 nop
10010e: 8b 5d fc mov -0x4(%ebp),%ebx
100111: c9 leave
100112: c3 ret
mem*()
или большинство функций str*()
), есть часть, зависимость которой от ОС реализована в терминах других функций libc (например printf()
может выделять память и может записывать в файл, но обе эти функции уже реализованы в других местах libc), а есть часть напрямую взаимодействующая с ОС.$ gcc -m32 boot.s -nodefaultlibs -nostartfiles -Wl,-Tlinker.ld -no-pie -o boot.elf
$ readelf -S boot.elf
There are 8 section headers, starting at offset 0x3140:
Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .note.gnu.bu[...] NOTE 00100000 001000 000024 00 A 0 0 4
[ 2] .multiboot PROGBITS 00101000 003000 00000c 00 0 0 4096
[ 3] .text PROGBITS 00102000 002000 000009 00 AX 0 0 4096
[ 4] .bss NOBITS 00103000 003000 004000 00 WA 0 0 4096
[ 5] .symtab SYMTAB 00000000 00300c 0000a0 10 6 9 4
[ 6] .strtab STRTAB 00000000 0030ac 00004d 00 0 0 1
[ 7] .shstrtab STRTAB 00000000 0030f9 000044 00 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
L (link order), O (extra OS processing required), G (group), T (TLS),
C (compressed), x (unknown), o (OS specific), E (exclude),
D (mbind), p (processor specific)
.multiboot
оказалась по смещению 0x3000. Почему программы с одних адресов начинаются?
Вот есть Tlb, представим это как линейный массив, или c , если все адреса будут одинаковы. То Очевидно что tlb будет работать в 1% своего множества
Из всего изученного стало понятно, что процессы - это некие "контейнеры", содержащие id, статус, instruction pointer, значение регистров, открытые файлы и другие данные контекста.
какую роль в планировании играют процессы?
Для чего они нужны?
Как планировщик ОС работает с процессами?
Моя единственная догадка в том, что планировщик как бы "заглядывает" в каждый процесс и уже там работает с потоками.
я так понял, происходит прыжок в никуда?
почему может не работать?
0:7c00
, но ты загрузил в ds 7c00
вместо нуля. В risc вроде там куча csr регистров
на разных компиляторах одна си операция ассемблируется то в комбинацию lui + addi, то в комбинацию auipc +addi
lui
и auipc
. Такие инструкции есть у RISC-V.lui
загружает константу собранную из 20 битов непосредственного значения из инструкции и 12 нулевых младших битов в целевой регистр, а auipc
прибавляет такую же точно константу к PC и загружает в целевой регистр результат сложения, и в этом вся разница между ними.где какая используется не совсем понимаю.
lui
используется для генерации констант, которые не зависят от того, где расположен код, а auipc
для генерации констант, которые двигаются вместе с кодом. Т.е. Если ты хочешь вызвать функцию, которая находится дальше чем ±2К от точки вызова, ты можешь сгенерировать её адрес инструкцией auipc
, и полученный код будет работать одинаково, независимо от того, по какому адресу он будет размещён. А если тебе надо поместить в регистр константу, например 0x12345678, то ты можешь это сделать парой инструкций lui rd, 0x12345 ; addi rd, rd, 0x678
и значение константы будет всегда одинаковым, вне зависимости от того, где будет этот код.Каким образом одинаковые адреса различаются. Или они просто не могут быть одинаковыми(типа ос позаботиться)?
Как они в tlb обрабатываются, если вдруг они реально могут быть одинаковыми, и там нету ни каких дополнительных индексов процесса)
TTBR
с примерно той же функцией, что и cr3
в x86.satp
, содержащий ASID и базовый адрес корневого каталога страничных таблиц. Об этом можно прочитать в разделе 4.1.12 Supervisor Address Translation and Protection (satp) Register спецификации The RISC-V Instruction Set Manual Volume II: Privi.... Может ли прерывание прервать выполнение конструктора / деструктора в С++?
нужно ли в конструкторах / деструкторах защищать код критическими секциями?
Как увеличить FPS в системе?
Основной способ стандартный -- не перерисовывать всё, если можно этого избежать.
mov al, [bp+12] mov bl, al mov cl, 3 shl al, cl sbb dh, dh cbw mov dl, [bp+8] mov al, [bp+10]
kernel.routine.mouse.init:
push es bx
int 0x11
test ax, 4
jz kernel.routine.mouse.init.error
mov ax, 0xC205
mov bh, 3
int 0x15
jc kernel.routine.mouse.init.error
mov ax, 0xC203
mov bh, MOUSE_RESOLUTION
int 0x15
jc kernel.routine.mouse.init.error
в скрипте линкера есть такая строка . = 0x100000;. Знаю, что grub загружает по этому адресу ядро
…
нужно чтобы grub по прежнему загружал ядро по адрсесу 0x100000. А адресация внутри ядра происходила по виртуальному адресу, допустим 0x60000000
.incbin
. Так делает ядро linux. Отсюда можно проследить как это делается.откуда прерывания знают адрес, куда им вернуть результат.
Прерывание в коде int 21h и прочие Это какое?
int
-- программное. В отличие от прерывания, инициируемого уровнем или фронтом сигнала подключённого к контроллеру прерываний.выполнение прерывания std::cin>>line; Может и сутки длиться.
std::cin >>line
в конце концов превращается в системный вызов read
.Вот как по пунктам для этой команды. (С условием что есть еще 1 поток жаждущий ЦП).
cat /proc/<PID>/stack
и увидеть следующую картину:[<0>] wait_woken+0x67/0x80
[<0>] n_tty_read+0x426/0x5a0
[<0>] tty_read+0x135/0x240
[<0>] new_sync_read+0x115/0x1a0
[<0>] vfs_read+0xf4/0x180
[<0>] ksys_read+0x5f/0xe0
[<0>] do_syscall_64+0x33/0x80
[<0>] entry_SYSCALL_64_after_hwframe+0x44/0xa9
Как происходит доступ к эл. массива на уровне ядра?
Например массив Int* arr = new int[1024*1024*1024] он как храниться?
А физическая, для массива то же? Ведь, так будет доступ намного быстрее?
получается эмулятор каждый адрес вычислять что ли?
почему-то не работает прерывание 0х20 для клавиатуры