Como posso reservar um bloco de memória do kernel do Linux?

25

Eu tenho um dispositivo que precisa de um bloco de memória reservado exclusivamente para ele, sem a interferência do sistema operacional. Existe alguma maneira de informar ao BIOS ou ao SO que um bloco de memória está reservado e não deve ser usado?

Estou usando este dispositivo em uma máquina openSUSE.

Nathan Fellman
fonte

Respostas:

23

O que você está pedindo é chamado DMA. Você precisa escrever um driver para reservar esta memória.

Sim, eu sei que você disse que não queria que o sistema operacional intervenha, e um driver se torna parte do sistema operacional, mas, na ausência de uma reserva de driver, o kernel acredita que toda a memória pertence a ele. (A menos que você diga ao kernel para ignorar o bloco de memória, de acordo com a resposta de Aaron).

O capítulo 15 (PDF) de " Linux Device Drivers, 3 / e " de Rubini, Corbet e Kroah-Hartmann aborda o DMA e tópicos relacionados.

Se você quiser uma versão em HTML disso, encontrei a versão da segunda edição do capítulo online em outros lugares. Cuidado que a 2ª edição tem mais de uma década, tendo sido lançada quando o kernel 2.4 era novo. Tem havido muito trabalho no subsistema de gerenciamento de memória do kernel desde os dias, portanto ele pode não se aplicar muito bem.

Warren Young
fonte
Com o DMA, posso escolher quais endereços físicos usar? O kernel me dará um bloco contíguo de memória? É garantido que esteja sempre disponível?
Nathan Fellman
1
Suas perguntas são respondidas a partir da página 442 do PDF que eu indiquei.
Warren Young
24

Se você deseja que o sistema operacional o ignore totalmente , é necessário fazer um furo na memória usando " memmap." Veja esta referência . Por exemplo, se você quiser 512M na barreira de 2GB, poderá " memmap=512M$2G" colocar na linha de comando do kernel.

Você precisará verificar o seu dmesgpara encontrar um buraco contíguo para roubar, para não pisar em nenhum dispositivo; Isso é específico para sua placa-mãe + placas.

Esta não é a maneira recomendada de fazer as coisas - consulte a resposta de Warren Young para saber como fazê-lo corretamente (drivers do kernel + DMA). Estou respondendo a pergunta exata que você fez. Se você planeja fazer isso para os usuários finais, eles o odiarão se você fizer isso com eles ... confie em mim, essa é a única razão pela qual eu soube essa resposta.


Edit: Se você estiver usando o grub2 w / grubby (por exemplo, CentOS 7), você precisa se livrar do $ . Deve haver um único \antes $. Exemplo:

$ sudo -v
$ sudo grubby --update-kernel=ALL --args=memmap='128M\\$0x57EF0000'
$ sudo grubby --info $(sudo grubby --default-kernel) | grep memmap
args="ro crashkernel=auto ... memmap=128M\$0x57EF0000"
Aaron D. Marasco
fonte
1
Embora sua resposta responda diretamente à minha pergunta, a resposta de Warren parece ser a melhor maneira de fazer isso. :-)
Nathan Fellman
1
@ WarrenYoung Eu não tenho idéia do que você deve fazer com isso. Eu acho que " uint8_t *ptr = 0x8000000" com o meu exemplo? Ou isso pode falhar ... Não sei mesmo. Novamente, eu sabia a resposta porque era um usuário final de uma placa PCI mal projetada, na qual tive que alocar manualmente um buffer abaixo da marca 4G e depois informar ao driver onde estava esse espaço; pode não ser possível na terra do usuário.
Aaron D. Marasco
2
Apenas por sorrisos, olhei um pouco mais fundo nisso e parece que você precisa MMAP_FIXED | MMAP_ANON. Sem um dispositivo DMA personalizado para brincar, não posso dizer se ele realmente faz o que o OP queria, mas minha caixa do CentOS felizmente me deu um bloco de 8 MB a 512 MB quando falei memmap=8M$512Mno GRUB. Nem sequer requer acesso root, como eu temia. Mas mesmo que isso faça a coisa certa, ainda acho que você provavelmente precisará de um driver para lidar com interrupções e coisas do tipo.
Warren Young
3
@ AaronD.Marasco: Não, mmap()as páginas são zeradas antes que o código da terra do usuário as veja. Isso é feito por segurança, para que os dados não vazem de um processo para o outro. Outro motivo para usar um driver, pois pode ser necessário preservar o conteúdo do buffer DMA no momento do carregamento do driver. Ah, a propósito, a mmap()chamada localizada arbitrariamente é bem- sucedida mesmo sem a memmapopção de inicialização do kernel, pelo menos enquanto ninguém estiver usando a memória localizada onde você pediu. A opção de inicialização sem dúvida aumenta as chances de sucesso, mas não é estritamente necessária.
Warren Young
1
@ AaronD.Marasco hmm, tudo bem. interessante. obrigado por esse link, é uma boa leitura.
Woodrow Barlow
5

Para reservar um bloco de memória do kernel no Linux baseado em ARM, você também pode usar um reserved-memorynó no arquivo da árvore de dispositivos (dts). Na documentação do kernel (veja aqui ), há um exemplo:

memory {
    reg = <0x40000000 0x40000000>;
};

reserved-memory {
    #address-cells = <1>;
    #size-cells = <1>;
    ranges;

    /* global autoconfigured region for contiguous allocations */
    linux,cma {
        compatible = "shared-dma-pool";
        reusable;
        size = <0x4000000>;
        alignment = <0x2000>;
        linux,cma-default;
    };

    display_reserved: framebuffer@78000000 {
        reg = <0x78000000 0x800000>;
    };

    multimedia_reserved: multimedia@77000000 {
        compatible = "acme,multimedia-memory";
        reg = <0x77000000 0x4000000>;
    };
};
Vladimir S.
fonte
0

Primeiro, digite este comando para verificar sua configuração atual:

sysctl vm.min_free_kbytes

Para alterar o valor definido, edite /etc/sysctl.conf. Procure a linha:

vm.min_free_kbytes=12888

Se não existir, crie-o (junto com o valor desejado). Os seguintes valores são aceitáveis:

8192
12288
16384
20480

8M é extremamente conservador; pode sentar-se confortavelmente em 16M. Depois de alterar o valor, execute isso e nenhuma reinicialização é necessária:

sudo sysctl -p
Michael Mrozek
fonte
2
Por favor, não anule suas postagens; exclua-o ou sinalize-o para que um moderador o remova.
precisa saber é o seguinte