From a8b800d1691263aa73054449b1721c1ec9516496 Mon Sep 17 00:00:00 2001 From: Minep Date: Tue, 24 Oct 2023 15:15:59 +0100 Subject: [PATCH] feat: gfxm: a layer provides user space access to low level interfacing of graphic adapter chore: clear things up --- lunaix-os/.gitignore | 2 + lunaix-os/hal/ahci/ahci.c | 4 +- lunaix-os/hal/gfxa/gfxm.c | 150 +++++++++++++++++++++++++ lunaix-os/hal/gfxa/vga/vga.c | 46 ++++---- lunaix-os/hal/gfxa/vga/vga.h | 14 +-- lunaix-os/hal/gfxa/vga/vga_gfxm_ops.c | 71 ++++++++++++ lunaix-os/hal/gfxa/vga/vga_mmio_ops.c | 8 +- lunaix-os/hal/gfxa/vga/vga_pci.c | 22 ++-- lunaix-os/hal/pci.c | 16 +++ lunaix-os/includes/hal/gfxm.h | 74 ++++++++++++ lunaix-os/includes/hal/pci.h | 7 ++ lunaix-os/includes/lunaix/device_num.h | 3 +- lunaix-os/includes/usr/lunaix/gfx.h | 44 ++++++++ 13 files changed, 417 insertions(+), 44 deletions(-) create mode 100644 lunaix-os/hal/gfxa/gfxm.c create mode 100644 lunaix-os/hal/gfxa/vga/vga_gfxm_ops.c create mode 100644 lunaix-os/includes/hal/gfxm.h create mode 100644 lunaix-os/includes/usr/lunaix/gfx.h diff --git a/lunaix-os/.gitignore b/lunaix-os/.gitignore index b48c604..31f081b 100644 --- a/lunaix-os/.gitignore +++ b/lunaix-os/.gitignore @@ -10,5 +10,7 @@ draft/ iso_inspect/ unused/ +.gdb_history + **.o **.d \ No newline at end of file diff --git a/lunaix-os/hal/ahci/ahci.c b/lunaix-os/hal/ahci/ahci.c index 8794bab..2aa37e5 100644 --- a/lunaix-os/hal/ahci/ahci.c +++ b/lunaix-os/hal/ahci/ahci.c @@ -444,9 +444,9 @@ achi_register_ops(struct hba_port* port) static struct pci_device_def ahcidef = { .dev_class = AHCI_HBA_CLASS, - .ident_mask = 0x0, + .ident_mask = PCI_MATCH_ANY, .devdef = { .class = DEVCLASS(DEVIF_PCI, DEVFN_STORAGE, DEV_SATA), .name = "Serial ATA Controller", .init_for = ahci_driver_init } }; -EXPORT_DEVICE(ahci, &ahcidef.devdef, load_pci_probe); \ No newline at end of file +EXPORT_PCI_DEVICE(ahci, &ahcidef); \ No newline at end of file diff --git a/lunaix-os/hal/gfxa/gfxm.c b/lunaix-os/hal/gfxa/gfxm.c new file mode 100644 index 0000000..26532a2 --- /dev/null +++ b/lunaix-os/hal/gfxa/gfxm.c @@ -0,0 +1,150 @@ +#include +#include +#include +#include + +#include + +#include + +DEFINE_LLIST(gfxa_flat); +DECLARE_HASHTABLE(gfxa_idset, 8); + +struct device* gfxa_devcat = NULL; +static int id = 0; + +static struct devclass gfxa_class = DEVCLASS(DEV_BUILTIN, DEVFN_DISP, DEV_GFXA); + +static int +__gfxa_cmd_router(struct device* dev, u32_t req, va_list args) +{ + struct gfxa* gfxa = (struct gfxa*)dev->underlay; + struct disp_profile* disp = &gfxa->disp_info; + + switch (req) { + case GFX_ADAPTER_INFO: { + struct gfxa_info* info = va_arg(args, struct gfxa_info*); + *info = + (struct gfxa_info){ .disp_mode = { .w_px = disp->mon.w_px, + .h_px = disp->mon.h_px, + .freq = disp->mon.freq, + .depth = disp->mon.depth } }; + gfxa->ops.hwioctl(gfxa, req, args); + break; + }; + case GFX_ADAPTER_CHMODE: { + struct gfxa_mon* mon_info = va_arg(args, struct gfxa_mon*); + gfxa->disp_info.mon = *mon_info; + + return gfxa->ops.update_profile(gfxa); + }; + case GFX_ADAPTER_VMCPY: + case GFX_ADAPTER_LFBCPY: { + void* buf = va_arg(args, void*); + off_t off = va_arg(args, off_t); + size_t len = va_arg(args, size_t); + if (req == GFX_ADAPTER_VMCPY) { + return gfxa->ops.vmcpy(gfxa, buf, off, len); + } + return gfxa->ops.lfbcpy(gfxa, buf, off, len); + }; + case GFX_ADAPTER_REG_WR: + case GFX_ADAPTER_REG_RD: { + u32_t* reg_addrmap = va_arg(args, u32_t*); + void* reg_val = va_arg(args, void*); + size_t reg_count = va_arg(args, size_t); + + if (req == GFX_ADAPTER_LUT_RD) { + return gfxa->ops.rreads(gfxa, reg_addrmap, reg_val, reg_count); + } + return gfxa->ops.rwrites(gfxa, reg_addrmap, reg_val, reg_count); + }; + case GFX_ADAPTER_LUT_RD: { + struct gfxa_clut* clut = va_arg(args, struct gfxa_clut*); + if (!clut->val || !clut->len) { + return disp->clut.len; + } + + size_t clut_len = MIN(clut->len, disp->clut.len); + memcpy(clut->val, disp->clut.val, clut_len * sizeof(color_t)); + return clut_len; + }; + case GFX_ADAPTER_LUT_WR: { + struct gfxa_clut* clut = va_arg(args, struct gfxa_clut*); + int err = gfxm_set_lut(gfxa, clut->val, clut->len); + if (!err) { + err = gfxa->ops.update_profile(gfxa); + } + return err; + }; + default: + return gfxa->ops.hwioctl(gfxa, req, args); + } + + return 0; +} + +struct gfxa* +gfxm_alloc_adapter(void* hw_obj) +{ + if (unlikely(!gfxa_devcat)) { + gfxa_devcat = device_addcat(NULL, "gfx"); + } + + struct gfxa* gfxa = valloc(sizeof(struct gfxa)); + struct device* gfxa_dev = device_allocsys(gfxa_devcat, gfxa); + + *gfxa = (struct gfxa){ .dev = gfxa_dev, .hw_obj = hw_obj }; + + gfxa_dev->ops.exec_cmd = __gfxa_cmd_router; + + return gfxa; +} + +void +gfxm_register(struct gfxa* gfxa) +{ + gfxa->id = gfxa_class.variant++; + + llist_append(&gfxa_flat, &gfxa->gfxas); + hashtable_hash_in(gfxa_idset, &gfxa->gfxas_id, gfxa->id); + + device_register(gfxa->dev, &gfxa_class, "gfxa%d", gfxa->id); +} + +struct gfxa* +gfxm_adapter(int gfxa_id) +{ + struct gfxa *pos, *n; + hashtable_hash_foreach(gfxa_idset, gfxa_id, pos, n, gfxas_id) + { + if (pos->id == gfxa_id) { + return pos; + } + } + + return NULL; +} + +int +gfxm_set_lut(struct gfxa* gfxa, u32_t* lut, size_t len) +{ + // It is generally not feasible for graphic adapter with >256 colors still + // using color lut + if (unlikely(len > 256)) { + return EINVAL; + } + + struct disp_profile* disp = &gfxa->disp_info; + size_t lutsz = len * sizeof(*lut); + + if (disp->clut.len != len) { + vfree_safe(disp->clut.val); + disp->clut.val = valloc(lutsz); + disp->clut.len = len; + } + + memcpy(disp->clut.val, lut, lutsz); + + return 0; +} \ No newline at end of file diff --git a/lunaix-os/hal/gfxa/vga/vga.c b/lunaix-os/hal/gfxa/vga/vga.c index 08bc54b..020e00c 100644 --- a/lunaix-os/hal/gfxa/vga/vga.c +++ b/lunaix-os/hal/gfxa/vga/vga.c @@ -13,6 +13,7 @@ #include #include #include +#include #include @@ -119,7 +120,7 @@ vga_crt_update(struct vga* state) // framebuffer: 16bit granule u32_t divsor = 2 * 2; - if (state->lut.len == 256) { + if (state->crt.depth == 256) { // if 8 bit color is used, 2 pixels per granule divsor *= 2; } else if ((state->options & VGA_MODE_GFX)) { @@ -135,32 +136,35 @@ vga_crt_update(struct vga* state) } void -vga_update_palette(struct vga* state) +vga_update_palette(struct vga* state, u32_t* lut, size_t len) { - state->reg_ops.set_dac_palette(state); - u32_t index[16]; - u32_t clr_len = MIN(state->lut.len, 16); + u32_t clr_len = MIN(len, 16); for (size_t i = 0; i < clr_len; i++) { index[i] = i; } + state->reg_ops.set_dac_palette(state, lut, len); state->reg_ops.set_seq(state, VGA_ARX, 0, index, clr_len); } -void +int vga_reload_config(struct vga* state) { cpu_disable_interrupt(); + int err = 0; struct vga_regops* reg = &state->reg_ops; - u32_t color = state->lut.len; - assert_msg((color == 2 || color == 4 || color == 16 || color == 256), - "invalid color depth"); + u32_t color = state->crt.depth; + if (!(color == 2 || color == 4 || color == 16 || color == 256)) { + err = EINVAL; + goto done; + } - if (!(state->options & VGA_MODE_GFX)) { - assert(color < 256); + if (!(state->options & VGA_MODE_GFX) && color > 256) { + err = EINVAL; + goto done; } // estimate actual fb size @@ -173,17 +177,20 @@ vga_reload_config(struct vga* state) total_px = total_px * 2; } - assert(state->fb_sz >= total_px); - state->fb_sz = total_px; + if (state->fb_sz && state->fb_sz < total_px) { + err = EINVAL; + } - reg->write(state, VGA_SRX, VGA_SR00, 0x0, ALL_FIELDS); + state->fb_sz = total_px; // RAM Enable, I/OAS u32_t clk_f = state->crt.h_cclk * state->crt.v_cclk * state->crt.freq; u32_t misc = 0b11; clk_f = (clk_f * dpc_sq) / 1000000; - assert(clk_f && clk_f <= 28); + if (!(clk_f && clk_f <= 28)) { + err = EINVAL; + } // require 28 MHz clock if (clk_f > 25) { @@ -191,6 +198,7 @@ vga_reload_config(struct vga* state) } // 25 MHz clock: 0b00 << 2 + reg->write(state, VGA_SRX, VGA_SR00, 0x0, ALL_FIELDS); reg->write(state, VGA_MISCX, 0, misc, 0b1111); // SEQN_CLK: shift every CCLK, DCLK passthrough, 8/9 DCLK @@ -219,8 +227,8 @@ vga_reload_config(struct vga* state) reg->write( state, VGA_GRX, VGA_GR05, (c256 << 6) | (1 << 4), ALL_FIELDS); - // Legacy GFX FB: 0xA000, GFX mode - reg->write(state, VGA_GRX, VGA_GR06, 0b0011, ALL_FIELDS); + // Legacy GFX FB (for compatibility): 0xb8000, GFX mode + reg->write(state, VGA_GRX, VGA_GR06, 0b1111, ALL_FIELDS); } else { // AN MOODE // Only map 0,1 enabled, (ascii and attribute) @@ -252,9 +260,9 @@ vga_reload_config(struct vga* state) reg->write(state, VGA_ARX, VGA_AR13, 0, ALL_FIELDS); reg->write(state, VGA_ARX, VGA_AR14, 0, ALL_FIELDS); - vga_update_palette(state); - reg->write(state, VGA_SRX, VGA_SR00, 0x3, ALL_FIELDS); +done: cpu_enable_interrupt(); + return err; } diff --git a/lunaix-os/hal/gfxa/vga/vga.h b/lunaix-os/hal/gfxa/vga/vga.h index 86afe4e..cd4a1b0 100644 --- a/lunaix-os/hal/gfxa/vga/vga.h +++ b/lunaix-os/hal/gfxa/vga/vga.h @@ -176,7 +176,7 @@ struct vga_regops void (*write)(struct vga*, u32_t type, u32_t index, u32_t val, u32_t mask); void ( *set_seq)(struct vga*, u32_t type, size_t off, u32_t* seq, size_t len); - void (*set_dac_palette)(struct vga*); + void (*set_dac_palette)(struct vga*, u32_t*, size_t); }; struct vga @@ -193,14 +193,9 @@ struct vga size_t pel_dot; // pixel per dot clock size_t freq; size_t fb_off; + size_t depth; } crt; - struct - { - u32_t* colors; - u32_t len; - } lut; - struct vga_regops reg_ops; }; @@ -226,7 +221,10 @@ vga_new_state(ptr_t reg_base, ptr_t fb, ptr_t fb_sz); void vga_config_rect(struct vga*, size_t width, size_t hight, size_t freq, int d9); -void +int vga_reload_config(struct vga*); +void +vga_update_palette(struct vga* state, u32_t* lut, size_t len); + #endif /* __LUNAIX_VGA_H */ diff --git a/lunaix-os/hal/gfxa/vga/vga_gfxm_ops.c b/lunaix-os/hal/gfxa/vga/vga_gfxm_ops.c new file mode 100644 index 0000000..0813da3 --- /dev/null +++ b/lunaix-os/hal/gfxa/vga/vga_gfxm_ops.c @@ -0,0 +1,71 @@ +#include "vga.h" +#include +#include + +static int +__vga_gfxa_update_profile(struct gfxa* gfxa) +{ + struct vga* v = (struct vga*)gfxa->hw_obj; + struct disp_profile* profile = &gfxa->disp_info; + + v->crt.depth = profile->mon.depth; + v->options = VGA_MODE_GFX; + + vga_config_rect( + v, profile->mon.w_px, profile->mon.h_px, profile->mon.freq, 0); + + int err = vga_reload_config(v); + + if (!err && profile->clut.val) { + vga_update_palette(v, profile->clut.val, profile->clut.len); + } + + return err; +} + +static int +__vga_gfxa_rreads(struct gfxa* gfxa, u32_t* map, void* rxbuf, size_t map_sz) +{ + return 0; +} + +static int +__vga_gfxa_rwrites(struct gfxa* gfxa, u32_t* map, void* txbuf, size_t map_sz) +{ + return 0; +} + +static int +__vga_gfxa_vmcpy(struct gfxa* gfxa, void* buf, off_t off, size_t sz) +{ + struct vga* v = (struct vga*)gfxa->hw_obj; + + if (off + sz > v->fb_sz) { + return 0; + } + + ptr_t vram_start = v->fb + off; + memcpy((void*)vram_start, buf, sz); + + return sz; +} + +static int +__vga_gfxa_lfbcpy(struct gfxa* gfxa, void* buf, off_t off, size_t sz) +{ + return __vga_gfxa_vmcpy(gfxa, buf, off, sz); +} + +static int +__vga_gfxa_hwioctl(struct gfxa* gfxa, int req, va_list args) +{ + // TODO + return 0; +} + +struct gfxa_ops vga_gfxa_ops = { .update_profile = __vga_gfxa_update_profile, + .rreads = __vga_gfxa_rreads, + .rwrites = __vga_gfxa_rwrites, + .vmcpy = __vga_gfxa_vmcpy, + .lfbcpy = __vga_gfxa_lfbcpy, + .hwioctl = __vga_gfxa_hwioctl }; \ No newline at end of file diff --git a/lunaix-os/hal/gfxa/vga/vga_mmio_ops.c b/lunaix-os/hal/gfxa/vga/vga_mmio_ops.c index 4ec8c3e..5e2193e 100644 --- a/lunaix-os/hal/gfxa/vga/vga_mmio_ops.c +++ b/lunaix-os/hal/gfxa/vga/vga_mmio_ops.c @@ -63,7 +63,7 @@ vga_mmio_set_regs(struct vga* v, u32_t type, size_t off, u32_t* seq, size_t len) } static void -vga_mmio_set_dacp(struct vga* v) +vga_mmio_set_dacp(struct vga* v, u32_t* lut, size_t len) { #define R(c) (u8_t)(((c) & 0xff0000) >> 16) #define G(c) (u8_t)(((c) & 0x00ff00) >> 8) @@ -72,11 +72,9 @@ vga_mmio_set_dacp(struct vga* v) vga_reg8* reg_ix = regaddr(VGA_DACX, VGA_REG_X, v); vga_reg8* reg_dat = regaddr(VGA_DACX, VGA_REG_D, v); - u32_t* color_map = v->lut.colors; - *reg_ix = 0; - for (size_t i = 0; i < v->lut.len; i++) { - u32_t color = color_map[i]; + for (size_t i = 0; i < len; i++) { + u32_t color = lut[i]; *reg_dat = R(color); *reg_dat = G(color); *reg_dat = B(color); diff --git a/lunaix-os/hal/gfxa/vga/vga_pci.c b/lunaix-os/hal/gfxa/vga/vga_pci.c index baf7fa4..5d4ed8d 100644 --- a/lunaix-os/hal/gfxa/vga/vga_pci.c +++ b/lunaix-os/hal/gfxa/vga/vga_pci.c @@ -4,6 +4,7 @@ #include #include +#include #include #include @@ -81,14 +82,17 @@ vga_pci_init(struct device_def* devdef, struct device* pcidev_base) struct vga* vga_state = vga_new_state(mmio_mapped + VGA_REG_OFF, fb_mapped, FB256K); vga_state->reg_ops = vga_default_mmio_ops; - vga_state->lut.colors = palette; - vga_state->lut.len = 256; - vga_state->options = VGA_MODE_GFX; - vga_config_rect(vga_state, 640, 360, 60, 0); + struct gfxa* vga_gfxa = gfxm_alloc_adapter(vga_state); + extern struct gfxa_ops vga_gfxa_ops; + vga_gfxa->ops = vga_gfxa_ops; - // TEMP: Test the change of VGA display mode and resolution - // vga_reload_config(vga_state); + // Preload a VESA-compilant configuration + vga_gfxa->disp_info = (struct disp_profile){ + .mon = { .w_px = 640, .h_px = 480, .freq = 60, .depth = 16 } + }; + + gfxm_register(vga_gfxa); return 0; } @@ -98,9 +102,9 @@ vga_pci_init(struct device_def* devdef, struct device* pcidev_base) static struct pci_device_def vga_pci_devdef = { .dev_class = VGA_PCI_CLASS, .dev_ident = PCI_DEVIDENT(0x1234, 0x1111), - .ident_mask = -1, + .ident_mask = PCI_MATCH_EXACT, .devdef = { .class = DEVCLASS(DEVIF_PCI, DEVFN_DISP, DEV_VGA), - .name = "VGA Generic Driver", + .name = "Generic VGA", .init_for = vga_pci_init } }; -EXPORT_DEVICE(vga_pci, &vga_pci_devdef.devdef, load_pci_probe); \ No newline at end of file +EXPORT_PCI_DEVICE(vga_pci, &vga_pci_devdef); \ No newline at end of file diff --git a/lunaix-os/hal/pci.c b/lunaix-os/hal/pci.c index 7a1967e..bc1e7cc 100644 --- a/lunaix-os/hal/pci.c +++ b/lunaix-os/hal/pci.c @@ -304,6 +304,19 @@ __pci_bar_gonext(struct twimap* map) return 1; } +static void +__pci_read_binding(struct twimap* map) +{ + struct pci_device* pcidev = twimap_data(map, struct pci_device*); + // check if device binding has been initialized + struct device* dev = device_cast(&pcidev->dev); + if (!dev) { + return; + } + + twimap_printf(map, "0x%x:0x%x", dev->ident.fn_grp, dev->ident.unique); +} + void pci_build_fsmapping() { @@ -329,6 +342,9 @@ pci_build_fsmapping() map = twifs_mapping(pci_dev, pos, "class"); map->read = __pci_read_class; + map = twifs_mapping(pci_dev, pos, "binding"); + map->read = __pci_read_binding; + map = twifs_mapping(pci_dev, pos, "io_bases"); map->read = __pci_bar_read; map->go_next = __pci_bar_gonext; diff --git a/lunaix-os/includes/hal/gfxm.h b/lunaix-os/includes/hal/gfxm.h new file mode 100644 index 0000000..bb30d50 --- /dev/null +++ b/lunaix-os/includes/hal/gfxm.h @@ -0,0 +1,74 @@ +#ifndef __LUNAIX_GFXM_H +#define __LUNAIX_GFXM_H + +#include +#include + +struct gfxa; + +struct disp_profile +{ + struct gfxa_mon mon; + + struct + { + color_t* val; + size_t len; + } clut; +}; + +struct gfxa_ops +{ + int (*update_profile)(struct gfxa*); + /** + * @brief Read adapter registers + * + */ + int (*rreads)(struct gfxa*, u32_t* map, void* rxbuf, size_t map_sz); + /** + * @brief Write adapter registers + * + */ + int (*rwrites)(struct gfxa*, u32_t* map, void* txbuf, size_t map_sz); + /** + * @brief send data to VRAM + * + */ + int (*vmcpy)(struct gfxa*, void*, off_t, size_t); + /** + * @brief send logical frame buffer to adapter + * + */ + int (*lfbcpy)(struct gfxa*, void*, off_t, size_t); + /** + * @brief Execute hardware dependent ioctl command + * + */ + int (*hwioctl)(struct gfxa*, int, va_list); +}; + +struct gfxa +{ + struct device* dev; + struct llist_header gfxas; + struct hlist_node gfxas_id; + struct disp_profile disp_info; + int id; + void* hw_obj; + + struct gfxa_ops ops; +}; + +struct gfxa* +gfxm_alloc_adapter(void* hw_obj); + +void +gfxm_register(struct gfxa*); + +struct gfxa* +gfxm_adapter(int gfxa_id); + +int +gfxm_set_lut(struct gfxa*, color_t* lut, size_t len); + +#endif /* __LUNAIX_GFXM_H */ \ No newline at end of file diff --git a/lunaix-os/includes/hal/pci.h b/lunaix-os/includes/hal/pci.h index 3131aba..8c18997 100644 --- a/lunaix-os/includes/hal/pci.h +++ b/lunaix-os/includes/hal/pci.h @@ -6,6 +6,13 @@ #include #include +#define EXPORT_PCI_DEVICE(id, pci_devdef) \ + EXPORT_DEVICE(id, &(pci_devdef)->devdef, load_pci_probe) + +#define PCI_MATCH_EXACT -1 +#define PCI_MATCH_ANY 0 +#define PCI_MATCH_VENDOR 0xffff + #define PCI_TDEV 0x0 #define PCI_TPCIBRIDGE 0x1 #define PCI_TCARDBRIDGE 0x2 diff --git a/lunaix-os/includes/lunaix/device_num.h b/lunaix-os/includes/lunaix/device_num.h index ad2d8a7..af1814a 100644 --- a/lunaix-os/includes/lunaix/device_num.h +++ b/lunaix-os/includes/lunaix/device_num.h @@ -96,7 +96,8 @@ #define DEV_NULL 9 #define DEV_ZERO 10 #define DEV_KBD 11 -#define DEV_VGA 12 +#define DEV_GFXA 12 +#define DEV_VGA 13 struct devident { diff --git a/lunaix-os/includes/usr/lunaix/gfx.h b/lunaix-os/includes/usr/lunaix/gfx.h new file mode 100644 index 0000000..e583be1 --- /dev/null +++ b/lunaix-os/includes/usr/lunaix/gfx.h @@ -0,0 +1,44 @@ +#ifndef __LUNAIX_UGFX_H +#define __LUNAIX_UGFX_H + +#define GFX_CMDA(type, cmd_id) (((type) << 8) | ((cmd_id) & 0xf)) + +#define GFX_ADAPTER_INFO 1 +#define GFX_ADAPTER_REG_RD 2 +#define GFX_ADAPTER_REG_WR 3 +#define GFX_ADAPTER_CHMODE 4 +#define GFX_ADAPTER_LUT_WR 5 +#define GFX_ADAPTER_LUT_RD 6 +#define GFX_ADAPTER_VMCPY 7 +#define GFX_ADAPTER_LFBCPY 8 + +typedef unsigned int color_t; + +struct gfxa_info +{ + struct + { + unsigned int w_px; + unsigned int h_px; + unsigned int depth; + unsigned int freq; + } disp_mode; + + void* hwdep_info; +}; + +struct gfxa_mon +{ + unsigned int w_px; + unsigned int h_px; + unsigned int depth; + unsigned int freq; +}; + +struct gfxa_clut +{ + color_t* val; + size_t len; +}; + +#endif /* __LUNAIX_UGFX_H */ -- 2.27.0