Изучаю курс про операционные системы, где в первую неделю уже пишут ядро. Непонятен механизм преобразования физических адресов в логические. В курсе загрузчик ядра писали на ассемблере - это очень простой язык для написания загрузчиков, но я захотел сделать то же самое на си, чтобы разобраться с адресацией. В загрузчике есть код, который пишет в видеобуфер: Код (Text): /* Set videobuffer as destination address for memcpy */ movw $0xB800, %ax movw %ax, %es /* es register points to video buffer */ movw $data, %si movw $0, %di movw $size, %cx call memcpy Запись производится в видеобуфер по физическому адресу 0xB8000. Используя фомулу перевода физического адреса в логический [math]addr = (SEG \cdot 16 + offset) mod {2}^{20}[/math], можно нормализовать адрес видеобуфера: в регистре ES будет адрес 0xB800, так что если мы умножим его на 16, используя приведенную формулу, то получим исходный адрес 0xB8000. Далее, в коде ядра, написанного на си, мне непонятен пересчет адресов: Код (Text): #ifndef __MEMORY_H__ #define __MEMORY_H__ /* Higher 2 GB of 64 bit logical address space start from this address */ #define VIRTUAL_BASE 0xffffffff80000000 /* First address after "canonical hole", beginning of the middle mapping. */ #define HIGHER_BASE 0xffff800000000000 /* Kernel 64 bit code and data segment selectors. */ #define KERNEL_CS 0x08 #define KERNEL_DS 0x10 #define PAGE_BITS 12 #define PAGE_SIZE (1 << PAGE_BITS) #define PAGE_MASK (PAGE_SIZE - 1) #ifndef __ASM_FILE__ #include <stdint.h> #define VA(x) ((void *)((uintptr_t)x + HIGHER_BASE)) #define PA(x) ((uintptr_t)x - HIGHER_BASE); static inline void *va(uintptr_t phys) { return VA(phys); } static inline uintptr_t pa(const void *virt) { return PA(virt); } #endif /*__ASM_FILE__*/ #endif /*__MEMORY_H__*/ Код (Text): #include <stddef.h> #include <memory.h> #include <vga.h> static char * const VBUF = VA(0xB8000); static const int ROWS = 25; static const int COLS = 80; static const int ATTR = 15; static char *__vga_at(int r, int c) { return VBUF + (r * COLS * 2 + c); } static void vga_set(int r, int c, char x) { *__vga_at(r, 2 * c) = x; *__vga_at(r, 2 * c + 1) = ATTR; } static char vga_get(int r, int c) { return *__vga_at(r, 2 * c); } static void scroll(void) { for (int r = 1; r != ROWS; ++r) for (int c = 0; c != COLS; ++c) vga_set(r - 1, c, vga_get(r, c)); } static void putchar(char x) { static int r = 0; static int c = 0; if (x == '\n') { for (; c != COLS; ++c) vga_set(r, c, ' '); c = 0; ++r; } else { vga_set(r, c, x); if (++c == COLS) { c = 0; ++r; } } if (r == ROWS) { scroll(); --r; } } void vga_write(const char *data, size_t size) { for (size_t i = 0; i != size; ++i) putchar(data[i]); } void vga_clr(void) { for (int r = 0; r != ROWS; ++r) for (int c = 0; c != COLS; ++c) vga_set(r, c, ' '); } Для чего используется строка Код (Text): static char * const VBUF = VA(0xB8000); ? А VA определен, как можно видеть, макросом Код (Text): #define VA(x) ((void *)((uintptr_t)x + HIGHER_BASE)) , где #define HIGHER_BASE 0xffff800000000000 Что это за магия? Почему, если записать по адресу 0xffff800000000000 + 0xB8000, мы попадем в видеобуфер по его физическому адресу?
От себя добавлю, что ваша ассемблерная цитата относится к реальному режиму работы процессора, а сишная - к защищенному. Трансляция адресов памяти в этих режимах совершенно различна и ничего общего между собой не имеет.