mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-01-31 11:37:35 +00:00
[WIP] Get bare metal working outside of an emulator (#609)
You can now run bare metal on bare metal!
* Fix handling of int 0x15 eax = 0xe820 memory map
* Fix some issues in initial page table creation
* hello4.com now works outside emulators
* Ensure area for identity page tables are zeroed first
* Simplify logic for creating page table entries, this partly
reverts 577c0f6226
* Add degenerate MBR partition entry, to ease testing
Co-authored-by: tkchia <tkchia-cosmo@gmx.com>
This commit is contained in:
parent
c03359c637
commit
116bda997e
3 changed files with 55 additions and 35 deletions
67
ape/ape.S
67
ape/ape.S
|
@ -329,7 +329,7 @@ dsknfo: push %bx
|
||||||
movpp %es,%ds
|
movpp %es,%ds
|
||||||
xor %si,%si
|
xor %si,%si
|
||||||
mov %si,%es
|
mov %si,%es
|
||||||
mov $0x1510,%si # mman::pc_drive_base_table
|
mov $0x1d10,%si # mman::pc_drive_base_table
|
||||||
xchg %si,%di
|
xchg %si,%di
|
||||||
movsw #→ headunloadtime, headloadtime
|
movsw #→ headunloadtime, headloadtime
|
||||||
movsw #→ shutofftime, bytespersector
|
movsw #→ shutofftime, bytespersector
|
||||||
|
@ -382,11 +382,11 @@ pcread: push %ax
|
||||||
add $512>>4,%si
|
add $512>>4,%si
|
||||||
mov %si,%es
|
mov %si,%es
|
||||||
inc %al # ++sector
|
inc %al # ++sector
|
||||||
cmp 0x151c,%al # mman::pc_drive_last_sector
|
cmp 0x1d1c,%al # mman::pc_drive_last_sector
|
||||||
jbe 2f
|
jbe 2f
|
||||||
mov $1,%al
|
mov $1,%al
|
||||||
inc %dh # ++head
|
inc %dh # ++head
|
||||||
cmp 0x1520,%dh # mman::pc_drive_last_head
|
cmp 0x1d20,%dh # mman::pc_drive_last_head
|
||||||
jbe 2f
|
jbe 2f
|
||||||
xor %dh,%dh
|
xor %dh,%dh
|
||||||
inc %cx # ++cylinder
|
inc %cx # ++cylinder
|
||||||
|
@ -485,19 +485,19 @@ ape.mbrpad:
|
||||||
ape_disk:
|
ape_disk:
|
||||||
.stub ape.diskid,quad
|
.stub ape.diskid,quad
|
||||||
.org 0x1be,0x00
|
.org 0x1be,0x00
|
||||||
.macro .partn x
|
.macro .partn x:req sta h0 s0 c0 fs h9 s9 c9 lba0 nsec
|
||||||
.stub ape.part\x\().status,byte # 0=absent / 0x80=present
|
.stub ape.part\x\().status,byte,\sta # 0=non-boot / 0x80=active
|
||||||
.stub ape.part\x\().first.head,byte # in low 6 bits
|
.stub ape.part\x\().first.head,byte,\h0
|
||||||
.stub ape.part\x\().first.cylinder,byte
|
.stub ape.part\x\().first.sector,byte,\s0 # in low 6 bits
|
||||||
.stub ape.part\x\().first.sector,byte
|
.stub ape.part\x\().first.cylinder,byte,\c0
|
||||||
.stub ape.part\x\().filesystem,byte
|
.stub ape.part\x\().filesystem,byte,\fs
|
||||||
.stub ape.part\x\().last.head,byte
|
.stub ape.part\x\().last.head,byte,\h9
|
||||||
.stub ape.part\x\().last.cylinder,byte
|
.stub ape.part\x\().last.sector,byte,\s9
|
||||||
.stub ape.part\x\().last.sector,byte
|
.stub ape.part\x\().last.cylinder,byte,\c9
|
||||||
.stub ape.part\x\().lba,long # c₀*Cₙ + h₀*Hₙ + s₀*Sₙ
|
.stub ape.part\x\().lba,long,\lba0 # c₀*Cₙ + h₀*Hₙ + s₀*Sₙ
|
||||||
.stub ape.part\x\().sector.count,long # sectors are 512 bytes
|
.stub ape.part\x\().sector.count,long,\nsec # sectors are 512 bytes
|
||||||
.endm
|
.endm
|
||||||
.partn 1
|
.partn 1,0x80,0,1,0,0x7f,0xff,0xff,0xff,0,0xffffffff
|
||||||
.partn 2
|
.partn 2
|
||||||
.partn 3
|
.partn 3
|
||||||
.partn 4
|
.partn 4
|
||||||
|
@ -1291,27 +1291,38 @@ lcheck: pushf # check for i8086 / i8088 / i80186
|
||||||
// Gets memory map from BIOS.
|
// Gets memory map from BIOS.
|
||||||
e820: mov $0x0510>>4,%di # mman::e820
|
e820: mov $0x0510>>4,%di # mman::e820
|
||||||
mov %di,%es
|
mov %di,%es
|
||||||
xor %edi,%edi # es:di is destination buffer
|
xor %di,%di # es:di is destination buffer
|
||||||
xor %ebx,%ebx # ebx is an api state tracker
|
xor %ebx,%ebx # ebx is an api state tracker
|
||||||
1: mov $0xE820,%eax # magic
|
1: mov $0xE820,%eax # magic
|
||||||
mov $8+8+4+4,%ecx # sizeof(struct SmapEntry)
|
mov $8+8+4+4,%ecx # sizeof(struct SmapEntry)
|
||||||
mov $0x534d4150,%edx # magic number
|
mov $0x534d4150,%edx # magic number
|
||||||
|
movl $1,8+8+4/*SmapEntry::acpi3*/(%di) # prefill ACPI attributes;
|
||||||
|
# apparently some buggy BIOSes say
|
||||||
|
# that they return this field, yet
|
||||||
|
# do not fill it correctly
|
||||||
int $0x15 # ax,bx,cx,dx,di → ax,bx,cx
|
int $0x15 # ax,bx,cx,dx,di → ax,bx,cx
|
||||||
jc 9f # cf = unsupported or abuse
|
jc 9f # cf = unsupported or abuse
|
||||||
cmp %edx,%eax # more magic means success
|
cmp %edx,%eax # more magic means success
|
||||||
jne 9f
|
jne 9f
|
||||||
test %cx,%cx # discard empty results
|
test %cx,%cx # discard empty results
|
||||||
jz 5f
|
jz 5f
|
||||||
|
mov 8/*LODWORD(SmapEntry::size)*/(%di),%eax
|
||||||
|
or 8+4/*HIDWORD(SmapEntry::size)*/(%di),%eax
|
||||||
|
jz 5f
|
||||||
cmp $8+8+4+1,%cx # discard if ignore flag
|
cmp $8+8+4+1,%cx # discard if ignore flag
|
||||||
jb 4f
|
jb 4f
|
||||||
testb $1/*ignore*/,8+8+4/*SmapEntry::__acpi3*/(%di)
|
testb $1/*don't ignore*/,8+8+4/*SmapEntry::acpi3*/(%di)
|
||||||
jnz 5f
|
jz 5f
|
||||||
4: add $8+8+4+4,%di # keep entry
|
4: add $8+8+4+4,%di # keep entry
|
||||||
5: test %ebx,%ebx # last entry?
|
5: test %ebx,%ebx # last entry?
|
||||||
jz 8f
|
jz 8f
|
||||||
cmp $0x1000,%di
|
cmp $(256-1)*(8+8+4+4),%di
|
||||||
jb 1b
|
jb 1b
|
||||||
8: ret
|
8: xor %ax,%ax # add a blank sentinel entry
|
||||||
|
mov $(8+8)/2,%cx
|
||||||
|
cld
|
||||||
|
rep stosw
|
||||||
|
ret
|
||||||
9: mov $REAL(str.e820),%di
|
9: mov $REAL(str.e820),%di
|
||||||
call rldie
|
call rldie
|
||||||
.endfn e820
|
.endfn e820
|
||||||
|
@ -1381,9 +1392,16 @@ a20: cli
|
||||||
|
|
||||||
// Initializes long mode paging.
|
// Initializes long mode paging.
|
||||||
pinit: push %ds
|
pinit: push %ds
|
||||||
|
push %es
|
||||||
#define SEG 0x79000
|
#define SEG 0x79000
|
||||||
mov $SEG>>4,%ax
|
mov $SEG>>4,%ax
|
||||||
mov %ax,%ds
|
mov %ax,%ds
|
||||||
|
mov %ax,%es
|
||||||
|
xor %di,%di
|
||||||
|
xor %ax,%ax
|
||||||
|
mov $(0x7f000-SEG)/2,%cx
|
||||||
|
cld
|
||||||
|
rep stosw
|
||||||
movl $0x7d000+PAGE_V+PAGE_RW,0x7e000-SEG # PDPT←PML4T (+)
|
movl $0x7d000+PAGE_V+PAGE_RW,0x7e000-SEG # PDPT←PML4T (+)
|
||||||
movl $0x7c000+PAGE_V+PAGE_RW,0x7e800-SEG # PDPT←PML4T (-)
|
movl $0x7c000+PAGE_V+PAGE_RW,0x7e800-SEG # PDPT←PML4T (-)
|
||||||
movl $0x7b000+PAGE_V+PAGE_RW,0x7d000-SEG # PDT←PDPT (+)
|
movl $0x7b000+PAGE_V+PAGE_RW,0x7d000-SEG # PDT←PDPT (+)
|
||||||
|
@ -1392,13 +1410,14 @@ pinit: push %ds
|
||||||
movl $0x79000+PAGE_V+PAGE_RW,0x7a000-SEG # PD←PDT (-)
|
movl $0x79000+PAGE_V+PAGE_RW,0x7a000-SEG # PD←PDT (-)
|
||||||
mov $512,%cx # PD±2MB
|
mov $512,%cx # PD±2MB
|
||||||
mov $PAGE_V+PAGE_RW,%eax
|
mov $PAGE_V+PAGE_RW,%eax
|
||||||
xor %si,%si
|
xor %di,%di
|
||||||
0: mov %eax,(%si)
|
0: stosl
|
||||||
add $0x1000,%eax
|
add $0x1000,%eax
|
||||||
add $8,%si
|
scasl # di += 4
|
||||||
loop 0b
|
loop 0b
|
||||||
mov $0x7e000,%eax # PML4T←CR3
|
mov $0x7e000,%eax # PML4T←CR3
|
||||||
mov %eax,%cr3
|
mov %eax,%cr3
|
||||||
|
pop %es
|
||||||
pop %ds
|
pop %ds
|
||||||
ret
|
ret
|
||||||
.endfn pinit
|
.endfn pinit
|
||||||
|
@ -1407,7 +1426,7 @@ pinit: push %ds
|
||||||
//
|
//
|
||||||
// @see Intel Manual V3A §4.1.2
|
// @see Intel Manual V3A §4.1.2
|
||||||
golong: cli
|
golong: cli
|
||||||
lidt 0x1522 # mman::bad_idt
|
lidt 0x1d22 # mman::bad_idt
|
||||||
mov %cr4,%eax
|
mov %cr4,%eax
|
||||||
or $CR4_PAE|CR4_PGE|CR4_OSFXSR,%eax
|
or $CR4_PAE|CR4_PGE|CR4_OSFXSR,%eax
|
||||||
mov %eax,%cr4
|
mov %eax,%cr4
|
||||||
|
|
|
@ -74,6 +74,7 @@ noasan textreal uint64_t *__get_virtual(struct mman *mm, uint64_t *t,
|
||||||
if (!(*e & PAGE_V)) {
|
if (!(*e & PAGE_V)) {
|
||||||
if (!maketables) return NULL;
|
if (!maketables) return NULL;
|
||||||
if (!(p = __new_page(mm))) return NULL;
|
if (!(p = __new_page(mm))) return NULL;
|
||||||
|
__clear_page(BANE + p);
|
||||||
*e = p | PAGE_V | PAGE_RW;
|
*e = p | PAGE_V | PAGE_RW;
|
||||||
}
|
}
|
||||||
t = (uint64_t *)(BANE + (*e & PAGE_TA));
|
t = (uint64_t *)(BANE + (*e & PAGE_TA));
|
||||||
|
@ -117,7 +118,7 @@ static noasan textreal void __invert_memory(struct mman *mm, uint64_t *pml4t) {
|
||||||
uint64_t i, j, *m, p, pe;
|
uint64_t i, j, *m, p, pe;
|
||||||
for (i = 0; i < mm->e820n; ++i) {
|
for (i = 0; i < mm->e820n; ++i) {
|
||||||
for (p = mm->e820[i].addr, pe = mm->e820[i].addr + mm->e820[i].size;
|
for (p = mm->e820[i].addr, pe = mm->e820[i].addr + mm->e820[i].size;
|
||||||
p + 0x200000 < pe; p += 4096) {
|
p != pe + 0x200000; p += 4096) {
|
||||||
m = __get_virtual(mm, pml4t, BANE + p, true);
|
m = __get_virtual(mm, pml4t, BANE + p, true);
|
||||||
if (m && !(*m & PAGE_V)) {
|
if (m && !(*m & PAGE_V)) {
|
||||||
*m = p | PAGE_V | PAGE_RW;
|
*m = p | PAGE_V | PAGE_RW;
|
||||||
|
@ -150,7 +151,7 @@ noasan textreal void __map_phdrs(struct mman *mm, uint64_t *pml4t, uint64_t b) {
|
||||||
v = b + p->p_offset + i;
|
v = b + p->p_offset + i;
|
||||||
m = MAX(m, v);
|
m = MAX(m, v);
|
||||||
} else {
|
} else {
|
||||||
v = __clear_page(__new_page(mm));
|
v = __clear_page(BANE + __new_page(mm));
|
||||||
}
|
}
|
||||||
*__get_virtual(mm, pml4t, p->p_vaddr + i, true) = (v & PAGE_TA) | f;
|
*__get_virtual(mm, pml4t, p->p_vaddr + i, true) = (v & PAGE_TA) | f;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,16 +7,16 @@ COSMOPOLITAN_C_START_
|
||||||
struct mman {
|
struct mman {
|
||||||
int64_t pdp; /* 0x0500 */
|
int64_t pdp; /* 0x0500 */
|
||||||
int32_t pdpi; /* 0x0508 */
|
int32_t pdpi; /* 0x0508 */
|
||||||
int32_t e820n; /* 0x050a */
|
int32_t e820n; /* 0x050c */
|
||||||
struct SmapEntry e820[256]; /* 0x0510 */
|
struct SmapEntry e820[256]; /* 0x0510 */
|
||||||
char pc_drive_base_table[11]; /* 0x1510 */
|
char pc_drive_base_table[11]; /* 0x1d10 */
|
||||||
unsigned char pc_drive_type; /* 0x151b */
|
unsigned char pc_drive_type; /* 0x1d1b */
|
||||||
unsigned char pc_drive_last_sector; /* 0x151c */
|
unsigned char pc_drive_last_sector; /* 0x1d1c */
|
||||||
unsigned short pc_drive_last_cylinder; /* 0x151d */
|
unsigned short pc_drive_last_cylinder; /* 0x1d1d */
|
||||||
unsigned char pc_drives_attached; /* 0x151f */
|
unsigned char pc_drives_attached; /* 0x1d1f */
|
||||||
unsigned char pc_drive_last_head; /* 0x1520 */
|
unsigned char pc_drive_last_head; /* 0x1d20 */
|
||||||
unsigned char pc_drive; /* 0x1521 */
|
unsigned char pc_drive; /* 0x1d21 */
|
||||||
char bad_idt[6]; /* 0x1522 */
|
char bad_idt[6]; /* 0x1d22 */
|
||||||
};
|
};
|
||||||
|
|
||||||
COSMOPOLITAN_C_END_
|
COSMOPOLITAN_C_END_
|
||||||
|
|
Loading…
Reference in a new issue