}
-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;
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);
}
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:
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");
- #include <multiboot2.h>
+#include <multiboot2.h>
- #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,
.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 = {
.flags = 0,
.size = sizeof(struct multiboot_header_tag),
},
- };
+};
}
// 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);
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
}
set architecture i386
+#b slub.c:62 if cache->name[0] != 'b'
#b acpi.c:144
#b main
#b boot_paging
#define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1))
// 定义最大显存为 16MB
+// 后续内核不映射显存了,以后可以提供映射到用户空间的功能,由用户态程序操作
#define VRAM_VADDR_SIZE (16 << 20)
// 最大支持的线性地址空间为1G
void init_apic() {
+#if 0
lapic_init();
+#endif
}
init_buffer();
- #if 1
+ #if 0
parse_rsdt(system.rsdt_addr);
void init_apic();
// 接下来为显存建立页映射
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) {
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();
qemu-system-i386 \
-boot d \
- -m 128 \
+ -m 3100\
-smp 2 \
-cpu qemu32,+x2apic \
-serial tcp::6666,server,nowait \
load_video
set gfxmode=auto
set gfxpayload=keep
-# terminal_output gfxterm
+terminal_output gfxterm
set default="0"
set timeout=0