The actual knowledge of nominal battery capacity doesn't generally come from the same place. For example, I worked with small embedded devices that would only ever be shipped with the same battery type – so the nominal capacity was simply hard-coded in the kernel driver (or the device tree file, I forget which, doesn't matter, it means "hardcoded in the software running on the CPU").
Other devices will have firmware runnning on the computer's main board's power controller that keeps track of capacity. Whether it knows that by knowing the factory capacity as a constant, or whether it gets the capacity from a microcontroller or memory built into the battery pack is again dependent on hardware design. Same for abilities to re-calibrate without operating system support.
Then, the question of where the knowledge on current battery state comes from: this again depends on the hardware design. Simplistic solutions might just read current battery voltage (and have an internal typical discharge curve that maps voltage to charge; which is what you'd expect in the dumbphone era: a battery symbol that signals "quite full", "somewhat full", "nearly empty", that's it), others will at least compensate for temperature, better ones will also actually count the Joules that came from the battery and give a more accurate reading, typically.
Then, either the ACPI controller, or quite often on non-ACPI systems, the kernel directly talks to these devices (e.g. via SMBUS, USB, some CPU UART…) and converts these readings to the values you see from the kernel interfaces (sysfs).