Resolvido:)
A causa parece ser uma característica estranha na implementação do UEFI, que também pode ser vista na implementação do Open Source TianoCore:
Eu finalmente o descobri depois de diferenciar meus despejos de variáveis do EFI depois da última "perda" de 21MB e encontrei variáveis interessantes:
Antes de perder os últimos 21MB de memória
Variable NV+RT+BS '4C19049F-4137-4DD3-9C10-8B97A83FFDFA:MemoryTypeInformationBackup' DataSize = 50
00000000: 09 00 00 00 60 00 00 00-0A 00 00 00 00 01 00 00 *....'...........*
00000010: 00 00 00 00 00 10 00 00-06 00 00 00 36 3A 00 00 *............6:..*
00000020: 05 00 00 00 00 02 00 00-03 00 00 00 00 8C 00 00 *................*
00000030: 04 00 00 00 00 40 00 00-01 00 00 00 00 02 00 00 *.....@..........*
00000040: 02 00 00 00 78 F2 03 00-0E 00 00 00 00 00 00 00 *....x...........*
Variable NV+RT+BS '4C19049F-4137-4DD3-9C10-8B97A83FFDFA:MemoryTypeInformation' DataSize = 50
00000000: 09 00 00 00 60 00 00 00-0A 00 00 00 00 01 00 00 *....'...........*
00000010: 00 00 00 00 00 10 00 00-06 00 00 00 36 3A 00 00 *............6:..*
00000020: 05 00 00 00 00 02 00 00-03 00 00 00 00 8C 00 00 *................*
00000030: 04 00 00 00 00 40 00 00-01 00 00 00 00 02 00 00 *.....@..........*
00000040: 02 00 00 00 38 E7 06 00-0E 00 00 00 00 00 00 00 *....8...........*
Depois de perdê-los
Variable NV+RT+BS '4C19049F-4137-4DD3-9C10-8B97A83FFDFA:MemoryTypeInformationBackup' DataSize = 50
00000000: 09 00 00 00 60 00 00 00-0A 00 00 00 00 01 00 00 *....'...........*
00000010: 00 00 00 00 00 10 00 00-06 00 00 00 36 3A 00 00 *............6:..*
00000020: 05 00 00 00 00 02 00 00-03 00 00 00 00 8C 00 00 *................*
00000030: 04 00 00 00 00 40 00 00-01 00 00 00 00 02 00 00 *.....@..........*
00000040: 02 00 00 00 38 E7 06 00-0E 00 00 00 00 00 00 00 *....8...........*
Variable NV+RT+BS '4C19049F-4137-4DD3-9C10-8B97A83FFDFA:MemoryTypeInformation' DataSize = 50
00000000: 09 00 00 00 60 00 00 00-0A 00 00 00 00 01 00 00 *....'...........*
00000010: 00 00 00 00 00 10 00 00-06 00 00 00 36 3A 00 00 *............6:..*
00000020: 05 00 00 00 00 02 00 00-03 00 00 00 00 8C 00 00 *................*
00000030: 04 00 00 00 82 55 00 00-01 00 00 00 00 02 00 00 *.....U..........*
00000040: 02 00 00 00 38 E7 06 00-0E 00 00 00 00 00 00 00 *....8...........*
Por que isso é interessante: o tempo todo eu testei coisas, atualizei e desativei o BIOS, alterei configurações, etc, essas variáveis nunca mudaram (e eu presumi que elas armazenam alguma informação sobre a marca / modelo da minha RAM instalada ou similar) .
Agora que minha memória diminuiu, foi feito backup do valor de MemoryTypeInformation como MemoryTypeInformationBackup (sobrescrevendo o backup antigo) e exatamente uma DWORD no valor alterado - no deslocamento 0x34: o valor antigo era 0x4000, o novo valor é 0x5582. A diferença é 0x1582 ou 5506 em decimal, o que corresponde exatamente ao número de páginas (blocos de 4K) que minha memória encolheu da última vez.
Indo um passo adiante: o valor antigo de MemoryTypeInformation e MemoryTypeInformationBackup também difere em exatamente um valor (em um deslocamento diferente, porém, 0x44). Ao comparar seus valores novamente, 0x2F4C0 ou 193728 em decimal, é exatamente o número de páginas em que minha memória diminuiu antes (quando o endereço inicial foi alterado de 871F2000 para 57D32000).
Comparando isso com o código TianoCore mencionado acima, isso de repente faz todo o sentido:
Esse código é acionado sempre que o sistema está prestes a inicializar uma opção de inicialização e verifica se as diferentes regiões de memória UEFI têm menos páginas alocadas do que armazenadas em MemoryTypeInformation. Caso contrário, o mapa de memória está incorreto e a variável é atualizada (com 125% do que está atualmente alocado) e uma reinicialização é acionada, para que o mapa de memória possa ser reconstruído a partir dos dados mais recentes. Observe que a implementação nunca reduzirá o tamanho do cache para qualquer tipo de memória, portanto, qualquer alteração aqui será permanente.
O problema aqui é que, se a inicialização do UEFI falhar, ele o colocará novamente no menu de seleção de inicialização (ou, no caso de ser um dispositivo na ordem de inicialização padrão, o próximo dispositivo será testado). Como a maioria dos carregadores de inicialização UEFI não se auto-limpam em caso de falha de inicialização, assim que o próximo menu for inicializado, esse código detectará que mais memória foi alocada e, portanto, decide que precisa atualizar o mapa de memória para que seguinte sistema operacional não vai entrar em apuros. Infelizmente, isso se repete para cada falha de inicialização, de modo que, eventualmente, há um "limite rígido" de quantas vezes você pode falhar na inicialização: - (
O código em TianoCore também possui opções de fallback caso a variável esteja ausente ou mal formada (o que, se eu entender o código corretamente pode custar até duas reinicializações extras, embora), mas considerando o fato de que a Lenovo incluiu um Backup variável (que não existe no TianoCore), eu decidi não confiar neste fallback e reverti para o backup mais antigo que eu tinha, menos 800 MB para o tipo LoaderData, que me dá uma memória reservada de 667 MB de hardware efetivo (bom o suficiente para agora) . E isso funciona:)
Lições aprendidas
-
Quando uma inicialização do UEFI falha e você retorna ao menu de inicialização, nunca tente inicializar mais nada, é melhor redefinir o sistema (espero que isso não acione o código; se isso acontecer, atualizarei o postar)
-
O EFI Shell tem um editor hexadecimal bastante útil para editar variáveis EFI e corrigir esses problemas
-
Mesmo que o seu fornecedor não possa ou não queira ajudá-lo - continue sendo teimoso; eventualmente você encontrará uma solução (mesmo que meses depois)