← Back to context

Comment by sleirsgoevy

3 hours ago

x86_64 seems not to care much. I've had a UART mapped as normal memory, and it somehow still worked.

Did you really map it as normal memory?

Standard UARTs are accessed in the x86 I/O space, which is uncacheable and strongly ordered, not in the normal memory space.

Non-standard UARTs that are on PCIe add-on cards might be mapped into memory, but when the computer boots, the BIOS already maps the PCIe memory as uncacheable, with the Memory Type Range Registers.

So if you do nothing, you get uncacheable memory for your UART, as you should.

To map the UART in normal memory, i.e. write-back cacheable, you must do this explicitly in the UART device driver, either by allocating a dedicated MTRR for it, or more likely, by locking a memory page for it in the virtual address translation tables and using the PAT bits to set the memory type (Page Attribute Table).

If you really mapped the UART as normal memory, i.e. write-back cacheable, it can work correctly only if you are incredibly lucky, because the writes to the UART control registers will not happen when you do them in your program, so I do not believe that you did that. With normal memory, not only you cannot predict when the UART registers will be written, but if you do multiple writes to the same register, all but the last will be omitted, so there is no way for the UART to work correctly.

On x86-64, any memory-mapped peripheral must be mapped into uncacheable memory, except for memory banks that are located on PCIe cards, like the GPU memories, which should be mapped as write-combining memory.