void check_kernel(unsigned long addr, unsigned long magic) {
init_serial();
- // init_ttys();
+ init_ttys();
printk("setup gdt\n");
setup_gdt();
if (0x80 & kbd_scan_code) { // break code
return;
}
+
uint8_t inx = kbd_scan_code & 0xFF;
char ch = kbd_char_tbl[inx];
- cnsl_kbd_write(ch);
+
+ vt_keyboard_input(ch);
}
void kbd_handler(unsigned int irq, pt_regs_t* regs, void* dev_id) {
add_irq_bh_handler(kbd_bh_handler, NULL);
}
-extern tty_t* const default_tty;
-extern tty_t* const monitor_tty;
-extern tty_t* const debug_tty;
-extern void tty_switch_to_next();
-
uint64_t kbd_irq_cnt = 0;
void kbd_debug(uint8_t scan_code) {
kbd_irq_cnt++;
- if (scan_code == 0x01) { // Esc
- // reboot();
- }
-
- // printd("[%02x]", scan_code);
-
- // if (scan_code == 0x3B) { // F1
- // // tty_switch(default_tty);
- // vt_switch(0);
- // } else if (scan_code == 0x3C) { // F2
- // // tty_switch(monitor_tty);
- // vt_switch(1);
- // } else if (scan_code == 0x3D) { // F3
- // // tty_switch(debug_tty);
- // vt_switch(2);
- // }
-
switch (scan_code) {
+ case 0x01: // Esc
+ break;
case 0x3B: // F1
vt_switch(0);
break;
default:
break;
}
-
- // if (scan_code == 0x43) { // F9
- // void ata_test(uint64_t nr);
- // ata_test(0);
- // }
- // if (scan_code == 0x44) { // F10
- // void ata_send_read_identify_cmd(int dev);
- // ata_send_read_identify_cmd(0);
- // }
-
- // if (scan_code == 0x57) // F11
- // {
- // asm("cli;");
- // while (1)
- // ;
- // }
-
- // if (scan_code == 0x58) { // F12
- // tty_switch_to_next();
- // }
-
- // ide_status();
}
*/
#include "vt.h"
+#include <vga.h>
#include <io.h>
#include <irq.h>
-static const paddr_t vga_vram_base_paddr = 0xB8000;
static uint16_t* vga_vram_base_vaddr = (uint16_t*)pa2va(vga_vram_base_paddr);
-static const size_t vga_cols = 80;
-static const size_t vga_rows = 25;
-static const size_t vga_vram_size = vga_cols * vga_rows;
-static const size_t vga_vram_byte_size = vga_vram_size * sizeof(uint16_t);
-static const size_t TAB_SPACE = 4;
-
-#define VGA_FG_HIGHLIGHT 0b1000
-#define VGA_BG_BLINK 0b1000
-
-#define VGA_BLACK 0b0000
-#define VGA_BLUE 0b0001
-#define VGA_GREEN 0b0010
-#define VGA_CYAN 0b0011
-#define VGA_RED 0b0100
-#define VGA_PURPLE 0b0101
-#define VGA_YELLOW 0b0110
-#define VGA_WHITE 0b0111
uint8_t vga_make_attr(uint8_t fg, uint8_t bg, bool fg_highlight, bool bg_blink) {
assert((fg & 0x7) == fg);
uint16_t* vram_vaddr = vc->vram_vaddr;
- for (int i = 0; i < ((vc->rows - 1) * vc->cols); i++) {
+ // 如果是VC0则最顶上一行保留用来显示内核版本及编译时间信息
+ const int keep = vc->id == 0 ? vc->cols : 0;
+
+ for (int i = keep; i < ((vc->rows - 1) * vc->cols); i++) {
vram_vaddr[i] = vram_vaddr[i + vc->cols];
}
vga_color_putc(vc, c, vc->default_color);
}
-void vga_write(vc_t* vc, const char* buf, size_t size) {
+int vga_write(vc_t* vc, const char* buf, size_t size) {
assert(buf != NULL);
for (size_t i = 0; i < size; i++) {
vga_putc(vc, buf[i]);
}
+
+ return size;
}
void vga_ap_clear() {
--- /dev/null
+/*
+ * ------------------------------------------------------------------------
+ * File Name: vga.h
+ * Author: Zhao Yanbai
+ * 2026-08-11 19:37:11 Tuesday CST
+ * Description: none
+ * ------------------------------------------------------------------------
+ */
+
+#pragma once
+
+static const paddr_t vga_vram_base_paddr = 0xB8000;
+static const size_t vga_cols = 80;
+static const size_t vga_rows = 25;
+static const size_t vga_vram_size = vga_cols * vga_rows;
+static const size_t vga_vram_byte_size = vga_vram_size * sizeof(uint16_t);
+static const size_t TAB_SPACE = 4;
+
+#define VGA_FG_HIGHLIGHT 0b1000
+#define VGA_BG_BLINK 0b1000
+
+#define VGA_BLACK 0b0000
+#define VGA_BLUE 0b0001
+#define VGA_GREEN 0b0010
+#define VGA_CYAN 0b0011
+#define VGA_RED 0b0100
+#define VGA_PURPLE 0b0101
+#define VGA_YELLOW 0b0110
+#define VGA_WHITE 0b0111
+
+void vga_init_vc(vc_t* vc);
+void vga_switch(vc_t* vc);
+int vga_write(vc_t* vc, const char* buf, size_t size);
+uint8_t vga_make_attr(uint8_t fg, uint8_t bg, bool fg_highlight, bool bg_blink);
+void vga_set_cursor_style(bool block);
\ No newline at end of file
*/
#include "vt.h"
-
-void vga_init_vc(vc_t* vc);
-void vga_switch(vc_t* vc);
-void vga_write(vc_t* vc, const char* buf, size_t size);
-uint8_t vga_make_attr(uint8_t fg, uint8_t bg, bool fg_highlight, bool bg_blink);
-void vga_set_cursor_style(bool block);
+#include <vga.h>
static vc_t vcs[VC_COUNT];
static vc_t* fg_vc = &vcs[0];
return vc == view_vc;
}
+int vt_write(vc_t* vc, const char* buf, size_t size) {
+ return vga_write(vc, buf, size);
+}
+
// VT CONSOLE: 仅桥接console用
int vt_console_write(const char* buf, size_t size) {
// 找到前台vt调用其write
assert(fg_vc != NULL);
assert(fg_vc->id < VC_FOR_TTY_COUNT);
- vga_write(fg_vc, buf, size);
- return 0;
+ return vt_write(fg_vc, buf, size);
}
int vt_console_setup(console_t* console) {
vt_switch(view_vc_id);
register_console(&vt_console);
-}
\ No newline at end of file
+}
+
+void vt_keyboard_input(uint8_t c) {
+ assert(fg_vc != NULL);
+ assert(fg_vc->id < VC_FOR_TTY_COUNT);
+
+ tty_t* tty = fg_vc->tty;
+ assert(tty != NULL);
+
+ tty_input(tty, c);
+}
+
+void print_kernel_version(const char* version) {
+ vc_t* vc = vt_get_vc(0);
+ uint8_t color = vt_make_attr(VT_WHITE, VT_CYAN, true, false);
+
+ // 清理第一行
+ for (int i = 0; i < vc->cols; i++) {
+ uint16_t c = (color << 8) | ' ';
+ vc->vram_vaddr[i] = c;
+ }
+
+ // 打印版本号
+ for (int i = 0; i < strlen(version); i++) {
+ uint16_t c = (color << 8) | version[i];
+ vc->vram_vaddr[i] = c;
+ }
+}
+
+int vt_tty_write(tty_t* tty, const char* buf, size_t size) {
+ assert(tty != NULL);
+
+ vc_t* vc = tty->private;
+ assert(vc != NULL);
+
+ return vt_write(vc, buf, size);
+
+ return 0;
+}
+
+tty_ops_t vt_tty_ops = {
+ .write = vt_tty_write,
+};
\ No newline at end of file
#pragma once
#include <console.h>
+#include <tty.h>
// 暂不考虑别的类型的VC,直接按VGA来写
bool show_cursor;
uint16_t* vram_vaddr;
+
+ tty_t* tty;
};
bool vc_is_fg_vc(vc_t* vc);
bool vc_is_view_vc(vc_t* vc);
vc_t* vt_get_vc(int id);
vc_t* vt_get_ap_vc();
-void vt_switch(int id);
\ No newline at end of file
+void vt_switch(int id);
+
+void vt_keyboard_input(uint8_t c);
+
+void print_kernel_version(const char* version);
+
+extern tty_ops_t vt_tty_ops;
\ No newline at end of file
//--------------------------------------------------------------------------
-extern chrdev_t cnsl_chrdev;
-
-chrdev_t* chrdev[CHRDEV_SIZE] = {&cnsl_chrdev};
-
// void ext2_setup_fs();
unsigned int ext2_search_inpath(const char* path);
#pragma once
-#define TTY_FG_HIGHLIGHT 0b1000
-#define TTY_BG_BLINK 0b1000
+#include <types.h>
-#define TTY_BLACK 0b0000
-#define TTY_BLUE 0b0001
-#define TTY_GREEN 0b0010
-#define TTY_CYAN 0b0011
-#define TTY_RED 0b0100
-#define TTY_PURPLE 0b0101
-#define TTY_YELLOW 0b0110
-#define TTY_WHITE 0b0111
+#define TTY_MAX_NAME_LEN 32
+#define TTY_MAX_COUNT 8
+#define TTY_MAX_IN_BUF_SIZE 512
-typedef struct tty {
- char name[32];
+typedef struct tty tty_t;
+typedef struct tty_ops tty_ops_t;
- // 记录字符显示位置
- unsigned int xpos;
- unsigned int ypos;
+struct tty_ops {
+ int (*write)(tty_t* tty, const char* buf, size_t size);
+};
- unsigned int fg_color;
- unsigned int bg_color;
+struct tty {
+ char name[TTY_MAX_NAME_LEN];
- // 最大字符数
- int max_x;
- int max_y;
+ uint8_t in_buf[TTY_MAX_IN_BUF_SIZE];
+ int ib_head;
+ int ib_tail;
- // 记录对应的显存起始位置
- unsigned long base_addr;
-} tty_t;
+ tty_ops_t* ops;
+ void* private;
+};
void init_ttys();
-void tty_write(tty_t* tty, const char* buf, size_t size);
-void tty_write_at(tty_t* tty, int xpos, int ypos, const char* buf, size_t size);
-void tty_color_putc(tty_t* tty, char c, unsigned int fg_color, unsigned bg_color);
+// 进程 -> read -> tty_read -> TTY (buf)
+// 键盘: 键盘中断 -> vt_keyboard_input -> tty_input -> TTY (in_buf)
+// └─echo(回显) -> tty_write -> TTY ops->write -> 键盘 TX
+// 串口 RX: 串口中断 -> serial_input -> tty_input -> TTY (in_buf)
+// └─echo(回显) -> tty_write -> TTY ops->write -> 串口 TX
+// 进程 -> write -> tty_write -> TTY ops->write -> [Serial, VT] write -> 硬件
-void tty_set_cursor(tty_t* tty);
-void tty_switch(tty_t* tty);
+int tty_write(tty_t* tty, const char* buf, size_t size);
+int tty_read(tty_t* tty, char* buf, size_t size);
-void tty_switch_to_next();
-
-void tty_clear(tty_t* tty);
-
-extern tty_t* current_tty;
+// 返回 1 表示成功,0 表示缓冲区满,丢弃
+int tty_input(tty_t* tty, uint8_t c);
return 0;
}
-void vga_putc(unsigned int nr, unsigned char c, const unsigned char color);
+#if 0
cnsl_t cnsl;
}
chrdev_t cnsl_chrdev = {.read = cnsl_read};
+#endif
#include <printk.h>
#include <string.h>
#include <system.h>
-#include <tty.h>
+#include <vt.h>
#include <hpet.h>
extern void init_mm();
extern void setup_ext2();
extern void reboot();
-extern void cnsl_init();
#define VERSION "0.3.1"
-const char* version = "KERNEL v" VERSION " @" BUILDER " [" __DATE__ " " __TIME__
- "]"
- "\n\n";
-
-void print_kernel_version() {
- //
- extern tty_t* const default_tty;
- tty_t* const tty = default_tty;
-
- int len = strlen(version);
-
- for (int i = 0; i < tty->max_x; i++) {
- char c = i < len ? version[i] : ' ';
- c = c != '\n' ? c : ' ';
- c = c != '\t' ? c : ' ';
-
- //
- uint32_t fg_color = tty->fg_color;
- uint32_t bg_color = tty->bg_color;
-
- fg_color = TTY_WHITE | TTY_FG_HIGHLIGHT;
- bg_color = TTY_CYAN;
-
- //
- char* dst = (char*)tty->base_addr;
-
- //
- dst[i * 2 + 0] = c;
- dst[i * 2 + 1] = ((bg_color) << 4) | (fg_color);
- }
-
- //
- printk(version);
-}
+const char* version = "KERNEL v" VERSION " @" BUILDER " [" __DATE__ " " __TIME__ "]";
void prepare_ap_code(paddr_t paddr) {
// 注意: 最开始时AP是运行在实模式
setup_sysc();
boot_delay(DEFAULT_BOOT_DELAY_TICKS);
- cnsl_init();
- boot_delay(DEFAULT_BOOT_DELAY_TICKS);
-
setup_fs();
setup_tasks();
detect_cpu();
boot_delay(DEFAULT_BOOT_DELAY_TICKS);
- print_kernel_version();
+ print_kernel_version(version);
boot_delay(DEFAULT_BOOT_DELAY_TICKS);
- // extern tty_t* const monitor_tty;
- // tty_switch(monitor_tty);
-
boot_delay(DEFAULT_BOOT_DELAY_TICKS);
setup_i8254(100);
#include <page.h>
#include <string.h>
#include <tty.h>
-
-// 从0xB8000处开始有32KB显存可利用
-// 而一屏所需要的显存为 80*25*2 = 4000 约为4K
-// 所以大致可以分出8个tty
-// 每个的起始地址以0x1000对齐
-const uint32_t PHY_VADDR = 0xB8000;
-const uint32_t VADDR = (uint32_t)pa2va(PHY_VADDR);
-#define TTY_VRAM_SIZE (0x1000)
+#include <vt.h>
+#include <errno.h>
#define MAX_NR_TTYS 8
tty_t ttys[NR_TTYS];
-#define MAX_X 80
-#define MAX_Y 25
-#define CHARS_PER_LINE (MAX_X)
-#define BYTES_PER_LINE (CHARS_PER_LINE * 2)
-#define TAB_SPACE 4
-
-tty_t* const default_tty = ttys + 0;
-tty_t* const monitor_tty = ttys + 1;
-tty_t* const debug_tty = ttys + 2;
-
-void tty_clear(tty_t* tty) {
- char* dst = (char*)tty->base_addr;
- for (int src = 0; src < (MAX_Y * BYTES_PER_LINE); src += 2) {
- *dst++ = 0;
- *dst++ = (tty->bg_color << 4) | tty->fg_color;
- }
-}
-
-// 因为光标要指向下一个待输出的位置
-// 在这个位置的光标的颜色与该位置已经设置的颜色一样
-// 一般输出一个字符,则光标位置在这个字符之后
-// 而如果输出字符颜色与光标所处位置已经设置的颜色不一致的话
-// 就需要将输出的这个字符的后一个位置的颜色设置成与之一致
-// 这样光标颜色才与输出字符一致
-void __tty_set_next_pos_color(tty_t* tty, char color) {
- unsigned int xpos = tty->xpos;
- unsigned int ypos = tty->ypos;
-
- xpos += 1; // 指向下一个位置
-
- ypos += xpos / CHARS_PER_LINE;
- xpos %= CHARS_PER_LINE;
-
- if (ypos < MAX_Y) {
- char* dst = (char*)(tty->base_addr + ypos * BYTES_PER_LINE + 2 * xpos);
- dst[0] = 0;
- dst[1] = color;
- }
-}
-
-void init_tty(tty_t* tty, const char* name, unsigned long base) {
- assert(0 != tty);
- assert(NR_TTYS >= 1);
- assert(NR_TTYS <= MAX_NR_TTYS);
-
- strlcpy(tty->name, name, sizeof(tty->name));
-
- tty->fg_color = TTY_FG_HIGHLIGHT | TTY_GREEN; // 高亮
- tty->bg_color = TTY_BLACK; // 不闪
-
- tty->max_x = MAX_X;
- tty->max_y = MAX_Y;
-
- tty->base_addr = base;
-
- for (int i = 0; i < TTY_VRAM_SIZE; i += 2) {
- uint8_t* p = (uint8_t*)base;
- p[i + 0] = ' ';
- p[i + 1] = (tty->bg_color << 4) | tty->fg_color;
- }
-}
-
void init_ttys() {
- assert(irq_disabled());
-
- for (int i = 0; i < NR_TTYS; i++) {
+ for (int i = 0; i < VC_FOR_TTY_COUNT; i++) {
tty_t* tty = ttys + i;
- char name[sizeof(tty->name)];
- sprintf(name, "tty.%u", i);
- init_tty(tty, name, VADDR + i * TTY_VRAM_SIZE);
+ char name[TTY_MAX_NAME_LEN];
+ sprintf(name, "tty%d", i);
- if (i != TTY_WHITE) {
- tty->fg_color = TTY_FG_HIGHLIGHT | TTY_WHITE;
- tty->bg_color = i;
- } else {
- tty->fg_color = TTY_FG_HIGHLIGHT | TTY_BLACK;
- tty->bg_color = TTY_WHITE;
- }
- }
+ strcpy(tty->name, name);
- default_tty->fg_color = TTY_FG_HIGHLIGHT | TTY_GREEN;
- default_tty->bg_color = TTY_BLACK;
+ tty->ib_head = 0;
+ tty->ib_tail = 0;
- monitor_tty->fg_color = TTY_FG_HIGHLIGHT | TTY_WHITE;
- monitor_tty->bg_color = TTY_BLUE;
+ tty->ops = &vt_tty_ops;
- debug_tty->fg_color = TTY_FG_HIGHLIGHT | TTY_WHITE;
- debug_tty->bg_color = TTY_BLACK; // TTY_CYAN;
+ vc_t* vc = vt_get_vc(i);
+ assert(vc != NULL);
- for (int i = 0; i < NR_TTYS; i++) {
- tty_t* tty = ttys + i;
- tty_clear(tty);
- }
- current_tty = default_tty;
-}
+ tty->private = vc;
+ vc->tty = tty;
-void tty_do_scroll_up(tty_t* tty) {
- // 没越过最后一行不需要上卷
- if (tty->ypos < MAX_Y - 1) {
- return;
+ printk("init_ttys: tty %x vcid %d\n", tty, i);
}
-
- // 达到最后一行,没到最后一个字符也不用上卷
- if (tty->ypos == (MAX_Y - 1) && tty->xpos < MAX_X) {
- return;
- }
-
- // 如果是default_tty则保留用来显示内核版本及编译时间信息
- const int keep = tty != default_tty ? 0 : BYTES_PER_LINE;
-
- char* dst = (char*)tty->base_addr + keep;
- for (int src = BYTES_PER_LINE + keep; src < (MAX_Y * BYTES_PER_LINE); src++) {
- *dst++ = *(char*)(tty->base_addr + src);
- }
-
- // 清空最后一行
- dst = (char*)(tty->base_addr + ((MAX_Y - 1) * BYTES_PER_LINE));
- for (int i = 0; i < BYTES_PER_LINE; i += 2) {
- *dst++ = 0;
- *dst++ = (tty->bg_color << 4) | tty->fg_color;
- }
-
- tty->xpos = 0;
- tty->ypos = MAX_Y - 1;
}
-void tty_color_putc(tty_t* tty, char c, unsigned int fg_color, unsigned bg_color) {
- bool display = false;
- bool move_to_next_pos = true;
- switch (c) {
- case '\r':
- tty->xpos = 0;
- case '\n':
- tty->xpos = 0;
- tty->ypos += 1;
- break;
- case '\t':
- tty->xpos += TAB_SPACE;
- tty->xpos &= ~(TAB_SPACE - 1);
- break;
- case '\b':
- if (tty->xpos == 0) {
- if (tty->ypos > 0) {
- tty->xpos = CHARS_PER_LINE - 1;
- tty->ypos -= 1;
- } else {
- tty->ypos = 0;
- }
- } else if (tty->xpos > 0) {
- tty->xpos -= 1;
- } else {
- tty->xpos = 0;
- }
- c = 0;
- display = true;
- move_to_next_pos = false;
- break;
- default:
- display = true;
- break;
- }
-
- tty->ypos += tty->xpos / CHARS_PER_LINE;
- tty->xpos %= CHARS_PER_LINE;
-
- // 显示
- if (display) {
- unsigned int pos = tty->ypos * BYTES_PER_LINE + tty->xpos * 2;
- char* va = (char*)(tty->base_addr + pos);
- va[0] = c;
- va[1] = (bg_color << 4) | fg_color;
+void tty_putc(tty_t* tty, char c) {
+}
- __tty_set_next_pos_color(tty, va[1]);
+int tty_write(tty_t* tty, const char* buf, size_t size) {
+ assert(tty != NULL);
+ assert(buf != NULL);
- if (move_to_next_pos) {
- tty->xpos++;
- }
- }
+ tty_ops_t* ops = tty->ops;
+ assert(ops != NULL);
- tty_do_scroll_up(tty);
+ return ops->write(tty, buf, size);
- tty_set_cursor(tty);
+ return 0;
}
-void tty_putc(tty_t* tty, char c) {
- tty_color_putc(tty, c, tty->fg_color, tty->bg_color);
-}
+int tty_read(tty_t* tty, char* buf, size_t size) {
+ assert(tty != NULL);
-void tty_write(tty_t* tty, const char* buf, size_t size) {
- return;
- assert(0 != tty);
- if (0 == buf) {
- return;
+ if (0 == size) {
+ return 0;
}
- for (size_t i = 0; i < size; i++) {
- tty_putc(tty, buf[i]);
+ if (NULL == buf) {
+ return -EINVAL;
}
-}
-
-void tty_write_at(tty_t* tty, int xpos, int ypos, const char* buf, size_t size) {
- assert(0 != tty);
- assert(xpos < BYTES_PER_LINE);
- assert(ypos < MAX_Y);
- tty->xpos = xpos;
- tty->ypos = ypos;
- tty_write(tty, buf, size);
-}
-
-#define VGA_CRTC_ADDR 0x3D4
-#define VGA_CRTC_DATA 0x3D5
-#define VGA_CRTC_START_ADDR_H 0xC
-#define VGA_CRTC_START_ADDR_L 0xD
-#define VGA_CRTC_CURSOR_H 0xE
-#define VGA_CRTC_CURSOR_L 0xF
-void tty_set_cursor(tty_t* tty) {
- if (tty != current_tty) {
- return;
- }
- unsigned int offset = tty->ypos * MAX_X + tty->xpos;
+ // TODO
- unsigned long flags;
- irq_save(flags);
- outb(VGA_CRTC_CURSOR_H, VGA_CRTC_ADDR);
- outb((offset >> 8) & 0xFF, VGA_CRTC_DATA);
- outb(VGA_CRTC_CURSOR_L, VGA_CRTC_ADDR);
- outb(offset & 0xFF, VGA_CRTC_DATA);
- irq_restore(flags);
+ return 0;
}
-void tty_switch(tty_t* tty) {
- if (0 == tty) {
- return;
- }
-
- unsigned int offset = (tty->base_addr - VADDR) / 2;
+int tty_input(tty_t* tty, uint8_t c) {
+ assert(tty != NULL);
- unsigned long flags;
- irq_save(flags);
- outb(VGA_CRTC_START_ADDR_H, VGA_CRTC_ADDR);
- outb((offset >> 8) & 0xFF, VGA_CRTC_DATA);
- outb(VGA_CRTC_START_ADDR_L, VGA_CRTC_ADDR);
- outb((offset) & 0xFF, VGA_CRTC_DATA);
- irq_restore(flags);
+ int next = (tty->ib_head + 1) % TTY_MAX_IN_BUF_SIZE;
+ if (next == tty->ib_tail) {
+ return 0;
+ }
- current_tty = tty;
+ tty->in_buf[tty->ib_head] = c;
+ tty->ib_head = next;
- tty_set_cursor(current_tty);
-}
+ // 目前先总是回显
+ tty_write(tty, (const char*)&c, 1);
-void tty_switch_to_next() {
- tty_t* tty = ttys + ((current_tty - ttys + 1) % NR_TTYS);
- tty_switch(tty);
-}
+ // TODO: 唤醒读进程
-tty_t* current_tty;
+ return 1;
+}
\ No newline at end of file
}
break;
case 's':
- p += write_buf(p, (const char*)va_arg(args, char*), char_fill, char_cnt, align);
+ p += write_buf(p, (const char*)va_arg(args, char*), char_fill, char_cnt, align);
break;
case 'u':
itou(tmp, va_arg(args, uint32_t));