Skip to content

Commit

Permalink
LPC bus sniffer program
Browse files Browse the repository at this point in the history
  • Loading branch information
MrGreensWorkshop committed Jun 8, 2023
1 parent f5b3485 commit fa33195
Show file tree
Hide file tree
Showing 3 changed files with 142 additions and 1 deletion.
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ Thank you for considering [supporting my work!](#you-can-support-my-work)

I usually use old or junk parts on my projects to reduce electronic waste and support the SDGs. I was working on a project to reuse an x86-based firewall that I came across in an online auction. And I found myself reading BIOS post-codes. I thought it would be a good opportunity to talk about how the LPC bus and I/O cycles work by making a BIOS POST code reader project. So, here we are.

### Features / Fixes

- LPC bus sniffer
- POST code output to USB CDC

### Compilation

1. Clone the repo as shown below, or [download latest release](https://github.com/MrGreensWorkshop/RasPiPicoSDK-PicoBiosPostCodeReader/releases/latest).
Expand Down
88 changes: 88 additions & 0 deletions src/lpc_bus_sniffer.pio
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
.program lpc_bus_sniffer
;.side_set 1 opt ; [DEBUG] side_set <count> (opt) (pindirs)

.define NIBBLE_LOOP_COUNT 6

pull ; Get the filter from TX FIFO to the OSR.
mov Y, OSR ; Copy OSR to Y.
.wrap_target
entry_point:
mov ISR, null ; Clean the ISR.
set X, (NIBBLE_LOOP_COUNT - 1) ; Set the value to X register.
wait 0 pin 5 ; Wait until the LFRAME pin goes low.

; Get 6 nibble (START + CY/DR + ADDR[3-0])
read_nibble1:
wait 0 pin 4 ; Wait until the LCLK pin goes low.
in pins, 4 ; Read the LAD[0-3] pins.
wait 1 pin 4 ; Wait until the LCLK pin goes high.
jmp X-- read_nibble1 ; If X is not equal to zero, decrement it and jump.

; Check the frame, START + CY/DR + ADDR[0-3]
mov X, ISR ; Copy ISR to X.
jmp X!=Y entry_point ; If X and Y registers are not equal jump.

; Get 1 nibble (DATA[0])
wait 0 pin 4 ; Wait until the LCLK pin goes low.
in pins, 4 ; Get the DATA[0].
wait 1 pin 4 ; Wait until the LCLK pin goes high.

; Get 1 nibble (DATA[1])
wait 0 pin 4 ; Wait until the LCLK pin goes low.
in pins, 4 ; Get the DATA[1].
wait 1 pin 4 ; Wait until the LCLK pin goes high.

in null, 24 ; Shift the ISR 24 bit to get DATA.
push ; Push to get the DATA value on terminal.
.wrap

% c-sdk {

//#define SIDE_PIN 26 // For debugging

void lpc_bus_sniffer_program_init(PIO pio, uint sm, uint offset, uint lpc_bus_pin_base) {
pio_sm_config c = lpc_bus_sniffer_program_get_default_config(offset);

// Connect the GPIOs to selected PIO block
for(uint i = lpc_bus_pin_base; i < lpc_bus_pin_base + 6; i++) {
pio_gpio_init(pio, i);
}

#ifdef SIDE_PIN
pio_gpio_init(pio, SIDE_PIN);
#endif

// Set the selected pin directions for the selected 6 pins. LAD[0-3] + LCLK + LFRAME (false: in)
pio_sm_set_consecutive_pindirs(pio, sm, lpc_bus_pin_base, 6, false);

#ifdef SIDE_PIN
// Set the selected pin direction for the selected 1 pin. SIDE_PIN (true: out)
pio_sm_set_consecutive_pindirs(pio, sm, SIDE_PIN, 1, true );
#endif

sm_config_set_in_shift(
&c,
true, // ShiftDir : true: shift ISR to right, false: shift ISR to left
false, // AutoPush : true: enabled, false: disabled
0 // AutoPush threshold: <0-32>
);

sm_config_set_out_shift(
&c,
true, // ShiftDir : true: shift OSR to right, false: shift OSR to left
false, // AutoPull : true: enabled, false: disabled
0 // AutoPull threshold: <0-32>
);

// Set 'IN' base pin. To read the LAD[0-3].
sm_config_set_in_pins(&c, lpc_bus_pin_base);

#ifdef SIDE_PIN
// Set 'SIDESET' base pin. It's for debugging.
sm_config_set_sideset_pins(&c, SIDE_PIN);
#endif

pio_sm_init(pio, sm, offset, &c);
}

%}
50 changes: 49 additions & 1 deletion src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@
#include "pico/stdlib.h"
#include "hardware/pio.h"
#include "hardware/clocks.h"
#include "lpc_bus_sniffer.pio.h"

// Set the system frequency to 33 MHz x 6 to make time for handling LPC frames.
#define SYS_FREQ_IN_KHZ (198 * 1000)

#define LED_STATUS_PIN PICO_DEFAULT_LED_PIN
#define INTERVAL_IM_ALIVE_MS (1000)
Expand All @@ -23,6 +27,37 @@ void flash_led_once(void) {
gpio_put(LED_STATUS_PIN, 0);
}

int init_lpc_bus_sniffer(PIO pio) {
// LAD[0-3] + LCLK + LFRAME which starts from GPIO0
uint lpc_bus_pin_base = 0;
uint offset;

printf("initializing the lpc bus sniffer program\n");

int sm = pio_claim_unused_sm(pio, true);
if(sm < 0){
printf("Error: Cannot claim a free state machine\n");
return -1;
}

if (pio_can_add_program(pio, &lpc_bus_sniffer_program)) {
offset = pio_add_program(pio, &lpc_bus_sniffer_program);
} else {
printf("Error: pio program can not be loaded\n");
return -2;
}

lpc_bus_sniffer_program_init(pio, sm, offset, lpc_bus_pin_base);
pio_sm_set_enabled(pio, sm, true);

// To sniff the POST codes
// Set the filter to I/O write cycle (0x2) and the address to 0x80.
pio->txf[sm] = 0x08002000;

printf("program loaded at %d, sm: %d\n", offset, sm);
return sm;
}

bool repeating_timer_callback(struct repeating_timer *t) {
// Print the I'm alive sign every 1 sec.
printf("...\n");
Expand All @@ -33,11 +68,19 @@ int main() {
// Initialize the GPIOs.
gpio_initialization();

// Set the system frequency.
set_sys_clock_khz(SYS_FREQ_IN_KHZ, true);

stdio_init_all();
// Wait for a while. Otherwise, USB CDC doesn't print all printfs.
sleep_ms(500);
printf("STARTED\n");

// Init the PIO
PIO _pio0 = pio0;
int sm_lpc_bus_sniffer = init_lpc_bus_sniffer(_pio0);
if (sm_lpc_bus_sniffer < 0) return -1;

// Print the system frequency.
printf("System clock is %u kHz\n", frequency_count_khz(CLOCKS_FC0_SRC_VALUE_CLK_SYS));

Expand All @@ -51,5 +94,10 @@ int main() {
flash_led_once();
printf("Starting to sample the POST codes.\n");

while(1);
while(1) {
if (!pio_sm_is_rx_fifo_empty(_pio0, sm_lpc_bus_sniffer)) {
uint32_t rxdata = _pio0->rxf[sm_lpc_bus_sniffer];
printf("data: %02x\n", rxdata);
}
}
}

0 comments on commit fa33195

Please sign in to comment.