babbleberry / rpi4-osdev

Tutorial: Writing a "bare metal" operating system for Raspberry Pi 4
https://www.rpi4os.com
Creative Commons Zero v1.0 Universal
3.37k stars 246 forks source link

Raspberry Pi 4 kernel load address #37

Closed tdh8316 closed 1 year ago

tdh8316 commented 1 year ago

Hi! first of all, thank you for writing this guide. I followed everything in part 2-building and wrote my own kernel.c due to I have no UART connector.

// kernel.c
#define BCM2711_PERI_BASE_ADDR 0xFE000000
#define GPIO_BASE_ADDR BCM2711_PERI_BASE_ADDR + 0x200000

#define OUT_PIN 21

volatile unsigned *m_pGPIO;

void setGPIOModeInput(int pin)
{
    const int reg = pin / 10;
    const int shift = (pin % 10) * 3;
    *(m_pGPIO + reg) = ((*(m_pGPIO + reg) & ~(7 << shift)) | (0 << shift));
}

void setGPIOModeOutput(int pin)
{
    setGPIOModeInput(pin);
    const int reg = pin / 10;
    const int shift = (pin % 10) * 3;
    *(m_pGPIO + reg) = ((*(m_pGPIO + reg) & ~(7 << shift)) | (1 << shift));
}

inline __attribute__((always_inline)) void setGPIO(int pin)
{
    *(m_pGPIO + 7) = 1 << pin;
}
inline __attribute__((always_inline)) void clrGPIO(int pin)
{
    *(m_pGPIO + 10) = 1 << pin;
}

int main(void)
{
    m_pGPIO = (volatile unsigned *)GPIO_BASE_ADDR;

    setGPIOModeOutput(OUT_PIN);

    while (1)
    {
        setGPIO(OUT_PIN);
        clrGPIO(OUT_PIN);
    }
}

And I made the latest Raspbian-Lite (64bit) micro SD card using raspberry pi imager. Then replaced the kernel8.img.

I expected GPIO21 (40 for hardware) to generate spikes, but it didn't. I'm not even sure whether the boot sequence is done; I found this post on the forum. They say the kernel load address is changed to 0x200000.

Is this guide affected by that post? If not, I'll assume that the kernel.c contains problems.

babbleberry commented 1 year ago

Hi,

Thanks for your message. The kernel load address should still be 0x80000.

I suspect you have an issue with your kernel.c.

All the best, Adam

babbleberry commented 1 year ago

You intrigued me, so I had a play tonight!

I couldn't get your code to work, but I put this together... It does exactly what you expect yours to do and I've tested it (with a LED and a resistor).

It doesn't help me work out what's wrong with your code, but at least it proves it should work (and all this at load address 0x80000).

All the best and happy bug hunting! Adam

#define PERIPHERAL_BASE         0xFE000000

#define GPFSEL0                 PERIPHERAL_BASE + 0x200000
#define GPSET0                  PERIPHERAL_BASE + 0x20001C
#define GPCLR0                  PERIPHERAL_BASE + 0x200028

#define GPIO_FUNCTION_OUT       1
#define GPIO_MAX_PIN            53

void mmio_write(long reg, unsigned int val) { *(volatile unsigned int *)reg = val; }
unsigned int mmio_read(long reg) { return *(volatile unsigned int *)reg; }

unsigned int gpio_call(unsigned int pin_number, unsigned int value, unsigned int base, unsigned int field_size, unsigned int field_max) {
    unsigned int field_mask = (1 << field_size) - 1;

    if (pin_number > field_max) return 0;
    if (value > field_mask) return 0;

    unsigned int num_fields = 32 / field_size;
    unsigned int reg = base + ((pin_number / num_fields) * 4);
    unsigned int shift = (pin_number % num_fields) * field_size;

    unsigned int curval = mmio_read(reg);
    curval &= ~(field_mask << shift);
    curval |= value << shift;
    mmio_write(reg, curval);

    return 1;
}

unsigned int gpio_set(unsigned int pin_number, unsigned int value) { return gpio_call(pin_number, value, GPSET0, 1, GPIO_MAX_PIN); }
unsigned int gpio_clear(unsigned int pin_number, unsigned int value) { return gpio_call(pin_number, value, GPCLR0, 1, GPIO_MAX_PIN); }
unsigned int gpio_function(unsigned int pin_number, unsigned int value) { return gpio_call(pin_number, value, GPFSEL0, 3, GPIO_MAX_PIN); }

int main(void)
{
    gpio_function(21, GPIO_FUNCTION_OUT);

    while (1)
    {
        gpio_set(21, 1);
        gpio_clear(21, 1);
    }
}

led