STM32 handmade USART driver
Running at 168 MHz, you'd have 1458 clock cycles between two consecutive bits at 115200 bps, that seems to be enough for the processing, but a bit tight for the output accuracy, see below.

Output is straightforward if you have a free timer, set it to generate an interrupt at the bitrate frequency, and shift out the start bit, data bits, stop bit in the interrupt routine. This interrupt must have the highest possible priority to achieve 5% accuracy, which is just 72 cycles. Put your stack and relevant variables in the CCM memory, vector table and interrupt routine in the internal SRAM, and disable saving floating point registers, to minimize interrupt latency. Read this ARM FAQ for the implications.

If your RX pin can be mapped to a timer input, do that. You can program the timer to generate an interrupt on both edges, it can be filtered by hardware, and you get a timestamp stored in the capture register, so you can determine the exact time when the edge arrived, even when the interrupt is delayed a bit.