Files
Deshab-OS/CODE/DKM/console_fb/console_fb.c
T
xyou f1a2a110d7 Record networking and DMA development progress
Add the current OS source tree, build scripts, system image layout, and development notes covering DMA page allocation, e1000 bring-up, net API dispatch, and DHCP work in progress.
2026-07-02 16:17:09 +08:00

260 lines
8.7 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* DKM Console Framebuffer Driver
* Stage 1, optional, provides "console".
* Light-blue background + centered circular loading animation (4-color arc ring).
*/
#include <stdint.h>
/* ---------------------------------------------------------------
* DKM ABI types
* --------------------------------------------------------------- */
#define DKM_DRIVER_MAGIC 0x444B4D31u
#define DKM_ABI_VERSION 1u
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
typedef unsigned long long u64;
typedef long long i64;
#define NULL ((void *)0)
struct dkm_log_api {
void (*info)(const char *msg);
void (*warn)(const char *msg);
void (*error)(const char *msg);
void (*panic)(const char *msg);
};
struct dkm_kernel_api {
u32 version; u32 size; u64 feature_bits;
const struct dkm_log_api *log;
const void *mem, *utsm, *irq, *pci_api, *dma, *vfs, *net, *timer, *drr;
const void *rsdp_address, *fb_address;
u64 fb_width, fb_height, fb_pitch; u16 fbpp;
};
struct dkm_driver_handle;
struct dkm_driver_desc {
u32 magic; u16 abi_version; u16 desc_size;
const char *name, *version, *vendor;
u32 driver_class, stage, flags, priority;
const char *const *depends; u32 depends_count;
const char *const *provides; u32 provides_count;
u64 min_kernel_abi, feature_bits, reserved0, reserved1;
};
static const char *const g_provides[] = { "console" };
__attribute__((visibility("default"), used))
const struct dkm_driver_desc driver_desc = {
.magic=DKM_DRIVER_MAGIC, .abi_version=DKM_ABI_VERSION,
.desc_size=sizeof(struct dkm_driver_desc),
.name="console_fb", .version="0.2.0", .vendor="Deshab",
.driver_class=5, .stage=1, .flags=0, .priority=0,
.depends=NULL, .depends_count=0,
.provides=g_provides, .provides_count=1,
.min_kernel_abi=1,
};
/* ---------------------------------------------------------------
* Colors
* --------------------------------------------------------------- */
static const u32 BG = 0xFFC8E0F0; /* light blue background */
static const u32 ARC[4] = { 0xFF4488CC, 0xFF2266AA, 0xFF66AAEE, 0xFF88CCFF };
/* ---------------------------------------------------------------
* Drawing helpers – all integer arithmetic, no soft-float
* --------------------------------------------------------------- */
static u64 fb_w, fb_h, fb_p;
/* double-buffer sprite for ring area (128×128 = no flicker) */
#define SPR_SIZE 128
static u32 g_sprite[SPR_SIZE * SPR_SIZE];
static void fb_fill(u32 *fb, u64 pitch, u64 w, u64 h, u32 color) {
for (u64 y = 0; y < h; y++) {
u32 *line = (u32 *)((u8 *)fb + y * pitch);
for (u64 x = 0; x < w; x++) line[x] = color;
}
}
/* alpha-blend c2 over c1, alpha 0-255 */
static u32 blend(u32 c1, u32 c2, u32 a) {
u32 na = 256 - a;
u32 r = ((c1 & 0xFF) * na + (c2 & 0xFF) * a) >> 8;
u32 g = (((c1 >> 8) & 0xFF) * na + ((c2 >> 8) & 0xFF) * a) >> 8;
u32 b = (((c1 >> 16) & 0xFF) * na + ((c2 >> 16) & 0xFF) * a) >> 8;
return 0xFF000000 | (b << 16) | (g << 8) | r;
}
/* integer sqrt – returns floor(sqrt(v)) */
static u64 isqrt(u64 v) {
u64 x = v, y = (x + 1) >> 1;
while (y < x) { x = y; y = (y + v / y) >> 1; }
return x;
}
/* approximate atan2 in degrees (0=right, CCW). dx,dy = pixel offset from center */
static i64 approx_angle(i64 dx, i64 dy) {
if (dx == 0) return dy < 0 ? 90 : 270;
i64 ax = dx < 0 ? -dx : dx;
i64 ay = dy < 0 ? -dy : dy;
i64 a;
if (ax > ay) {
a = ay * 45 / ax;
} else {
a = 90 - ax * 45 / (ay ? ay : 1);
}
/* quadrant correction */
if (dx >= 0 && dy <= 0) return a; /* Q1 */
else if (dx < 0 && dy <= 0) return 180 - a; /* Q2 */
else if (dx < 0 && dy > 0) return 180 + a; /* Q3 */
else return 360 - a; /* Q4 */
}
/* draw one arc segment: rounded caps (6° head/tail), bright mid, comet-tail fade */
static void arc_segment(u32 *fb, i64 cx, i64 cy, i64 r, i64 start, i64 sweep, u32 color, i64 thk) {
i64 ro = r + thk, ri = r - thk;
i64 ri2 = ri * ri, ro2 = (ro + 1) * (ro + 1);
i64 rnd = 6; /* rounding zone at each end, in degrees */
for (i64 dy = -ro - 1; dy <= ro + 1; dy++) {
i64 y = cy + dy;
if ((u64)y >= fb_h) continue;
u32 *line = (u32 *)((u8 *)fb + (u64)y * fb_p);
for (i64 dx = -ro - 1; dx <= ro + 1; dx++) {
i64 x = cx + dx;
if ((u64)x >= fb_w) continue;
i64 d2 = dx * dx + dy * dy;
if (d2 < ri2 - 2 || d2 > ro2 + 2) continue;
i64 ang = approx_angle(dx, dy);
i64 a = ang - start;
if (a < 0) a += 360;
if ((u64)a > (u64)sweep) continue;
/* rounded-cap fade: 0→255 over rnd°, then 255→0 over last rnd° */
u32 fade;
if ((u64)a < (u64)rnd) {
fade = (u32)(a * 255 / rnd);
} else if ((u64)a > (u64)(sweep - rnd)) {
fade = (u32)((sweep - a) * 255 / rnd);
} else {
fade = 255;
}
i64 dist = (i64)isqrt((u64)d2);
u32 effective = blend(BG, color, fade);
if (dist >= ri && dist <= ro) {
line[(u64)x] = effective;
} else if (dist >= ri - 2 && dist < ri) {
line[(u64)x] = blend(BG, effective, (u32)((dist - (ri - 2)) * 85));
} else if (dist > ro && dist <= ro + 2) {
line[(u64)x] = blend(effective, BG, (u32)((dist - ro) * 85));
}
}
}
}
/* filled disc with anti-aliased edge */
static void fill_disc(u32 *fb, i64 cx, i64 cy, i64 r, u32 color) {
i64 r2 = r * r, o2 = (r + 1) * (r + 1);
for (i64 dy = -r - 2; dy <= r + 2; dy++) {
i64 y = cy + dy;
if ((u64)y >= fb_h) continue;
u32 *line = (u32 *)((u8 *)fb + (u64)y * fb_p);
for (i64 dx = -r - 2; dx <= r + 2; dx++) {
i64 x = cx + dx;
if ((u64)x >= fb_w) continue;
i64 d2 = dx * dx + dy * dy;
if (d2 <= r2) {
line[(u64)x] = color;
} else if (d2 <= o2) {
u32 a = (u32)((o2 - d2) * 255 / (o2 - r2));
line[(u64)x] = blend(BG, color, a);
}
}
}
}
/* ---------------------------------------------------------------
* Driver entry
* --------------------------------------------------------------- */
__attribute__((visibility("default")))
int driver_init(const struct dkm_kernel_api *api,
struct dkm_driver_handle *handle) {
(void)handle;
if (!api || !api->log) return -1;
if (!api->fb_address || !api->fb_width) {
api->log->warn("[console_fb] no framebuffer");
return 0;
}
api->log->info("[console_fb] boot screen");
fb_w = api->fb_width; fb_h = api->fb_height; fb_p = api->fb_pitch;
u32 *fb = (u32 *)api->fb_address;
i64 cx = (i64)fb_w / 2, cy = (i64)fb_h / 2, r = 48, thk = 4;
/* light-blue background */
fb_fill(fb, fb_p, fb_w, fb_h, BG);
/* animation: 2000 frames × 2° clockwise × ~1ms, no flicker */
i64 spr_p = SPR_SIZE * 4;
i64 scx = SPR_SIZE / 2;
i64 scy = SPR_SIZE / 2;
i64 frame = 0, base = 0;
i64 bx = cx - scx; /* screen position of sprite top-left */
i64 by = cy - scy;
while (frame < 2000) {
/* draw into sprite buffer — swap globals to sprite layout */
u64 save_w = fb_w, save_h = fb_h, save_p = fb_p;
fb_w = SPR_SIZE; fb_h = SPR_SIZE; fb_p = spr_p;
fb_fill(g_sprite, spr_p, SPR_SIZE, SPR_SIZE, BG);
arc_segment(g_sprite, scx, scy, r, base + 0, 82, ARC[0], thk);
arc_segment(g_sprite, scx, scy, r, base + 90, 82, ARC[1], thk);
arc_segment(g_sprite, scx, scy, r, base +180, 82, ARC[2], thk);
arc_segment(g_sprite, scx, scy, r, base +270, 82, ARC[3], thk);
fill_disc(g_sprite, scx, scy, r - 8, blend(BG, 0xFFD0F0FF, 80));
/* restore screen globals for blit */
fb_w = save_w; fb_h = save_h; fb_p = save_p;
/* blit sprite to screen */
for (i64 sr = 0; sr < SPR_SIZE; sr++) {
i64 sy = by + sr;
if ((u64)sy >= fb_h) continue;
u32 *dst = (u32 *)((u8 *)fb + (u64)sy * fb_p) + bx;
u32 *src = &g_sprite[sr * SPR_SIZE];
for (i64 sc = 0; sc < SPR_SIZE; sc++) {
i64 sx = bx + sc;
if ((u64)sx >= fb_w) continue;
dst[sc] = src[sc];
}
}
for (volatile u32 d = 0; d < 72000; d++) {
__asm__ volatile ("pause");
}
base -= 2;
if (base < 0) base += 360;
frame++;
}
api->log->info("[console_fb] ready");
return 0;
}
__attribute__((visibility("default")))
int driver_exit(struct dkm_driver_handle *handle) {
(void)handle;
return 0;
}