summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author3gg <3gg@shellblade.net>2025-10-15 19:32:21 -0700
committer3gg <3gg@shellblade.net>2025-10-15 19:32:21 -0700
commit55bcdf37342d782c723166de54ff031d09b1281f (patch)
tree11a95bfb390ba6f73e122a17fe0a00312f25dc78
parentc099bcb7402421985e6e8c025e8cde591eaa073a (diff)
Clear framebuffer to pink
-rw-r--r--src/framebuffer.c84
-rw-r--r--src/framebuffer.h17
-rw-r--r--src/kernel.c23
-rw-r--r--src/mailbox.c19
-rw-r--r--src/mailbox.h2
-rw-r--r--src/string.c59
-rw-r--r--src/string.h9
-rw-r--r--src/uart.c1
8 files changed, 171 insertions, 43 deletions
diff --git a/src/framebuffer.c b/src/framebuffer.c
index c3845b1..6505ace 100644
--- a/src/framebuffer.c
+++ b/src/framebuffer.c
@@ -1,58 +1,74 @@
1#include <framebuffer.h> 1#include <framebuffer.h>
2 2
3#include <mailbox.h> 3#include <mailbox.h>
4#include <string.h>
4 5
5#include <stddef.h> 6#include <stddef.h>
6#include <stdint.h> 7#include <stdint.h>
7 8
8#define WIDTH 640 9#define WIDTH 640
9#define HEIGHT 480 10#define HEIGHT 480
10#define DEPTH 32 11#define DEPTH 24
11#define ALIGNMENT 16 // Framebuffer byte alignment. 12#define ALIGNMENT 16 // Framebuffer byte alignment.
12 13
13typedef struct Framebuffer {
14 volatile void* pixels;
15 size_t size;
16} Framebuffer;
17
18static Framebuffer framebuffer = {}; 14static Framebuffer framebuffer = {};
19 15
20bool framebuffer_init(uint32_t* error) { 16bool framebuffer_init(uint32_t* error) {
21 MAIL_T uint32_t ConfigureScreen[20] = { 17 // TODO: We can combine both messages, this one and the one below, into a
22 80, // Size in bytes, aligned to MAIL_ALIGN. 18 // single array and make a single call to mbox_write().
23 MAILBOX_REQUEST, 19 MAIL_T uint32_t InitFramebuffer[24] = {
24 TAG_FRAMEBUFFER_SET_PHYSICAL_SCREEN_SIZE, 8, MAILBOX_REQUEST, WIDTH, HEIGHT, 20 /*00*/96, // Size in bytes, aligned to MAIL_ALIGN.
25 TAG_FRAMEBUFFER_SET_VIRTUAL_SCREEN_SIZE, 8, MAILBOX_REQUEST, WIDTH, HEIGHT, 21 /*01*/MAILBOX_REQUEST,
26 TAG_FRAMEBUFFER_SET_DEPTH, 4, MAILBOX_REQUEST, DEPTH, 22 /*02*/TAG_FRAMEBUFFER_SET_PHYSICAL_SCREEN_SIZE, 8, MAILBOX_REQUEST, WIDTH, HEIGHT,
27 TAG_END, 23 /*07*/TAG_FRAMEBUFFER_SET_VIRTUAL_SCREEN_SIZE, 8, MAILBOX_REQUEST, WIDTH, HEIGHT,
28 0, 0, 0 // Padding. 24 /*12*/TAG_FRAMEBUFFER_SET_DEPTH, 4, MAILBOX_REQUEST, DEPTH,
29 }; 25 /*16*/TAG_FRAMEBUFFER_ALLOCATE, 8, MAILBOX_REQUEST, ALIGNMENT, 0,
30 mbox_write(PROPERTY_CHANNEL, ConfigureScreen); 26 /*21*/TAG_END,
31 const Mail* response = mbox_read(PROPERTY_CHANNEL); 27 /*22*/0, 0 // Padding.
32 if (response->code != MAILBOX_SUCCESS) {
33 goto end;
34 }
35
36 MAIL_T uint32_t InitFramebuffer[8] = {
37 32, // Size in bytes, aligned to MAIL_ALIGN.
38 MAILBOX_REQUEST,
39 TAG_FRAMEBUFFER_ALLOCATE, 8, MAILBOX_REQUEST, ALIGNMENT, 0,
40 TAG_END
41 }; 28 };
42 mbox_write(PROPERTY_CHANNEL, InitFramebuffer); 29 const uint32_t result = mbox_write(PROPERTY_CHANNEL, InitFramebuffer);
43 response = mbox_read(PROPERTY_CHANNEL); 30 if (result != MAILBOX_SUCCESS) {
44 if (response->code != MAILBOX_SUCCESS) {
45 goto end; 31 goto end;
46 } 32 }
47 33
48 // The input mail is overwritten with the response. 34 // The input mail is overwritten with the response.
35 //
36 // TAG_FRAMEBUFFER_ALLOCATE response:
49 // u32 fb base address 37 // u32 fb base address
50 // u32 fb size 38 // u32 fb size
51 framebuffer.pixels = (void*)(uintptr_t)InitFramebuffer[5]; 39 // TODO: Do we need & 0x3FFFFFFF? Something about converting GPU address space
52 framebuffer.size = InitFramebuffer[6]; 40 // to ARM address space.
53 41 // TODO: Should we read back the pitch, or does pitch match width?
42 framebuffer = (Framebuffer) {
43 .pixels = (Pixel*)((uintptr_t)InitFramebuffer[19] & 0x3FFFFFFF),
44 .size = InitFramebuffer[20],
45 .width = InitFramebuffer[5],
46 .height = InitFramebuffer[6],
47 .depth = InitFramebuffer[15]
48 };
49
54end: 50end:
55 *error = response->code; 51 *error = result;
56 return response->code == MAILBOX_SUCCESS; 52 return result == MAILBOX_SUCCESS;
53}
54
55const Framebuffer* framebuffer_get() {
56 return &framebuffer;
57}
58
59void framebuffer_present(const Pixel* pixels) {
60 memcpy(framebuffer.pixels, pixels, framebuffer.size);
61}
62
63void framebuffer_clear(Pixel colour) {
64 const uint32_t num_channels = framebuffer.depth / 8;
65 const uint32_t num_pixels = framebuffer.size / num_channels;
66 volatile Pixel* fb = framebuffer.pixels;
67 for (size_t i = 0; i < num_pixels; i++) {
68 fb->r = colour.r;
69 fb->g = colour.g;
70 fb->b = colour.b;
71 fb++;
72 }
57} 73}
58 74
diff --git a/src/framebuffer.h b/src/framebuffer.h
index d2d57cd..b44fa44 100644
--- a/src/framebuffer.h
+++ b/src/framebuffer.h
@@ -3,5 +3,22 @@
3#include <stdbool.h> 3#include <stdbool.h>
4#include <stdint.h> 4#include <stdint.h>
5 5
6typedef uint8_t Channel;
7
8typedef struct Pixel {
9 Channel r, g, b;
10} Pixel;
11
12typedef struct Framebuffer {
13 Pixel* pixels;
14 uint32_t size;
15 uint32_t width;
16 uint32_t height;
17 uint32_t depth;
18} Framebuffer;
19
6bool framebuffer_init(uint32_t* error); 20bool framebuffer_init(uint32_t* error);
21const Framebuffer* framebuffer_get();
22void framebuffer_present(const Pixel* pixels);
23void framebuffer_clear(Pixel colour);
7 24
diff --git a/src/kernel.c b/src/kernel.c
index 151028d..2a4005a 100644
--- a/src/kernel.c
+++ b/src/kernel.c
@@ -2,8 +2,11 @@
2#include <mailbox.h> 2#include <mailbox.h>
3#include <mmio.h> 3#include <mmio.h>
4#include <raspi.h> 4#include <raspi.h>
5#include <string.h>
5#include <uart.h> 6#include <uart.h>
6 7
8#include <stdint.h>
9
7static void halt() { 10static void halt() {
8 while (1) { 11 while (1) {
9 asm volatile("wfi"); // Wait for interrupt. Core enters low-power state. 12 asm volatile("wfi"); // Wait for interrupt. Core enters low-power state.
@@ -13,6 +16,7 @@ static void halt() {
13void main() { 16void main() {
14 bool success = true; 17 bool success = true;
15 uint32_t error = -1; 18 uint32_t error = -1;
19 char buf[32];
16 20
17 const int raspi = raspi_init(); 21 const int raspi = raspi_init();
18 mmio_init(raspi); // Must be initialized before other peripherals. 22 mmio_init(raspi); // Must be initialized before other peripherals.
@@ -31,7 +35,24 @@ void main() {
31 goto end; 35 goto end;
32 } 36 }
33 37
34 uart_print("Hello world!\n"); 38 const Framebuffer* fb = framebuffer_get();
39 uart_print("Framebuffer:");
40 uart_print("\n width: ");
41 uart_print(utoa(fb->width, buf, sizeof(buf)));
42 uart_print("\n height: ");
43 uart_print(utoa(fb->height, buf, sizeof(buf)));
44 uart_print("\n depth: ");
45 uart_print(utoa(fb->depth, buf, sizeof(buf)));
46 uart_print("\n addr: ");
47 uart_print(ptoa(fb->pixels, buf, sizeof(buf)));
48 uart_print("\n size: ");
49 uart_print(utoa(fb->size, buf, sizeof(buf)));
50 uart_print("\n");
51
52 uart_print("Clearing framebuffer\n");
53 framebuffer_clear((Pixel){255, 0, 255});
54
55 uart_print("All done\n");
35 56
36end: 57end:
37 halt(); 58 halt();
diff --git a/src/mailbox.c b/src/mailbox.c
index 310b2b1..fcad179 100644
--- a/src/mailbox.c
+++ b/src/mailbox.c
@@ -7,7 +7,9 @@
7 7
8enum 8enum
9{ 9{
10 MAILBOX = 0xB880 // Mailbox address relative to MMIO base address. 10 MAILBOX = 0xB880, // Mailbox address relative to MMIO base address.
11 STATUS_EMPTY = 0x40000000, // Empty bit.
12 STATUS_FULL = 0x80000000, // Full bit.
11}; 13};
12 14
13typedef uint32_t Message; 15typedef uint32_t Message;
@@ -21,7 +23,7 @@ static inline Message msg_make(uint8_t channel, volatile const void* data) {
21} 23}
22 24
23typedef struct Mailbox { 25typedef struct Mailbox {
24 Message inbox; // 0x00 26 Message inbox; // 0x00
25 uint32_t unused_1; // 0x04 27 uint32_t unused_1; // 0x04
26 uint32_t unused_2; // 0x08 28 uint32_t unused_2; // 0x08
27 uint32_t unused_3; // 0x0C 29 uint32_t unused_3; // 0x0C
@@ -29,15 +31,15 @@ typedef struct Mailbox {
29 uint32_t unused_5; // 0x14 31 uint32_t unused_5; // 0x14
30 uint32_t status; // 0x18 32 uint32_t status; // 0x18
31 uint32_t unused_6; // 0x1C 33 uint32_t unused_6; // 0x1C
32 Message outbox; // 0x20 34 Message outbox; // 0x20
33} Mailbox; 35} Mailbox;
34 36
35static inline bool inbox_empty(const volatile Mailbox* pMailbox) { 37static inline bool inbox_empty(const volatile Mailbox* pMailbox) {
36 return (pMailbox->status & 0x40000000) != 0; 38 return (pMailbox->status & STATUS_EMPTY) != 0;
37} 39}
38 40
39static inline bool outbox_full(const volatile Mailbox* pMailbox) { 41static inline bool outbox_full(const volatile Mailbox* pMailbox) {
40 return (pMailbox->status & 0x80000000) != 0; 42 return (pMailbox->status & STATUS_FULL) != 0;
41} 43}
42 44
43static volatile Mailbox* pMailbox; 45static volatile Mailbox* pMailbox;
@@ -59,10 +61,15 @@ const Mail* mbox_read(uint8_t channel) {
59 return (const Mail*)((uintptr_t)msg & ~0xf); 61 return (const Mail*)((uintptr_t)msg & ~0xf);
60} 62}
61 63
62void mbox_write(uint8_t channel, volatile const void* mail) { 64uint32_t mbox_write(uint8_t channel, volatile const void* mail) {
63 // Wait until the outbox is clear. 65 // Wait until the outbox is clear.
64 while (outbox_full(pMailbox)); 66 while (outbox_full(pMailbox));
65 // Send the mail. 67 // Send the mail.
66 pMailbox->outbox = msg_make(channel, mail); 68 pMailbox->outbox = msg_make(channel, mail);
69 // Wait for the response.
70 // Mailbox messages cannot be streamed anyway, so wait here so that the API
71 // does not allow the caller to write two messages in a row without waiting.
72 const Mail* response = mbox_read(channel);
73 return response->code;
67} 74}
68 75
diff --git a/src/mailbox.h b/src/mailbox.h
index 2104265..dbd7be0 100644
--- a/src/mailbox.h
+++ b/src/mailbox.h
@@ -66,5 +66,5 @@ typedef struct __attribute__((aligned(MAIL_ALIGN))) Mail {
66 66
67void mbox_init(); 67void mbox_init();
68const Mail* mbox_read(uint8_t channel); 68const Mail* mbox_read(uint8_t channel);
69void mbox_write(uint8_t channel, volatile const void* mail); 69uint32_t mbox_write(uint8_t channel, volatile const void* mail);
70 70
diff --git a/src/string.c b/src/string.c
new file mode 100644
index 0000000..4801154
--- /dev/null
+++ b/src/string.c
@@ -0,0 +1,59 @@
1#include <string.h>
2
3#include <stdint.h>
4
5void* memcpy(void* dst, const void* src, size_t count) {
6 // TODO: Can probably use better implementations based on hw instruction set.
7 uint32_t* dst32 = (uint32_t*)dst;
8 const uint32_t* src32 = (uint32_t*)src;
9 for(; count >= 4; count -= 4) {
10 *dst32++ = *src32++;
11 }
12 uint8_t* dst8 = (uint8_t*)dst32;
13 const uint8_t* src8 = (uint8_t*)src32;
14 for(; count != 0; count--) {
15 *dst8++ = *src8++;
16 }
17 return dst8;
18}
19
20static int count_digits_u(unsigned int x) {
21 int count = 0;
22 for(; x != 0; x /= 10, count++);
23 return count;
24}
25
26char* utoa(unsigned int x, char* buffer, size_t size) {
27 if (size > 0) {
28 const int num_digits = count_digits_u(x);
29 size_t i = 0;
30 while ((x != 0) && ((i+1) < size)) {
31 const unsigned int digit = x % 10;
32 x /= 10;
33 buffer[num_digits-1 - i++] = '0' + digit;
34 }
35 buffer[i] = 0;
36 }
37 return buffer;
38}
39
40char* ptoa(const void* ptr, char* buffer, size_t size) {
41 if (size > 2) {
42 size_t i = 0;
43 buffer[i++] = '0';
44 buffer[i++] = 'x';
45 uintptr_t x = (uintptr_t)ptr;
46 const int num_digits = count_digits_u(x);
47 while ((x != 0) && (i < size)) {
48 const unsigned int digit = x % 16;
49 x /= 16;
50 const char hex = (digit < 10) ? ('0' + digit) : ('a' + (digit-10));
51 buffer[num_digits-1+2 - i++] = hex;
52 }
53 buffer[i] = 0;
54 } else if (size > 0) {
55 buffer[0] = 0;
56 }
57 return buffer;
58}
59
diff --git a/src/string.h b/src/string.h
new file mode 100644
index 0000000..3f0e200
--- /dev/null
+++ b/src/string.h
@@ -0,0 +1,9 @@
1#pragma once
2
3#include <stddef.h>
4
5void* memcpy(void* dest, const void* src, size_t count);
6
7char* utoa(unsigned int x, char* buffer, size_t size);
8char* ptoa(const void* ptr, char* buffer, size_t size);
9
diff --git a/src/uart.c b/src/uart.c
index f8be797..0a2684b 100644
--- a/src/uart.c
+++ b/src/uart.c
@@ -75,7 +75,6 @@ void uart_init(int raspi) {
75 if (raspi >= 3) { 75 if (raspi >= 3) {
76 // Send message over property channel to configure UART clock. 76 // Send message over property channel to configure UART clock.
77 mbox_write(PROPERTY_CHANNEL, UART_SET_CLK); 77 mbox_write(PROPERTY_CHANNEL, UART_SET_CLK);
78 mbox_read(PROPERTY_CHANNEL);
79 } 78 }
80 79
81 // Divider = 3000000 / (16 * 115200) = 1.627 = ~1. 80 // Divider = 3000000 / (16 * 115200) = 1.627 = ~1.