From 959afcab360c37707482f79be8345b92457f885b Mon Sep 17 00:00:00 2001 From: acevest Date: Tue, 30 Dec 2025 15:29:57 +0800 Subject: [PATCH] =?utf8?q?=E6=B7=BB=E5=8A=A0serial=5Fmonitor=E7=9A=84?= =?utf8?q?=E6=B8=85=E5=B1=8F=E8=83=BD=E5=8A=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit --- boot/acpi.c | 2 +- boot/boot.c | 36 ++++++++++++++++++++--- boot/multiboot2_header.c | 27 ++++++++++------- boot/vbe.c | 26 +++++++++++------ gdbscript | 1 + include/system.h | 1 + kernel/apic.c | 2 ++ kernel/setup.c | 2 +- mm/mm.c | 62 ++++++++++++++++++++++++++-------------- qemu.sh | 2 +- scripts/iso.grub.cfg | 2 +- 11 files changed, 115 insertions(+), 48 deletions(-) diff --git a/boot/acpi.c b/boot/acpi.c index cbe8727..faf8a09 100644 --- a/boot/acpi.c +++ b/boot/acpi.c @@ -171,7 +171,7 @@ void parse_rsdt(void *addr) { } -void check_acpi(void *tag) { +void parse_acpi(void *tag) { printk("ACPI[old].RSDP "); struct multiboot_tag_old_acpi *acpi_tag = (struct multiboot_tag_old_acpi *)tag; uint8_t *rsdp = (uint8_t *)acpi_tag->rsdp; diff --git a/boot/boot.c b/boot/boot.c index 1b2905b..5f3fa45 100644 --- a/boot/boot.c +++ b/boot/boot.c @@ -66,16 +66,44 @@ void parse_framebuffer(void *addr) { uint32_t type = fb->common.type; uint32_t size = fb->common.size; uint64_t fb_addr = fb->common.framebuffer_addr; + // pitch(也称为 stride 或 bytes per scanline) 表示在帧缓冲区中,从一行像素的开始到下一行像素开始的字节数。 + // 简单说: 每行像素占用字节数 + // 比如 800x600x32 的pitch为3200,则每行像素数为 pitch / (bpp/8) = 3200 / (32/8) = 800 + // 既然分辨率上写了 800 为什么要多此一举搞个pitch,主要是为了内存对齐 + // + // 例[只是举例,不代表一定是这样]: + // 800x600 16位色 + // 理论:800 × 2 = 1600 字节 + // 如果显卡要求 2048 字节对齐(2KB边界) + // 实际 pitch = 2048 + // 填充:2048 - 1600 = 448 字节/行 + // + // 所以每行的实际的内存空间可能更大 + // 所以应该按如下方法访问像素 + // uint32_t *framebuffer = (uint32_t *)fb_addr; + // uint32_t pixels_per_row = pitch / (bpp / 8); // 每行像素数(包括填充) + // uint32_t pixel = framebuffer[y * pixels_per_row + x]; + // + // 而不是这种方法 + // uint32_t *framebuffer = (uint32_t *)fb_addr; + // uint32_t pixel = framebuffer[y * width + x]; // 下一行开头的内容可能写到上一行不显示的内存区域去了 + // uint32_t fb_pitch = fb->common.framebuffer_pitch; uint32_t fb_width = fb->common.framebuffer_width; uint32_t fb_height = fb->common.framebuffer_height; uint8_t fb_bpp = fb->common.framebuffer_bpp; uint8_t fb_type = fb->common.framebuffer_type; + + system.vbe_phys_addr = fb_addr; + system.x_resolution = fb_width; + system.y_resolution = fb_height; + printk("type %u size %u addr %lx pitch %u width %u height %u bpp %u type %u\n", type, size, fb_addr, fb_pitch, fb_width, fb_height, fb_bpp, fb_type); - + // 直接就不打算支持32位以外的色深 + // assert(fb_bpp == 32); } @@ -203,7 +231,7 @@ void check_kernel(unsigned long addr, unsigned long magic) { vbe = (struct multiboot_tag_vbe *)tag; void *vci = (void *)vbe->vbe_control_info.external_specification; void *vmi = (void *)vbe->vbe_mode_info.external_specification; - printk("VBE MODE %04x\n", vbe->vbe_mode); + printk("VBE[deprecated] mode %04x\n", vbe->vbe_mode); init_vbe(vci, vmi); break; case MULTIBOOT_TAG_TYPE_FRAMEBUFFER: @@ -250,8 +278,8 @@ void check_kernel(unsigned long addr, unsigned long magic) { printk("load base addr %08x\n", ((struct multiboot_tag_load_base_addr *)tag)->load_base_addr); break; case MULTIBOOT_TAG_TYPE_ACPI_OLD: - extern void check_acpi(void *); - check_acpi(tag); + extern void parse_acpi(void *); + parse_acpi(tag); break; case MULTIBOOT_TAG_TYPE_ACPI_NEW: printk("ACPI new\n"); diff --git a/boot/multiboot2_header.c b/boot/multiboot2_header.c index b493c3a..85b7618 100644 --- a/boot/multiboot2_header.c +++ b/boot/multiboot2_header.c @@ -9,25 +9,30 @@ - #include +#include - #define ENABLE_FB 0 +// 启用FB这个功能,需要修改grub.cfg,添加如下内容 +// load_video +// set gfxmode=auto +// set gfxpayload=keep +// terminal_output gfxterm +#define ENABLE_FB 0 - #define ALIGN8 __attribute__((aligned(8))) +#define ALIGN8 __attribute__((aligned(8))) - typedef struct ALIGN8 multiboot2_elf_header { +typedef struct ALIGN8 multiboot2_elf_header { ALIGN8 struct multiboot_header header; #if ENABLE_FB ALIGN8 struct multiboot_header_tag_framebuffer fb; #endif ALIGN8 struct multiboot_header_tag end; - } multiboot2_bin_header_t; +} multiboot2_bin_header_t; - __attribute__((section(".multiboot2_header"), used)) - const multiboot2_bin_header_t multiboot2_elf_header = { +__attribute__((section(".multiboot2_header"), used)) +const multiboot2_bin_header_t multiboot2_elf_header = { .header = { .magic = MULTIBOOT2_HEADER_MAGIC, .architecture = MULTIBOOT_ARCHITECTURE_I386, @@ -39,9 +44,9 @@ .type = MULTIBOOT_HEADER_TAG_FRAMEBUFFER, .flags = MULTIBOOT_HEADER_TAG_OPTIONAL, .size = sizeof(struct multiboot_header_tag_framebuffer), - .width = 0, - .height = 0, - .depth = 0, + .width = 1280, + .height = 800, + .depth = 32, }, #endif .end = { @@ -52,4 +57,4 @@ .flags = 0, .size = sizeof(struct multiboot_header_tag), }, - }; +}; diff --git a/boot/vbe.c b/boot/vbe.c index 598905d..57913b2 100644 --- a/boot/vbe.c +++ b/boot/vbe.c @@ -123,10 +123,14 @@ vbe_mode_info_t *get_vbe_mode_info(uint16_t) { } // extern pde_t init_pgd[]; void init_vbe(void *vciptr, void *vmiptr) { + // VBE是传统BIOS接口,在现代系统上可能没有被正确初始化 + // 也无法在保护模式下调用VBE BIOS功能 + // 因此这里只是打印VBE信息 + // 更可靠的数据是 MULTIBOOT_TAG_TYPE_FRAMEBUFFER 的数据 vbe_controller_info_t *vci = vciptr; vbe_mode_info_t *vmi = (vbe_mode_info_t *)vmiptr; - printk("VBE:\n"); + printk("VBE[deprecated]:\n"); printk("Signature %c%c%c%c\n", vci->signature[0], vci->signature[1], vci->signature[2], vci->signature[3]); printk("version %04x\n", vci->version); printk("total memory %u x 64K\n", vci->total_memory); @@ -137,18 +141,24 @@ void init_vbe(void *vciptr, void *vmiptr) { printk("SEG %04X OFFSET %04X\n", vci->video_mode_ptr.segment, vci->video_mode_ptr.offset); uint16_t *modes = (uint16_t *)segoff_to_addr(vci->video_mode_ptr); + printk("vbe modes:"); while (*modes != VBE_MODE_END) { - printk("mode: %04x\n", *modes); - // vbe_mode_info_t *mi = get_vbe_mode_info(*modes); - // if (mi->mode_attributes & 0x01) { - // printk("R %u x %u\n", mi->x_resolution, mi->y_resolution); - // } + printk(" %04x", *modes); + vbe_mode_info_t *mi = get_vbe_mode_info(*modes); + + // 目前以下判断不会生效 + if ((mi != 0) && (mi->mode_attributes & 0x01)) { + printk("R %u x %u\n", mi->x_resolution, mi->y_resolution); + } + modes++; } + printk("\n"); + printk("vbe[deprecated] phys addr %08x resolution %u x %u\n", vmi->phys_base_ptr, vmi->x_resolution, vmi->y_resolution); +#if 0 system.vbe_phys_addr = vmi->phys_base_ptr; system.x_resolution = vmi->x_resolution; system.y_resolution = vmi->y_resolution; - - printk(" phys addr %08x resolution %u x %u\n", system.vbe_phys_addr, system.x_resolution, system.y_resolution); +#endif } diff --git a/gdbscript b/gdbscript index 06a6b20..a5dc4f1 100644 --- a/gdbscript +++ b/gdbscript @@ -3,6 +3,7 @@ set confirm off set architecture i386 +#b slub.c:62 if cache->name[0] != 'b' #b acpi.c:144 #b main #b boot_paging diff --git a/include/system.h b/include/system.h index 81054b3..3a58745 100644 --- a/include/system.h +++ b/include/system.h @@ -81,6 +81,7 @@ extern char etext, edata, end; #define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1)) // 定义最大显存为 16MB +// 后续内核不映射显存了,以后可以提供映射到用户空间的功能,由用户态程序操作 #define VRAM_VADDR_SIZE (16 << 20) // 最大支持的线性地址空间为1G diff --git a/kernel/apic.c b/kernel/apic.c index c23a3b2..a18268a 100644 --- a/kernel/apic.c +++ b/kernel/apic.c @@ -65,5 +65,7 @@ void init_apic() { +#if 0 lapic_init(); +#endif } diff --git a/kernel/setup.c b/kernel/setup.c index 70689f1..c75f301 100644 --- a/kernel/setup.c +++ b/kernel/setup.c @@ -91,7 +91,7 @@ void setup_kernel() { init_buffer(); - #if 1 + #if 0 parse_rsdt(system.rsdt_addr); void init_apic(); diff --git a/mm/mm.c b/mm/mm.c index 7aa09e8..c370ea7 100644 --- a/mm/mm.c +++ b/mm/mm.c @@ -76,6 +76,7 @@ void init_paging() { // 接下来为显存建立页映射 unsigned long vram_phys_addr = system.vbe_phys_addr; + printk("vram_phys_addr: 0x%x\n", vram_phys_addr); for (int pde_inx = 0; pde_inx < get_npde(VRAM_VADDR_SIZE); pde_inx++) { pgtb_addr = (unsigned long *)(alloc_from_bootmem(PAGE_SIZE, "vrampaging")); if (0 == pgtb_addr) { @@ -97,27 +98,46 @@ void init_paging() { LoadCR3(va2pa(init_pgd)); - // // 测试显存 - // for (int i = 0; i < system.x_resolution * (system.y_resolution - 32); i++) { - // unsigned long *vram = (unsigned long *)VRAM_VADDR_BASE; - // vram[i] = 0x000000FF; - // } - - // while (1) { - // u16 lineH = 32; - // unsigned long *vram = (unsigned long *)VRAM_VADDR_BASE; - // int sep = system.x_resolution * (system.y_resolution - lineH); - // for (int i = 0; i < sep; i++) { - // vram[i] = vram[i + system.x_resolution * lineH]; - // } - - // unsigned int long color = 0x0000FF; - // color = (vram[0] == 0x0000FF ? 0x00FF00 : 0x0000FF); - - // for (int i = sep; i < sep + system.x_resolution * lineH; i++) { - // vram[i] = color; - // } - // } + // 测试显存 + for (int i = 0; i < system.x_resolution * (system.y_resolution - 32); i++) { + unsigned long *vram = (unsigned long *)VRAM_VADDR_BASE; + // 仅为32bit色深 + // 在内存中 [B, G, R, A] 因为x86是小端序 所以实际是 ARGB 顺序 + vram[i] = 0x000000FF; + } + +#if 0 + bool flag = false; + while (1) { + u16 lineH = 32; + unsigned long *vram = (unsigned long *)VRAM_VADDR_BASE; + int sep = system.x_resolution * (system.y_resolution - lineH); + for (int i = 0; i < sep; i++) { + vram[i] = vram[i + system.x_resolution * lineH] | 0x00FF0000; + } + + unsigned int long color = 0x0000FF; + color = (vram[0] == 0x0000FF ? 0x00FF00 : 0x0000FF); + + for (int i = sep; i < sep + system.x_resolution * lineH; i++) { + vram[i] = color; + } + + for(int i=0; i<32; i++) { + for(int j=0; j<64; j++) { + unsigned int long c = vram[j*system.x_resolution+i]; + c = flag ? 0x00FFFFFF : 0x000000FF; + // c &= 0x00FFFFFF; + vram[j*system.x_resolution+i] = c; + } + } + flag = !flag; + + for(int i=0; i<10*1000*10000; i++) { + asm("nop"); + } + } +#endif } extern void init_ttys(); diff --git a/qemu.sh b/qemu.sh index 456d476..455675e 100755 --- a/qemu.sh +++ b/qemu.sh @@ -19,7 +19,7 @@ set -m qemu-system-i386 \ -boot d \ - -m 128 \ + -m 3100\ -smp 2 \ -cpu qemu32,+x2apic \ -serial tcp::6666,server,nowait \ diff --git a/scripts/iso.grub.cfg b/scripts/iso.grub.cfg index f8a932c..3b8c8a8 100644 --- a/scripts/iso.grub.cfg +++ b/scripts/iso.grub.cfg @@ -10,7 +10,7 @@ load_video set gfxmode=auto set gfxpayload=keep -# terminal_output gfxterm +terminal_output gfxterm set default="0" set timeout=0 -- 2.47.0