При старте экран чёрный (так и задумано на этом этапе), но клавиатура реагирует на клавишу ESC — код отрабатывает корректно.
Прерывания будто блокируются после первого-второго вызова.
dummy_handler_asm, который вызывается по таймеру, но не завершается отправкой кода окончания обработки прерывания в PIC.diff --git a/system/drivers/interrupts.asm b/system/drivers/interrupts.asm
index 75ea06c4bc2f..17ac87fa6b06 100644
--- a/system/drivers/interrupts.asm
+++ b/system/drivers/interrupts.asm
@@ -98,5 +98,7 @@ dummy_handler_asm:
push rax
mov rax, 0xFEE000B0
mov dword [rax], 0
+ mov al, 0x20
+ out 0x20, al
pop rax
iretqbs->AllocatePages(2, 4, ...), а 2 -- это AllocateAddress, т.е. запрос на выделение памяти по фиксированному тобой адресу. У меня этот код сразу возвращает ошибку, а вот bs->AllocatePages(0, 4, ...) -- работает:diff --git a/boot/bootloader.c b/boot/bootloader.c
index 377e907c1728..5ae82dca7fc0 100644
--- a/boot/bootloader.c
+++ b/boot/bootloader.c
@@ -59,7 +59,7 @@ EFIAPI long long efi_main(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable)
// 1. Выделяем память под скрытый буфер экрана (1024 * 768 * 4 байта = 3145728 байт = 768 страниц по 4КБ)
unsigned long long v_buffer_addr = 0;
// 2 = EfiAllocateAnyPages, 4 = EfiRuntimeServicesData (чтобы ядро гарантированно видело эту память)
- long long status = bs->AllocatePages(2, 4, 768, &v_buffer_addr);
+ long long status = bs->AllocatePages(0, 4, 768, &v_buffer_addr);
if (status != 0) {
while(1) { __asm__ __volatile__("hlt"); }
}
@@ -85,7 +85,7 @@ EFIAPI long long efi_main(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable)
unsigned long long map_buffer = 0;
// Выделяем временную память под саму карту памяти (округлим map_size до страниц)
- bs->AllocatePages(2, 4, (map_size / 4096) + 1, &map_buffer);
+ bs->AllocatePages(0, 4, (map_size / 4096) + 1, &map_buffer);
// Получаем финальную карту памяти и MapKey
status = bs->GetMemoryMap(&map_size, (void*)map_buffer, &map_key, &desc_size, &desc_ver);(a + i) (API) и (-1)^i (M1PI), переменную для результата (result), текущее слагаемое собирать в регистре 1. На каждой итерации вычислять текущее слагаемое ряда, прибавлять его к результату, а потом обновлять значения (-1)^i и (a + i) для следующей итерации. Как-то так:movr 0, N
srm 0, ONE
jz PRINT
CYCL:
movr 1, M1PI
mrm 1, API
arm 1, result
movm 1, result
mmm M1PI, M1
amm API, ONE
loop CYCL
PRINT:
movr 1, result
out 1
stop
ONE: .dw 1
M1: .dw -1
M1PI: .dw 1
API: .dw 1
result: .dw 0
end я починил эту ос, теперь хотел понемногу добавлять C, т.к. на чистом ассемблере далеко не уйдешь. Если получится запустить хоть Hello, World! - буду очень благодарен
make run и введя команду hello в консоли внутри qemu.Может надо сделать их объектными elf файлами, затем скомпоновать и зачистить формат?
gcc для компиляции исходников на С (*.c) и ассемблере (*.S), gcc или ld для линковки, objcopy для преобразования ELF-файла с выхода линковщика в бинарник.Почему у меня не хотят работать корректно цепные команды?
mov ax,Data2
mov es,ax ; запис адреси data2 в ds
...
lea si, node1 ; <---node1 находится в сегменте Data2, адрес которого загружен в es, но команда lodsb загружает данные из ds:si.@finish_cycle_namex:
inc I_struc ;+1 до ітерації
add si, 5si? si указывает на область памяти в которой лежит массив 5-символьных имён, внутренний цикл как раз перемещает si на следующее имя. Почему от добавления функций помимо main() в начало кода ядро перестает работать?
i686-elf-ld -Ttext 0x7E00 --oformat binary kernel.o -o kernel -e main; Jump to the kernel's entry point
JMP 0x0000:0x7E00-e main?main(). Чтобы поместить нужный код в нужное место собранного образа обычно используют скрипт линковщика.// Получаю ошибку:
7FFF0000: The instruction at 0x7FFF0000 referenced memory at 0x7FFF0000. The memory could not be executed -> 7FFF0000 (exc.code c0000005, tid 6332)
В чем проблема?
7FFF0000 -- не исполняемая.Как починить?
7FFF0000 исполняемой. После этого вывод в лог должен заработать, но будет падать после него, потому что функция mySuperFunction не возвращается. $ 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. movw $0x4F02, %ax
movb $0x03, %bl
int $0x10
bh остался мусор, а этот вызов принимает аргумент в bx. возможно, я неправильно использую sf флаг?
mov al, mas[si] cmp ax, ax jns positiveOut ;;;;
cmp ax, ax сравнивает ax с самим собой, результат немного предсказуем: они равны, т.е. sf = 0, zf = 1. Чтобы узнать знак числа нужно либо сравнивать его с нулём, либо использовать вместо cmp логическую операцию -- test, or или and.mov al, mas[si] загружает из памяти только al, в ah остаётся мусор от предыдущих операций. По-нормальному после mov нужно сделать знаковое расширение al в ax, если собираешься дальше работать с ax, например так:mov al, mas[si]
cbwsub ax, 1 not ax
neg ax? traverse_loop держит указатель на текущую запись в eax, но первый же вызов PrintName портит почти все регистры и не восстанавливает их, поэтому первый же movzx esi, byte [eax + 10h] после этого вызова обращается мимо памяти и вызывает segfault. Проще всего это исправить каким-нибудь pusha / popa вокруг тела PrintName. После этого ты доберёшься до вызова PrintMark, где увидишь, что эта функция ожидает в eax + 10h текстового представления оценки, а у тебя пока есть только двоичное. что не так
mov ecx, 5 ; Загружает количество гласных
…
inc ecx ; Увеличивает счетчик гласных
…
loop checkVowels ; Переходит к проверке следующей гласной
…
test ecx, ecx ; Проверяет, содержится ли гласная буква в слове
; Вывод суммы элементов выше главной диагонали mov ah, 2 mov dl, cl int 21h
Что же сделает программа на чистом ассемблере?
у меня получилось найти только…
cs * 10h + ip. В твоём случае получается 48ff9.Почему не переписать вместо этого
add ebx,dword ptr [rbp+ECX*4+10h]
add ebx,dword ptr [rbp+rcx*4+10h], но для этого счётчик цикла должен был бы быть 64-битным, а он, как мы видим, 32-битный (int i). Т.е. ответ на вопрос "для чего это": для беззнакового расширения 32-битного счётчика цикла в регистр, который можно использовать для доступа к памяти.i не выходит из диапазона 0..9, так что разницы между ecx и rcx нет и не может быть. Возможно я что-то упускаю и у компилятора другое мнение на этот счёт, но может быть он просто туповат и не имеет кода который бы мог использовать эту возможность оптимизации, а может такая оптимизация и есть, но она не была включена во время генерации этого кода.