O GRUB não precisa carregar todo o kernel na memória. A imagem do kernel é dividida em duas partes:
- O código do kernel em modo real, que é pequeno e pode ser carregado dentro do limite de 640kB de memória disponível;
- O restante do kernel, que é executado no modo protegido e é carregado após o primeiro megabyte de memória.
O carregador de inicialização só carrega o código do kernel em modo real, que por sua vez inicializa o restante (veja go_to_protected_mode()
in arch/x86/boot/pm.c
). É assim que o processo pode ficar dentro das limitações de memória da execução em modo real.
Uma pequena nota: o GRUB pode ser executado em ambos modo real e modo protegido, dependendo do que está fazendo. Pode mudar para o modo protegido para algumas coisas (alguma detecção de hardware e exibição de menu). Você está certo, no entanto, em pensar que está no modo real quando atinge o kernel.