Compare commits

...

3 Commits

17 changed files with 334 additions and 1 deletions

View File

@ -14,6 +14,7 @@ uint64_t gInitEndpointCap = 0;
uint64_t gBootDenaliVmmoCap = 0; uint64_t gBootDenaliVmmoCap = 0;
uint64_t gBootVictoriaFallsVmmoCap = 0; uint64_t gBootVictoriaFallsVmmoCap = 0;
uint64_t gBootPciVmmoCap = 0; uint64_t gBootPciVmmoCap = 0;
uint64_t gBootFramebufferVmmoCap = 0;
z_err_t ParseInitPort(uint64_t init_port_cap) { z_err_t ParseInitPort(uint64_t init_port_cap) {
PortServer port = PortServer::AdoptCap(init_port_cap); PortServer port = PortServer::AdoptCap(init_port_cap);
@ -40,6 +41,8 @@ z_err_t ParseInitPort(uint64_t init_port_cap) {
case Z_BOOT_PCI_VMMO: case Z_BOOT_PCI_VMMO:
gBootPciVmmoCap = init_cap; gBootPciVmmoCap = init_cap;
break; break;
case Z_BOOT_FRAMEBUFFER_INFO_VMMO:
gBootFramebufferVmmoCap = init_cap;
default: default:
dbgln("Unexpected init type {}, continuing.", init_sig); dbgln("Unexpected init type {}, continuing.", init_sig);
} }

View File

@ -1,6 +1,7 @@
interface Yellowstone { interface Yellowstone {
method RegisterEndpoint(RegisterEndpointRequest) -> (Empty); method RegisterEndpoint(RegisterEndpointRequest) -> (Empty);
method GetAhciInfo(Empty) -> (AhciInfo); method GetAhciInfo(Empty) -> (AhciInfo);
method GetFramebufferInfo(Empty) -> (FramebufferInfo);
method GetDenali(Empty) -> (DenaliInfo); method GetDenali(Empty) -> (DenaliInfo);
} }
@ -18,6 +19,23 @@ message AhciInfo {
u64 region_length; u64 region_length;
} }
message FramebufferInfo {
u64 address_phys;
u64 width;
u64 height;
u64 pitch;
// TODO: Add u16 & u8 to the yunq language so
// the following can be appropriate widths.
u64 bpp;
u64 memory_model;
u64 red_mask_size;
u64 red_mask_shift;
u64 green_mask_size;
u64 green_mask_shift;
u64 blue_mask_size;
u64 blue_mask_shift;
}
message DenaliInfo { message DenaliInfo {
capability denali_endpoint; capability denali_endpoint;
u64 device_id; u64 device_id;

View File

@ -72,7 +72,7 @@ glcr::ErrorCode YellowstoneClient::GetAhciInfo(const Empty& request, AhciInfo& r
glcr::ErrorCode YellowstoneClient::GetDenali(const Empty& request, DenaliInfo& response) { glcr::ErrorCode YellowstoneClient::GetFramebufferInfo(const Empty& request, FramebufferInfo& response) {
uint64_t buffer_size = kBufferSize; uint64_t buffer_size = kBufferSize;
uint64_t cap_size = kCapBufferSize; uint64_t cap_size = kCapBufferSize;
@ -103,3 +103,35 @@ glcr::ErrorCode YellowstoneClient::GetDenali(const Empty& request, DenaliInfo& r
} }
glcr::ErrorCode YellowstoneClient::GetDenali(const Empty& request, DenaliInfo& response) {
uint64_t buffer_size = kBufferSize;
uint64_t cap_size = kCapBufferSize;
const uint32_t kSentinel = 0xBEEFDEAD;
buffer_.WriteAt<uint32_t>(0, kSentinel);
buffer_.WriteAt<uint64_t>(8, 3);
cap_buffer_.Reset();
uint64_t length = request.SerializeToBytes(buffer_, /*offset=*/16, cap_buffer_);
buffer_.WriteAt<uint32_t>(4, 16 + length);
z_cap_t reply_port_cap;
RET_ERR(ZEndpointSend(endpoint_, 16 + length, buffer_.RawPtr(), cap_buffer_.UsedSlots(), cap_buffer_.RawPtr(), &reply_port_cap));
// FIXME: Add a way to zero out the first buffer.
RET_ERR(ZReplyPortRecv(reply_port_cap, &buffer_size, buffer_.RawPtr(), &cap_size, cap_buffer_.RawPtr()));
if (buffer_.At<uint32_t>(0) != kSentinel) {
return glcr::INVALID_RESPONSE;
}
// Check Response Code.
RET_ERR(buffer_.At<uint64_t>(8));
response.ParseFromBytes(buffer_, 16, cap_buffer_);
return glcr::OK;
}

View File

@ -21,6 +21,8 @@ class YellowstoneClient {
[[nodiscard]] glcr::ErrorCode GetAhciInfo(const Empty& request, AhciInfo& response); [[nodiscard]] glcr::ErrorCode GetAhciInfo(const Empty& request, AhciInfo& response);
[[nodiscard]] glcr::ErrorCode GetFramebufferInfo(const Empty& request, FramebufferInfo& response);
[[nodiscard]] glcr::ErrorCode GetDenali(const Empty& request, DenaliInfo& response); [[nodiscard]] glcr::ErrorCode GetDenali(const Empty& request, DenaliInfo& response);
private: private:

View File

@ -175,6 +175,130 @@ uint64_t AhciInfo::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset, gl
return next_extension; return next_extension;
} }
void FramebufferInfo::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset) {
CheckHeader(bytes);
// Parse address_phys.
set_address_phys(bytes.At<uint64_t>(offset + header_size + (8 * 0)));
// Parse width.
set_width(bytes.At<uint64_t>(offset + header_size + (8 * 1)));
// Parse height.
set_height(bytes.At<uint64_t>(offset + header_size + (8 * 2)));
// Parse pitch.
set_pitch(bytes.At<uint64_t>(offset + header_size + (8 * 3)));
// Parse bpp.
set_bpp(bytes.At<uint64_t>(offset + header_size + (8 * 4)));
// Parse memory_model.
set_memory_model(bytes.At<uint64_t>(offset + header_size + (8 * 5)));
// Parse red_mask_size.
set_red_mask_size(bytes.At<uint64_t>(offset + header_size + (8 * 6)));
// Parse red_mask_shift.
set_red_mask_shift(bytes.At<uint64_t>(offset + header_size + (8 * 7)));
// Parse green_mask_size.
set_green_mask_size(bytes.At<uint64_t>(offset + header_size + (8 * 8)));
// Parse green_mask_shift.
set_green_mask_shift(bytes.At<uint64_t>(offset + header_size + (8 * 9)));
// Parse blue_mask_size.
set_blue_mask_size(bytes.At<uint64_t>(offset + header_size + (8 * 10)));
// Parse blue_mask_shift.
set_blue_mask_shift(bytes.At<uint64_t>(offset + header_size + (8 * 11)));
}
void FramebufferInfo::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset, const glcr::CapBuffer& caps) {
CheckHeader(bytes);
// Parse address_phys.
set_address_phys(bytes.At<uint64_t>(offset + header_size + (8 * 0)));
// Parse width.
set_width(bytes.At<uint64_t>(offset + header_size + (8 * 1)));
// Parse height.
set_height(bytes.At<uint64_t>(offset + header_size + (8 * 2)));
// Parse pitch.
set_pitch(bytes.At<uint64_t>(offset + header_size + (8 * 3)));
// Parse bpp.
set_bpp(bytes.At<uint64_t>(offset + header_size + (8 * 4)));
// Parse memory_model.
set_memory_model(bytes.At<uint64_t>(offset + header_size + (8 * 5)));
// Parse red_mask_size.
set_red_mask_size(bytes.At<uint64_t>(offset + header_size + (8 * 6)));
// Parse red_mask_shift.
set_red_mask_shift(bytes.At<uint64_t>(offset + header_size + (8 * 7)));
// Parse green_mask_size.
set_green_mask_size(bytes.At<uint64_t>(offset + header_size + (8 * 8)));
// Parse green_mask_shift.
set_green_mask_shift(bytes.At<uint64_t>(offset + header_size + (8 * 9)));
// Parse blue_mask_size.
set_blue_mask_size(bytes.At<uint64_t>(offset + header_size + (8 * 10)));
// Parse blue_mask_shift.
set_blue_mask_shift(bytes.At<uint64_t>(offset + header_size + (8 * 11)));
}
uint64_t FramebufferInfo::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset) const {
uint32_t next_extension = header_size + 8 * 12;
const uint32_t core_size = next_extension;
// Write address_phys.
bytes.WriteAt<uint64_t>(offset + header_size + (8 * 0), address_phys());
// Write width.
bytes.WriteAt<uint64_t>(offset + header_size + (8 * 1), width());
// Write height.
bytes.WriteAt<uint64_t>(offset + header_size + (8 * 2), height());
// Write pitch.
bytes.WriteAt<uint64_t>(offset + header_size + (8 * 3), pitch());
// Write bpp.
bytes.WriteAt<uint64_t>(offset + header_size + (8 * 4), bpp());
// Write memory_model.
bytes.WriteAt<uint64_t>(offset + header_size + (8 * 5), memory_model());
// Write red_mask_size.
bytes.WriteAt<uint64_t>(offset + header_size + (8 * 6), red_mask_size());
// Write red_mask_shift.
bytes.WriteAt<uint64_t>(offset + header_size + (8 * 7), red_mask_shift());
// Write green_mask_size.
bytes.WriteAt<uint64_t>(offset + header_size + (8 * 8), green_mask_size());
// Write green_mask_shift.
bytes.WriteAt<uint64_t>(offset + header_size + (8 * 9), green_mask_shift());
// Write blue_mask_size.
bytes.WriteAt<uint64_t>(offset + header_size + (8 * 10), blue_mask_size());
// Write blue_mask_shift.
bytes.WriteAt<uint64_t>(offset + header_size + (8 * 11), blue_mask_shift());
// The next extension pointer is the length of the message.
WriteHeader(bytes, offset, core_size, next_extension);
return next_extension;
}
uint64_t FramebufferInfo::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset, glcr::CapBuffer& caps) const {
uint32_t next_extension = header_size + 8 * 12;
const uint32_t core_size = next_extension;
uint64_t next_cap = 0;
// Write address_phys.
bytes.WriteAt<uint64_t>(offset + header_size + (8 * 0), address_phys());
// Write width.
bytes.WriteAt<uint64_t>(offset + header_size + (8 * 1), width());
// Write height.
bytes.WriteAt<uint64_t>(offset + header_size + (8 * 2), height());
// Write pitch.
bytes.WriteAt<uint64_t>(offset + header_size + (8 * 3), pitch());
// Write bpp.
bytes.WriteAt<uint64_t>(offset + header_size + (8 * 4), bpp());
// Write memory_model.
bytes.WriteAt<uint64_t>(offset + header_size + (8 * 5), memory_model());
// Write red_mask_size.
bytes.WriteAt<uint64_t>(offset + header_size + (8 * 6), red_mask_size());
// Write red_mask_shift.
bytes.WriteAt<uint64_t>(offset + header_size + (8 * 7), red_mask_shift());
// Write green_mask_size.
bytes.WriteAt<uint64_t>(offset + header_size + (8 * 8), green_mask_size());
// Write green_mask_shift.
bytes.WriteAt<uint64_t>(offset + header_size + (8 * 9), green_mask_shift());
// Write blue_mask_size.
bytes.WriteAt<uint64_t>(offset + header_size + (8 * 10), blue_mask_size());
// Write blue_mask_shift.
bytes.WriteAt<uint64_t>(offset + header_size + (8 * 11), blue_mask_shift());
// The next extension pointer is the length of the message.
WriteHeader(bytes, offset, core_size, next_extension);
return next_extension;
}
void DenaliInfo::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset) { void DenaliInfo::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset) {
CheckHeader(bytes); CheckHeader(bytes);
// Parse denali_endpoint. // Parse denali_endpoint.

View File

@ -61,6 +61,57 @@ class AhciInfo {
z_cap_t ahci_region_; z_cap_t ahci_region_;
uint64_t region_length_; uint64_t region_length_;
};
class FramebufferInfo {
public:
FramebufferInfo() {}
// Delete copy and move until implemented.
FramebufferInfo(const FramebufferInfo&) = delete;
FramebufferInfo(FramebufferInfo&&) = delete;
void ParseFromBytes(const glcr::ByteBuffer&, uint64_t offset);
void ParseFromBytes(const glcr::ByteBuffer&, uint64_t offset, const glcr::CapBuffer&);
uint64_t SerializeToBytes(glcr::ByteBuffer&, uint64_t offset) const;
uint64_t SerializeToBytes(glcr::ByteBuffer&, uint64_t offset, glcr::CapBuffer&) const;
uint64_t address_phys() const { return address_phys_; }
void set_address_phys(const uint64_t& value) { address_phys_ = value; }
uint64_t width() const { return width_; }
void set_width(const uint64_t& value) { width_ = value; }
uint64_t height() const { return height_; }
void set_height(const uint64_t& value) { height_ = value; }
uint64_t pitch() const { return pitch_; }
void set_pitch(const uint64_t& value) { pitch_ = value; }
uint64_t bpp() const { return bpp_; }
void set_bpp(const uint64_t& value) { bpp_ = value; }
uint64_t memory_model() const { return memory_model_; }
void set_memory_model(const uint64_t& value) { memory_model_ = value; }
uint64_t red_mask_size() const { return red_mask_size_; }
void set_red_mask_size(const uint64_t& value) { red_mask_size_ = value; }
uint64_t red_mask_shift() const { return red_mask_shift_; }
void set_red_mask_shift(const uint64_t& value) { red_mask_shift_ = value; }
uint64_t green_mask_size() const { return green_mask_size_; }
void set_green_mask_size(const uint64_t& value) { green_mask_size_ = value; }
uint64_t green_mask_shift() const { return green_mask_shift_; }
void set_green_mask_shift(const uint64_t& value) { green_mask_shift_ = value; }
uint64_t blue_mask_size() const { return blue_mask_size_; }
void set_blue_mask_size(const uint64_t& value) { blue_mask_size_ = value; }
uint64_t blue_mask_shift() const { return blue_mask_shift_; }
void set_blue_mask_shift(const uint64_t& value) { blue_mask_shift_ = value; }
private:
uint64_t address_phys_;
uint64_t width_;
uint64_t height_;
uint64_t pitch_;
uint64_t bpp_;
uint64_t memory_model_;
uint64_t red_mask_size_;
uint64_t red_mask_shift_;
uint64_t green_mask_size_;
uint64_t green_mask_shift_;
uint64_t blue_mask_size_;
uint64_t blue_mask_shift_;
}; };
class DenaliInfo { class DenaliInfo {
public: public:

View File

@ -109,6 +109,17 @@ glcr::ErrorCode YellowstoneServerBase::HandleRequest(const glcr::ByteBuffer& req
break; break;
} }
case 2: { case 2: {
Empty yunq_request;
FramebufferInfo yunq_response;
yunq_request.ParseFromBytes(request, kHeaderSize, req_caps);
RET_ERR(HandleGetFramebufferInfo(yunq_request, yunq_response));
resp_length = yunq_response.SerializeToBytes(response, kHeaderSize, resp_caps);
break;
}
case 3: {
Empty yunq_request; Empty yunq_request;
DenaliInfo yunq_response; DenaliInfo yunq_response;

View File

@ -25,6 +25,8 @@ class YellowstoneServerBase {
[[nodiscard]] virtual glcr::ErrorCode HandleGetAhciInfo(const Empty&, AhciInfo&) = 0; [[nodiscard]] virtual glcr::ErrorCode HandleGetAhciInfo(const Empty&, AhciInfo&) = 0;
[[nodiscard]] virtual glcr::ErrorCode HandleGetFramebufferInfo(const Empty&, FramebufferInfo&) = 0;
[[nodiscard]] virtual glcr::ErrorCode HandleGetDenali(const Empty&, DenaliInfo&) = 0; [[nodiscard]] virtual glcr::ErrorCode HandleGetDenali(const Empty&, DenaliInfo&) = 0;

View File

@ -5,6 +5,7 @@
#include <mammoth/memory_region.h> #include <mammoth/memory_region.h>
#include <mammoth/process.h> #include <mammoth/process.h>
#include <zcall.h> #include <zcall.h>
#include <ztypes.h>
#include "hw/gpt.h" #include "hw/gpt.h"
#include "hw/pcie.h" #include "hw/pcie.h"

View File

@ -4,6 +4,7 @@
#include <glacier/string/string.h> #include <glacier/string/string.h>
#include <mammoth/debug.h> #include <mammoth/debug.h>
#include <mammoth/init.h> #include <mammoth/init.h>
#include <mammoth/memory_region.h>
#include <mammoth/process.h> #include <mammoth/process.h>
#include <stdlib.h> #include <stdlib.h>
@ -57,6 +58,29 @@ glcr::ErrorCode YellowstoneServer::HandleGetAhciInfo(const Empty&,
return glcr::OK; return glcr::OK;
} }
glcr::ErrorCode YellowstoneServer::HandleGetFramebufferInfo(
const Empty&, FramebufferInfo& info) {
// FIXME: Don't do this for each request.
MappedMemoryRegion region =
MappedMemoryRegion::FromCapability(gBootFramebufferVmmoCap);
ZFramebufferInfo* fb = reinterpret_cast<ZFramebufferInfo*>(region.vaddr());
info.set_address_phys(fb->address_phys);
info.set_width(fb->width);
info.set_height(fb->height);
info.set_pitch(fb->pitch);
info.set_bpp(fb->bpp);
info.set_memory_model(fb->memory_model);
info.set_red_mask_size(fb->red_mask_size);
info.set_red_mask_shift(fb->red_mask_shift);
info.set_green_mask_size(fb->green_mask_size);
info.set_green_mask_shift(fb->green_mask_shift);
info.set_blue_mask_size(fb->blue_mask_size);
info.set_blue_mask_shift(fb->blue_mask_shift);
return glcr::OK;
}
glcr::ErrorCode YellowstoneServer::HandleGetDenali(const Empty&, glcr::ErrorCode YellowstoneServer::HandleGetDenali(const Empty&,
DenaliInfo& info) { DenaliInfo& info) {
z_cap_t new_denali; z_cap_t new_denali;

View File

@ -17,6 +17,8 @@ class YellowstoneServer : public YellowstoneServerBase {
static glcr::ErrorOr<glcr::UniquePtr<YellowstoneServer>> Create(); static glcr::ErrorOr<glcr::UniquePtr<YellowstoneServer>> Create();
glcr::ErrorCode HandleGetAhciInfo(const Empty&, AhciInfo&) override; glcr::ErrorCode HandleGetAhciInfo(const Empty&, AhciInfo&) override;
glcr::ErrorCode HandleGetFramebufferInfo(const Empty&,
FramebufferInfo&) override;
glcr::ErrorCode HandleGetDenali(const Empty&, DenaliInfo&) override; glcr::ErrorCode HandleGetDenali(const Empty&, DenaliInfo&) override;
glcr::ErrorCode HandleRegisterEndpoint(const RegisterEndpointRequest&, glcr::ErrorCode HandleRegisterEndpoint(const RegisterEndpointRequest&,
Empty&) override; Empty&) override;

View File

@ -65,6 +65,9 @@ def lexer(program: str):
while program[current + 1].isalnum() or program[current + 1] == '_': while program[current + 1].isalnum() or program[current + 1] == '_':
current += 1 current += 1
tokens.append(Lexeme(LexemeType.NAME, program[start:current + 1])) tokens.append(Lexeme(LexemeType.NAME, program[start:current + 1]))
elif curr == '/' and program[current + 1] == '/':
while program[current] != '\n':
current += 1
else: else:
sys.exit("Got unexpected token %s on line %s." % (curr, line)) sys.exit("Got unexpected token %s on line %s." % (curr, line))

View File

@ -47,4 +47,19 @@ void* GetRsdpAddr() {
return gRsdpRequest.response->address; return gRsdpRequest.response->address;
} }
static volatile struct limine_framebuffer_request gFramebufferRequest {
.id = LIMINE_FRAMEBUFFER_REQUEST, .revision = 0, .response = 0,
};
const limine_framebuffer& GetFramebuffer() {
if (!gFramebufferRequest.response) {
panic("No framebuffer response from limine");
}
if (gFramebufferRequest.response->framebuffer_count < 1) {
panic("No framebuffers in response from limine.");
}
return *gFramebufferRequest.response->framebuffers[0];
}
} // namespace boot } // namespace boot

View File

@ -11,4 +11,6 @@ const limine_module_response& GetModules();
void* GetRsdpAddr(); void* GetRsdpAddr();
const limine_framebuffer& GetFramebuffer();
} // namespace boot } // namespace boot

View File

@ -10,3 +10,4 @@ extern uint64_t gInitEndpointCap;
extern uint64_t gBootDenaliVmmoCap; extern uint64_t gBootDenaliVmmoCap;
extern uint64_t gBootVictoriaFallsVmmoCap; extern uint64_t gBootVictoriaFallsVmmoCap;
extern uint64_t gBootPciVmmoCap; extern uint64_t gBootPciVmmoCap;
extern uint64_t gBootFramebufferVmmoCap;

View File

@ -109,3 +109,19 @@ const z_perm_t kZionPerm_All = -1;
#define Z_BOOT_DENALI_VMMO 0x4200'0000 #define Z_BOOT_DENALI_VMMO 0x4200'0000
#define Z_BOOT_VICTORIA_FALLS_VMMO 0x4200'0001 #define Z_BOOT_VICTORIA_FALLS_VMMO 0x4200'0001
#define Z_BOOT_PCI_VMMO 0x4200'0002 #define Z_BOOT_PCI_VMMO 0x4200'0002
#define Z_BOOT_FRAMEBUFFER_INFO_VMMO 0x4200'0003
struct ZFramebufferInfo {
uint64_t address_phys;
uint64_t width;
uint64_t height;
uint64_t pitch;
uint16_t bpp;
uint8_t memory_model;
uint8_t red_mask_size;
uint8_t red_mask_shift;
uint8_t green_mask_size;
uint8_t green_mask_shift;
uint8_t blue_mask_size;
uint8_t blue_mask_shift;
};

View File

@ -137,6 +137,30 @@ glcr::ErrorCode WritePciVmmo(glcr::RefPtr<Port> port, uint64_t id) {
return glcr::OK; return glcr::OK;
} }
void WriteFramebufferVmmo(glcr::RefPtr<Port> port) {
const limine_framebuffer& buf = boot::GetFramebuffer();
ZFramebufferInfo ubuf{
.address_phys = reinterpret_cast<uint64_t>(buf.address) -
boot::GetHigherHalfDirectMap(),
.width = buf.width,
.height = buf.height,
.pitch = buf.pitch,
.bpp = buf.bpp,
.memory_model = buf.memory_model,
.red_mask_size = buf.red_mask_size,
.red_mask_shift = buf.red_mask_shift,
.green_mask_size = buf.green_mask_size,
.green_mask_shift = buf.green_mask_shift,
.blue_mask_size = buf.blue_mask_size,
.blue_mask_shift = buf.blue_mask_shift,
};
glcr::RefPtr<MemoryObject> ubuf_vmmo =
glcr::MakeRefCounted<MemoryObject>(sizeof(ubuf));
ubuf_vmmo->CopyBytesToObject(reinterpret_cast<uint64_t>(&ubuf), sizeof(ubuf));
port->WriteKernel(Z_BOOT_FRAMEBUFFER_INFO_VMMO,
MakeRefCounted<Capability>(ubuf_vmmo));
}
} // namespace } // namespace
void LoadInitProgram() { void LoadInitProgram() {
@ -154,6 +178,8 @@ void LoadInitProgram() {
WriteInitProgram(port, "/sys/denali", Z_BOOT_DENALI_VMMO); WriteInitProgram(port, "/sys/denali", Z_BOOT_DENALI_VMMO);
WriteInitProgram(port, "/sys/victoriafalls", Z_BOOT_VICTORIA_FALLS_VMMO); WriteInitProgram(port, "/sys/victoriafalls", Z_BOOT_VICTORIA_FALLS_VMMO);
WriteFramebufferVmmo(port);
if (WritePciVmmo(port, Z_BOOT_PCI_VMMO) != glcr::OK) { if (WritePciVmmo(port, Z_BOOT_PCI_VMMO) != glcr::OK) {
panic("Failed to provide PCI info to init."); panic("Failed to provide PCI info to init.");
} }