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.
260 lines
8.7 KiB
C
260 lines
8.7 KiB
C
/* 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;
|
||
}
|