* Remove legacy boot, MP, ACPI. * Disable SMP. * Modify startup: boot -> arch::init -> kmain. * Fix FrameAllocator on x86_64. * Remove kernel remap. * Alloc kernel heap at bss.master
parent
0437e5cb17
commit
0a9c294814
@ -1,173 +0,0 @@
|
|||||||
global start
|
|
||||||
global stack_bottom
|
|
||||||
global stack_top
|
|
||||||
extern long_mode_start
|
|
||||||
|
|
||||||
section .text
|
|
||||||
bits 32
|
|
||||||
start:
|
|
||||||
mov esp, stack_top
|
|
||||||
push ebx ; push Multiboot info pointer to stack_top
|
|
||||||
|
|
||||||
call check_multiboot
|
|
||||||
call check_cpuid
|
|
||||||
call check_long_mode
|
|
||||||
|
|
||||||
call set_up_page_tables
|
|
||||||
call enable_paging
|
|
||||||
|
|
||||||
; load the 64-bit GDT
|
|
||||||
lgdt [gdt64.pointer]
|
|
||||||
|
|
||||||
jmp gdt64.code:long_mode_start
|
|
||||||
|
|
||||||
; print `OK` to screen
|
|
||||||
mov dword [0xb8000], 0x2f4b2f4f
|
|
||||||
hlt
|
|
||||||
|
|
||||||
check_multiboot:
|
|
||||||
cmp eax, 0x36d76289
|
|
||||||
jne .no_multiboot
|
|
||||||
ret
|
|
||||||
.no_multiboot:
|
|
||||||
mov al, "0"
|
|
||||||
jmp error
|
|
||||||
|
|
||||||
check_cpuid:
|
|
||||||
; Check if CPUID is supported by attempting to flip the ID bit (bit 21)
|
|
||||||
; in the FLAGS register. If we can flip it, CPUID is available.
|
|
||||||
|
|
||||||
; Copy FLAGS in to EAX via stack
|
|
||||||
pushfd
|
|
||||||
pop eax
|
|
||||||
|
|
||||||
; Copy to ECX as well for comparing later on
|
|
||||||
mov ecx, eax
|
|
||||||
|
|
||||||
; Flip the ID bit
|
|
||||||
xor eax, 1 << 21
|
|
||||||
|
|
||||||
; Copy EAX to FLAGS via the stack
|
|
||||||
push eax
|
|
||||||
popfd
|
|
||||||
|
|
||||||
; Copy FLAGS back to EAX (with the flipped bit if CPUID is supported)
|
|
||||||
pushfd
|
|
||||||
pop eax
|
|
||||||
|
|
||||||
; Restore FLAGS from the old version stored in ECX (i.e. flipping the
|
|
||||||
; ID bit back if it was ever flipped).
|
|
||||||
push ecx
|
|
||||||
popfd
|
|
||||||
|
|
||||||
; Compare EAX and ECX. If they are equal then that means the bit
|
|
||||||
; wasn't flipped, and CPUID isn't supported.
|
|
||||||
cmp eax, ecx
|
|
||||||
je .no_cpuid
|
|
||||||
ret
|
|
||||||
.no_cpuid:
|
|
||||||
mov al, "1"
|
|
||||||
jmp error
|
|
||||||
|
|
||||||
check_long_mode:
|
|
||||||
; test if extended processor info in available
|
|
||||||
mov eax, 0x80000000 ; implicit argument for cpuid
|
|
||||||
cpuid ; get highest supported argument
|
|
||||||
cmp eax, 0x80000001 ; it needs to be at least 0x80000001
|
|
||||||
jb .no_long_mode ; if it's less, the CPU is too old for long mode
|
|
||||||
|
|
||||||
; use extended info to test if long mode is available
|
|
||||||
mov eax, 0x80000001 ; argument for extended processor info
|
|
||||||
cpuid ; returns various feature bits in ecx and edx
|
|
||||||
test edx, 1 << 29 ; test if the LM-bit is set in the D-register
|
|
||||||
jz .no_long_mode ; If it's not set, there is no long mode
|
|
||||||
ret
|
|
||||||
.no_long_mode:
|
|
||||||
mov al, "2"
|
|
||||||
jmp error
|
|
||||||
|
|
||||||
set_up_page_tables:
|
|
||||||
; map P4 table recursively
|
|
||||||
mov eax, p4_table
|
|
||||||
or eax, 0b11 ; present + writable
|
|
||||||
mov [p4_table + 511 * 8], eax
|
|
||||||
|
|
||||||
; map first & 510th P4 entry to P3 table
|
|
||||||
mov eax, p3_table
|
|
||||||
or eax, 0b11 ; present + writable
|
|
||||||
mov [p4_table], eax
|
|
||||||
mov [p4_table + 510 * 8], eax
|
|
||||||
|
|
||||||
; map first P3 entry to P2 table
|
|
||||||
mov eax, p2_table
|
|
||||||
or eax, 0b11 ; present + writable
|
|
||||||
mov [p3_table], eax
|
|
||||||
|
|
||||||
; map each P2 entry to a huge 2MiB page
|
|
||||||
mov ecx, 0 ; counter variable
|
|
||||||
|
|
||||||
.map_p2_table:
|
|
||||||
; map ecx-th P2 entry to a huge page that starts at address 2MiB*ecx
|
|
||||||
mov eax, 0x200000 ; 2MiB
|
|
||||||
mul ecx ; start address of ecx-th page
|
|
||||||
or eax, 0b10000011 ; present + writable + huge
|
|
||||||
mov [p2_table + ecx * 8], eax ; map ecx-th entry
|
|
||||||
|
|
||||||
inc ecx ; increase counter
|
|
||||||
cmp ecx, 512 ; if counter == 512, the whole P2 table is mapped
|
|
||||||
jne .map_p2_table ; else map the next entry
|
|
||||||
|
|
||||||
ret
|
|
||||||
|
|
||||||
enable_paging:
|
|
||||||
; load P4 to cr3 register (cpu uses this to access the P4 table)
|
|
||||||
mov eax, p4_table
|
|
||||||
mov cr3, eax
|
|
||||||
|
|
||||||
; enable PAE-flag in cr4 (Physical Address Extension)
|
|
||||||
mov eax, cr4
|
|
||||||
or eax, 1 << 5
|
|
||||||
mov cr4, eax
|
|
||||||
|
|
||||||
; set the long mode bit & no execute bit in the EFER MSR (model specific register)
|
|
||||||
mov ecx, 0xC0000080
|
|
||||||
rdmsr
|
|
||||||
or eax, 1 << 8 | 1 << 11
|
|
||||||
wrmsr
|
|
||||||
|
|
||||||
; enable paging & write protect in the cr0 register
|
|
||||||
mov eax, cr0
|
|
||||||
or eax, 1 << 31 | 1 << 16
|
|
||||||
mov cr0, eax
|
|
||||||
|
|
||||||
ret
|
|
||||||
|
|
||||||
; Prints `ERR: ` and the given error code to screen and hangs.
|
|
||||||
; parameter: error code (in ascii) in al
|
|
||||||
error:
|
|
||||||
mov dword [0xb8000], 0x4f524f45
|
|
||||||
mov dword [0xb8004], 0x4f3a4f52
|
|
||||||
mov dword [0xb8008], 0x4f204f20
|
|
||||||
mov byte [0xb800a], al
|
|
||||||
hlt
|
|
||||||
|
|
||||||
section .bss
|
|
||||||
align 4096
|
|
||||||
p4_table:
|
|
||||||
resb 4096
|
|
||||||
p3_table:
|
|
||||||
resb 4096
|
|
||||||
p2_table:
|
|
||||||
resb 4096
|
|
||||||
stack_bottom:
|
|
||||||
resb 4096 * 8
|
|
||||||
stack_top:
|
|
||||||
|
|
||||||
section .rodata
|
|
||||||
gdt64:
|
|
||||||
dq 0 ; zero entry
|
|
||||||
.code: equ $ - gdt64 ; new
|
|
||||||
dq (1<<43) | (1<<44) | (1<<47) | (1<<53) ; code segment
|
|
||||||
.pointer:
|
|
||||||
dw $ - gdt64 - 1
|
|
||||||
dq gdt64
|
|
@ -1,141 +0,0 @@
|
|||||||
; xv6 x86_64 entryother.S
|
|
||||||
|
|
||||||
; Each non-boot CPU ("AP") is started up in response to a STARTUP
|
|
||||||
; IPI from the boot CPU. Section B.4.2 of the Multi-Processor
|
|
||||||
; Specification says that the AP will start in real mode with CS:IP
|
|
||||||
; set to XY00:0000, where XY is an 8-bit value sent with the
|
|
||||||
; STARTUP. Thus this code must start at a 4096-byte boundary.
|
|
||||||
;
|
|
||||||
; Because this code sets DS to zero, it must sit
|
|
||||||
; at an address in the low 2^16 bytes.
|
|
||||||
;
|
|
||||||
; Startothers (in main.c) sends the STARTUPs one at a time.
|
|
||||||
; It copies this code (start) at 0x7000. It puts the address of
|
|
||||||
; a newly allocated per-core stack in start-4,the address of the
|
|
||||||
; place to jump to (mpenter) in start-8, and the physical address
|
|
||||||
; of entrypgdir in start-12.
|
|
||||||
;
|
|
||||||
; This code is identical to bootasm.S except:
|
|
||||||
; - it does not need to enable A20
|
|
||||||
; - it uses the address at start-4, start-8, and start-12
|
|
||||||
|
|
||||||
%define CR0_PE 1
|
|
||||||
%define STA_X 0x8 ; Executable segment
|
|
||||||
%define STA_E 0x4 ; Expand down (non-executable segments)
|
|
||||||
%define STA_C 0x4 ; Conforming code segment (executable only)
|
|
||||||
%define STA_W 0x2 ; Writeable (non-executable segments)
|
|
||||||
%define STA_R 0x2 ; Readable (executable segments)
|
|
||||||
%define STA_A 0x1 ; Accessed
|
|
||||||
|
|
||||||
extern other_main
|
|
||||||
|
|
||||||
section .text
|
|
||||||
bits 16
|
|
||||||
start:
|
|
||||||
cli
|
|
||||||
|
|
||||||
xor ax, ax
|
|
||||||
mov ds, ax
|
|
||||||
mov es, ax
|
|
||||||
mov ss, ax
|
|
||||||
|
|
||||||
lgdt [gdt.desc]
|
|
||||||
mov eax, cr0
|
|
||||||
or eax, CR0_PE
|
|
||||||
mov cr0, eax
|
|
||||||
|
|
||||||
jmp gdt.code: start32
|
|
||||||
|
|
||||||
bits 32
|
|
||||||
start32:
|
|
||||||
mov ax, gdt.data
|
|
||||||
mov ds, ax
|
|
||||||
mov es, ax
|
|
||||||
mov ss, ax
|
|
||||||
mov ax, 0
|
|
||||||
mov fs, ax
|
|
||||||
mov gs, ax
|
|
||||||
|
|
||||||
; Switch to the stack allocated by startothers()
|
|
||||||
mov esp, [top - 4]
|
|
||||||
|
|
||||||
call enable_paging
|
|
||||||
|
|
||||||
; load the 64-bit GDT
|
|
||||||
lgdt [gdt64.pointer]
|
|
||||||
|
|
||||||
jmp gdt64.code: start64
|
|
||||||
|
|
||||||
error:
|
|
||||||
mov ax, 0x8a00
|
|
||||||
mov dx, ax
|
|
||||||
out dx, ax
|
|
||||||
mov ax, 0x8ae0
|
|
||||||
out dx, ax
|
|
||||||
spin:
|
|
||||||
jmp spin
|
|
||||||
|
|
||||||
enable_paging:
|
|
||||||
; load P4 to cr3 register (cpu uses this to access the P4 table)
|
|
||||||
mov eax, [top - 8]
|
|
||||||
mov cr3, eax
|
|
||||||
|
|
||||||
; enable PAE-flag in cr4 (Physical Address Extension)
|
|
||||||
mov eax, cr4
|
|
||||||
or eax, 1 << 5
|
|
||||||
mov cr4, eax
|
|
||||||
|
|
||||||
; set the long mode bit & no execute bit in the EFER MSR (model specific register)
|
|
||||||
mov ecx, 0xC0000080
|
|
||||||
rdmsr
|
|
||||||
or eax, 1 << 8 | 1 << 11
|
|
||||||
wrmsr
|
|
||||||
|
|
||||||
; enable paging & write protect in the cr0 register
|
|
||||||
mov eax, cr0
|
|
||||||
or eax, 1 << 31 | 1 << 16
|
|
||||||
mov cr0, eax
|
|
||||||
|
|
||||||
ret
|
|
||||||
|
|
||||||
bits 64
|
|
||||||
start64:
|
|
||||||
; load 0 into all data segment registers
|
|
||||||
mov ax, 0
|
|
||||||
mov ss, ax
|
|
||||||
mov ds, ax
|
|
||||||
mov es, ax
|
|
||||||
mov fs, ax
|
|
||||||
mov gs, ax
|
|
||||||
|
|
||||||
; obtain kstack from data block before entryother
|
|
||||||
mov rsp, [top - 16]
|
|
||||||
|
|
||||||
mov rax, other_main
|
|
||||||
call rax
|
|
||||||
|
|
||||||
; section .rodata
|
|
||||||
align 4
|
|
||||||
gdt:
|
|
||||||
; NULL
|
|
||||||
dw 0, 0
|
|
||||||
db 0, 0, 0, 0
|
|
||||||
.code: equ $ - gdt
|
|
||||||
dw 0xffff, 0
|
|
||||||
db 0, (0x90 | STA_X | STA_R), 0xcf, 0
|
|
||||||
.data: equ $ - gdt
|
|
||||||
dw 0xffff, 0
|
|
||||||
db 0, (0x90 | STA_W), 0xcf, 0
|
|
||||||
.desc:
|
|
||||||
dw $ - gdt - 1
|
|
||||||
dq gdt
|
|
||||||
|
|
||||||
gdt64:
|
|
||||||
dq 0 ; zero entry
|
|
||||||
.code: equ $ - gdt64 ; new
|
|
||||||
dq (1<<43) | (1<<44) | (1<<47) | (1<<53) ; code segment
|
|
||||||
.pointer:
|
|
||||||
dw $ - gdt64 - 1
|
|
||||||
dq gdt64
|
|
||||||
|
|
||||||
top: equ start + 0x1000
|
|
@ -1,7 +0,0 @@
|
|||||||
set timeout=0
|
|
||||||
set default=0
|
|
||||||
|
|
||||||
menuentry "my os" {
|
|
||||||
multiboot2 /boot/kernel.bin
|
|
||||||
boot
|
|
||||||
}
|
|
@ -1,104 +0,0 @@
|
|||||||
ENTRY(start)
|
|
||||||
|
|
||||||
OTHER_OFFSET = 0x7000;
|
|
||||||
BOOT_OFFSET = 0x100000;
|
|
||||||
KERNEL_OFFSET = 0xffffff0000000000;
|
|
||||||
|
|
||||||
SECTIONS {
|
|
||||||
|
|
||||||
/* ensure that the multiboot header is at the beginning */
|
|
||||||
|
|
||||||
.multiboot_header :
|
|
||||||
{
|
|
||||||
KEEP(*(.multiboot_header))
|
|
||||||
}
|
|
||||||
|
|
||||||
/* bootloader for other processors */
|
|
||||||
|
|
||||||
. = OTHER_OFFSET;
|
|
||||||
|
|
||||||
.text.other : AT(OTHER_OFFSET)
|
|
||||||
{
|
|
||||||
KEEP(*/entryother.o (.text))
|
|
||||||
. = ALIGN(4K);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* bootloader for first processor */
|
|
||||||
|
|
||||||
. = BOOT_OFFSET;
|
|
||||||
|
|
||||||
.rodata.32 :
|
|
||||||
{
|
|
||||||
*/boot.o (.rodata)
|
|
||||||
. = ALIGN(4K);
|
|
||||||
}
|
|
||||||
.text.32 :
|
|
||||||
{
|
|
||||||
*/boot.o (.text)
|
|
||||||
*/long_mode_init.o (.text)
|
|
||||||
. = ALIGN(4K);
|
|
||||||
}
|
|
||||||
.bss.32 :
|
|
||||||
{
|
|
||||||
*/boot.o (.bss)
|
|
||||||
. = ALIGN(4K);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* kernel */
|
|
||||||
|
|
||||||
. += KERNEL_OFFSET;
|
|
||||||
|
|
||||||
.user ALIGN(4K): AT(ADDR(.user) - KERNEL_OFFSET)
|
|
||||||
{
|
|
||||||
KEEP(user/*.o (.data))
|
|
||||||
. = ALIGN(4K);
|
|
||||||
}
|
|
||||||
|
|
||||||
.rodata : AT(ADDR(.rodata) - KERNEL_OFFSET)
|
|
||||||
{
|
|
||||||
*(.rodata .rodata.*)
|
|
||||||
. = ALIGN(4K);
|
|
||||||
}
|
|
||||||
|
|
||||||
.text : AT(ADDR(.text) - KERNEL_OFFSET)
|
|
||||||
{
|
|
||||||
*(.text .text.*)
|
|
||||||
. = ALIGN(4K);
|
|
||||||
}
|
|
||||||
|
|
||||||
.data : AT(ADDR(.data) - KERNEL_OFFSET)
|
|
||||||
{
|
|
||||||
*(.data .data.*)
|
|
||||||
. = ALIGN(4K);
|
|
||||||
}
|
|
||||||
|
|
||||||
.bss ALIGN(4K): AT(ADDR(.bss) - KERNEL_OFFSET)
|
|
||||||
{
|
|
||||||
*(.bss .bss.*)
|
|
||||||
. = ALIGN(4K);
|
|
||||||
}
|
|
||||||
|
|
||||||
.got ALIGN(4K): AT(ADDR(.got) - KERNEL_OFFSET)
|
|
||||||
{
|
|
||||||
*(.got)
|
|
||||||
. = ALIGN(4K);
|
|
||||||
}
|
|
||||||
|
|
||||||
.got.plt : AT(ADDR(.got.plt) - KERNEL_OFFSET)
|
|
||||||
{
|
|
||||||
*(.got.plt)
|
|
||||||
. = ALIGN(4K);
|
|
||||||
}
|
|
||||||
|
|
||||||
.data.rel.ro : AT(ADDR(.data.rel.ro) - KERNEL_OFFSET)
|
|
||||||
{
|
|
||||||
*(.data.rel.ro.local*) *(.data.rel.ro .data.rel.ro.*)
|
|
||||||
. = ALIGN(4K);
|
|
||||||
}
|
|
||||||
|
|
||||||
.gcc_except_table : AT(ADDR(.gcc_except_table) - KERNEL_OFFSET)
|
|
||||||
{
|
|
||||||
*(.gcc_except_table)
|
|
||||||
. = ALIGN(4K);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,29 +0,0 @@
|
|||||||
global long_mode_start
|
|
||||||
extern rust_main
|
|
||||||
|
|
||||||
KERNEL_OFFSET equ 0xffff_ff00_0000_0000
|
|
||||||
|
|
||||||
section .text
|
|
||||||
bits 64
|
|
||||||
long_mode_start:
|
|
||||||
; load 0 into all data segment registers
|
|
||||||
mov ax, 0
|
|
||||||
mov ss, ax
|
|
||||||
mov ds, ax
|
|
||||||
mov es, ax
|
|
||||||
mov fs, ax
|
|
||||||
mov gs, ax
|
|
||||||
|
|
||||||
; translate rsp to virtual address
|
|
||||||
mov rax, KERNEL_OFFSET
|
|
||||||
add rsp, rax
|
|
||||||
|
|
||||||
; call the rust main
|
|
||||||
extern rust_main
|
|
||||||
mov rax, rust_main
|
|
||||||
call rax
|
|
||||||
|
|
||||||
; print `OKAY` to screen
|
|
||||||
mov rax, 0x2f592f412f4b2f4f
|
|
||||||
mov qword [0xb8000], rax
|
|
||||||
hlt
|
|
@ -1,15 +0,0 @@
|
|||||||
section .multiboot_header
|
|
||||||
header_start:
|
|
||||||
dd 0xe85250d6 ; magic number (multiboot 2)
|
|
||||||
dd 0 ; architecture 0 (protected mode i386)
|
|
||||||
dd header_end - header_start ; header length
|
|
||||||
; checksum
|
|
||||||
dd 0x100000000 - (0xe85250d6 + 0 + (header_end - header_start))
|
|
||||||
|
|
||||||
; insert optional multiboot tags here
|
|
||||||
|
|
||||||
; required end tag
|
|
||||||
dw 0 ; type
|
|
||||||
dw 0 ; flags
|
|
||||||
dd 8 ; size
|
|
||||||
header_end:
|
|
@ -1,61 +0,0 @@
|
|||||||
// Migrate from xv6-x86_64 acpi.c
|
|
||||||
|
|
||||||
mod structs;
|
|
||||||
use self::structs::*;
|
|
||||||
use consts::*;
|
|
||||||
|
|
||||||
pub fn init(rsdt_addr: usize) -> Result<AcpiResult, AcpiError> {
|
|
||||||
let rsdt = unsafe { &*(rsdt_addr as *const Rsdt) };
|
|
||||||
let mut madt: Option<&'static Madt> = None;
|
|
||||||
for i in 0 .. rsdt.entry_count() {
|
|
||||||
let entry = rsdt.entry_at(i);
|
|
||||||
let header = unsafe{ &*(entry as *const Header) };
|
|
||||||
trace!("{:?}", header);
|
|
||||||
if &header.signature == b"APIC" {
|
|
||||||
madt = Some(unsafe{ &*(entry as *const Madt) });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
trace!("{:?}", madt);
|
|
||||||
config_smp(madt.expect("acpi: madt not found."))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct AcpiResult {
|
|
||||||
pub cpu_num: u8,
|
|
||||||
pub cpu_acpi_ids: [u8; MAX_CPU_NUM],
|
|
||||||
pub ioapic_id: u8,
|
|
||||||
pub lapic_addr: *const (),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum AcpiError {
|
|
||||||
NotMapped,
|
|
||||||
IoacpiNotFound,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn config_smp(madt: &'static Madt) -> Result<AcpiResult, AcpiError> {
|
|
||||||
let lapic_addr = madt.lapic_address as *const ();
|
|
||||||
|
|
||||||
let mut cpu_num = 0u8;
|
|
||||||
let mut cpu_acpi_ids: [u8; MAX_CPU_NUM] = [0; MAX_CPU_NUM];
|
|
||||||
let mut ioapic_id: Option<u8> = None;
|
|
||||||
for entry in madt.entry_iter() {
|
|
||||||
trace!("{:?}", entry);
|
|
||||||
match &entry {
|
|
||||||
&MadtEntry::LocalApic(ref lapic) => {
|
|
||||||
cpu_acpi_ids[cpu_num as usize] = lapic.id;
|
|
||||||
cpu_num += 1;
|
|
||||||
},
|
|
||||||
&MadtEntry::IoApic(ref ioapic) => {
|
|
||||||
ioapic_id = Some(ioapic.id);
|
|
||||||
},
|
|
||||||
_ => {},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ioapic_id.is_none() {
|
|
||||||
return Err(AcpiError::IoacpiNotFound);
|
|
||||||
}
|
|
||||||
let ioapic_id = ioapic_id.unwrap();
|
|
||||||
Ok(AcpiResult { cpu_num, cpu_acpi_ids, ioapic_id, lapic_addr })
|
|
||||||
}
|
|
@ -1,141 +0,0 @@
|
|||||||
// Reference: xv6-x86_64 acpi.h
|
|
||||||
// Copy from crate 'acpica-sys'
|
|
||||||
|
|
||||||
use util::{Checkable, bytes_sum};
|
|
||||||
use core::mem::size_of;
|
|
||||||
|
|
||||||
#[repr(C)]
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct Rsdp {
|
|
||||||
pub signature: [u8; 8],
|
|
||||||
pub checksum: u8,
|
|
||||||
pub oem_id: [i8; 6],
|
|
||||||
pub revision: u8,
|
|
||||||
pub rsdt_physical_address: u32,
|
|
||||||
pub length: u32,
|
|
||||||
pub xsdt_physical_address: u64,
|
|
||||||
pub extended_checksum: u8,
|
|
||||||
pub reserved: [u8; 3],
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Checkable for Rsdp {
|
|
||||||
fn check(&self) -> bool {
|
|
||||||
&self.signature == b"RSD PTR " && bytes_sum(self) == 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[repr(C)]
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct Header {
|
|
||||||
pub signature: [u8; 4],
|
|
||||||
pub length: u32,
|
|
||||||
pub revision: u8,
|
|
||||||
pub checksum: u8,
|
|
||||||
pub oem_id: [i8; 6],
|
|
||||||
pub oem_table_id: [i8; 8],
|
|
||||||
pub oem_revision: u32,
|
|
||||||
pub asl_compiler_id: [i8; 4],
|
|
||||||
pub asl_compiler_revision: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[repr(C)]
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct Rsdt {
|
|
||||||
pub header: Header,
|
|
||||||
table_offset_entry: [u32; 0],
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Rsdt {
|
|
||||||
pub fn entry_count(&self) -> usize {
|
|
||||||
(self.header.length as usize - size_of::<Self>()) / 4
|
|
||||||
}
|
|
||||||
pub fn entry_at(&self, id: usize) -> u32 {
|
|
||||||
assert!(id < self.entry_count());
|
|
||||||
unsafe {
|
|
||||||
let p = (self as *const Self).offset(1) as *const u32;
|
|
||||||
*(p.offset(id as isize))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[repr(C)]
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct Madt {
|
|
||||||
pub header: Header,
|
|
||||||
pub lapic_address: u32,
|
|
||||||
pub flags: u32,
|
|
||||||
table: [u32; 0],
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Checkable for Madt {
|
|
||||||
fn check(&self) -> bool {
|
|
||||||
&self.header.signature == b"APIC" && self.header.length >= size_of::<Self>() as u32
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum MadtEntry {
|
|
||||||
Unknown(MadtEntryUnknown),
|
|
||||||
LocalApic(MadtEntryLocalApic),
|
|
||||||
IoApic(MadtEntryIoApic),
|
|
||||||
}
|
|
||||||
#[repr(C)]
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct MadtEntryUnknown {
|
|
||||||
pub type_: u8,
|
|
||||||
pub length: u8,
|
|
||||||
}
|
|
||||||
#[repr(C)]
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct MadtEntryLocalApic {
|
|
||||||
pub type_: u8, // 0
|
|
||||||
pub length: u8,
|
|
||||||
pub processor_id: u8,
|
|
||||||
pub id: u8,
|
|
||||||
pub lapic_flags: u32,
|
|
||||||
}
|
|
||||||
#[repr(C)]
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct MadtEntryIoApic {
|
|
||||||
pub type_: u8, // 1
|
|
||||||
pub length: u8,
|
|
||||||
pub id: u8,
|
|
||||||
pub reserved: u8,
|
|
||||||
pub address: u32,
|
|
||||||
pub global_irq_base: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct MadtEntryIter<'a> {
|
|
||||||
madt: &'a Madt,
|
|
||||||
ptr: *const u8,
|
|
||||||
end_ptr: *const u8,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Madt {
|
|
||||||
pub fn entry_iter(&self) -> MadtEntryIter {
|
|
||||||
let ptr = unsafe{ (self as *const Self).offset(1) } as *const u8;
|
|
||||||
let end_ptr = unsafe{ ptr.offset(self.header.length as isize) };
|
|
||||||
MadtEntryIter { madt: self, ptr, end_ptr }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Iterator for MadtEntryIter<'a> {
|
|
||||||
type Item = MadtEntry;
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
|
||||||
if self.ptr >= self.end_ptr {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
unsafe {
|
|
||||||
let type_id = *self.ptr.offset(0);
|
|
||||||
let len = *self.ptr.offset(1);
|
|
||||||
let ret = Some(match type_id {
|
|
||||||
0 => MadtEntry::LocalApic( (&*(self.ptr as *const MadtEntryLocalApic)).clone() ),
|
|
||||||
1 => MadtEntry::IoApic( (&*(self.ptr as *const MadtEntryIoApic)).clone() ),
|
|
||||||
_ => MadtEntry::Unknown( (&*(self.ptr as *const MadtEntryUnknown)).clone() ),
|
|
||||||
});
|
|
||||||
self.ptr = self.ptr.offset(len as isize);
|
|
||||||
ret
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,31 +1,23 @@
|
|||||||
extern crate syscall as redox_syscall;
|
extern crate syscall as redox_syscall;
|
||||||
|
|
||||||
pub mod vga;
|
pub mod vga;
|
||||||
pub mod acpi;
|
|
||||||
pub mod apic;
|
pub mod apic;
|
||||||
pub mod mp;
|
|
||||||
pub mod serial;
|
pub mod serial;
|
||||||
pub mod pic;
|
pub mod pic;
|
||||||
pub mod keyboard;
|
pub mod keyboard;
|
||||||
pub mod pit;
|
pub mod pit;
|
||||||
pub mod ide;
|
pub mod ide;
|
||||||
|
|
||||||
pub fn init(rsdt_addr: usize) -> acpi::AcpiResult {
|
pub fn init() {
|
||||||
assert_has_not_been_called!();
|
assert_has_not_been_called!();
|
||||||
|
|
||||||
let acpi = acpi::init(rsdt_addr).expect("Failed to init ACPI");
|
|
||||||
assert_eq!(acpi.lapic_addr as usize, 0xfee00000);
|
|
||||||
trace!("acpi = {:?}", acpi);
|
|
||||||
|
|
||||||
if cfg!(feature = "use_apic") {
|
if cfg!(feature = "use_apic") {
|
||||||
pic::disable();
|
pic::disable();
|
||||||
use consts::KERNEL_OFFSET;
|
apic::init();
|
||||||
apic::init((KERNEL_OFFSET + 0xfee00000) as *const (), acpi.ioapic_id);
|
|
||||||
} else {
|
} else {
|
||||||
pic::init();
|
pic::init();
|
||||||
}
|
}
|
||||||
pit::init();
|
pit::init();
|
||||||
serial::init();
|
serial::init();
|
||||||
keyboard::init();
|
keyboard::init();
|
||||||
acpi
|
|
||||||
}
|
}
|
@ -1,113 +0,0 @@
|
|||||||
// Migrate from xv6 mp.c
|
|
||||||
|
|
||||||
// Multiprocessor support
|
|
||||||
// Search memory for MP description structures.
|
|
||||||
// http://developer.intel.com/design/pentium/datashts/24201606.pdf
|
|
||||||
|
|
||||||
mod structs;
|
|
||||||
use self::structs::*;
|
|
||||||
|
|
||||||
/// Search for the MP Floating Pointer Structure, which according to the
|
|
||||||
/// spec is in one of the following three locations:
|
|
||||||
/// 1) in the first KB of the EBDA;
|
|
||||||
/// 2) in the last KB of system base memory;
|
|
||||||
/// 3) in the BIOS ROM address space between 0F0000h and 0FFFFFh.
|
|
||||||
pub fn find_mp() -> Option<*const MP>
|
|
||||||
{
|
|
||||||
use core::mem::size_of;
|
|
||||||
use util::find_in_memory;
|
|
||||||
let ebda = unsafe { *(0x40E as *const u16) as usize } << 4;
|
|
||||||
if ebda != 0 {
|
|
||||||
let res = unsafe{ find_in_memory::<MP>(ebda, 1024, size_of::<MP>()) };
|
|
||||||
if let Some(addr) = res {
|
|
||||||
return Some(addr as *const MP);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let p = unsafe { *(0x413 as *const u16) as usize } << 10;
|
|
||||||
let res = unsafe{ find_in_memory::<MP>(p-1024, 1024, size_of::<MP>()) };
|
|
||||||
if let Some(addr) = res {
|
|
||||||
return Some(addr as *const MP);
|
|
||||||
}
|
|
||||||
let res = unsafe{ find_in_memory::<MP>(0xF0000, 0x10000, size_of::<MP>()) };
|
|
||||||
res.map(|addr| addr as *const MP)
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
struct cpu cpus[NCPU];
|
|
||||||
int ncpu;
|
|
||||||
uchar ioapicid;
|
|
||||||
|
|
||||||
// Search for an MP configuration table. For now,
|
|
||||||
// don't accept the default configurations (physaddr == 0).
|
|
||||||
// Check for correct signature, calculate the checksum and,
|
|
||||||
// if correct, check the version.
|
|
||||||
// To do: check extended table checksum.
|
|
||||||
static struct mpconf*
|
|
||||||
mpconfig(struct mp **pmp)
|
|
||||||
{
|
|
||||||
struct mpconf *conf;
|
|
||||||
struct mp *mp;
|
|
||||||
|
|
||||||
if((mp = mpsearch()) == 0 || mp->physaddr == 0)
|
|
||||||
return 0;
|
|
||||||
conf = (struct mpconf*) P2V((uint) mp->physaddr);
|
|
||||||
if(memcmp(conf, "PCMP", 4) != 0)
|
|
||||||
return 0;
|
|
||||||
if(conf->version != 1 && conf->version != 4)
|
|
||||||
return 0;
|
|
||||||
if(sum((uchar*)conf, conf->length) != 0)
|
|
||||||
return 0;
|
|
||||||
*pmp = mp;
|
|
||||||
return conf;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
mpinit(void)
|
|
||||||
{
|
|
||||||
uchar *p, *e;
|
|
||||||
int ismp;
|
|
||||||
struct mp *mp;
|
|
||||||
struct mpconf *conf;
|
|
||||||
struct mpproc *proc;
|
|
||||||
struct mpioapic *ioapic;
|
|
||||||
|
|
||||||
if((conf = mpconfig(&mp)) == 0)
|
|
||||||
panic("Expect to run on an SMP");
|
|
||||||
ismp = 1;
|
|
||||||
lapic = (uint*)conf->lapicaddr;
|
|
||||||
for(p=(uchar*)(conf+1), e=(uchar*)conf+conf->length; p<e; ){
|
|
||||||
switch(*p){
|
|
||||||
case MPPROC:
|
|
||||||
proc = (struct mpproc*)p;
|
|
||||||
if(ncpu < NCPU) {
|
|
||||||
cpus[ncpu].apicid = proc->apicid; // apicid may differ from ncpu
|
|
||||||
ncpu++;
|
|
||||||
}
|
|
||||||
p += sizeof(struct mpproc);
|
|
||||||
continue;
|
|
||||||
case MPIOAPIC:
|
|
||||||
ioapic = (struct mpioapic*)p;
|
|
||||||
ioapicid = ioapic->apicno;
|
|
||||||
p += sizeof(struct mpioapic);
|
|
||||||
continue;
|
|
||||||
case MPBUS:
|
|
||||||
case MPIOINTR:
|
|
||||||
case MPLINTR:
|
|
||||||
p += 8;
|
|
||||||
continue;
|
|
||||||
default:
|
|
||||||
ismp = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(!ismp)
|
|
||||||
panic("Didn't find a suitable machine");
|
|
||||||
|
|
||||||
if(mp->imcrp){
|
|
||||||
// Bochs doesn't support IMCR, so this doesn't run on Bochs.
|
|
||||||
// But it would on real hardware.
|
|
||||||
outb(0x22, 0x70); // Select IMCR
|
|
||||||
outb(0x23, inb(0x23) | 1); // Mask external interrupts.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
@ -1,74 +0,0 @@
|
|||||||
// Migrate from xv6 mp.h
|
|
||||||
|
|
||||||
// See MultiProcessor Specification Version 1.[14]
|
|
||||||
|
|
||||||
use util::{Checkable, bytes_sum};
|
|
||||||
|
|
||||||
#[repr(C)]
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct MP { // floating pointer
|
|
||||||
signature: [u8; 4], // "_MP_"
|
|
||||||
physaddr: u32, // phys addr of MP config table
|
|
||||||
length: u8, // 1
|
|
||||||
specrev: u8, // [14]
|
|
||||||
checksum: u8, // all bytes must add up to 0
|
|
||||||
type_: u8, // MP system config type
|
|
||||||
imcrp: u8,
|
|
||||||
reserved: [u8; 3],
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Checkable for MP {
|
|
||||||
fn check(&self) -> bool {
|
|
||||||
&self.signature == b"_MP_" && bytes_sum(self) == 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
|
|
||||||
#[repr(C)]
|
|
||||||
struct mpconf { // configuration table header
|
|
||||||
signature: [byte; 4]; // "PCMP"
|
|
||||||
length: u16, // total table length
|
|
||||||
version: u8, // [14]
|
|
||||||
checksum: u8, // all bytes must add up to 0
|
|
||||||
product: [u8; 20], // product id
|
|
||||||
uint *oemtable, // OEM table pointer
|
|
||||||
ushort oemlength, // OEM table length
|
|
||||||
ushort entry, // entry count
|
|
||||||
uint *lapicaddr, // address of local APIC
|
|
||||||
ushort xlength, // extended table length
|
|
||||||
u8 xchecksum, // extended table checksum
|
|
||||||
u8 reserved,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[repr(C)]
|
|
||||||
struct mpproc { // processor table entry
|
|
||||||
u8 type; // entry type (0)
|
|
||||||
u8 apicid; // local APIC id
|
|
||||||
u8 version; // local APIC verison
|
|
||||||
u8 flags; // CPU flags
|
|
||||||
#define MPBOOT 0x02 // This proc is the bootstrap processor.
|
|
||||||
u8 signature[4]; // CPU signature
|
|
||||||
uint feature; // feature flags from CPUID instruction
|
|
||||||
u8 reserved[8];
|
|
||||||
}
|
|
||||||
|
|
||||||
struct mpioapic { // I/O APIC table entry
|
|
||||||
u8 type; // entry type (2)
|
|
||||||
u8 apicno; // I/O APIC id
|
|
||||||
u8 version; // I/O APIC version
|
|
||||||
u8 flags; // I/O APIC flags
|
|
||||||
uint *addr; // I/O APIC address
|
|
||||||
}
|
|
||||||
|
|
||||||
// Table entry types
|
|
||||||
const MPPROC : u8 = 0x00; // One per processor
|
|
||||||
const MPBUS : u8 = 0x01; // One per bus
|
|
||||||
const MPIOAPIC : u8 = 0x02; // One per I/O APIC
|
|
||||||
const MPIOINTR : u8 = 0x03; // One per bus interrupt source
|
|
||||||
const MPLINTR : u8 = 0x04; // One per system interrupt source
|
|
||||||
|
|
||||||
//PAGEBREAK!
|
|
||||||
// Blank page.
|
|
||||||
|
|
||||||
*/
|
|
@ -1,112 +1,24 @@
|
|||||||
use bit_allocator::{BitAlloc, BitAlloc64K};
|
use bit_allocator::BitAlloc;
|
||||||
use consts::KERNEL_OFFSET;
|
use consts::KERNEL_OFFSET;
|
||||||
// Depends on kernel
|
// Depends on kernel
|
||||||
use memory::{active_table, FRAME_ALLOCATOR, init_heap, MemoryArea, MemoryAttr, MemorySet, Stack};
|
use memory::{FRAME_ALLOCATOR, init_heap};
|
||||||
use super::multiboot2::{ElfSection, ElfSectionFlags, ElfSectionsTag};
|
use super::{BootInfo, MemoryRegionType};
|
||||||
use super::multiboot2::BootInformation;
|
|
||||||
use ucore_memory::PAGE_SIZE;
|
use ucore_memory::PAGE_SIZE;
|
||||||
use ucore_memory::paging::PageTable;
|
use ucore_memory::paging::PageTable;
|
||||||
|
|
||||||
// BootInformation may trigger page fault after kernel remap
|
pub fn init(boot_info: &BootInfo) {
|
||||||
// So just take its ownership
|
|
||||||
pub fn init(boot_info: BootInformation) {
|
|
||||||
assert_has_not_been_called!("memory::init must be called only once");
|
assert_has_not_been_called!("memory::init must be called only once");
|
||||||
info!("{:?}", boot_info);
|
init_frame_allocator(boot_info);
|
||||||
init_frame_allocator(&boot_info);
|
|
||||||
// remap_the_kernel(&boot_info);
|
|
||||||
init_heap();
|
init_heap();
|
||||||
|
info!("memory: init end");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn init_frame_allocator(boot_info: &BootInformation) {
|
/// Init FrameAllocator and insert all 'Usable' regions from BootInfo.
|
||||||
let memory_areas = boot_info.memory_map_tag().expect("Memory map tag required")
|
fn init_frame_allocator(boot_info: &BootInfo) {
|
||||||
.memory_areas();
|
|
||||||
let elf_sections = boot_info.elf_sections_tag().expect("Elf sections tag required")
|
|
||||||
.sections().filter(|s| s.is_allocated());
|
|
||||||
|
|
||||||
let mut ba = FRAME_ALLOCATOR.lock();
|
let mut ba = FRAME_ALLOCATOR.lock();
|
||||||
for area in memory_areas {
|
for region in boot_info.memory_map.iter() {
|
||||||
ba.insert(to_range(area.start_address() as usize, area.end_address() as usize));
|
if region.region_type == MemoryRegionType::Usable {
|
||||||
}
|
ba.insert(region.range.start_frame_number as usize..region.range.end_frame_number as usize);
|
||||||
for section in elf_sections {
|
|
||||||
ba.remove(to_range(section.start_address() as usize, section.end_address() as usize));
|
|
||||||
}
|
|
||||||
ba.remove(to_range(boot_info.start_address(), boot_info.end_address()));
|
|
||||||
|
|
||||||
use core::ops::Range;
|
|
||||||
fn to_range(mut start_addr: usize, mut end_addr: usize) -> Range<usize> {
|
|
||||||
use consts::KERNEL_OFFSET;
|
|
||||||
if start_addr >= KERNEL_OFFSET {
|
|
||||||
start_addr -= KERNEL_OFFSET;
|
|
||||||
}
|
|
||||||
if end_addr >= KERNEL_OFFSET {
|
|
||||||
end_addr -= KERNEL_OFFSET;
|
|
||||||
}
|
|
||||||
let page_start = start_addr / PAGE_SIZE;
|
|
||||||
let mut page_end = (end_addr - 1) / PAGE_SIZE + 1;
|
|
||||||
if page_end >= BitAlloc64K::CAP {
|
|
||||||
warn!("page num {:#x} out of range {:#x}", page_end, BitAlloc64K::CAP);
|
|
||||||
page_end = BitAlloc64K::CAP;
|
|
||||||
}
|
}
|
||||||
page_start..page_end
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remap_the_kernel(boot_info: &BootInformation) {
|
|
||||||
extern { fn stack_bottom(); }
|
|
||||||
extern { fn stack_top(); }
|
|
||||||
let kstack = Stack {
|
|
||||||
top: stack_top as usize + KERNEL_OFFSET,
|
|
||||||
bottom: stack_bottom as usize + PAGE_SIZE + KERNEL_OFFSET,
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut memory_set = memory_set_from(boot_info.elf_sections_tag().unwrap(), kstack);
|
|
||||||
|
|
||||||
use consts::{KERNEL_HEAP_OFFSET, KERNEL_HEAP_SIZE};
|
|
||||||
use super::smp::ENTRYOTHER_ADDR;
|
|
||||||
memory_set.push(MemoryArea::new_physical(0xb8000, 0xb9000, KERNEL_OFFSET, MemoryAttr::default(), "VGA"));
|
|
||||||
memory_set.push(MemoryArea::new_physical(0xfee00000, 0xfee01000, KERNEL_OFFSET, MemoryAttr::default(), "LAPIC"));
|
|
||||||
memory_set.push(MemoryArea::new_identity(0x07fe1000, 0x07fe1000 + PAGE_SIZE, MemoryAttr::default(), "RSDT"));
|
|
||||||
memory_set.push(MemoryArea::new_identity(0xfec00000, 0xfec00000 + PAGE_SIZE, MemoryAttr::default(), "IOAPIC"));
|
|
||||||
memory_set.push(MemoryArea::new(KERNEL_HEAP_OFFSET, KERNEL_HEAP_OFFSET + KERNEL_HEAP_SIZE, MemoryAttr::default(), "kernel_heap"));
|
|
||||||
memory_set.push(MemoryArea::new_identity(ENTRYOTHER_ADDR, ENTRYOTHER_ADDR + PAGE_SIZE, MemoryAttr::default().execute(), "entry_other.text"));
|
|
||||||
memory_set.push(MemoryArea::new_physical(0, 4096, KERNEL_OFFSET, MemoryAttr::default(), "entry_other.ctrl"));
|
|
||||||
debug!("{:#x?}", memory_set);
|
|
||||||
|
|
||||||
unsafe { memory_set.activate(); }
|
|
||||||
info!("NEW TABLE!!!");
|
|
||||||
|
|
||||||
use core::mem::forget;
|
|
||||||
forget(memory_set);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn memory_set_from(sections: ElfSectionsTag, kstack: Stack) -> MemorySet {
|
|
||||||
assert_has_not_been_called!();
|
|
||||||
// WARNING: must ensure it's large enough
|
|
||||||
static mut SPACE: [u8; 0x1000] = [0; 0x1000];
|
|
||||||
let mut set = unsafe { MemorySet::new_from_raw_space(&mut SPACE, kstack) };
|
|
||||||
for section in sections.sections().filter(|s| s.is_allocated()) {
|
|
||||||
set.push(memory_area_from(section));
|
|
||||||
}
|
|
||||||
set
|
|
||||||
}
|
|
||||||
|
|
||||||
fn memory_area_from(section: ElfSection) -> MemoryArea {
|
|
||||||
let mut start_addr = section.start_address() as usize;
|
|
||||||
let mut end_addr = section.end_address() as usize;
|
|
||||||
assert_eq!(start_addr % PAGE_SIZE, 0, "sections need to be page aligned");
|
|
||||||
let name = unsafe { &*(section.name() as *const str) };
|
|
||||||
if start_addr >= KERNEL_OFFSET {
|
|
||||||
start_addr -= KERNEL_OFFSET;
|
|
||||||
end_addr -= KERNEL_OFFSET;
|
|
||||||
}
|
|
||||||
MemoryArea::new_physical(start_addr, end_addr, KERNEL_OFFSET, memory_attr_from(section.flags()), name)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn memory_attr_from(elf_flags: ElfSectionFlags) -> MemoryAttr {
|
|
||||||
let mut flags = MemoryAttr::default();
|
|
||||||
|
|
||||||
if !elf_flags.contains(ElfSectionFlags::ALLOCATED) { flags = flags.hide(); }
|
|
||||||
if !elf_flags.contains(ElfSectionFlags::WRITABLE) { flags = flags.readonly(); }
|
|
||||||
if elf_flags.contains(ElfSectionFlags::EXECUTABLE) { flags = flags.execute(); }
|
|
||||||
flags
|
|
||||||
}
|
|
Loading…
Reference in new issue