Ядро зависает при очистке области экрана размером 80x25

Тема в разделе "WASM.BEGINNERS", создана пользователем Aoizora, 4 янв 2024.

  1. Aoizora

    Aoizora Active Member

    Публикаций:
    0
    Регистрация:
    29 янв 2017
    Сообщения:
    362
    То есть должно быть вот так? Только все равно выводится не так, как я хочу


    Код (Text):
    1. [BITS 16]
    2. [ORG 0x7C00]
    3.  
    4. start:
    5.   jmp 0:real_start
    6.  
    7. real_start:
    8.   xor ax, ax
    9.   mov ds, ax
    10.   mov ss, ax
    11.   mov sp, 0x7C00
    12.   add sp, 0x0400
    13.  
    14.   mov ax, 0xB800
    15.   mov es, ax
    16.   mov si, msg
    17.   xor di, di
    18.   mov cx, 10
    19.   call memcpy
    20.  
    21. hang:
    22.   jmp hang
    23.  
    24. memcpy:
    25.   test cx, cx
    26.   jz out
    27. again:
    28.   mov ah, [si]
    29.   mov es:[di], ah
    30.   inc si
    31.   inc di
    32.   dec cx
    33.   jnz again
    34. out:
    35.   ret
    36.  
    37. msg db "H\017e\017l\017l\017o\017",0
    38.  
    39. times 510 - ($ - $$) db 0
    40.  
    41. db 0x55
    42. db 0xAA
    Наверное у меня в строке msg символы \017 интерпретируются как часть строки, а не как hex код
    msg db "H\017e\017l\017l\017o\017",0
     
  2. HoShiMin

    HoShiMin Well-Known Member

    Публикаций:
    5
    Регистрация:
    17 дек 2016
    Сообщения:
    1.455
    Адрес:
    Россия, Нижний Новгород
    Попробуй:
    Код (ASM):
    1. db 'H', 17, 'e', 17, 'l', 17, 'l', 17, 'o', 17, 0
    --- Сообщение объединено, 9 янв 2024 ---
    А насчёт gdb, судя по вопросам и ответам на stackoverflow, set architecture i8086 сломан об колено. Под рукой нет гдб, чтобы проверить, но на это жалуешься не ты один: https://stackoverflow.com/questions...oot-sector-code-in-gdb-with-x-i-pc-it-gets-tr
    Там в ответах выкладывают xml’ки, пробуй их.
     
    Последнее редактирование: 9 янв 2024
    Aoizora нравится это.
  3. Aoizora

    Aoizora Active Member

    Публикаций:
    0
    Регистрация:
    29 янв 2017
    Сообщения:
    362
    Как программисты на C++ относятся к неявным преобразованиям типов? Например, корректно ли будет написать

    Код (Text):
    1. constexpr inline bool isEven(int x)
    2. {
    3.   return x & 1 == 0
    4. }
    Или неявно преобразовывать типы нельзя и надо писать что-то типа static_cast из int в bool? Если так делать постоянно, то C++ становится очень многословным языком.
     
  4. HoShiMin

    HoShiMin Well-Known Member

    Публикаций:
    5
    Регистрация:
    17 дек 2016
    Сообщения:
    1.455
    Адрес:
    Россия, Нижний Новгород
    Корректно: оператор == на выходе даёт bool, никаких проблем.
    Кстати, у констэкспров инлайн не нужен.
     
  5. Aoizora

    Aoizora Active Member

    Публикаций:
    0
    Регистрация:
    29 янв 2017
    Сообщения:
    362
    Я хочу переписать этот код с GNU ассемблера на NASM: https://github.com/cscenter/OS_online_course/blob/master/week2/phys_mem/physmem-map/src/bootstrap.S
    В репозитории имеется такой скрипт линкера: https://github.com/cscenter/OS_online_course/blob/master/week1/load/multiboot-boot/kernel.ld

    Я переписал начало этого сорца:

    Код (ASM):
    1. %define MULTIBOOT_AOUT_KLUDGE 0x00010000
    2. %define MULTIBOOT_INFO_MEMORY 0x00000001
    3.  
    4. %define MB_HEADER_MAGIC 0x1BADB002
    5. %define MB_HEADER_FLAGS (MULTIBOOT_AOUT_KLUDGE | MULTIBOOT_INFO_MEMORY)
    6. %define MB_HEADER_CKSUM    -(MB_HEADER_MAGIC + MB_HEADER_FLAGS)
    7.  
    8. %define PTE_PRESENT (1 << 0)
    9. %define PTE_WRITE   (1 << 1)
    10. %define PTE_LARGE   (1 << 7)
    11. %define CR4_PAE     (1 << 5)
    12. %define CR0_PG      (1 << 31)
    13. %define CR0_NE      (1 << 5)
    14. %define EFER_MSR    0xC0000080
    15. %define EFER_LM     (1 << b)
    16.  
    17. section .bootstrap
    18. [BITS 32]
    19. global start32
    20. extern main
    21. align 16
    22.  
    23. start32:
    24.   jmp real_start
    25.  
    26.   align 16
    27.  
    28. multiboot_header:
    29.   dd MB_HEADER_MAGIC
    30.   dd MB_HEADER_FLAGS
    31.   dd MB_HEADER_CKSUM
    32.   dd multiboot_header
    33.   dd text_phys_begin
    34.   dd data_phys_end
    35.   dd bss_phys_end
    36.   dd start32
    37.  
    38.   align 16
    39.  
    40. gdt:
    41.   dq 0x0000000000000000
    42.   dq 0x00209b0000000000
    43.  
    44. gdt_ptr:
    45.   dw (gdt_ptr - gdt - 1)
    46.   dd gdt_ptr
    47.  
    48. gdt_ptr64:
    49.   dw (gdt_ptr - gdt - 1)
    50.   dq (gdt + VIRTUAL_BASE)
    51.  
    52.   align 16
    53.  
    54.   resb 0x100
    55. stack_top:
    56.  
    57. real_start:
    58.   mov esp, stack_top
    59.   push ebx
    60.  
    61.  
    Как мне получит из него объектный файл? Компилятор nasm не может сгенерировать его. Я запускаю компиляцию с такими параметрами: nasm -f elf64 ./src/bootstrap.s и получаю ошибки:

    Как понимаю, не хватает определений символов, которые определяются в скрипте линкера .ld. Но есть проблема: nasm не принимает параметр скрипта линкера -T, я вообще не смог нагуглить, как ему передать скрипт линкера. И что получается, при помощи nasm нельзя скомпилировать этот код?
     
  6. HoShiMin

    HoShiMin Well-Known Member

    Публикаций:
    5
    Регистрация:
    17 дек 2016
    Сообщения:
    1.455
    Адрес:
    Россия, Нижний Новгород
    Можно сделать недостающие символы EXTERN'ами, а VIRTUAL_BASE задать явно.
    Допиши в самом верху:
    Код (ASM):
    1.  
    2. extern text_phys_begin
    3. extern data_phys_end
    4. extern bss_phys_end
    5.  
    6. VIRTUAL_BASE equ 0xffffffff80000000  ; Из линкер-скрипта
    7.  
    А затем попробуй слинковать через:
    Код (Bash):
    1. ld -T kernel.ld ./bootstrap.o -o ./bootstrap
     
  7. Aoizora

    Aoizora Active Member

    Публикаций:
    0
    Регистрация:
    29 янв 2017
    Сообщения:
    362
    А как можно воспроизвести у себя этот туториал? Мне нравится, что он написан на ассемблере с синтаксисом intel, но там походу используется 16-битный компилятор C++, которых давно уже в природе нет. Получается, без 16-битного компилятора C++ эта статья не актуальна?

    https://www.codeproject.com/Articles/36907/How-to-develop-your-own-Boot-Loader
     
  8. HoShiMin

    HoShiMin Well-Known Member

    Публикаций:
    5
    Регистрация:
    17 дек 2016
    Сообщения:
    1.455
    Адрес:
    Россия, Нижний Новгород
    Актуальна, но с оговорками.
    Под 8086 современных компиляторов не существует: даже gcc и llvm не умеют создавать настоящий 16-битный код.
    Однако, в реальном режиме ты можешь использовать 32х-битные инструкции.
    Это становится возможным, благодаря использованию префикса 0x66 (operand-size prefix), которым компилятор снабжает практически каждую инструкцию, переключая её в 32х-битный режим.
    Таким образом, ты можешь писать 32х-битный бутлоадер, не переключаясь в защищённый режим, при необходимости делая вставки на 16-битном ассемблере.
    Но у этого способа есть недостатки: 32х-битный код с префиксами почти у каждой инструкции занимает много места, и ты рискуешь быстро вылезти за доступные для кода 446 байт (512 - sizeof(MBR) - sizeof(0xAA55)).
     
    Последнее редактирование: 19 янв 2024
  9. TermoSINteZ

    TermoSINteZ Синоби даоса Команда форума

    Публикаций:
    2
    Регистрация:
    11 июн 2004
    Сообщения:
    3.552
    Адрес:
    Russia
    Почему не актуально. Куча эмуляторов позволит тебе делать что угодно. QEMU\VBox
     
  10. UbIvItS

    UbIvItS Well-Known Member

    Публикаций:
    0
    Регистрация:
    5 янв 2007
    Сообщения:
    6.243
    :grin:
     
  11. HoShiMin

    HoShiMin Well-Known Member

    Публикаций:
    5
    Регистрация:
    17 дек 2016
    Сообщения:
    1.455
    Адрес:
    Россия, Нижний Новгород
    [​IMG]
     
  12. UbIvItS

    UbIvItS Well-Known Member

    Публикаций:
    0
    Регистрация:
    5 янв 2007
    Сообщения:
    6.243
    нас всех заметили :grin:
     
  13. Aoizora

    Aoizora Active Member

    Публикаций:
    0
    Регистрация:
    29 янв 2017
    Сообщения:
    362
    Я продолжаю понемногу писать свое ядро ОС. Вот такой код получается.

    Загрузчик boot.s


    Код (ASM):
    1. BITS 32
    2.  
    3. section .text
    4.   ALIGN 4
    5.   dd 0x1BADB002
    6.   dd 0x00000000
    7.   dd -(0x1BADB002 + 0x00000000)
    8.  
    9. global start
    10. extern KernelMain
    11.  
    12. start:
    13.   cli
    14.   mov esp, stack_space
    15.   call KernelMain
    16.   hlt
    17.  
    18. halt_kernel:
    19.   cli
    20.   hlt
    21.   jmp halt_kernel
    22.  
    23. section .bss
    24. resb 8192
    25. stack_space:
    Работа с GDT


    Код (ASM):
    1. global FlushGDT
    2.  
    3. FlushGDT:
    4.   mov eax, [esp + 4]
    5.   lgdt [eax]
    6.  
    7.   mov eax, 0x10
    8.   mov ds, ax
    9.   mov es, ax
    10.   mov fs, ax
    11.   mov gs, ax
    12.   mov ss, ax
    13.   jmp 0x08:Flush
    14.  
    15. Flush:
    16.   ret
    Работа с IDT


    Код (ASM):
    1. global FlushIDT
    2.  
    3. FlushIDT:
    4.   mov eax, [esp + 4]
    5.   lidt [eax]
    6.   sti
    7.   ret
    8.  
    9. %macro ISR_NOERRCODE 1
    10.   global isr%1
    11.   isr%1:
    12.     cli
    13.     push long 0
    14.     push long %1
    15.     jmp isr_common_stub
    16. %endmacro
    17.  
    18. %macro ISR_ERRCODE 1
    19.   global isr%1
    20.   isr%1:
    21.     cli
    22.     push long %1
    23.     jmp isr_common_stub
    24. %endmacro
    25.  
    26. ISR_NOERRCODE 0
    27. ISR_NOERRCODE 1
    28. ISR_NOERRCODE 2
    29. ISR_NOERRCODE 3
    30. ISR_NOERRCODE 4
    31. ISR_NOERRCODE 5
    32. ISR_NOERRCODE 6
    33. ISR_NOERRCODE 7
    34. ISR_ERRCODE 8
    35. ISR_NOERRCODE 9
    36. ISR_ERRCODE 10
    37. ISR_ERRCODE 11
    38. ISR_ERRCODE 12
    39. ISR_ERRCODE 13
    40. ISR_ERRCODE 14
    41. ISR_NOERRCODE 15
    42. ISR_NOERRCODE 16
    43. ISR_NOERRCODE 17
    44. ISR_NOERRCODE 18
    45. ISR_NOERRCODE 19
    46. ISR_NOERRCODE 20
    47. ISR_NOERRCODE 21
    48. ISR_NOERRCODE 22
    49. ISR_NOERRCODE 23
    50. ISR_NOERRCODE 24
    51. ISR_NOERRCODE 25
    52. ISR_NOERRCODE 26
    53. ISR_NOERRCODE 27
    54. ISR_NOERRCODE 28
    55. ISR_NOERRCODE 29
    56. ISR_NOERRCODE 30
    57. ISR_NOERRCODE 31
    58. ISR_NOERRCODE 128
    59. ISR_NOERRCODE 177
    60.  
    61. extern isr_handler
    62.  
    63. isr_common_stub:
    64.   pusha
    65.   mov eax, ds
    66.   push eax
    67.   mov eax, cr2
    68.   push eax
    69.   mov ax, 0x10
    70.   mov ds, ax
    71.   mov es, ax
    72.   mov fs, ax
    73.   mov gs, ax
    74.   push esp
    75.   call isr_handler
    76.   add esp, 8
    77.   pop ebx
    78.   mov dx, bx
    79.   mov es,bx
    80.   mov fs, bx
    81.   mov gs, bx
    82.   popa
    83.   add esp, 8
    84.   sti
    85.   iret

    Код (C++):
    1. #pragma once
    2.  
    3. #include <cstdint>
    4.  
    5. struct GDT_ENTRY
    6. {
    7.     uint16_t Limit;
    8.     uint16_t BaseLow;
    9.     uint8_t  BaseMiddle;
    10.     uint8_t  Access;
    11.     uint8_t  Flags;
    12.     uint8_t  BaseHigh;
    13. } __attribute__((packed));
    14.  
    15. struct GDT_PTR
    16. {
    17.     uint16_t Limit;
    18.     unsigned int Base;
    19. } __attribute__((packed));
    20.  
    21. void InitGDT();
    22. void SetGDTGate(uint32_t num, uint32_t base, uint32_t limit, uint8_t access, int8_t gran);
    23.  

    Код (C++):
    1. #include "gdt.h"
    2.  
    3. extern "C" void FlushGDT(void *);
    4.  
    5. GDT_ENTRY gdt[5];
    6. GDT_PTR   ptr;
    7.  
    8. void InitGDT()
    9. {
    10.     ptr.Limit = sizeof(GDT_ENTRY) * 5 - 1;
    11.     ptr.Base = reinterpret_cast<unsigned int>(&gdt);
    12.  
    13.     SetGDTGate(0, 0, 0, 0, 0);                  // Null segment
    14.     SetGDTGate(1, 0, 0xFFFFFFFF, 0x9A, 0xCF);   // Kernel code segment
    15.     SetGDTGate(2, 0, 0xFFFFFFFF, 0x92, 0xCF);   // Kernel data segment
    16.     SetGDTGate(3, 0, 0xFFFFFFFF, 0xFA, 0xCF);   // User code segment
    17.     SetGDTGate(4, 0, 0xFFFFFFFF, 0xF2, 0xCF);   // User data segment
    18.  
    19.     FlushGDT(&ptr);
    20. }
    21.  
    22. void SetGDTGate(uint32_t num, uint32_t base, uint32_t limit, uint8_t access, int8_t gran)
    23. {
    24.     gdt[num].BaseLow    = base & 0xFFFF;
    25.     gdt[num].BaseMiddle = (base >> 16) & 0xFF;
    26.     gdt[num].BaseHigh   = (base >> 24) & 0xFF;
    27.     gdt[num].Limit      = limit & 0xFFFF;
    28.     gdt[num].Flags      = (limit >> 16) & 0x0F;
    29.     gdt[num].Flags |= gran & 0xF0;
    30.     gdt[num].Access     = access;
    31. }
    Код (C++):
    1. #pragma once
    2.  
    3. #include <cstdint>
    4.  
    5. #include "../stdlib/memset.h"
    6.  
    7. struct IDT_ENTRY
    8. {
    9.     uint16_t BaseLow;
    10.     uint16_t Selector;
    11.     uint8_t Always0;
    12.     uint8_t Flags;
    13.     uint16_t BaseHigh;
    14. } __attribute__((packed));
    15.  
    16. struct IDT_PTR
    17. {
    18.     uint16_t Limit;
    19.     uint32_t Base;
    20. } __attribute__((packed));
    21.  
    22. void InitIDT();
    23. void SetIDTGate(uint8_t num, uint32_t base, uint16_t selector, uint8_t flags);
    24.  
    25. struct INTERRUPT_REGISTERS
    26. {
    27.     uint32_t cr2;
    28.     uint32_t ds;
    29.     uint32_t edi;
    30.     uint32_t esi;
    31.     uint32_t ebp;
    32.     uint32_t esp;
    33.     uint32_t ebx;
    34.     uint32_t edx;
    35.     uint32_t ecx;
    36.     uint32_t eax;
    37.     uint32_t int_no;
    38.     uint32_t err_code;
    39.     uint32_t eip;
    40.     uint32_t eflags;
    41.     uint32_t csm;
    42.     uint32_t useresp;
    43.     uint32_t ss;
    44. };
    45.  
    46. extern "C" void isr0();
    47. extern "C" void isr1();
    48. extern "C" void isr2();
    49. extern "C" void isr3();
    50. extern "C" void isr4();
    51. extern "C" void isr5();
    52. extern "C" void isr6();
    53. extern "C" void isr7();
    54. extern "C" void isr8();
    55. extern "C" void isr9();
    56. extern "C" void isr10();
    57. extern "C" void isr11();
    58. extern "C" void isr12();
    59. extern "C" void isr13();
    60. extern "C" void isr14();
    61. extern "C" void isr15();
    62. extern "C" void isr16();
    63. extern "C" void isr17();
    64. extern "C" void isr18();
    65. extern "C" void isr19();
    66. extern "C" void isr20();
    67. extern "C" void isr21();
    68. extern "C" void isr22();
    69. extern "C" void isr23();
    70. extern "C" void isr24();
    71. extern "C" void isr25();
    72. extern "C" void isr26();
    73. extern "C" void isr27();
    74. extern "C" void isr28();
    75. extern "C" void isr29();
    76. extern "C" void isr30();
    77. extern "C" void isr31();
    78.  
    79. extern "C" void isr128();
    80. extern "C" void isr177();

    Код (C++):
    1. #include "idt.h"
    2. #include "../vga.h"
    3.  
    4. static IDT_ENTRY idt[256];
    5. static IDT_PTR   ptr;
    6.  
    7. extern "C" void FlushIDT(void *);
    8. extern "C" void WritePort(char port, char data);
    9.  
    10. void InitIDT()
    11. {
    12.     ptr.Base = reinterpret_cast<uint32_t>(&idt);
    13.     ptr.Limit = sizeof(IDT_ENTRY) * 256 - 1;
    14.  
    15.     memset(&idt, 0, sizeof(IDT_ENTRY) * 256);
    16.  
    17.     WritePort(0x20, 0x11);
    18.     WritePort(0xA0, 0x11);
    19.  
    20.     WritePort(0x21, 0x20);
    21.     WritePort(0xA1, 0x28);
    22.  
    23.     WritePort(0x21, 0x04);
    24.     WritePort(0xA1, 0x02);
    25.  
    26.     WritePort(0x21, 0x01);
    27.     WritePort(0xA1, 0x01);
    28.  
    29.     WritePort(0x21, 0x0);
    30.     WritePort(0xA1, 0x00);
    31.  
    32.     SetIDTGate(0, reinterpret_cast<uint32_t>(isr0), 0x08, 0x8E);
    33.     SetIDTGate(0, reinterpret_cast<uint32_t>(isr1), 0x08, 0x8E);
    34.     SetIDTGate(0, reinterpret_cast<uint32_t>(isr2), 0x08, 0x8E);
    35.     SetIDTGate(0, reinterpret_cast<uint32_t>(isr3), 0x08, 0x8E);
    36.     SetIDTGate(0, reinterpret_cast<uint32_t>(isr4), 0x08, 0x8E);
    37.     SetIDTGate(0, reinterpret_cast<uint32_t>(isr5), 0x08, 0x8E);
    38.     SetIDTGate(0, reinterpret_cast<uint32_t>(isr6), 0x08, 0x8E);
    39.     SetIDTGate(0, reinterpret_cast<uint32_t>(isr7), 0x08, 0x8E);
    40.     SetIDTGate(0, reinterpret_cast<uint32_t>(isr8), 0x08, 0x8E);
    41.     SetIDTGate(0, reinterpret_cast<uint32_t>(isr9), 0x08, 0x8E);
    42.     SetIDTGate(0, reinterpret_cast<uint32_t>(isr10), 0x08, 0x8E);
    43.     SetIDTGate(0, reinterpret_cast<uint32_t>(isr11), 0x08, 0x8E);
    44.     SetIDTGate(0, reinterpret_cast<uint32_t>(isr12), 0x08, 0x8E);
    45.     SetIDTGate(0, reinterpret_cast<uint32_t>(isr13), 0x08, 0x8E);
    46.     SetIDTGate(0, reinterpret_cast<uint32_t>(isr14), 0x08, 0x8E);
    47.     SetIDTGate(0, reinterpret_cast<uint32_t>(isr15), 0x08, 0x8E);
    48.     SetIDTGate(0, reinterpret_cast<uint32_t>(isr16), 0x08, 0x8E);
    49.     SetIDTGate(0, reinterpret_cast<uint32_t>(isr17), 0x08, 0x8E);
    50.     SetIDTGate(0, reinterpret_cast<uint32_t>(isr18), 0x08, 0x8E);
    51.     SetIDTGate(0, reinterpret_cast<uint32_t>(isr19), 0x08, 0x8E);
    52.     SetIDTGate(0, reinterpret_cast<uint32_t>(isr20), 0x08, 0x8E);
    53.     SetIDTGate(0, reinterpret_cast<uint32_t>(isr21), 0x08, 0x8E);
    54.     SetIDTGate(0, reinterpret_cast<uint32_t>(isr22), 0x08, 0x8E);
    55.     SetIDTGate(0, reinterpret_cast<uint32_t>(isr23), 0x08, 0x8E);
    56.     SetIDTGate(0, reinterpret_cast<uint32_t>(isr24), 0x08, 0x8E);
    57.     SetIDTGate(0, reinterpret_cast<uint32_t>(isr25), 0x08, 0x8E);
    58.     SetIDTGate(0, reinterpret_cast<uint32_t>(isr26), 0x08, 0x8E);
    59.     SetIDTGate(0, reinterpret_cast<uint32_t>(isr27), 0x08, 0x8E);
    60.     SetIDTGate(0, reinterpret_cast<uint32_t>(isr28), 0x08, 0x8E);
    61.     SetIDTGate(0, reinterpret_cast<uint32_t>(isr29), 0x08, 0x8E);
    62.     SetIDTGate(0, reinterpret_cast<uint32_t>(isr30), 0x08, 0x8E);
    63.     SetIDTGate(0, reinterpret_cast<uint32_t>(isr31), 0x08, 0x8E);
    64.  
    65.     FlushIDT(&ptr);
    66. }
    67.  
    68. void SetIDTGate(uint8_t num, uint32_t base, uint16_t selector, uint8_t flags)
    69. {
    70.     idt[num].BaseLow = base & 0xFFFF;
    71.     idt[num].BaseHigh = (base >> 16) & 0xFFFF;
    72.     idt[num].Selector = selector;
    73.     idt[num].Always0 = 0;
    74.     idt[num].Flags = flags | 0x60;
    75. }
    76.  
    77. const char* exception_messages[] = {
    78.     "Division By Zero",
    79.     "Debug",
    80.     "Non Maskable Interrupt",
    81.     "Breakpoint",
    82.     "Into Detected Overflow",
    83.     "Out of Bounds",
    84.     "Invalid Opcode",
    85.     "No Coprocessor",
    86.     "Double fault",
    87.     "Coprocessor Segment Overrun",
    88.     "Bad TSS",
    89.     "Segment not present",
    90.     "Stack fault",
    91.     "General protection fault",
    92.     "Page fault",
    93.     "Unknown Interrupt",
    94.     "Coprocessor Fault",
    95.     "Alignment Fault",
    96.     "Machine Check",
    97.     "Reserved",
    98.     "Reserved",
    99.     "Reserved",
    100.     "Reserved",
    101.     "Reserved",
    102.     "Reserved",
    103.     "Reserved",
    104.     "Reserved",
    105.     "Reserved",
    106.     "Reserved",
    107.     "Reserved",
    108.     "Reserved",
    109.     "Reserved"
    110. };
    111.  
    112. extern "C" void isr_handler(INTERRUPT_REGISTERS* regs)
    113. {
    114.     if (regs->int_no < 32)
    115.     {
    116.         vga::print(exception_messages[regs->int_no]);
    117.         vga::print("\n");
    118.         vga::print("Exception! System halted.");
    119.  
    120.         while (true);
    121.     }
    122. }

    Код (ASM):
    1. global WritePort
    2.  
    3. WritePort:
    4.   mov ax, [esp + 8]
    5.   mov dx, [esp + 4]
    6.   out dx, ax
    7.   ret

    Код (C++):
    1. #include "vga.h"
    2. #include "gdt.h"
    3. #include "interrupts/idt.h"
    4.  
    5. extern "C" void KernelMain()
    6. {
    7.     InitGDT();
    8.  
    9.     vga::reset();
    10.     vga::print("GDT initialized!\n");
    11.  
    12.     InitIDT();
    13.     vga::print("IDT initialized!\n");
    14.  
    15.     int x = 1 / 0;
    16. }
    17.  

    Как мне отрефакторить этот код, чтобы он был написан на C++17 с современными фичами? Я перфекционист и люблю современные инструменты, но код у меня почему-то часто получается в стиле чистого си.
     
  14. HoShiMin

    HoShiMin Well-Known Member

    Публикаций:
    5
    Регистрация:
    17 дек 2016
    Сообщения:
    1.455
    Адрес:
    Россия, Нижний Новгород
    В первую очередь нужно убрать все волшебные числа и битовую магию.
    За каждым из них стоит вполне конкретная битовая структурка: стоит описать их все, и код станет намного читаемее, независимо от того, пишешь ты его на C++ или на чистом C.
    Вот пример для твоих дескрипторов.

    Во вторую очередь присмотрись ко всем данным, для которых есть связанные функции такого вида:
    Код (C++):
    1.  
    2. struct Data
    3. {
    4.     ...
    5. };
    6.  
    7. void func(Data* data, ...);
    8.  
    Их все можно преобразовать в методы: data.func().

    В-третьих, делай инициализацию данных там же, где их объявляешь - просто ставь пустые фигурные скобки.

    В-четвёртых, не забывай про константность:
    Код (C++):
    1.  
    2. const char* exception_messages[] = { ...
    3.  
    Здесь у тебя мутабельный массив указателей на константные данные. Это не то, что ты хочешь, т.к. сам массив всё ещё можно изменить.
    Тебе же нужен константный массив указателей на константные данные - т.е., два конста: один для указателя, другой для массива:
    Код (C++):
    1.  
    2. const char* const g_exceptionMessages[]
    3. {
    4.     "Sample text",
    5.     "Another text"
    6. };
    7.  
    Также константным делай всё, что только можно: если метод не меняет состояние класса - делай его const'ом; если переменная задаётся только единожды - тоже делай const'ом.
    Чем более константный твой код - тем лучше.

    В-пятых, приведи код к одному стилю. Используй стиль, как в джаве или в Qt: CamelCase для типов, camelCase для методов и переменных.
    Не забывай про префиксы: "g_" для глобальных переменных, "m_" для приватных полей классов, "k_" для констант и констэкспров, "t_" для thread-local, "s_" для статических переменных.
    Для полей структур префиксы писать не надо.

    В-шестых, вместо static, чтобы задать внутренний тип линковки, используй анонимные неймспейсы:
    Код (C++):
    1.  
    2. // Было:
    3. static IDT_ENTRY idt[256];
    4. static IDT_PTR   ptr;
    5.  
    6. // Стало:
    7. class Idt
    8. {
    9. public:
    10.     class Entry
    11.     {
    12.         ...
    13.     };
    14.  
    15. private:
    16.     Entry m_table[256];
    17.  
    18. public:
    19.     constexpr Idt() noexcept
    20.         : m_table{}
    21.     {
    22.     }
    23.  
    24.     ...
    25. };
    26.  
    27. namespace
    28. {
    29.     Idt g_idt{};
    30.     Idtr g_idtr{};
    31. }
    32.  
    И, в-седьмых, используй средства самоконтроля: пиши быстрые тесты на static_assert'ах.
    Написал сложную битовую структурку - статик-ассертом проверь её размер: убедись, что не потерял биты.

    Вот примерно так.
     
    Aoizora нравится это.
  15. Aoizora

    Aoizora Active Member

    Публикаций:
    0
    Регистрация:
    29 янв 2017
    Сообщения:
    362
    То есть как-то так получается? Битовую магию потом уберу и распишу все поля подробно. А где вызывать метод set для заполнения таблицы и как при помощи ассемблерной функции FlushGDT установить указатель на эту таблицу в регистр?


    Код (C++):
    1. namespace seg
    2. {
    3.     class GDT
    4.     {
    5.     public:
    6.         struct Entry
    7.         {
    8.             uint16_t Limit;
    9.             uint16_t BaseLow;
    10.             uint8_t BaseMiddle;
    11.             uint8_t Access;
    12.             uint8_t Flags;
    13.             uint8_t BaseHigh;
    14.         };
    15.  
    16.         static_assert(sizeof(Entry) == sizeof(long long));
    17.  
    18.         constexpr GDT() noexcept
    19.             : table{}
    20.         {
    21.  
    22.         }
    23.  
    24.         void set(int index, uint32_t base, uint16_t limit, uint8_t access, uint8_t flags)
    25.         {
    26.             table[index].BaseLow = base & 0xFFFF;
    27.             table[index].BaseMiddle = (base >> 16) & 0xFF;
    28.             table[index].BaseHigh = (base >> 24) & 0xFF;
    29.             table[index].Limit = limit;
    30.             table[index].Access = access;
    31.             table[index].Flags = flags;
    32.         }
    33.  
    34.     private:
    35.         Entry table[5];
    36.     };
    37.  
    38.     struct GDTR
    39.     {
    40.         unsigned short Limit;
    41.         unsigned int BaseAddress;
    42.     };
    43.  
    44.     namespace
    45.     {
    46.         GDT gdt{};
    47.         GDTR gdtr{};
    48.     }
    49. }
    50.  
     
  16. Marylin

    Marylin Active Member

    Публикаций:
    0
    Регистрация:
    17 фев 2023
    Сообщения:
    189
    Инструкция ассемблера lgdt (load) загружает в регистр GDTR адрес/размер таблицы, а sgdt (store) наоборот считывает. Оформлять каждый 8-байтный дескриптор таблицы отдельно совсем не обязательно, т.к. это давно известные всем константы - просто выстаиваешь эти константы по селекторам в виде таблицы, и передаёшь инструкции lgdt её адрес.

    Интел рекомендует строго соблюдать порядок следования дескрипторов в GDT. Например на х32 селектор ядра CS должен иметь значение(08h), а DS 10h. Если на х32 в резерве должен быть только первый дескриптор, то на х64 уже первый + второй. Соблюдение этих простых правил позволит съэкономить много времени в будующем, например если захочешь вставить в свою ос какой-нибудь готовый модуль чужой оси (win/react/linux).

    Собрать все константы можно запросив таблицу у WinDbg командой dg (dump gdt) - получишь порядок селекторов, тип и флаги дескрипторов.

    Код (Text):
    1. 0: kd> dg 00 80
    2.                                                            P  Si  Gr  Pr  Lo
    3.    Sel          Base              Limit           Type     l  ze  an  es  ng  Flags
    4.    ----  -----------------  -----------------  ----------  -  --  --  --  --  --------
    5.    0000  00000000`00000000  00000000`00000000  Reserved    0  Nb  By  Np  Nl  00000000
    6.    0008  00000000`00000000  00000000`00000000  Reserved    0  Nb  By  Np  Nl  00000000
    7.    0010  00000000`00000000  00000000`00000000  Code RE Ac  0  Nb  By  P   Lo  0000029b
    8.    0018  00000000`00000000  00000000`ffffffff  Data RW Ac  0  Bg  Pg  P   Nl  00000c93
    9.    0020  00000000`00000000  00000000`ffffffff  Code RE Ac  3  Bg  Pg  P   Nl  00000cfb
    10.    0028  00000000`00000000  00000000`ffffffff  Data RW Ac  3  Bg  Pg  P   Nl  00000cf3
    11.    0030  00000000`00000000  00000000`00000000  Code RE Ac  3  Nb  By  P   Lo  000002fb
    12.    0038  00000000`00000000  00000000`00000000  Reserved    0  Nb  By  Np  Nl  00000000
    13.    0040  00000000`00b92080  00000000`00000067  TSS32 Busy  0  Nb  By  P   Nl  0000008b
    14.    0048  00000000`0000ffff  00000000`0000f800  Reserved    0  Nb  By  Np  Nl  00000000
    15.    0050  ffffffff`fffd9000  00000000`00003c00  Data RW Ac  3  Bg  By  P   Nl  000004f3
    16.    0058  00000000`00000000  00000000`00000000  Reserved    0  Nb  By  Np  Nl  00000000
    17.    0060  00000000`00000000  00000000`ffffffff  Code RE     0  Bg  Pg  P   Nl  00000c9a
    18.    0068  00000000`00000000  00000000`00000000  Reserved    0  Nb  By  Np  Nl  00000000
    19.    0070  00000000`00000000  00000000`00000000  Reserved    0  Nb  By  Np  Nl  00000000
    20.    0078  00000000`00000000  00000000`00000000  Reserved    0  Nb  By  Np  Nl  00000000
    21.  
    Но это общий уже расшифрованный вид.
    Если-же нужны только значения дескрипторов, можно запросить их явно по адресу в GDTR

    Код (Text):
    1. 0: kd> r @gdtr
    2.    gdtr =  fffff800`00b91000
    3.  
    4. 0: kd> dqs fffff800`00b91000
    5. ;---------------------------------------
    6.    fffff800`00b91000   00000000`00000000
    7.    fffff800`00b91008   00000000`00000000
    8.    fffff800`00b91010   00209b00`00000000
    9.    fffff800`00b91018   00cf9300`0000ffff
    10.    fffff800`00b91020   00cffb00`0000ffff
    11.    fffff800`00b91028   00cff300`0000ffff
    12.    fffff800`00b91030   0020fb00`00000000
    13.    fffff800`00b91038   00000000`00000000
    14.    fffff800`00b91040   00008bb9`20800067
    15.    fffff800`00b91048   00000000`fffff800
    16.    fffff800`00b91050   ff40f3fd`90003c00
    17.    fffff800`00b91058   00000000`00000000
    18.    fffff800`00b91060   00cf9a00`0000ffff
    19.    fffff800`00b91068   00000000`00000000
    20.    fffff800`00b91070   00000000`00000000
    21.    fffff800`00b91078   00000000`00000000
    22.  
    Остаётся оформить этот лог в виде таблицы, и загрузить в GDTR её адрес
    Чтобы не забыть назначение дескрипторов, можно добавить комменты из столбца "Type" WinDbg:

    Код (ASM):
    1.     lgdt   fword[newGdt]
    2.     jmp    longMode
    3.  
    4. ;//------------ Таблица GDT ---------------------------------------
    5. align      16                         ; адрес должен быть кратен 16
    6. descTable  dq   0000000000000000
    7.            dq   0000000000000000
    8.            dq   00209b0000000000
    9.            dq   00cf93000000ffff
    10.            dq   00cffb000000ffff
    11.            dq   00cff3000000ffff
    12.            dq   0020fb0000000000
    13.            dq   0000000000000000
    14.            dq   00008bb920800067
    15.            dq   00000000fffff800
    16.            dq   ff40f3fd90003c00
    17.            dq   0000000000000000
    18.            dq   00cf9a000000ffff
    19.            dq   0000000000000000
    20.  
    21. newGdt     dw  ($ - descTable) - 1   ; размер таблицы,
    22.            dq  descTable             ; ...и её линейный адрес
    23. ;//----------------------------------------------------------
    24. longMode:  nop
    25. ......
    26.  
     
    Mikl___ нравится это.
  17. Aoizora

    Aoizora Active Member

    Публикаций:
    0
    Регистрация:
    29 янв 2017
    Сообщения:
    362
    Мне было бы интереснее сделать все на C++
    Понятно, что можно сделать и на асме, но хочется на С++
     
  18. sl0n

    sl0n Мамонт дзена **

    Публикаций:
    0
    Регистрация:
    26 сен 2003
    Сообщения:
    703
    Ну как бы и ядро венды не на плюсах писано а на си+ асм ... хотя вон S.T.A.S. помню сделал плюсовую либу для дров и спокойненько руткитеки на плюсах писал =)) Нинзя котик =))
     
  19. Marylin

    Marylin Active Member

    Публикаций:
    0
    Регистрация:
    17 фев 2023
    Сообщения:
    189
    Так реализовать можно на чём угодно, а записывать адрес в регистр GDTR всё-равно придётся через _asm lgdt, хоть и завернув её в какой-нибудь сишный фантик.

    Кстати сам факт записи адреса в GDTR ещё не меняет режим адресации памяти, поэтому это можно делать из любого участка кода. Переключение происходит только в момент записи соответствующего селектора из GDT, в сегментные регистры CS..GS. Известно, что их размер 10-байт: это видимая нам 2-байтная часть для селектора, и скрытый 8-байтный кэш как-раз для дескриптора из GDT. Когда цп обнаруживает например mov cs,10h, он по адресу в GDTR находит таблицу, и копирует в кэш CS весь 8-байтный дескриптор под номером(10h). Именно в этот момент и переключается режим в блоке MMU цп. Запись селекторов в сег/регистры возможна только из Protected-Ring(0), а в реальном не воздействует на MemoryManagementUnit.
    --- Сообщение объединено, 5 июн 2024 ---
    любопытно, что после того-как в РМ сменили дескриптор например в fs/gs,
    можно опять вернуться в RM, и юзать уже все 4ГБ памяти с прерываниями биос - UnrealMode.
     
    Mikl___ нравится это.