Estou bastante confuso sobre como o Linux gerencia a memória compartilhada de E/S para se comunicar com os dispositivos que o utilizam.
Se bem entendi, o kernel do Linux inicia mapeado em 0x100000 (para evitar os primeiros dados de memória RAM herdados de megabyte e ser armazenado em locais de memória contíguos) e depois de entrar no modo protegido:
- em sistemas de 32 bits há um mapeamento como este
O ZONE_NORMAL deve estar abaixo de 896 MB, portanto o mapeamento entre os 1GB lineares do kernel e os 896 MB físicos é sempre possível. Vamos ignorar ZONE_DMA por enquanto (li que isso é apenas para sistemas legados, já que o PCI agora pode usar transferências DMA em qualquer lugar da memória)
- em sistemas de 64 bits, o espaço de endereço linear do kernel deve começar em PAGE_OFFSET= 0xffff810000000000 e adiante
Em ambos os casos, se um endereço no espaço do kernel for maior que PAGE_OFFSET, deverá referir-se a um mapeamento ioremap (a ser resolvido através de paginação), se for menor que PAGE_OFFSET poderá ser resolvido com um simples NEW_ADDRESS = OLD_ADDRESS - PAGE_OFFSET. Isso está correto?
Pergunta bônus: quando o kernel está instalado e funcionando e a organização foi feita, ele ainda reside fisicamente de 0x100000 em diante (dentro do primeiro GB)? Mesmo em sistemas de 64 bits?
Responder1
Em PCs, os intervalos de E/S mapeados na memória de hardware são atribuídos pelo BIOS a endereços de memória física entre 3GiB e 4 GiB. Quando um driver solicita acesso à memória, o kernel a mapeia em algum lugar no espaço de endereço virtual do kernel.
Nenhuma das suas outras duas perguntas parece ter algo a ver com memória compartilhada, mas:
Em ambos os casos, se um endereço no espaço do kernel for maior que PAGE_OFFSET, deverá referir-se a um mapeamento ioremap (a ser resolvido através de paginação), se for menor que PAGE_OFFSET poderá ser resolvido com um simples NEW_ADDRESS = OLD_ADDRESS - PAGE_OFFSET. Isso está correto?
Mentalmente, sim. O hardware usa as tabelas de páginas em ambos os casos.
Responder2
Pense na sua pergunta, como funciona o ioremap.
vaddr = ioremap(paddr_io_mapped_device, tamanho);
vaddr é o endereço virtual retornado no espaço do kernel. O kernel cria as entradas da tabela de páginas para o intervalo de endereços virtuais (vaddr , size) e mapeia-o para o endereço físico paddr_io_shared_device. Portanto, se você acessar o intervalo de endereços virtuais, será tão bom quanto acessar o endereço físico dentro do dispositivo io_mapped.
É importante ressaltar que o vaddr retornado énão armazenável em cache. Cada vez que você lê/grava o intervalo de endereços, ele será lido/gravado no dispositivo io_mapped e não no cache.